1 __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 import resources
20 class InfoBox(wx.Panel):
21 def __init__(self, parent):
22 super(InfoBox, self).__init__(parent)
23 self.SetBackgroundColour('#FFFF80')
25 self.sizer = wx.GridBagSizer(5, 5)
26 self.SetSizer(self.sizer)
28 self.attentionBitmap = wx.Bitmap(resources.getPathForImage('attention.png'))
29 self.errorBitmap = wx.Bitmap(resources.getPathForImage('error.png'))
30 self.readyBitmap = wx.Bitmap(resources.getPathForImage('ready.png'))
32 wx.Bitmap(resources.getPathForImage('busy-0.png')),
33 wx.Bitmap(resources.getPathForImage('busy-1.png')),
34 wx.Bitmap(resources.getPathForImage('busy-2.png')),
35 wx.Bitmap(resources.getPathForImage('busy-3.png'))
38 self.bitmap = wx.StaticBitmap(self, -1, wx.EmptyBitmapRGBA(24, 24, red=255, green=255, blue=255, alpha=1))
39 self.text = wx.StaticText(self, -1, '')
40 self.extraInfoButton = wx.Button(self, -1, 'i', style=wx.BU_EXACTFIT)
41 self.sizer.Add(self.bitmap, pos=(0, 0), flag=wx.ALL, border=5)
42 self.sizer.Add(self.text, pos=(0, 1), flag=wx.TOP | wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL, border=5)
43 self.sizer.Add(self.extraInfoButton, pos=(0,2), flag=wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, border=5)
44 self.sizer.AddGrowableCol(1)
46 self.extraInfoButton.Show(False)
48 self.extraInfoUrl = ''
50 self.timer = wx.Timer(self)
51 self.Bind(wx.EVT_TIMER, self.doBusyUpdate, self.timer)
52 self.Bind(wx.EVT_BUTTON, self.doExtraInfo, self.extraInfoButton)
55 def SetInfo(self, info):
56 self.SetBackgroundColour('#FFFF80')
57 self.text.SetLabel(info)
58 self.extraInfoButton.Show(False)
61 def SetError(self, info, extraInfoUrl):
62 self.extraInfoUrl = extraInfoUrl
63 self.SetBackgroundColour('#FF8080')
64 self.text.SetLabel(info)
65 self.extraInfoButton.Show(True)
67 self.SetErrorIndicator()
70 def SetAttention(self, info):
71 self.SetBackgroundColour('#FFFF80')
72 self.text.SetLabel(info)
73 self.extraInfoButton.Show(False)
74 self.SetAttentionIndicator()
78 def SetBusy(self, info):
80 self.SetBusyIndicator()
82 def SetBusyIndicator(self):
84 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
86 def doExtraInfo(self, e):
87 webbrowser.open(self.extraInfoUrl)
89 def doBusyUpdate(self, e):
90 if self.busyState is None:
93 if self.busyState >= len(self.busyBitmap):
95 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
97 def SetReadyIndicator(self):
99 self.bitmap.SetBitmap(self.readyBitmap)
101 def SetErrorIndicator(self):
102 self.busyState = None
103 self.bitmap.SetBitmap(self.errorBitmap)
105 def SetAttentionIndicator(self):
106 self.busyState = None
107 self.bitmap.SetBitmap(self.attentionBitmap)
110 class InfoPage(wx.wizard.WizardPageSimple):
111 def __init__(self, parent, title):
112 wx.wizard.WizardPageSimple.__init__(self, parent)
114 sizer = wx.GridBagSizer(5, 5)
118 title = wx.StaticText(self, -1, title)
119 title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
120 sizer.Add(title, pos=(0, 0), span=(1, 2), flag=wx.ALIGN_CENTRE | wx.ALL)
121 sizer.Add(wx.StaticLine(self, -1), pos=(1, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
122 sizer.AddGrowableCol(1)
126 def AddText(self, info):
127 text = wx.StaticText(self, -1, info)
128 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
132 def AddSeperator(self):
133 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
136 def AddHiddenSeperator(self):
139 def AddInfoBox(self):
140 infoBox = InfoBox(self)
141 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
145 def AddRadioButton(self, label, style=0):
146 radio = wx.RadioButton(self, -1, label, style=style)
147 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
151 def AddCheckbox(self, label, checked=False):
152 check = wx.CheckBox(self, -1)
153 text = wx.StaticText(self, -1, label)
154 check.SetValue(checked)
155 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
156 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 2), flag=wx.ALL)
160 def AddButton(self, label):
161 button = wx.Button(self, -1, label)
162 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
166 def AddDualButton(self, label1, label2):
167 button1 = wx.Button(self, -1, label1)
168 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
169 button2 = wx.Button(self, -1, label2)
170 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
172 return button1, button2
174 def AddTextCtrl(self, value):
175 ret = wx.TextCtrl(self, -1, value)
176 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
180 def AddLabelTextCtrl(self, info, value):
181 text = wx.StaticText(self, -1, info)
182 ret = wx.TextCtrl(self, -1, value)
183 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
184 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
188 def AddTextCtrlButton(self, value, buttonText):
189 text = wx.TextCtrl(self, -1, value)
190 button = wx.Button(self, -1, buttonText)
191 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
192 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
196 def AddBitmap(self, bitmap):
197 bitmap = wx.StaticBitmap(self, -1, bitmap)
198 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
202 def AddCheckmark(self, label, bitmap):
203 check = wx.StaticBitmap(self, -1, bitmap)
204 text = wx.StaticText(self, -1, label)
205 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
206 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 1), flag=wx.ALL)
220 class FirstInfoPage(InfoPage):
221 def __init__(self, parent, addNew):
223 super(FirstInfoPage, self).__init__(parent, _("Add new machine wizard"))
225 super(FirstInfoPage, self).__init__(parent, _("First time run wizard"))
226 self.AddText(_("Welcome, and thanks for trying Cura!"))
228 self.AddText(_("This wizard will help you in setting up Cura for your machine."))
229 # self.AddText(_("This wizard will help you with the following steps:"))
230 # self.AddText(_("* Configure Cura for your machine"))
231 # self.AddText(_("* Optionally upgrade your firmware"))
232 # self.AddText(_("* Optionally check if your machine is working safely"))
233 # self.AddText(_("* Optionally level your printer bed"))
235 #self.AddText('* Calibrate your machine')
236 #self.AddText('* Do your first print')
242 class OtherMachineSelectPage(InfoPage):
243 def __init__(self, parent):
244 super(OtherMachineSelectPage, self).__init__(parent, "Other machine information")
245 self.AddText(_("The following pre-defined machine profiles are available"))
246 self.AddText(_("Note that these profiles are not guaranteed to give good results,\nor work at all. Extra tweaks might be required.\nIf you find issues with the predefined profiles,\nor want an extra profile.\nPlease report it at the github issue tracker."))
248 machines = resources.getDefaultMachineProfiles()
250 for filename in machines:
251 name = os.path.splitext(os.path.basename(filename))[0]
252 item = self.AddRadioButton(name)
253 item.filename = filename
254 item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
255 self.options.append(item)
257 item = self.AddRadioButton('Custom...')
259 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
261 def OnProfileSelect(self, e):
262 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
264 def OnOtherSelect(self, e):
265 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
268 for option in self.options:
269 if option.GetValue():
270 profile.loadProfile(option.filename)
271 profile.loadMachineSettings(option.filename)
273 class OtherMachineInfoPage(InfoPage):
274 def __init__(self, parent):
275 super(OtherMachineInfoPage, self).__init__(parent, "Cura Ready!")
276 self.AddText(_("Cura is now ready to be used!"))
278 class CustomRepRapInfoPage(InfoPage):
279 def __init__(self, parent):
280 super(CustomRepRapInfoPage, self).__init__(parent, "Custom RepRap information")
281 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
282 self.AddText(_("Be sure to review the default profile before running it on your machine."))
283 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
285 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
287 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
288 self.machineWidth = self.AddLabelTextCtrl(_("Machine width (mm)"), "80")
289 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth (mm)"), "80")
290 self.machineHeight = self.AddLabelTextCtrl(_("Machine height (mm)"), "55")
291 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
292 self.heatedBed = self.AddCheckbox(_("Heated bed"))
293 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
296 profile.putMachineSetting('machine_name', self.machineName.GetValue())
297 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
298 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
299 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
300 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
301 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
302 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
303 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
304 profile.putMachineSetting('extruder_head_size_min_x', '0')
305 profile.putMachineSetting('extruder_head_size_min_y', '0')
306 profile.putMachineSetting('extruder_head_size_max_x', '0')
307 profile.putMachineSetting('extruder_head_size_max_y', '0')
308 profile.putMachineSetting('extruder_head_size_height', '0')
309 profile.checkAndUpdateMachineName()
311 class MachineSelectPage(InfoPage):
312 def __init__(self, parent):
313 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
314 self.AddText(_("What kind of machine do you have:"))
316 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2", style=wx.RB_GROUP)
317 self.Ultimaker2Radio.SetValue(True)
318 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
319 self.UltimakerRadio = self.AddRadioButton("Ultimaker Original")
320 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
321 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot)"))
322 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
324 self.AddText(_("The collection of anonymous usage information helps with the continued improvement of Cura."))
325 self.AddText(_("This does NOT submit your models online nor gathers any privacy related information."))
326 self.SubmitUserStats = self.AddCheckbox(_("Submit anonymous usage information:"))
327 self.AddText(_("For full details see: http://wiki.ultimaker.com/Cura:stats"))
328 self.SubmitUserStats.SetValue(True)
330 def OnUltimaker2Select(self, e):
331 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
333 def OnUltimakerSelect(self, e):
334 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
336 def OnOtherSelect(self, e):
337 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
340 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
344 profile.putProfileSetting('retraction_enable', 'True')
345 if self.Ultimaker2Radio.GetValue():
346 profile.putMachineSetting('machine_width', '230')
347 profile.putMachineSetting('machine_depth', '225')
348 profile.putMachineSetting('machine_height', '205')
349 profile.putMachineSetting('machine_name', 'ultimaker2')
350 profile.putMachineSetting('machine_type', 'ultimaker2')
351 profile.putMachineSetting('machine_center_is_zero', 'False')
352 profile.putMachineSetting('has_heated_bed', 'True')
353 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
354 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
355 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
356 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
357 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
358 profile.putMachineSetting('extruder_head_size_height', '55.0')
359 profile.putProfileSetting('nozzle_size', '0.4')
360 profile.putProfileSetting('fan_full_height', '5.0')
361 profile.putMachineSetting('extruder_offset_x1', '18.0')
362 profile.putMachineSetting('extruder_offset_y1', '0.0')
363 elif self.UltimakerRadio.GetValue():
364 profile.putMachineSetting('machine_width', '205')
365 profile.putMachineSetting('machine_depth', '205')
366 profile.putMachineSetting('machine_height', '200')
367 profile.putMachineSetting('machine_name', 'ultimaker original')
368 profile.putMachineSetting('machine_type', 'ultimaker')
369 profile.putMachineSetting('machine_center_is_zero', 'False')
370 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
371 profile.putProfileSetting('nozzle_size', '0.4')
372 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
373 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
374 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
375 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
376 profile.putMachineSetting('extruder_head_size_height', '55.0')
378 profile.putMachineSetting('machine_width', '80')
379 profile.putMachineSetting('machine_depth', '80')
380 profile.putMachineSetting('machine_height', '60')
381 profile.putMachineSetting('machine_name', 'reprap')
382 profile.putMachineSetting('machine_type', 'reprap')
383 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
384 profile.putPreference('startMode', 'Normal')
385 profile.putProfileSetting('nozzle_size', '0.5')
386 profile.checkAndUpdateMachineName()
387 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
388 if self.SubmitUserStats.GetValue():
389 profile.putPreference('submit_slice_information', 'True')
391 profile.putPreference('submit_slice_information', 'False')
394 class SelectParts(InfoPage):
395 def __init__(self, parent):
396 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
397 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."))
399 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
400 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
401 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
402 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
404 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."))
405 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
406 self.springExtruder.SetValue(True)
409 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
410 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
411 profile.putMachineSetting('has_heated_bed', 'True')
413 profile.putMachineSetting('has_heated_bed', 'False')
414 if self.dualExtrusion.GetValue():
415 profile.putMachineSetting('extruder_amount', '2')
416 profile.putMachineSetting('machine_depth', '195')
418 profile.putMachineSetting('extruder_amount', '1')
419 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
420 profile.putProfileSetting('retraction_enable', 'True')
422 profile.putProfileSetting('retraction_enable', 'False')
425 class UltimakerFirmwareUpgradePage(InfoPage):
426 def __init__(self, parent):
427 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
428 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."))
429 self.AddHiddenSeperator()
430 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
431 self.AddHiddenSeperator()
432 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."))
433 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
434 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
435 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
436 self.AddHiddenSeperator()
437 self.AddText(_("Do not upgrade to this firmware if:"))
438 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
439 self.AddText(_("* Have other changes in the firmware"))
440 # button = self.AddButton('Goto this page for a custom firmware')
441 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
446 def OnUpgradeClick(self, e):
447 if firmwareInstall.InstallFirmware():
448 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
450 def OnSkipClick(self, e):
451 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
452 self.GetParent().ShowPage(self.GetNext())
454 def OnUrlClick(self, e):
455 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
457 class UltimakerCheckupPage(InfoPage):
458 def __init__(self, parent):
459 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
461 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
462 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
463 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
464 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
465 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
466 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
467 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
468 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
469 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
470 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
473 _("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."))
474 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
475 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
476 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
478 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
479 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
480 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
482 self.infoBox = self.AddInfoBox()
483 self.machineState = self.AddText("")
484 self.temperatureLabel = self.AddText("")
485 self.errorLogButton = self.AddButton(_("Show error log"))
486 self.errorLogButton.Show(False)
488 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
490 self.xMinStop = False
491 self.xMaxStop = False
492 self.yMinStop = False
493 self.yMaxStop = False
494 self.zMinStop = False
495 self.zMaxStop = False
497 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
500 if self.comm is not None:
504 self.endstopBitmap.Show(False)
507 def OnSkipClick(self, e):
508 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
509 self.GetParent().ShowPage(self.GetNext())
511 def OnCheckClick(self, e=None):
512 self.errorLogButton.Show(False)
513 if self.comm is not None:
517 wx.CallAfter(self.OnCheckClick)
519 self.infoBox.SetBusy(_("Connecting to machine."))
520 self.commState.SetBitmap(self.unknownBitmap)
521 self.tempState.SetBitmap(self.unknownBitmap)
522 self.stopState.SetBitmap(self.unknownBitmap)
523 self.checkupState = 0
524 self.checkExtruderNr = 0
525 self.comm = machineCom.MachineCom(callbackObject=self)
527 def OnErrorLog(self, e):
528 printWindow.LogWindow('\n'.join(self.comm.getLog()))
530 def mcLog(self, message):
533 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
534 if not self.comm.isOperational():
536 if self.checkupState == 0:
537 self.tempCheckTimeout = 20
538 if temp[self.checkExtruderNr] > 70:
539 self.checkupState = 1
540 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
541 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
542 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
544 self.startTemp = temp[self.checkExtruderNr]
545 self.checkupState = 2
546 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
547 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
548 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
549 elif self.checkupState == 1:
551 self.startTemp = temp[self.checkExtruderNr]
552 self.checkupState = 2
553 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
554 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
555 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
556 elif self.checkupState == 2:
557 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
558 if temp[self.checkExtruderNr] > self.startTemp + 40:
559 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
560 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
561 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
562 self.checkExtruderNr = 0
563 self.checkupState = 3
564 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
565 wx.CallAfter(self.endstopBitmap.Show, True)
566 wx.CallAfter(self.Layout)
567 self.comm.sendCommand('M119')
568 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
570 self.checkupState = 0
571 self.checkExtruderNr += 1
573 self.tempCheckTimeout -= 1
574 if self.tempCheckTimeout < 1:
575 self.checkupState = -1
576 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
577 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
578 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
579 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
580 elif self.checkupState >= 3 and self.checkupState < 10:
581 self.comm.sendCommand('M119')
582 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
584 def mcStateChange(self, state):
585 if self.comm is None:
587 if self.comm.isOperational():
588 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
589 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
590 elif self.comm.isError():
591 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
592 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
593 wx.CallAfter(self.endstopBitmap.Show, False)
594 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
595 wx.CallAfter(self.errorLogButton.Show, True)
596 wx.CallAfter(self.Layout)
598 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
600 def mcMessage(self, message):
601 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
602 for data in message.split(' '):
604 tag, value = data.split(':', 1)
606 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
608 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
610 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
612 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
614 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
616 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
618 tag, value = map(str.strip, message.split(':', 1))
620 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
622 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
624 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
626 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
628 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
630 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
631 if 'z_max' in message:
632 self.comm.sendCommand('M119')
634 if self.checkupState == 3:
635 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
636 self.checkupState = 4
637 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
638 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
639 elif self.checkupState == 4:
640 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
641 self.checkupState = 5
642 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
643 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
644 elif self.checkupState == 5:
645 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
646 self.checkupState = 6
647 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
648 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
649 elif self.checkupState == 6:
650 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
651 self.checkupState = 7
652 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
653 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
654 elif self.checkupState == 7:
655 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
656 self.checkupState = 8
657 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
658 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
659 elif self.checkupState == 8:
660 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
661 self.checkupState = 9
662 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
663 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
664 elif self.checkupState == 9:
665 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
666 self.checkupState = 10
668 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
669 wx.CallAfter(self.infoBox.SetReadyIndicator)
670 wx.CallAfter(self.endstopBitmap.Show, False)
671 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
672 wx.CallAfter(self.OnSkipClick, None)
674 def mcProgress(self, lineNr):
677 def mcZChange(self, newZ):
681 class UltimakerCalibrationPage(InfoPage):
682 def __init__(self, parent):
683 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
685 self.AddText("Your Ultimaker requires some calibration.")
686 self.AddText("This calibration is needed for a proper extrusion amount.")
688 self.AddText("The following values are needed:")
689 self.AddText("* Diameter of filament")
690 self.AddText("* Number of steps per mm of filament extrusion")
692 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
694 self.AddText("First we need the diameter of your filament:")
695 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
697 "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.")
698 self.AddText("Note: This value can be changed later at any time.")
701 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
704 class UltimakerCalibrateStepsPerEPage(InfoPage):
705 def __init__(self, parent):
706 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
708 #if profile.getMachineSetting('steps_per_e') == '0':
709 # profile.putMachineSetting('steps_per_e', '865.888')
711 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
712 self.AddText(_("First remove any filament from your machine."))
713 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
714 self.AddText(_("We'll push the filament 100mm"))
715 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
716 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
717 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
718 self.AddText(_("This results in the following steps per E:"))
719 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
720 self.AddText(_("You can repeat these steps to get better calibration."))
723 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
724 self.heatButton = self.AddButton(_("Heatup for filament removal"))
726 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
727 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
728 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
730 def OnSaveLengthClick(self, e):
731 currentEValue = float(self.stepsPerEInput.GetValue())
732 realExtrudeLength = float(self.lengthInput.GetValue())
733 newEValue = currentEValue * 100 / realExtrudeLength
734 self.stepsPerEInput.SetValue(str(newEValue))
735 self.lengthInput.SetValue("100")
737 def OnExtrudeClick(self, e):
738 t = threading.Thread(target=self.OnExtrudeRun)
742 def OnExtrudeRun(self):
743 self.heatButton.Enable(False)
744 self.extrudeButton.Enable(False)
745 currentEValue = float(self.stepsPerEInput.GetValue())
746 self.comm = machineCom.MachineCom()
747 if not self.comm.isOpen():
749 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
750 'Printer error', wx.OK | wx.ICON_INFORMATION)
751 self.heatButton.Enable(True)
752 self.extrudeButton.Enable(True)
755 line = self.comm.readline()
760 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
763 self.sendGCommand('M302') #Disable cold extrusion protection
764 self.sendGCommand("M92 E%f" % (currentEValue))
765 self.sendGCommand("G92 E0")
766 self.sendGCommand("G1 E100 F600")
769 self.extrudeButton.Enable()
770 self.heatButton.Enable()
772 def OnHeatClick(self, e):
773 t = threading.Thread(target=self.OnHeatRun)
778 self.heatButton.Enable(False)
779 self.extrudeButton.Enable(False)
780 self.comm = machineCom.MachineCom()
781 if not self.comm.isOpen():
783 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
784 'Printer error', wx.OK | wx.ICON_INFORMATION)
785 self.heatButton.Enable(True)
786 self.extrudeButton.Enable(True)
789 line = self.comm.readline()
791 self.heatButton.Enable(True)
792 self.extrudeButton.Enable(True)
796 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
799 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
801 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
802 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
803 self.sendGCommand('M104 S0')
806 self.heatButton.Enable(True)
807 self.extrudeButton.Enable(True)
809 def sendGCommand(self, cmd):
810 self.comm.sendCommand(cmd) #Disable cold extrusion protection
812 line = self.comm.readline()
815 if line.startswith('ok'):
819 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
821 class Ultimaker2ReadyPage(InfoPage):
822 def __init__(self, parent):
823 super(Ultimaker2ReadyPage, self).__init__(parent, "Ultimaker2")
824 self.AddText('Congratulations on your the purchase of your brand new Ultimaker2.')
825 self.AddText('Cura is now ready to be used with your Ultimaker2.')
828 class configWizard(wx.wizard.Wizard):
829 def __init__(self, addNew = False):
830 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
832 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
833 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
835 self.firstInfoPage = FirstInfoPage(self, addNew)
836 self.machineSelectPage = MachineSelectPage(self)
837 self.ultimakerSelectParts = SelectParts(self)
838 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
839 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
840 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
841 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
842 self.bedLevelPage = bedLevelWizardMain(self)
843 self.headOffsetCalibration = headOffsetCalibrationPage(self)
844 self.otherMachineSelectPage = OtherMachineSelectPage(self)
845 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
846 self.otherMachineInfoPage = OtherMachineInfoPage(self)
848 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
850 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
851 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
852 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
853 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
854 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
855 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
856 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
857 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
859 self.FitToPage(self.firstInfoPage)
860 self.GetPageAreaSizer().Add(self.firstInfoPage)
862 self.RunWizard(self.firstInfoPage)
865 def OnPageChanging(self, e):
866 e.GetPage().StoreData()
868 def OnPageChanged(self, e):
869 if e.GetPage().AllowNext():
870 self.FindWindowById(wx.ID_FORWARD).Enable()
872 self.FindWindowById(wx.ID_FORWARD).Disable()
873 if e.GetPage().AllowBack():
874 self.FindWindowById(wx.ID_BACKWARD).Enable()
876 self.FindWindowById(wx.ID_BACKWARD).Disable()
878 class bedLevelWizardMain(InfoPage):
879 def __init__(self, parent):
880 super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
882 self.AddText('This wizard will help you in leveling your printer bed')
884 self.AddText('It will do the following steps')
885 self.AddText('* Move the printer head to each corner')
886 self.AddText(' and let you adjust the height of the bed to the nozzle')
887 self.AddText('* Print a line around the bed to check if it is level')
890 self.connectButton = self.AddButton('Connect to printer')
893 self.infoBox = self.AddInfoBox()
894 self.resumeButton = self.AddButton('Resume')
895 self.resumeButton.Enable(False)
897 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
898 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
900 def OnConnect(self, e = None):
901 if self.comm is not None:
905 wx.CallAfter(self.OnConnect)
907 self.connectButton.Enable(False)
908 self.comm = machineCom.MachineCom(callbackObject=self)
909 self.infoBox.SetBusy('Connecting to machine.')
910 self._wizardState = 0
913 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
914 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
917 def OnResume(self, e):
918 feedZ = profile.getProfileSettingFloat('print_speed') * 60
919 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
920 if self._wizardState == 2:
921 if profile.getMachineSetting('has_heated_bed') == 'True':
922 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back center...')
923 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
924 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
925 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
926 self.comm.sendCommand('M400')
927 self._wizardState = 3
929 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
930 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
931 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
932 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
933 self.comm.sendCommand('M400')
934 self._wizardState = 3
935 elif self._wizardState == 4:
936 if profile.getMachineSetting('has_heated_bed') == 'True':
937 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
938 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
939 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
940 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
941 self.comm.sendCommand('M400')
942 self._wizardState = 7
944 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
945 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
946 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
947 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
948 self.comm.sendCommand('M400')
949 self._wizardState = 5
950 elif self._wizardState == 6:
951 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
952 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
953 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
954 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
955 self.comm.sendCommand('M400')
956 self._wizardState = 7
957 elif self._wizardState == 8:
958 wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
959 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
960 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
961 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
962 self._wizardState = 9
963 elif self._wizardState == 10:
964 self._wizardState = 11
965 wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
966 feedZ = profile.getProfileSettingFloat('print_speed') * 60
967 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
968 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
969 w = profile.getMachineSettingFloat('machine_width')
970 d = profile.getMachineSettingFloat('machine_depth')
971 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
972 filamentArea = math.pi * filamentRadius * filamentRadius
973 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
977 'G1 Z2 F%d' % (feedZ),
979 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
980 'G1 Z0.3 F%d' % (feedZ)]
982 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
984 for i in xrange(0, 3):
985 dist = 5.0 + 0.4 * float(i)
986 eValue += (d - 2.0*dist) * ePerMM
987 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
988 eValue += (w - 2.0*dist) * ePerMM
989 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
990 eValue += (d - 2.0*dist) * ePerMM
991 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
992 eValue += (w - 2.0*dist) * ePerMM
993 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
995 gcodeList.append('M400')
996 self.comm.printGCode(gcodeList)
997 self.resumeButton.Enable(False)
999 def mcLog(self, message):
1000 print 'Log:', message
1002 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1003 if self._wizardState == 1:
1004 self._wizardState = 2
1005 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
1006 wx.CallAfter(self.resumeButton.Enable, True)
1007 elif self._wizardState == 3:
1008 self._wizardState = 4
1009 if profile.getMachineSetting('has_heated_bed') == 'True':
1010 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.')
1012 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
1013 wx.CallAfter(self.resumeButton.Enable, True)
1014 elif self._wizardState == 5:
1015 self._wizardState = 6
1016 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
1017 wx.CallAfter(self.resumeButton.Enable, True)
1018 elif self._wizardState == 7:
1019 self._wizardState = 8
1020 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
1021 wx.CallAfter(self.resumeButton.Enable, True)
1022 elif self._wizardState == 9:
1023 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1024 wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1026 wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
1027 wx.CallAfter(self.resumeButton.Enable, True)
1028 self._wizardState = 10
1030 def mcStateChange(self, state):
1031 if self.comm is None:
1033 if self.comm.isOperational():
1034 if self._wizardState == 0:
1035 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
1036 self.comm.sendCommand('M105')
1037 self.comm.sendCommand('G28')
1038 self._wizardState = 1
1039 elif self._wizardState == 11 and not self.comm.isPrinting():
1040 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1041 self.comm.sendCommand('G92 E0')
1042 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1043 self.comm.sendCommand('M104 S0')
1044 wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
1045 wx.CallAfter(self.infoBox.SetReadyIndicator)
1046 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1047 wx.CallAfter(self.connectButton.Enable, True)
1048 self._wizardState = 12
1049 elif self.comm.isError():
1050 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1052 def mcMessage(self, message):
1055 def mcProgress(self, lineNr):
1058 def mcZChange(self, newZ):
1061 class headOffsetCalibrationPage(InfoPage):
1062 def __init__(self, parent):
1063 super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
1065 self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
1068 self.connectButton = self.AddButton('Connect to printer')
1071 self.infoBox = self.AddInfoBox()
1072 self.textEntry = self.AddTextCtrl('')
1073 self.textEntry.Enable(False)
1074 self.resumeButton = self.AddButton('Resume')
1075 self.resumeButton.Enable(False)
1077 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1078 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1080 def AllowBack(self):
1083 def OnConnect(self, e = None):
1084 if self.comm is not None:
1088 wx.CallAfter(self.OnConnect)
1090 self.connectButton.Enable(False)
1091 self.comm = machineCom.MachineCom(callbackObject=self)
1092 self.infoBox.SetBusy('Connecting to machine.')
1093 self._wizardState = 0
1095 def OnResume(self, e):
1096 if self._wizardState == 2:
1097 self._wizardState = 3
1098 wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
1100 w = profile.getMachineSettingFloat('machine_width')
1101 d = profile.getMachineSettingFloat('machine_depth')
1103 gcode = gcodeGenerator.gcodeGenerator()
1104 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1105 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1112 gcode.addMove(w/2, 5)
1113 gcode.addMove(z=0.2)
1115 gcode.addExtrude(w/2, d-5.0)
1117 gcode.addMove(5, d/2)
1119 gcode.addExtrude(w-5.0, d/2)
1120 gcode.addRetract(15)
1123 gcode.addMove(w/2, 5)
1125 gcode.addExtrude(w/2, d-5.0)
1127 gcode.addMove(5, d/2)
1129 gcode.addExtrude(w-5.0, d/2)
1130 gcode.addRetract(15)
1135 gcode.addCmd('M400')
1137 self.comm.printGCode(gcode.list())
1138 self.resumeButton.Enable(False)
1139 elif self._wizardState == 4:
1141 float(self.textEntry.GetValue())
1144 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1145 self._wizardState = 5
1146 self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
1147 self.textEntry.SetValue('0.0')
1148 self.textEntry.Enable(True)
1149 elif self._wizardState == 5:
1151 float(self.textEntry.GetValue())
1154 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1155 self._wizardState = 6
1156 self.infoBox.SetBusy('Printing the fine calibration lines.')
1157 self.textEntry.SetValue('')
1158 self.textEntry.Enable(False)
1159 self.resumeButton.Enable(False)
1161 x = profile.getMachineSettingFloat('extruder_offset_x1')
1162 y = profile.getMachineSettingFloat('extruder_offset_y1')
1163 gcode = gcodeGenerator.gcodeGenerator()
1164 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1165 gcode.setPrintSpeed(25)
1168 gcode.addMove(50, 40, 0.2)
1170 for n in xrange(0, 10):
1171 gcode.addExtrude(50 + n * 10, 150)
1172 gcode.addExtrude(50 + n * 10 + 5, 150)
1173 gcode.addExtrude(50 + n * 10 + 5, 40)
1174 gcode.addExtrude(50 + n * 10 + 10, 40)
1175 gcode.addMove(40, 50)
1176 for n in xrange(0, 10):
1177 gcode.addExtrude(150, 50 + n * 10)
1178 gcode.addExtrude(150, 50 + n * 10 + 5)
1179 gcode.addExtrude(40, 50 + n * 10 + 5)
1180 gcode.addExtrude(40, 50 + n * 10 + 10)
1181 gcode.addRetract(15)
1184 gcode.addMove(50 - x, 30 - y, 0.2)
1186 for n in xrange(0, 10):
1187 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1188 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1189 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1190 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1191 gcode.addMove(30 - x, 50 - y, 0.2)
1192 for n in xrange(0, 10):
1193 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1194 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1195 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1196 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1197 gcode.addRetract(15)
1199 gcode.addCmd('M400')
1200 gcode.addCmd('M104 T0 S0')
1201 gcode.addCmd('M104 T1 S0')
1202 self.comm.printGCode(gcode.list())
1203 elif self._wizardState == 7:
1205 n = int(self.textEntry.GetValue()) - 1
1208 x = profile.getMachineSettingFloat('extruder_offset_x1')
1210 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1211 self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
1212 self.textEntry.SetValue('10')
1213 self._wizardState = 8
1214 elif self._wizardState == 8:
1216 n = int(self.textEntry.GetValue()) - 1
1219 y = profile.getMachineSettingFloat('extruder_offset_y1')
1221 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1222 self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1223 self.infoBox.SetReadyIndicator()
1224 self._wizardState = 8
1226 self.resumeButton.Enable(False)
1228 def mcLog(self, message):
1229 print 'Log:', message
1231 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1232 if self._wizardState == 1:
1233 if temp[0] >= 210 and temp[1] >= 210:
1234 self._wizardState = 2
1235 wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
1236 wx.CallAfter(self.resumeButton.Enable, True)
1237 wx.CallAfter(self.resumeButton.SetFocus)
1239 def mcStateChange(self, state):
1240 if self.comm is None:
1242 if self.comm.isOperational():
1243 if self._wizardState == 0:
1244 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
1245 self.comm.sendCommand('M105')
1246 self.comm.sendCommand('M104 S220 T0')
1247 self.comm.sendCommand('M104 S220 T1')
1248 self.comm.sendCommand('G28')
1249 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1250 self._wizardState = 1
1251 if not self.comm.isPrinting():
1252 if self._wizardState == 3:
1253 self._wizardState = 4
1254 wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
1255 wx.CallAfter(self.textEntry.SetValue, '0.0')
1256 wx.CallAfter(self.textEntry.Enable, True)
1257 wx.CallAfter(self.resumeButton.Enable, True)
1258 wx.CallAfter(self.resumeButton.SetFocus)
1259 elif self._wizardState == 6:
1260 self._wizardState = 7
1261 wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
1262 wx.CallAfter(self.textEntry.SetValue, '10')
1263 wx.CallAfter(self.textEntry.Enable, True)
1264 wx.CallAfter(self.resumeButton.Enable, True)
1265 wx.CallAfter(self.resumeButton.SetFocus)
1267 elif self.comm.isError():
1268 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1270 def mcMessage(self, message):
1273 def mcProgress(self, lineNr):
1276 def mcZChange(self, newZ):
1279 class bedLevelWizard(wx.wizard.Wizard):
1281 super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
1283 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1284 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1286 self.mainPage = bedLevelWizardMain(self)
1287 self.headOffsetCalibration = None
1289 self.FitToPage(self.mainPage)
1290 self.GetPageAreaSizer().Add(self.mainPage)
1292 self.RunWizard(self.mainPage)
1295 def OnPageChanging(self, e):
1296 e.GetPage().StoreData()
1298 def OnPageChanged(self, e):
1299 if e.GetPage().AllowNext():
1300 self.FindWindowById(wx.ID_FORWARD).Enable()
1302 self.FindWindowById(wx.ID_FORWARD).Disable()
1303 if e.GetPage().AllowBack():
1304 self.FindWindowById(wx.ID_BACKWARD).Enable()
1306 self.FindWindowById(wx.ID_BACKWARD).Disable()
1308 class headOffsetWizard(wx.wizard.Wizard):
1310 super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
1312 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1313 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1315 self.mainPage = headOffsetCalibrationPage(self)
1317 self.FitToPage(self.mainPage)
1318 self.GetPageAreaSizer().Add(self.mainPage)
1320 self.RunWizard(self.mainPage)
1323 def OnPageChanging(self, e):
1324 e.GetPage().StoreData()
1326 def OnPageChanged(self, e):
1327 if e.GetPage().AllowNext():
1328 self.FindWindowById(wx.ID_FORWARD).Enable()
1330 self.FindWindowById(wx.ID_FORWARD).Disable()
1331 if e.GetPage().AllowBack():
1332 self.FindWindowById(wx.ID_BACKWARD).Enable()
1334 self.FindWindowById(wx.ID_BACKWARD).Disable()