1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
12 from Cura.gui import firmwareInstall
13 from Cura.gui import printWindow
14 from Cura.util import machineCom
15 from Cura.util import profile
16 from Cura.util import gcodeGenerator
17 from Cura.util.resources import getPathForImage
19 class InfoBox(wx.Panel):
20 def __init__(self, parent):
21 super(InfoBox, self).__init__(parent)
22 self.SetBackgroundColour('#FFFF80')
24 self.sizer = wx.GridBagSizer(5, 5)
25 self.SetSizer(self.sizer)
27 self.attentionBitmap = wx.Bitmap(getPathForImage('attention.png'))
28 self.errorBitmap = wx.Bitmap(getPathForImage('error.png'))
29 self.readyBitmap = wx.Bitmap(getPathForImage('ready.png'))
31 wx.Bitmap(getPathForImage('busy-0.png')),
32 wx.Bitmap(getPathForImage('busy-1.png')),
33 wx.Bitmap(getPathForImage('busy-2.png')),
34 wx.Bitmap(getPathForImage('busy-3.png'))
37 self.bitmap = wx.StaticBitmap(self, -1, wx.EmptyBitmapRGBA(24, 24, red=255, green=255, blue=255, alpha=1))
38 self.text = wx.StaticText(self, -1, '')
39 self.extraInfoButton = wx.Button(self, -1, 'i', style=wx.BU_EXACTFIT)
40 self.sizer.Add(self.bitmap, pos=(0, 0), flag=wx.ALL, border=5)
41 self.sizer.Add(self.text, pos=(0, 1), flag=wx.TOP | wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL, border=5)
42 self.sizer.Add(self.extraInfoButton, pos=(0,2), flag=wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, border=5)
43 self.sizer.AddGrowableCol(1)
45 self.extraInfoButton.Show(False)
47 self.extraInfoUrl = ''
49 self.timer = wx.Timer(self)
50 self.Bind(wx.EVT_TIMER, self.doBusyUpdate, self.timer)
51 self.Bind(wx.EVT_BUTTON, self.doExtraInfo, self.extraInfoButton)
54 def SetInfo(self, info):
55 self.SetBackgroundColour('#FFFF80')
56 self.text.SetLabel(info)
57 self.extraInfoButton.Show(False)
60 def SetError(self, info, extraInfoUrl):
61 self.extraInfoUrl = extraInfoUrl
62 self.SetBackgroundColour('#FF8080')
63 self.text.SetLabel(info)
64 self.extraInfoButton.Show(True)
66 self.SetErrorIndicator()
69 def SetAttention(self, info):
70 self.SetBackgroundColour('#FFFF80')
71 self.text.SetLabel(info)
72 self.extraInfoButton.Show(False)
73 self.SetAttentionIndicator()
77 def SetBusy(self, info):
79 self.SetBusyIndicator()
81 def SetBusyIndicator(self):
83 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
85 def doExtraInfo(self, e):
86 webbrowser.open(self.extraInfoUrl)
88 def doBusyUpdate(self, e):
89 if self.busyState is None:
92 if self.busyState >= len(self.busyBitmap):
94 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
96 def SetReadyIndicator(self):
98 self.bitmap.SetBitmap(self.readyBitmap)
100 def SetErrorIndicator(self):
101 self.busyState = None
102 self.bitmap.SetBitmap(self.errorBitmap)
104 def SetAttentionIndicator(self):
105 self.busyState = None
106 self.bitmap.SetBitmap(self.attentionBitmap)
109 class InfoPage(wx.wizard.WizardPageSimple):
110 def __init__(self, parent, title):
111 wx.wizard.WizardPageSimple.__init__(self, parent)
113 sizer = wx.GridBagSizer(5, 5)
117 title = wx.StaticText(self, -1, title)
118 title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
119 sizer.Add(title, pos=(0, 0), span=(1, 2), flag=wx.ALIGN_CENTRE | wx.ALL)
120 sizer.Add(wx.StaticLine(self, -1), pos=(1, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
121 sizer.AddGrowableCol(1)
125 def AddText(self, info):
126 text = wx.StaticText(self, -1, info)
127 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
131 def AddSeperator(self):
132 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
135 def AddHiddenSeperator(self):
138 def AddInfoBox(self):
139 infoBox = InfoBox(self)
140 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
144 def AddRadioButton(self, label, style=0):
145 radio = wx.RadioButton(self, -1, label, style=style)
146 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
150 def AddCheckbox(self, label, checked=False):
151 check = wx.CheckBox(self, -1)
152 text = wx.StaticText(self, -1, label)
153 check.SetValue(checked)
154 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
155 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 2), flag=wx.ALL)
159 def AddButton(self, label):
160 button = wx.Button(self, -1, label)
161 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
165 def AddDualButton(self, label1, label2):
166 button1 = wx.Button(self, -1, label1)
167 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
168 button2 = wx.Button(self, -1, label2)
169 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
171 return button1, button2
173 def AddTextCtrl(self, value):
174 ret = wx.TextCtrl(self, -1, value)
175 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
179 def AddLabelTextCtrl(self, info, value):
180 text = wx.StaticText(self, -1, info)
181 ret = wx.TextCtrl(self, -1, value)
182 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
183 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
187 def AddTextCtrlButton(self, value, buttonText):
188 text = wx.TextCtrl(self, -1, value)
189 button = wx.Button(self, -1, buttonText)
190 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
191 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
195 def AddBitmap(self, bitmap):
196 bitmap = wx.StaticBitmap(self, -1, bitmap)
197 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
201 def AddCheckmark(self, label, bitmap):
202 check = wx.StaticBitmap(self, -1, bitmap)
203 text = wx.StaticText(self, -1, label)
204 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
205 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 1), flag=wx.ALL)
216 class FirstInfoPage(InfoPage):
217 def __init__(self, parent):
218 super(FirstInfoPage, self).__init__(parent, "First time run wizard")
219 self.AddText('Welcome, and thanks for trying Cura!')
221 self.AddText('This wizard will help you with the following steps:')
222 self.AddText('* Configure Cura for your machine')
223 self.AddText('* Upgrade your firmware')
224 self.AddText('* Check if your machine is working safely')
225 self.AddText('* Level your printer bed')
227 #self.AddText('* Calibrate your machine')
228 #self.AddText('* Do your first print')
231 class RepRapInfoPage(InfoPage):
232 def __init__(self, parent):
233 super(RepRapInfoPage, self).__init__(parent, "RepRap information")
235 'RepRap machines are vastly different, and there is no\ndefault configuration in Cura for any of them.')
236 self.AddText('If you like a default profile for your machine added,\nthen make an issue on github.')
238 self.AddText('You will have to manually install Marlin or Sprinter firmware.')
240 self.machineWidth = self.AddLabelTextCtrl('Machine width (mm)', '80')
241 self.machineDepth = self.AddLabelTextCtrl('Machine depth (mm)', '80')
242 self.machineHeight = self.AddLabelTextCtrl('Machine height (mm)', '60')
243 self.nozzleSize = self.AddLabelTextCtrl('Nozzle size (mm)', '0.5')
244 self.heatedBed = self.AddCheckbox('Heated bed')
245 self.HomeAtCenter = self.AddCheckbox('Bed center is 0,0,0 (RoStock)')
248 profile.putPreference('machine_width', self.machineWidth.GetValue())
249 profile.putPreference('machine_depth', self.machineDepth.GetValue())
250 profile.putPreference('machine_height', self.machineHeight.GetValue())
251 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
252 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
253 profile.putPreference('has_heated_bed', str(self.heatedBed.GetValue()))
254 profile.putPreference('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
255 profile.putPreference('extruder_head_size_min_x', '0')
256 profile.putPreference('extruder_head_size_min_y', '0')
257 profile.putPreference('extruder_head_size_max_x', '0')
258 profile.putPreference('extruder_head_size_max_y', '0')
259 profile.putPreference('extruder_head_size_height', '0')
262 class MachineSelectPage(InfoPage):
263 def __init__(self, parent):
264 super(MachineSelectPage, self).__init__(parent, "Select your machine")
265 self.AddText('What kind of machine do you have:')
267 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2", style=wx.RB_GROUP)
268 self.Ultimaker2Radio.SetValue(True)
269 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
270 self.UltimakerRadio = self.AddRadioButton("Ultimaker")
271 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
272 self.OtherRadio = self.AddRadioButton("Other (Ex: RepRap)")
273 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
275 self.AddText('The collection of anonymous usage information helps with the continued improvement of Cura.')
276 self.AddText('This does NOT submit your models online nor gathers any privacy related information.')
277 self.SubmitUserStats = self.AddCheckbox('Submit anonymous usage information:')
278 self.AddText('For full details see: http://wiki.ultimaker.com/Cura:stats')
279 self.SubmitUserStats.SetValue(True)
281 def OnUltimaker2Select(self, e):
282 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
284 def OnUltimakerSelect(self, e):
285 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
287 def OnOtherSelect(self, e):
288 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().repRapInfoPage)
291 if self.Ultimaker2Radio.GetValue():
292 profile.putPreference('machine_width', '230')
293 profile.putPreference('machine_depth', '225')
294 profile.putPreference('machine_height', '205')
295 profile.putPreference('machine_type', 'ultimaker2')
296 profile.putPreference('machine_center_is_zero', 'False')
297 profile.putPreference('gcode_flavor', 'UltiGCode')
298 profile.putProfileSetting('nozzle_size', '0.4')
299 profile.putPreference('extruder_head_size_min_x', '75.0')
300 profile.putPreference('extruder_head_size_min_y', '18.0')
301 profile.putPreference('extruder_head_size_max_x', '18.0')
302 profile.putPreference('extruder_head_size_max_y', '35.0')
303 profile.putPreference('extruder_head_size_height', '60.0')
304 elif self.UltimakerRadio.GetValue():
305 profile.putPreference('machine_width', '205')
306 profile.putPreference('machine_depth', '205')
307 profile.putPreference('machine_height', '200')
308 profile.putPreference('machine_type', 'ultimaker')
309 profile.putPreference('machine_center_is_zero', 'False')
310 profile.putPreference('gcode_flavor', 'RepRap (Marlin/Sprinter)')
311 profile.putProfileSetting('nozzle_size', '0.4')
312 profile.putPreference('extruder_head_size_min_x', '75.0')
313 profile.putPreference('extruder_head_size_min_y', '18.0')
314 profile.putPreference('extruder_head_size_max_x', '18.0')
315 profile.putPreference('extruder_head_size_max_y', '35.0')
316 profile.putPreference('extruder_head_size_height', '60.0')
318 profile.putPreference('machine_width', '80')
319 profile.putPreference('machine_depth', '80')
320 profile.putPreference('machine_height', '60')
321 profile.putPreference('machine_type', 'reprap')
322 profile.putPreference('gcode_flavor', 'RepRap (Marlin/Sprinter)')
323 profile.putPreference('startMode', 'Normal')
324 profile.putProfileSetting('nozzle_size', '0.5')
325 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
326 if self.SubmitUserStats.GetValue():
327 profile.putPreference('submit_slice_information', 'True')
329 profile.putPreference('submit_slice_information', 'False')
331 class SelectParts(InfoPage):
332 def __init__(self, parent):
333 super(SelectParts, self).__init__(parent, "Select upgraded parts you have")
334 self.AddText('To assist you in having better default settings for your Ultimaker\nCura would like to know which upgrades you have in your machine.')
336 self.springExtruder = self.AddCheckbox('Extruder drive upgrade')
337 self.heatedBed = self.AddCheckbox('Heated printer bed (self built)')
338 self.dualExtrusion = self.AddCheckbox('Dual extrusion (experimental)')
340 self.AddText('If you have an Ultimaker bought after october 2012 you will have the\nExtruder drive upgrade. If you do not have this upgrade,\nit is highly recommended to improve reliability.')
341 self.AddText('This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094')
342 self.springExtruder.SetValue(True)
345 profile.putPreference('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
346 profile.putPreference('has_heated_bed', str(self.heatedBed.GetValue()))
347 if self.dualExtrusion.GetValue():
348 profile.putPreference('extruder_amount', '2')
349 profile.putPreference('machine_depth', '195')
351 profile.putPreference('extruder_amount', '1')
352 if profile.getPreference('ultimaker_extruder_upgrade') == 'True':
353 profile.putProfileSetting('retraction_enable', 'True')
355 profile.putProfileSetting('retraction_enable', 'False')
358 class UltimakerFirmwareUpgradePage(InfoPage):
359 def __init__(self, parent):
360 super(UltimakerFirmwareUpgradePage, self).__init__(parent, "Upgrade Ultimaker Firmware")
361 self.AddText('Firmware is the piece of software running directly on your 3D printer.\nThis firmware controls the step motors, regulates the temperature\nand ultimately makes your printer work.')
362 self.AddHiddenSeperator()
363 self.AddText('The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier.')
364 self.AddHiddenSeperator()
365 self.AddText('Cura requires these new features and thus\nyour firmware will most likely need to be upgraded.\nYou will get the chance to do so now.')
366 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
367 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
368 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
369 self.AddHiddenSeperator()
370 self.AddText('Do not upgrade to this firmware if:')
371 self.AddText('* You have an older machine based on ATMega1280')
372 self.AddText('* Have other changes in the firmware')
373 # button = self.AddButton('Goto this page for a custom firmware')
374 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
379 def OnUpgradeClick(self, e):
380 if firmwareInstall.InstallFirmware():
381 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
383 def OnSkipClick(self, e):
384 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
385 self.GetParent().ShowPage(self.GetNext())
387 def OnUrlClick(self, e):
388 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
390 class UltimakerCheckupPage(InfoPage):
391 def __init__(self, parent):
392 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
394 self.checkBitmap = wx.Bitmap(getPathForImage('checkmark.png'))
395 self.crossBitmap = wx.Bitmap(getPathForImage('cross.png'))
396 self.unknownBitmap = wx.Bitmap(getPathForImage('question.png'))
397 self.endStopNoneBitmap = wx.Bitmap(getPathForImage('endstop_none.png'))
398 self.endStopXMinBitmap = wx.Bitmap(getPathForImage('endstop_xmin.png'))
399 self.endStopXMaxBitmap = wx.Bitmap(getPathForImage('endstop_xmax.png'))
400 self.endStopYMinBitmap = wx.Bitmap(getPathForImage('endstop_ymin.png'))
401 self.endStopYMaxBitmap = wx.Bitmap(getPathForImage('endstop_ymax.png'))
402 self.endStopZMinBitmap = wx.Bitmap(getPathForImage('endstop_zmin.png'))
403 self.endStopZMaxBitmap = wx.Bitmap(getPathForImage('endstop_zmax.png'))
406 'It is a good idea to do a few sanity checks now on your Ultimaker.\nYou can skip these if you know your machine is functional.')
407 b1, b2 = self.AddDualButton('Run checks', 'Skip checks')
408 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
409 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
411 self.commState = self.AddCheckmark('Communication:', self.unknownBitmap)
412 self.tempState = self.AddCheckmark('Temperature:', self.unknownBitmap)
413 self.stopState = self.AddCheckmark('Endstops:', self.unknownBitmap)
415 self.infoBox = self.AddInfoBox()
416 self.machineState = self.AddText('')
417 self.temperatureLabel = self.AddText('')
418 self.errorLogButton = self.AddButton('Show error log')
419 self.errorLogButton.Show(False)
421 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
423 self.xMinStop = False
424 self.xMaxStop = False
425 self.yMinStop = False
426 self.yMaxStop = False
427 self.zMinStop = False
428 self.zMaxStop = False
430 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
433 if self.comm is not None:
437 self.endstopBitmap.Show(False)
440 def OnSkipClick(self, e):
441 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
442 self.GetParent().ShowPage(self.GetNext())
444 def OnCheckClick(self, e=None):
445 self.errorLogButton.Show(False)
446 if self.comm is not None:
450 wx.CallAfter(self.OnCheckClick)
452 self.infoBox.SetBusy('Connecting to machine.')
453 self.commState.SetBitmap(self.unknownBitmap)
454 self.tempState.SetBitmap(self.unknownBitmap)
455 self.stopState.SetBitmap(self.unknownBitmap)
456 self.checkupState = 0
457 self.checkExtruderNr = 0
458 self.comm = machineCom.MachineCom(callbackObject=self)
460 def OnErrorLog(self, e):
461 printWindow.LogWindow('\n'.join(self.comm.getLog()))
463 def mcLog(self, message):
466 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
467 if not self.comm.isOperational():
469 if self.checkupState == 0:
470 self.tempCheckTimeout = 20
471 if temp[self.checkExtruderNr] > 70:
472 self.checkupState = 1
473 wx.CallAfter(self.infoBox.SetInfo, 'Cooldown before temperature check.')
474 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
475 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
477 self.startTemp = temp[self.checkExtruderNr]
478 self.checkupState = 2
479 wx.CallAfter(self.infoBox.SetInfo, 'Checking the heater and temperature sensor.')
480 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
481 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
482 elif self.checkupState == 1:
484 self.startTemp = temp[self.checkExtruderNr]
485 self.checkupState = 2
486 wx.CallAfter(self.infoBox.SetInfo, 'Checking the heater and temperature sensor.')
487 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
488 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
489 elif self.checkupState == 2:
490 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
491 if temp[self.checkExtruderNr] > self.startTemp + 40:
492 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
493 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
494 if self.checkExtruderNr < int(profile.getPreference('extruder_amount')):
495 self.checkExtruderNr = 0
496 self.checkupState = 3
497 wx.CallAfter(self.infoBox.SetAttention, 'Please make sure none of the endstops are pressed.')
498 wx.CallAfter(self.endstopBitmap.Show, True)
499 wx.CallAfter(self.Layout)
500 self.comm.sendCommand('M119')
501 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
503 self.checkupState = 0
504 self.checkExtruderNr += 1
506 self.tempCheckTimeout -= 1
507 if self.tempCheckTimeout < 1:
508 self.checkupState = -1
509 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
510 wx.CallAfter(self.infoBox.SetError, 'Temperature measurement FAILED!', 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
511 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
512 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
513 elif self.checkupState >= 3 and self.checkupState < 10:
514 self.comm.sendCommand('M119')
515 wx.CallAfter(self.temperatureLabel.SetLabel, 'Head temperature: %d' % (temp[self.checkExtruderNr]))
517 def mcStateChange(self, state):
518 if self.comm is None:
520 if self.comm.isOperational():
521 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
522 wx.CallAfter(self.machineState.SetLabel, 'Communication State: %s' % (self.comm.getStateString()))
523 elif self.comm.isError():
524 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
525 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
526 wx.CallAfter(self.endstopBitmap.Show, False)
527 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
528 wx.CallAfter(self.errorLogButton.Show, True)
529 wx.CallAfter(self.Layout)
531 wx.CallAfter(self.machineState.SetLabel, 'Communication State: %s' % (self.comm.getStateString()))
533 def mcMessage(self, message):
534 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
535 for data in message.split(' '):
537 tag, value = data.split(':', 1)
539 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
541 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
543 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
545 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
547 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
549 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
551 tag, value = map(str.strip, message.split(':', 1))
553 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
555 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
557 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
559 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
561 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
563 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
564 if 'z_max' in message:
565 self.comm.sendCommand('M119')
567 if self.checkupState == 3:
568 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
569 self.checkupState = 4
570 wx.CallAfter(self.infoBox.SetAttention, 'Please press the right X endstop.')
571 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
572 elif self.checkupState == 4:
573 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
574 self.checkupState = 5
575 wx.CallAfter(self.infoBox.SetAttention, 'Please press the left X endstop.')
576 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
577 elif self.checkupState == 5:
578 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
579 self.checkupState = 6
580 wx.CallAfter(self.infoBox.SetAttention, 'Please press the front Y endstop.')
581 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
582 elif self.checkupState == 6:
583 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
584 self.checkupState = 7
585 wx.CallAfter(self.infoBox.SetAttention, 'Please press the back Y endstop.')
586 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
587 elif self.checkupState == 7:
588 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
589 self.checkupState = 8
590 wx.CallAfter(self.infoBox.SetAttention, 'Please press the top Z endstop.')
591 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
592 elif self.checkupState == 8:
593 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
594 self.checkupState = 9
595 wx.CallAfter(self.infoBox.SetAttention, 'Please press the bottom Z endstop.')
596 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
597 elif self.checkupState == 9:
598 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
599 self.checkupState = 10
601 wx.CallAfter(self.infoBox.SetInfo, 'Checkup finished')
602 wx.CallAfter(self.infoBox.SetReadyIndicator)
603 wx.CallAfter(self.endstopBitmap.Show, False)
604 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
605 wx.CallAfter(self.OnSkipClick, None)
607 def mcProgress(self, lineNr):
610 def mcZChange(self, newZ):
614 class UltimakerCalibrationPage(InfoPage):
615 def __init__(self, parent):
616 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
618 self.AddText("Your Ultimaker requires some calibration.")
619 self.AddText("This calibration is needed for a proper extrusion amount.")
621 self.AddText("The following values are needed:")
622 self.AddText("* Diameter of filament")
623 self.AddText("* Number of steps per mm of filament extrusion")
625 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
627 self.AddText("First we need the diameter of your filament:")
628 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
630 "If you do not own digital Calipers that can measure\nat least 2 digits then use 2.89mm.\nWhich is the average diameter of most filament.")
631 self.AddText("Note: This value can be changed later at any time.")
634 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
637 class UltimakerCalibrateStepsPerEPage(InfoPage):
638 def __init__(self, parent):
639 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
641 #if profile.getPreference('steps_per_e') == '0':
642 # profile.putPreference('steps_per_e', '865.888')
644 self.AddText("Calibrating the Steps Per E requires some manual actions.")
645 self.AddText("First remove any filament from your machine.")
646 self.AddText("Next put in your filament so the tip is aligned with the\ntop of the extruder drive.")
647 self.AddText("We'll push the filament 100mm")
648 self.extrudeButton = self.AddButton("Extrude 100mm filament")
649 self.AddText("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)")
650 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton('100', 'Save')
651 self.AddText("This results in the following steps per E:")
652 self.stepsPerEInput = self.AddTextCtrl(profile.getPreference('steps_per_e'))
653 self.AddText("You can repeat these steps to get better calibration.")
656 "If you still have filament in your printer which needs\nheat to remove, press the heat up button below:")
657 self.heatButton = self.AddButton("Heatup for filament removal")
659 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
660 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
661 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
663 def OnSaveLengthClick(self, e):
664 currentEValue = float(self.stepsPerEInput.GetValue())
665 realExtrudeLength = float(self.lengthInput.GetValue())
666 newEValue = currentEValue * 100 / realExtrudeLength
667 self.stepsPerEInput.SetValue(str(newEValue))
668 self.lengthInput.SetValue("100")
670 def OnExtrudeClick(self, e):
671 threading.Thread(target=self.OnExtrudeRun).start()
673 def OnExtrudeRun(self):
674 self.heatButton.Enable(False)
675 self.extrudeButton.Enable(False)
676 currentEValue = float(self.stepsPerEInput.GetValue())
677 self.comm = machineCom.MachineCom()
678 if not self.comm.isOpen():
680 "Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable",
681 'Printer error', wx.OK | wx.ICON_INFORMATION)
682 self.heatButton.Enable(True)
683 self.extrudeButton.Enable(True)
686 line = self.comm.readline()
691 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
694 self.sendGCommand('M302') #Disable cold extrusion protection
695 self.sendGCommand("M92 E%f" % (currentEValue))
696 self.sendGCommand("G92 E0")
697 self.sendGCommand("G1 E100 F600")
700 self.extrudeButton.Enable()
701 self.heatButton.Enable()
703 def OnHeatClick(self, e):
704 threading.Thread(target=self.OnHeatRun).start()
707 self.heatButton.Enable(False)
708 self.extrudeButton.Enable(False)
709 self.comm = machineCom.MachineCom()
710 if not self.comm.isOpen():
712 "Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable",
713 'Printer error', wx.OK | wx.ICON_INFORMATION)
714 self.heatButton.Enable(True)
715 self.extrudeButton.Enable(True)
718 line = self.comm.readline()
720 self.heatButton.Enable(True)
721 self.extrudeButton.Enable(True)
725 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
728 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
730 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
731 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
732 self.sendGCommand('M104 S0')
735 self.heatButton.Enable(True)
736 self.extrudeButton.Enable(True)
738 def sendGCommand(self, cmd):
739 self.comm.sendCommand(cmd) #Disable cold extrusion protection
741 line = self.comm.readline()
744 if line.startswith('ok'):
748 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
750 class Ultimaker2ReadyPage(InfoPage):
751 def __init__(self, parent):
752 super(Ultimaker2ReadyPage, self).__init__(parent, "Ultimaker2")
753 self.AddText('Congratulations on your the purchase of your brand new Ultimaker2.')
754 self.AddText('Cura is now ready to be used with your Ultimaker2.')
757 class configWizard(wx.wizard.Wizard):
759 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
761 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
762 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
764 self.firstInfoPage = FirstInfoPage(self)
765 self.machineSelectPage = MachineSelectPage(self)
766 self.ultimakerSelectParts = SelectParts(self)
767 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
768 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
769 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
770 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
771 self.bedLevelPage = bedLevelWizardMain(self)
772 self.headOffsetCalibration = headOffsetCalibrationPage(self)
773 self.repRapInfoPage = RepRapInfoPage(self)
775 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
777 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
778 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
779 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
780 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
781 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
782 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
784 self.FitToPage(self.firstInfoPage)
785 self.GetPageAreaSizer().Add(self.firstInfoPage)
787 self.RunWizard(self.firstInfoPage)
790 def OnPageChanging(self, e):
791 e.GetPage().StoreData()
793 def OnPageChanged(self, e):
794 if e.GetPage().AllowNext():
795 self.FindWindowById(wx.ID_FORWARD).Enable()
797 self.FindWindowById(wx.ID_FORWARD).Disable()
798 self.FindWindowById(wx.ID_BACKWARD).Disable()
800 class bedLevelWizardMain(InfoPage):
801 def __init__(self, parent):
802 super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
804 self.AddText('This wizard will help you in leveling your printer bed')
806 self.AddText('It will do the following steps')
807 self.AddText('* Move the printer head to each corner')
808 self.AddText(' and let you adjust the height of the bed to the nozzle')
809 self.AddText('* Print a line around the bed to check if it is level')
812 self.connectButton = self.AddButton('Connect to printer')
815 self.infoBox = self.AddInfoBox()
816 self.resumeButton = self.AddButton('Resume')
817 self.resumeButton.Enable(False)
819 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
820 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
822 def OnConnect(self, e = None):
823 if self.comm is not None:
827 wx.CallAfter(self.OnConnect)
829 self.connectButton.Enable(False)
830 self.comm = machineCom.MachineCom(callbackObject=self)
831 self.infoBox.SetBusy('Connecting to machine.')
832 self._wizardState = 0
835 if self.GetParent().headOffsetCalibration is not None and int(profile.getPreference('extruder_amount')) > 1:
836 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
839 def OnResume(self, e):
840 feedZ = profile.getProfileSettingFloat('print_speed') * 60
841 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
842 if self._wizardState == 2:
843 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
844 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
845 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getPreferenceFloat('machine_depth'), feedTravel))
846 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
847 self.comm.sendCommand('M400')
848 self._wizardState = 3
849 elif self._wizardState == 4:
850 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
851 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
852 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getPreferenceFloat('machine_width') - 5.0, profile.getPreferenceFloat('machine_depth') - 25, feedTravel))
853 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
854 self.comm.sendCommand('M400')
855 self._wizardState = 5
856 elif self._wizardState == 6:
857 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
858 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
859 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getPreferenceFloat('machine_width') - 5.0, 20, feedTravel))
860 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
861 self.comm.sendCommand('M400')
862 self._wizardState = 7
863 elif self._wizardState == 8:
864 wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
865 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
866 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
867 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
868 self._wizardState = 9
869 elif self._wizardState == 10:
870 self._wizardState = 11
871 wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
872 feedZ = profile.getProfileSettingFloat('print_speed') * 60
873 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
874 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
875 w = profile.getPreferenceFloat('machine_width')
876 d = profile.getPreferenceFloat('machine_depth')
877 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
878 filamentArea = math.pi * filamentRadius * filamentRadius
879 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
883 'G1 Z2 F%d' % (feedZ),
885 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
886 'G1 Z0.3 F%d' % (feedZ)]
888 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
890 for i in xrange(0, 3):
891 dist = 5.0 + 0.4 * float(i)
892 eValue += (d - 2.0*dist) * ePerMM
893 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
894 eValue += (w - 2.0*dist) * ePerMM
895 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
896 eValue += (d - 2.0*dist) * ePerMM
897 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
898 eValue += (w - 2.0*dist) * ePerMM
899 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
901 gcodeList.append('M400')
902 self.comm.printGCode(gcodeList)
903 self.resumeButton.Enable(False)
905 def mcLog(self, message):
906 print 'Log:', message
908 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
909 if self._wizardState == 1:
910 self._wizardState = 2
911 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
912 wx.CallAfter(self.resumeButton.Enable, True)
913 elif self._wizardState == 3:
914 self._wizardState = 4
915 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
916 wx.CallAfter(self.resumeButton.Enable, True)
917 elif self._wizardState == 5:
918 self._wizardState = 6
919 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
920 wx.CallAfter(self.resumeButton.Enable, True)
921 elif self._wizardState == 7:
922 self._wizardState = 8
923 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
924 wx.CallAfter(self.resumeButton.Enable, True)
925 elif self._wizardState == 9:
926 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
927 wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
929 wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
930 wx.CallAfter(self.resumeButton.Enable, True)
931 self._wizardState = 10
933 def mcStateChange(self, state):
934 if self.comm is None:
936 if self.comm.isOperational():
937 if self._wizardState == 0:
938 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
939 self.comm.sendCommand('M105')
940 self.comm.sendCommand('G28')
941 self._wizardState = 1
942 elif self._wizardState == 11 and not self.comm.isPrinting():
943 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
944 self.comm.sendCommand('G92 E0')
945 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
946 self.comm.sendCommand('M104 S0')
947 wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
948 wx.CallAfter(self.infoBox.SetReadyIndicator)
949 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
950 wx.CallAfter(self.connectButton.Enable, True)
951 self._wizardState = 12
952 elif self.comm.isError():
953 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
955 def mcMessage(self, message):
958 def mcProgress(self, lineNr):
961 def mcZChange(self, newZ):
964 class headOffsetCalibrationPage(InfoPage):
965 def __init__(self, parent):
966 super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
968 self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
971 self.connectButton = self.AddButton('Connect to printer')
974 self.infoBox = self.AddInfoBox()
975 self.textEntry = self.AddTextCtrl('')
976 self.textEntry.Enable(False)
977 self.resumeButton = self.AddButton('Resume')
978 self.resumeButton.Enable(False)
980 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
981 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
983 def OnConnect(self, e = None):
984 if self.comm is not None:
988 wx.CallAfter(self.OnConnect)
990 self.connectButton.Enable(False)
991 self.comm = machineCom.MachineCom(callbackObject=self)
992 self.infoBox.SetBusy('Connecting to machine.')
993 self._wizardState = 0
995 def OnResume(self, e):
996 if self._wizardState == 2:
997 self._wizardState = 3
998 wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
1000 w = profile.getPreferenceFloat('machine_width')
1001 d = profile.getPreferenceFloat('machine_depth')
1003 gcode = gcodeGenerator.gcodeGenerator()
1004 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1005 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1012 gcode.addMove(w/2, 5)
1013 gcode.addMove(z=0.2)
1015 gcode.addExtrude(w/2, d-5.0)
1017 gcode.addMove(5, d/2)
1019 gcode.addExtrude(w-5.0, d/2)
1020 gcode.addRetract(15)
1023 gcode.addMove(w/2, 5)
1025 gcode.addExtrude(w/2, d-5.0)
1027 gcode.addMove(5, d/2)
1029 gcode.addExtrude(w-5.0, d/2)
1030 gcode.addRetract(15)
1035 gcode.addCmd('M400')
1037 self.comm.printGCode(gcode.list())
1038 self.resumeButton.Enable(False)
1039 elif self._wizardState == 4:
1041 float(self.textEntry.GetValue())
1044 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1045 self._wizardState = 5
1046 self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
1047 self.textEntry.SetValue('0.0')
1048 self.textEntry.Enable(True)
1049 elif self._wizardState == 5:
1051 float(self.textEntry.GetValue())
1054 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1055 self._wizardState = 6
1056 self.infoBox.SetBusy('Printing the fine calibration lines.')
1057 self.textEntry.SetValue('')
1058 self.textEntry.Enable(False)
1059 self.resumeButton.Enable(False)
1061 x = profile.getPreferenceFloat('extruder_offset_x1')
1062 y = profile.getPreferenceFloat('extruder_offset_y1')
1063 gcode = gcodeGenerator.gcodeGenerator()
1064 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1065 gcode.setPrintSpeed(25)
1068 gcode.addMove(50, 40, 0.2)
1070 for n in xrange(0, 10):
1071 gcode.addExtrude(50 + n * 10, 150)
1072 gcode.addExtrude(50 + n * 10 + 5, 150)
1073 gcode.addExtrude(50 + n * 10 + 5, 40)
1074 gcode.addExtrude(50 + n * 10 + 10, 40)
1075 gcode.addMove(40, 50)
1076 for n in xrange(0, 10):
1077 gcode.addExtrude(150, 50 + n * 10)
1078 gcode.addExtrude(150, 50 + n * 10 + 5)
1079 gcode.addExtrude(40, 50 + n * 10 + 5)
1080 gcode.addExtrude(40, 50 + n * 10 + 10)
1081 gcode.addRetract(15)
1084 gcode.addMove(50 - x, 30 - y, 0.2)
1086 for n in xrange(0, 10):
1087 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1088 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1089 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1090 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1091 gcode.addMove(30 - x, 50 - y, 0.2)
1092 for n in xrange(0, 10):
1093 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1094 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1095 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1096 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1097 gcode.addRetract(15)
1099 gcode.addCmd('M400')
1100 gcode.addCmd('M104 T0 S0')
1101 gcode.addCmd('M104 T1 S0')
1102 self.comm.printGCode(gcode.list())
1103 elif self._wizardState == 7:
1105 n = int(self.textEntry.GetValue()) - 1
1108 x = profile.getPreferenceFloat('extruder_offset_x1')
1110 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1111 self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
1112 self.textEntry.SetValue('10')
1113 self._wizardState = 8
1114 elif self._wizardState == 8:
1116 n = int(self.textEntry.GetValue()) - 1
1119 y = profile.getPreferenceFloat('extruder_offset_y1')
1121 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1122 self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getPreferenceFloat('extruder_offset_x1'), profile.getPreferenceFloat('extruder_offset_y1')))
1123 self.infoBox.SetReadyIndicator()
1124 self._wizardState = 8
1126 self.resumeButton.Enable(False)
1128 def mcLog(self, message):
1129 print 'Log:', message
1131 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1132 if self._wizardState == 1:
1133 if temp[0] >= 210 and temp[1] >= 210:
1134 self._wizardState = 2
1135 wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
1136 wx.CallAfter(self.resumeButton.Enable, True)
1137 wx.CallAfter(self.resumeButton.SetFocus)
1139 def mcStateChange(self, state):
1140 if self.comm is None:
1142 if self.comm.isOperational():
1143 if self._wizardState == 0:
1144 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
1145 self.comm.sendCommand('M105')
1146 self.comm.sendCommand('M104 S220 T0')
1147 self.comm.sendCommand('M104 S220 T1')
1148 self.comm.sendCommand('G28')
1149 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1150 self._wizardState = 1
1151 if not self.comm.isPrinting():
1152 if self._wizardState == 3:
1153 self._wizardState = 4
1154 wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
1155 wx.CallAfter(self.textEntry.SetValue, '0.0')
1156 wx.CallAfter(self.textEntry.Enable, True)
1157 wx.CallAfter(self.resumeButton.Enable, True)
1158 wx.CallAfter(self.resumeButton.SetFocus)
1159 elif self._wizardState == 6:
1160 self._wizardState = 7
1161 wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
1162 wx.CallAfter(self.textEntry.SetValue, '10')
1163 wx.CallAfter(self.textEntry.Enable, True)
1164 wx.CallAfter(self.resumeButton.Enable, True)
1165 wx.CallAfter(self.resumeButton.SetFocus)
1167 elif self.comm.isError():
1168 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1170 def mcMessage(self, message):
1173 def mcProgress(self, lineNr):
1176 def mcZChange(self, newZ):
1179 class bedLevelWizard(wx.wizard.Wizard):
1181 super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
1183 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1184 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1186 self.mainPage = bedLevelWizardMain(self)
1187 self.headOffsetCalibration = None
1189 self.FitToPage(self.mainPage)
1190 self.GetPageAreaSizer().Add(self.mainPage)
1192 self.RunWizard(self.mainPage)
1195 def OnPageChanging(self, e):
1196 e.GetPage().StoreData()
1198 def OnPageChanged(self, e):
1199 if e.GetPage().AllowNext():
1200 self.FindWindowById(wx.ID_FORWARD).Enable()
1202 self.FindWindowById(wx.ID_FORWARD).Disable()
1203 self.FindWindowById(wx.ID_BACKWARD).Disable()
1205 class headOffsetWizard(wx.wizard.Wizard):
1207 super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
1209 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1210 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1212 self.mainPage = headOffsetCalibrationPage(self)
1214 self.FitToPage(self.mainPage)
1215 self.GetPageAreaSizer().Add(self.mainPage)
1217 self.RunWizard(self.mainPage)
1220 def OnPageChanging(self, e):
1221 e.GetPage().StoreData()
1223 def OnPageChanged(self, e):
1224 if e.GetPage().AllowNext():
1225 self.FindWindowById(wx.ID_FORWARD).Enable()
1227 self.FindWindowById(wx.ID_FORWARD).Disable()
1228 self.FindWindowById(wx.ID_BACKWARD).Disable()