1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
13 from Cura.gui import firmwareInstall
14 from Cura.gui import printWindow
15 from Cura.util import machineCom
16 from Cura.util import profile
17 from Cura.util import gcodeGenerator
18 from Cura.util import resources
21 class InfoBox(wx.Panel):
22 def __init__(self, parent):
23 super(InfoBox, self).__init__(parent)
24 self.SetBackgroundColour('#FFFF80')
26 self.sizer = wx.GridBagSizer(5, 5)
27 self.SetSizer(self.sizer)
29 self.attentionBitmap = wx.Bitmap(resources.getPathForImage('attention.png'))
30 self.errorBitmap = wx.Bitmap(resources.getPathForImage('error.png'))
31 self.readyBitmap = wx.Bitmap(resources.getPathForImage('ready.png'))
33 wx.Bitmap(resources.getPathForImage('busy-0.png')),
34 wx.Bitmap(resources.getPathForImage('busy-1.png')),
35 wx.Bitmap(resources.getPathForImage('busy-2.png')),
36 wx.Bitmap(resources.getPathForImage('busy-3.png'))
39 self.bitmap = wx.StaticBitmap(self, -1, wx.EmptyBitmapRGBA(24, 24, red=255, green=255, blue=255, alpha=1))
40 self.text = wx.StaticText(self, -1, '')
41 self.extraInfoButton = wx.Button(self, -1, 'i', style=wx.BU_EXACTFIT)
42 self.sizer.Add(self.bitmap, pos=(0, 0), flag=wx.ALL, border=5)
43 self.sizer.Add(self.text, pos=(0, 1), flag=wx.TOP | wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL, border=5)
44 self.sizer.Add(self.extraInfoButton, pos=(0,2), flag=wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, border=5)
45 self.sizer.AddGrowableCol(1)
47 self.extraInfoButton.Show(False)
49 self.extraInfoUrl = ''
51 self.timer = wx.Timer(self)
52 self.Bind(wx.EVT_TIMER, self.doBusyUpdate, self.timer)
53 self.Bind(wx.EVT_BUTTON, self.doExtraInfo, self.extraInfoButton)
56 def SetInfo(self, info):
57 self.SetBackgroundColour('#FFFF80')
58 self.text.SetLabel(info)
59 self.extraInfoButton.Show(False)
62 def SetError(self, info, extraInfoUrl):
63 self.extraInfoUrl = extraInfoUrl
64 self.SetBackgroundColour('#FF8080')
65 self.text.SetLabel(info)
66 self.extraInfoButton.Show(True)
68 self.SetErrorIndicator()
71 def SetAttention(self, info):
72 self.SetBackgroundColour('#FFFF80')
73 self.text.SetLabel(info)
74 self.extraInfoButton.Show(False)
75 self.SetAttentionIndicator()
79 def SetBusy(self, info):
81 self.SetBusyIndicator()
83 def SetBusyIndicator(self):
85 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
87 def doExtraInfo(self, e):
88 webbrowser.open(self.extraInfoUrl)
90 def doBusyUpdate(self, e):
91 if self.busyState is None:
94 if self.busyState >= len(self.busyBitmap):
96 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
98 def SetReadyIndicator(self):
100 self.bitmap.SetBitmap(self.readyBitmap)
102 def SetErrorIndicator(self):
103 self.busyState = None
104 self.bitmap.SetBitmap(self.errorBitmap)
106 def SetAttentionIndicator(self):
107 self.busyState = None
108 self.bitmap.SetBitmap(self.attentionBitmap)
111 class InfoPage(wx.wizard.WizardPageSimple):
112 def __init__(self, parent, title):
113 wx.wizard.WizardPageSimple.__init__(self, parent)
115 sizer = wx.GridBagSizer(5, 5)
119 title = wx.StaticText(self, -1, title)
120 title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
121 sizer.Add(title, pos=(0, 0), span=(1, 2), flag=wx.ALIGN_CENTRE | wx.ALL)
122 sizer.Add(wx.StaticLine(self, -1), pos=(1, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
123 sizer.AddGrowableCol(1)
127 def AddText(self, info):
128 text = wx.StaticText(self, -1, info)
129 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
133 def AddSeperator(self):
134 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
137 def AddHiddenSeperator(self):
140 def AddInfoBox(self):
141 infoBox = InfoBox(self)
142 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
146 def AddRadioButton(self, label, style=0):
147 radio = wx.RadioButton(self, -1, label, style=style)
148 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
152 def AddCheckbox(self, label, checked=False):
153 check = wx.CheckBox(self, -1)
154 text = wx.StaticText(self, -1, label)
155 check.SetValue(checked)
156 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
157 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 2), flag=wx.ALL)
161 def AddButton(self, label):
162 button = wx.Button(self, -1, label)
163 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
167 def AddDualButton(self, label1, label2):
168 button1 = wx.Button(self, -1, label1)
169 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
170 button2 = wx.Button(self, -1, label2)
171 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
173 return button1, button2
175 def AddTextCtrl(self, value):
176 ret = wx.TextCtrl(self, -1, value)
177 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
181 def AddLabelTextCtrl(self, info, value):
182 text = wx.StaticText(self, -1, info)
183 ret = wx.TextCtrl(self, -1, value)
184 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
185 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
189 def AddTextCtrlButton(self, value, buttonText):
190 text = wx.TextCtrl(self, -1, value)
191 button = wx.Button(self, -1, buttonText)
192 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
193 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
197 def AddBitmap(self, bitmap):
198 bitmap = wx.StaticBitmap(self, -1, bitmap)
199 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
203 def AddCheckmark(self, label, bitmap):
204 check = wx.StaticBitmap(self, -1, bitmap)
205 text = wx.StaticText(self, -1, label)
206 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
207 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 1), flag=wx.ALL)
218 class FirstInfoPage(InfoPage):
219 def __init__(self, parent, addNew):
221 super(FirstInfoPage, self).__init__(parent, _("Add new machine wizard"))
223 super(FirstInfoPage, self).__init__(parent, _("First time run wizard"))
224 self.AddText(_("Welcome, and thanks for trying Cura!"))
226 self.AddText(_("This wizard will help you with the following steps:"))
227 self.AddText(_("* Configure Cura for your machine"))
228 self.AddText(_("* Optionally upgrade your firmware"))
229 self.AddText(_("* Optionally check if your machine is working safely"))
230 self.AddText(_("* Optionally level your printer bed"))
232 #self.AddText('* Calibrate your machine')
233 #self.AddText('* Do your first print')
236 class OtherMachineSelectPage(InfoPage):
237 def __init__(self, parent):
238 super(OtherMachineSelectPage, self).__init__(parent, "Other machine information")
239 self.AddText(_("The following pre-defined machine profiles are available"))
240 self.AddText(_("Note that these profiles are not guaranteed to give good results,\nor work at all. Extra tweaks might be required."))
242 machines = resources.getDefaultMachineProfiles()
244 for filename in machines:
245 name = os.path.splitext(os.path.basename(filename))[0]
246 item = self.AddRadioButton(name)
247 item.filename = filename
248 item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
249 self.options.append(item)
251 item = self.AddRadioButton('Custom...')
253 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
255 def OnProfileSelect(self, e):
256 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
258 def OnOtherSelect(self, e):
259 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
262 for option in self.options:
263 if option.GetValue():
264 profile.loadProfile(option.filename)
265 profile.loadMachineSettings(option.filename)
267 class OtherMachineInfoPage(InfoPage):
268 def __init__(self, parent):
269 super(OtherMachineInfoPage, self).__init__(parent, "Cura Ready!")
270 self.AddText(_("Cura is now ready to be used!"))
272 class CustomRepRapInfoPage(InfoPage):
273 def __init__(self, parent):
274 super(CustomRepRapInfoPage, self).__init__(parent, "Custom RepRap information")
275 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
276 self.AddText(_("Be sure to review the default profile before running it on your machine."))
277 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
279 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
281 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
282 self.machineWidth = self.AddLabelTextCtrl(_("Machine width (mm)"), "80")
283 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth (mm)"), "80")
284 self.machineHeight = self.AddLabelTextCtrl(_("Machine height (mm)"), "60")
285 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
286 self.heatedBed = self.AddCheckbox(_("Heated bed"))
287 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
290 profile.putMachineSetting('machine_name', self.machineName.GetValue())
291 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
292 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
293 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
294 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
295 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
296 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
297 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
298 profile.putMachineSetting('extruder_head_size_min_x', '0')
299 profile.putMachineSetting('extruder_head_size_min_y', '0')
300 profile.putMachineSetting('extruder_head_size_max_x', '0')
301 profile.putMachineSetting('extruder_head_size_max_y', '0')
302 profile.putMachineSetting('extruder_head_size_height', '0')
303 profile.checkAndUpdateMachineName()
305 class MachineSelectPage(InfoPage):
306 def __init__(self, parent):
307 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
308 self.AddText(_("What kind of machine do you have:"))
310 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2", style=wx.RB_GROUP)
311 self.Ultimaker2Radio.SetValue(True)
312 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
313 self.UltimakerRadio = self.AddRadioButton("Ultimaker")
314 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
315 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot)"))
316 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
318 self.AddText(_("The collection of anonymous usage information helps with the continued improvement of Cura."))
319 self.AddText(_("This does NOT submit your models online nor gathers any privacy related information."))
320 self.SubmitUserStats = self.AddCheckbox(_("Submit anonymous usage information:"))
321 self.AddText(_("For full details see: http://wiki.ultimaker.com/Cura:stats"))
322 self.SubmitUserStats.SetValue(True)
324 def OnUltimaker2Select(self, e):
325 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
327 def OnUltimakerSelect(self, e):
328 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
330 def OnOtherSelect(self, e):
331 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
334 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
338 if self.Ultimaker2Radio.GetValue():
339 profile.putMachineSetting('machine_width', '230')
340 profile.putMachineSetting('machine_depth', '225')
341 profile.putMachineSetting('machine_height', '205')
342 profile.putMachineSetting('machine_type', 'ultimaker2')
343 profile.putMachineSetting('machine_center_is_zero', 'False')
344 profile.putMachineSetting('has_heated_bed', 'True')
345 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
346 profile.putProfileSetting('nozzle_size', '0.4')
347 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
348 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
349 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
350 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
351 profile.putMachineSetting('extruder_head_size_height', '60.0')
352 elif self.UltimakerRadio.GetValue():
353 profile.putMachineSetting('machine_width', '205')
354 profile.putMachineSetting('machine_depth', '205')
355 profile.putMachineSetting('machine_height', '200')
356 profile.putMachineSetting('machine_type', 'ultimaker')
357 profile.putMachineSetting('machine_center_is_zero', 'False')
358 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
359 profile.putProfileSetting('nozzle_size', '0.4')
360 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
361 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
362 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
363 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
364 profile.putMachineSetting('extruder_head_size_height', '60.0')
366 profile.putMachineSetting('machine_width', '80')
367 profile.putMachineSetting('machine_depth', '80')
368 profile.putMachineSetting('machine_height', '60')
369 profile.putMachineSetting('machine_type', 'reprap')
370 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
371 profile.putPreference('startMode', 'Normal')
372 profile.putProfileSetting('nozzle_size', '0.5')
373 profile.checkAndUpdateMachineName()
374 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
375 if self.SubmitUserStats.GetValue():
376 profile.putPreference('submit_slice_information', 'True')
378 profile.putPreference('submit_slice_information', 'False')
381 class SelectParts(InfoPage):
382 def __init__(self, parent):
383 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
384 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."))
386 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
387 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
388 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
390 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."))
391 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
392 self.springExtruder.SetValue(True)
395 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
396 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
397 if self.dualExtrusion.GetValue():
398 profile.putMachineSetting('extruder_amount', '2')
399 profile.putMachineSetting('machine_depth', '195')
401 profile.putMachineSetting('extruder_amount', '1')
402 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
403 profile.putProfileSetting('retraction_enable', 'True')
405 profile.putProfileSetting('retraction_enable', 'False')
408 class UltimakerFirmwareUpgradePage(InfoPage):
409 def __init__(self, parent):
410 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
411 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."))
412 self.AddHiddenSeperator()
413 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
414 self.AddHiddenSeperator()
415 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."))
416 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
417 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
418 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
419 self.AddHiddenSeperator()
420 self.AddText(_("Do not upgrade to this firmware if:"))
421 self.AddText(_("* You have an older machine based on ATMega1280"))
422 self.AddText(_("* Have other changes in the firmware"))
423 # button = self.AddButton('Goto this page for a custom firmware')
424 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
429 def OnUpgradeClick(self, e):
430 if firmwareInstall.InstallFirmware():
431 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
433 def OnSkipClick(self, e):
434 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
435 self.GetParent().ShowPage(self.GetNext())
437 def OnUrlClick(self, e):
438 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
440 class UltimakerCheckupPage(InfoPage):
441 def __init__(self, parent):
442 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
444 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
445 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
446 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
447 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
448 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
449 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
450 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
451 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
452 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
453 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
456 _("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."))
457 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
458 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
459 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
461 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
462 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
463 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
465 self.infoBox = self.AddInfoBox()
466 self.machineState = self.AddText("")
467 self.temperatureLabel = self.AddText("")
468 self.errorLogButton = self.AddButton(_("Show error log"))
469 self.errorLogButton.Show(False)
471 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
473 self.xMinStop = False
474 self.xMaxStop = False
475 self.yMinStop = False
476 self.yMaxStop = False
477 self.zMinStop = False
478 self.zMaxStop = False
480 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
483 if self.comm is not None:
487 self.endstopBitmap.Show(False)
490 def OnSkipClick(self, e):
491 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
492 self.GetParent().ShowPage(self.GetNext())
494 def OnCheckClick(self, e=None):
495 self.errorLogButton.Show(False)
496 if self.comm is not None:
500 wx.CallAfter(self.OnCheckClick)
502 self.infoBox.SetBusy(_("Connecting to machine."))
503 self.commState.SetBitmap(self.unknownBitmap)
504 self.tempState.SetBitmap(self.unknownBitmap)
505 self.stopState.SetBitmap(self.unknownBitmap)
506 self.checkupState = 0
507 self.checkExtruderNr = 0
508 self.comm = machineCom.MachineCom(callbackObject=self)
510 def OnErrorLog(self, e):
511 printWindow.LogWindow('\n'.join(self.comm.getLog()))
513 def mcLog(self, message):
516 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
517 if not self.comm.isOperational():
519 if self.checkupState == 0:
520 self.tempCheckTimeout = 20
521 if temp[self.checkExtruderNr] > 70:
522 self.checkupState = 1
523 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
524 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
525 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
527 self.startTemp = temp[self.checkExtruderNr]
528 self.checkupState = 2
529 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
530 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
531 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
532 elif self.checkupState == 1:
534 self.startTemp = temp[self.checkExtruderNr]
535 self.checkupState = 2
536 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
537 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
538 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
539 elif self.checkupState == 2:
540 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
541 if temp[self.checkExtruderNr] > self.startTemp + 40:
542 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
543 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
544 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
545 self.checkExtruderNr = 0
546 self.checkupState = 3
547 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
548 wx.CallAfter(self.endstopBitmap.Show, True)
549 wx.CallAfter(self.Layout)
550 self.comm.sendCommand('M119')
551 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
553 self.checkupState = 0
554 self.checkExtruderNr += 1
556 self.tempCheckTimeout -= 1
557 if self.tempCheckTimeout < 1:
558 self.checkupState = -1
559 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
560 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
561 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
562 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
563 elif self.checkupState >= 3 and self.checkupState < 10:
564 self.comm.sendCommand('M119')
565 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
567 def mcStateChange(self, state):
568 if self.comm is None:
570 if self.comm.isOperational():
571 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
572 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
573 elif self.comm.isError():
574 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
575 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
576 wx.CallAfter(self.endstopBitmap.Show, False)
577 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
578 wx.CallAfter(self.errorLogButton.Show, True)
579 wx.CallAfter(self.Layout)
581 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
583 def mcMessage(self, message):
584 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
585 for data in message.split(' '):
587 tag, value = data.split(':', 1)
589 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
591 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
593 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
595 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
597 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
599 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
601 tag, value = map(str.strip, message.split(':', 1))
603 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
605 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
607 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
609 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
611 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
613 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
614 if 'z_max' in message:
615 self.comm.sendCommand('M119')
617 if self.checkupState == 3:
618 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
619 self.checkupState = 4
620 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
621 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
622 elif self.checkupState == 4:
623 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
624 self.checkupState = 5
625 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
626 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
627 elif self.checkupState == 5:
628 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
629 self.checkupState = 6
630 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
631 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
632 elif self.checkupState == 6:
633 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
634 self.checkupState = 7
635 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
636 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
637 elif self.checkupState == 7:
638 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
639 self.checkupState = 8
640 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
641 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
642 elif self.checkupState == 8:
643 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
644 self.checkupState = 9
645 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
646 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
647 elif self.checkupState == 9:
648 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
649 self.checkupState = 10
651 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
652 wx.CallAfter(self.infoBox.SetReadyIndicator)
653 wx.CallAfter(self.endstopBitmap.Show, False)
654 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
655 wx.CallAfter(self.OnSkipClick, None)
657 def mcProgress(self, lineNr):
660 def mcZChange(self, newZ):
664 class UltimakerCalibrationPage(InfoPage):
665 def __init__(self, parent):
666 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
668 self.AddText("Your Ultimaker requires some calibration.")
669 self.AddText("This calibration is needed for a proper extrusion amount.")
671 self.AddText("The following values are needed:")
672 self.AddText("* Diameter of filament")
673 self.AddText("* Number of steps per mm of filament extrusion")
675 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
677 self.AddText("First we need the diameter of your filament:")
678 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
680 "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.")
681 self.AddText("Note: This value can be changed later at any time.")
684 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
687 class UltimakerCalibrateStepsPerEPage(InfoPage):
688 def __init__(self, parent):
689 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
691 #if profile.getMachineSetting('steps_per_e') == '0':
692 # profile.putMachineSetting('steps_per_e', '865.888')
694 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
695 self.AddText(_("First remove any filament from your machine."))
696 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
697 self.AddText(_("We'll push the filament 100mm"))
698 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
699 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
700 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
701 self.AddText(_("This results in the following steps per E:"))
702 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
703 self.AddText(_("You can repeat these steps to get better calibration."))
706 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
707 self.heatButton = self.AddButton(_("Heatup for filament removal"))
709 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
710 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
711 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
713 def OnSaveLengthClick(self, e):
714 currentEValue = float(self.stepsPerEInput.GetValue())
715 realExtrudeLength = float(self.lengthInput.GetValue())
716 newEValue = currentEValue * 100 / realExtrudeLength
717 self.stepsPerEInput.SetValue(str(newEValue))
718 self.lengthInput.SetValue("100")
720 def OnExtrudeClick(self, e):
721 threading.Thread(target=self.OnExtrudeRun).start()
723 def OnExtrudeRun(self):
724 self.heatButton.Enable(False)
725 self.extrudeButton.Enable(False)
726 currentEValue = float(self.stepsPerEInput.GetValue())
727 self.comm = machineCom.MachineCom()
728 if not self.comm.isOpen():
730 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
731 'Printer error', wx.OK | wx.ICON_INFORMATION)
732 self.heatButton.Enable(True)
733 self.extrudeButton.Enable(True)
736 line = self.comm.readline()
741 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
744 self.sendGCommand('M302') #Disable cold extrusion protection
745 self.sendGCommand("M92 E%f" % (currentEValue))
746 self.sendGCommand("G92 E0")
747 self.sendGCommand("G1 E100 F600")
750 self.extrudeButton.Enable()
751 self.heatButton.Enable()
753 def OnHeatClick(self, e):
754 threading.Thread(target=self.OnHeatRun).start()
757 self.heatButton.Enable(False)
758 self.extrudeButton.Enable(False)
759 self.comm = machineCom.MachineCom()
760 if not self.comm.isOpen():
762 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
763 'Printer error', wx.OK | wx.ICON_INFORMATION)
764 self.heatButton.Enable(True)
765 self.extrudeButton.Enable(True)
768 line = self.comm.readline()
770 self.heatButton.Enable(True)
771 self.extrudeButton.Enable(True)
775 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
778 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
780 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
781 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
782 self.sendGCommand('M104 S0')
785 self.heatButton.Enable(True)
786 self.extrudeButton.Enable(True)
788 def sendGCommand(self, cmd):
789 self.comm.sendCommand(cmd) #Disable cold extrusion protection
791 line = self.comm.readline()
794 if line.startswith('ok'):
798 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
800 class Ultimaker2ReadyPage(InfoPage):
801 def __init__(self, parent):
802 super(Ultimaker2ReadyPage, self).__init__(parent, "Ultimaker2")
803 self.AddText('Congratulations on your the purchase of your brand new Ultimaker2.')
804 self.AddText('Cura is now ready to be used with your Ultimaker2.')
807 class configWizard(wx.wizard.Wizard):
808 def __init__(self, addNew = False):
809 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
811 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
812 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
814 self.firstInfoPage = FirstInfoPage(self, addNew)
815 self.machineSelectPage = MachineSelectPage(self)
816 self.ultimakerSelectParts = SelectParts(self)
817 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
818 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
819 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
820 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
821 self.bedLevelPage = bedLevelWizardMain(self)
822 self.headOffsetCalibration = headOffsetCalibrationPage(self)
823 self.otherMachineSelectPage = OtherMachineSelectPage(self)
824 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
825 self.otherMachineInfoPage = OtherMachineInfoPage(self)
827 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
829 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
830 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
831 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
832 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
833 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
834 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
835 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
836 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
838 self.FitToPage(self.firstInfoPage)
839 self.GetPageAreaSizer().Add(self.firstInfoPage)
841 self.RunWizard(self.firstInfoPage)
844 def OnPageChanging(self, e):
845 e.GetPage().StoreData()
847 def OnPageChanged(self, e):
848 if e.GetPage().AllowNext():
849 self.FindWindowById(wx.ID_FORWARD).Enable()
851 self.FindWindowById(wx.ID_FORWARD).Disable()
852 self.FindWindowById(wx.ID_BACKWARD).Disable()
854 class bedLevelWizardMain(InfoPage):
855 def __init__(self, parent):
856 super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
858 self.AddText('This wizard will help you in leveling your printer bed')
860 self.AddText('It will do the following steps')
861 self.AddText('* Move the printer head to each corner')
862 self.AddText(' and let you adjust the height of the bed to the nozzle')
863 self.AddText('* Print a line around the bed to check if it is level')
866 self.connectButton = self.AddButton('Connect to printer')
869 self.infoBox = self.AddInfoBox()
870 self.resumeButton = self.AddButton('Resume')
871 self.resumeButton.Enable(False)
873 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
874 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
876 def OnConnect(self, e = None):
877 if self.comm is not None:
881 wx.CallAfter(self.OnConnect)
883 self.connectButton.Enable(False)
884 self.comm = machineCom.MachineCom(callbackObject=self)
885 self.infoBox.SetBusy('Connecting to machine.')
886 self._wizardState = 0
889 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
890 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
893 def OnResume(self, e):
894 feedZ = profile.getProfileSettingFloat('print_speed') * 60
895 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
896 if self._wizardState == 2:
897 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
898 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
899 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
900 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
901 self.comm.sendCommand('M400')
902 self._wizardState = 3
903 elif self._wizardState == 4:
904 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
905 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
906 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
907 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
908 self.comm.sendCommand('M400')
909 self._wizardState = 5
910 elif self._wizardState == 6:
911 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
912 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
913 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
914 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
915 self.comm.sendCommand('M400')
916 self._wizardState = 7
917 elif self._wizardState == 8:
918 wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
919 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
920 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
921 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
922 self._wizardState = 9
923 elif self._wizardState == 10:
924 self._wizardState = 11
925 wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
926 feedZ = profile.getProfileSettingFloat('print_speed') * 60
927 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
928 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
929 w = profile.getMachineSettingFloat('machine_width')
930 d = profile.getMachineSettingFloat('machine_depth')
931 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
932 filamentArea = math.pi * filamentRadius * filamentRadius
933 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
937 'G1 Z2 F%d' % (feedZ),
939 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
940 'G1 Z0.3 F%d' % (feedZ)]
942 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
944 for i in xrange(0, 3):
945 dist = 5.0 + 0.4 * float(i)
946 eValue += (d - 2.0*dist) * ePerMM
947 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
948 eValue += (w - 2.0*dist) * ePerMM
949 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
950 eValue += (d - 2.0*dist) * ePerMM
951 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
952 eValue += (w - 2.0*dist) * ePerMM
953 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
955 gcodeList.append('M400')
956 self.comm.printGCode(gcodeList)
957 self.resumeButton.Enable(False)
959 def mcLog(self, message):
960 print 'Log:', message
962 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
963 if self._wizardState == 1:
964 self._wizardState = 2
965 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
966 wx.CallAfter(self.resumeButton.Enable, True)
967 elif self._wizardState == 3:
968 self._wizardState = 4
969 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
970 wx.CallAfter(self.resumeButton.Enable, True)
971 elif self._wizardState == 5:
972 self._wizardState = 6
973 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
974 wx.CallAfter(self.resumeButton.Enable, True)
975 elif self._wizardState == 7:
976 self._wizardState = 8
977 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
978 wx.CallAfter(self.resumeButton.Enable, True)
979 elif self._wizardState == 9:
980 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
981 wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
983 wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
984 wx.CallAfter(self.resumeButton.Enable, True)
985 self._wizardState = 10
987 def mcStateChange(self, state):
988 if self.comm is None:
990 if self.comm.isOperational():
991 if self._wizardState == 0:
992 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
993 self.comm.sendCommand('M105')
994 self.comm.sendCommand('G28')
995 self._wizardState = 1
996 elif self._wizardState == 11 and not self.comm.isPrinting():
997 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
998 self.comm.sendCommand('G92 E0')
999 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1000 self.comm.sendCommand('M104 S0')
1001 wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
1002 wx.CallAfter(self.infoBox.SetReadyIndicator)
1003 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1004 wx.CallAfter(self.connectButton.Enable, True)
1005 self._wizardState = 12
1006 elif self.comm.isError():
1007 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1009 def mcMessage(self, message):
1012 def mcProgress(self, lineNr):
1015 def mcZChange(self, newZ):
1018 class headOffsetCalibrationPage(InfoPage):
1019 def __init__(self, parent):
1020 super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
1022 self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
1025 self.connectButton = self.AddButton('Connect to printer')
1028 self.infoBox = self.AddInfoBox()
1029 self.textEntry = self.AddTextCtrl('')
1030 self.textEntry.Enable(False)
1031 self.resumeButton = self.AddButton('Resume')
1032 self.resumeButton.Enable(False)
1034 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1035 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1037 def OnConnect(self, e = None):
1038 if self.comm is not None:
1042 wx.CallAfter(self.OnConnect)
1044 self.connectButton.Enable(False)
1045 self.comm = machineCom.MachineCom(callbackObject=self)
1046 self.infoBox.SetBusy('Connecting to machine.')
1047 self._wizardState = 0
1049 def OnResume(self, e):
1050 if self._wizardState == 2:
1051 self._wizardState = 3
1052 wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
1054 w = profile.getMachineSettingFloat('machine_width')
1055 d = profile.getMachineSettingFloat('machine_depth')
1057 gcode = gcodeGenerator.gcodeGenerator()
1058 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1059 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1066 gcode.addMove(w/2, 5)
1067 gcode.addMove(z=0.2)
1069 gcode.addExtrude(w/2, d-5.0)
1071 gcode.addMove(5, d/2)
1073 gcode.addExtrude(w-5.0, d/2)
1074 gcode.addRetract(15)
1077 gcode.addMove(w/2, 5)
1079 gcode.addExtrude(w/2, d-5.0)
1081 gcode.addMove(5, d/2)
1083 gcode.addExtrude(w-5.0, d/2)
1084 gcode.addRetract(15)
1089 gcode.addCmd('M400')
1091 self.comm.printGCode(gcode.list())
1092 self.resumeButton.Enable(False)
1093 elif self._wizardState == 4:
1095 float(self.textEntry.GetValue())
1098 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1099 self._wizardState = 5
1100 self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
1101 self.textEntry.SetValue('0.0')
1102 self.textEntry.Enable(True)
1103 elif self._wizardState == 5:
1105 float(self.textEntry.GetValue())
1108 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1109 self._wizardState = 6
1110 self.infoBox.SetBusy('Printing the fine calibration lines.')
1111 self.textEntry.SetValue('')
1112 self.textEntry.Enable(False)
1113 self.resumeButton.Enable(False)
1115 x = profile.getMachineSettingFloat('extruder_offset_x1')
1116 y = profile.getMachineSettingFloat('extruder_offset_y1')
1117 gcode = gcodeGenerator.gcodeGenerator()
1118 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1119 gcode.setPrintSpeed(25)
1122 gcode.addMove(50, 40, 0.2)
1124 for n in xrange(0, 10):
1125 gcode.addExtrude(50 + n * 10, 150)
1126 gcode.addExtrude(50 + n * 10 + 5, 150)
1127 gcode.addExtrude(50 + n * 10 + 5, 40)
1128 gcode.addExtrude(50 + n * 10 + 10, 40)
1129 gcode.addMove(40, 50)
1130 for n in xrange(0, 10):
1131 gcode.addExtrude(150, 50 + n * 10)
1132 gcode.addExtrude(150, 50 + n * 10 + 5)
1133 gcode.addExtrude(40, 50 + n * 10 + 5)
1134 gcode.addExtrude(40, 50 + n * 10 + 10)
1135 gcode.addRetract(15)
1138 gcode.addMove(50 - x, 30 - y, 0.2)
1140 for n in xrange(0, 10):
1141 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1142 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1143 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1144 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1145 gcode.addMove(30 - x, 50 - y, 0.2)
1146 for n in xrange(0, 10):
1147 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1148 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1149 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1150 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1151 gcode.addRetract(15)
1153 gcode.addCmd('M400')
1154 gcode.addCmd('M104 T0 S0')
1155 gcode.addCmd('M104 T1 S0')
1156 self.comm.printGCode(gcode.list())
1157 elif self._wizardState == 7:
1159 n = int(self.textEntry.GetValue()) - 1
1162 x = profile.getMachineSettingFloat('extruder_offset_x1')
1164 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1165 self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
1166 self.textEntry.SetValue('10')
1167 self._wizardState = 8
1168 elif self._wizardState == 8:
1170 n = int(self.textEntry.GetValue()) - 1
1173 y = profile.getMachineSettingFloat('extruder_offset_y1')
1175 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1176 self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1177 self.infoBox.SetReadyIndicator()
1178 self._wizardState = 8
1180 self.resumeButton.Enable(False)
1182 def mcLog(self, message):
1183 print 'Log:', message
1185 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1186 if self._wizardState == 1:
1187 if temp[0] >= 210 and temp[1] >= 210:
1188 self._wizardState = 2
1189 wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
1190 wx.CallAfter(self.resumeButton.Enable, True)
1191 wx.CallAfter(self.resumeButton.SetFocus)
1193 def mcStateChange(self, state):
1194 if self.comm is None:
1196 if self.comm.isOperational():
1197 if self._wizardState == 0:
1198 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
1199 self.comm.sendCommand('M105')
1200 self.comm.sendCommand('M104 S220 T0')
1201 self.comm.sendCommand('M104 S220 T1')
1202 self.comm.sendCommand('G28')
1203 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1204 self._wizardState = 1
1205 if not self.comm.isPrinting():
1206 if self._wizardState == 3:
1207 self._wizardState = 4
1208 wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
1209 wx.CallAfter(self.textEntry.SetValue, '0.0')
1210 wx.CallAfter(self.textEntry.Enable, True)
1211 wx.CallAfter(self.resumeButton.Enable, True)
1212 wx.CallAfter(self.resumeButton.SetFocus)
1213 elif self._wizardState == 6:
1214 self._wizardState = 7
1215 wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
1216 wx.CallAfter(self.textEntry.SetValue, '10')
1217 wx.CallAfter(self.textEntry.Enable, True)
1218 wx.CallAfter(self.resumeButton.Enable, True)
1219 wx.CallAfter(self.resumeButton.SetFocus)
1221 elif self.comm.isError():
1222 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1224 def mcMessage(self, message):
1227 def mcProgress(self, lineNr):
1230 def mcZChange(self, newZ):
1233 class bedLevelWizard(wx.wizard.Wizard):
1235 super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
1237 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1238 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1240 self.mainPage = bedLevelWizardMain(self)
1241 self.headOffsetCalibration = None
1243 self.FitToPage(self.mainPage)
1244 self.GetPageAreaSizer().Add(self.mainPage)
1246 self.RunWizard(self.mainPage)
1249 def OnPageChanging(self, e):
1250 e.GetPage().StoreData()
1252 def OnPageChanged(self, e):
1253 if e.GetPage().AllowNext():
1254 self.FindWindowById(wx.ID_FORWARD).Enable()
1256 self.FindWindowById(wx.ID_FORWARD).Disable()
1257 self.FindWindowById(wx.ID_BACKWARD).Disable()
1259 class headOffsetWizard(wx.wizard.Wizard):
1261 super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
1263 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1264 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1266 self.mainPage = headOffsetCalibrationPage(self)
1268 self.FitToPage(self.mainPage)
1269 self.GetPageAreaSizer().Add(self.mainPage)
1271 self.RunWizard(self.mainPage)
1274 def OnPageChanging(self, e):
1275 e.GetPage().StoreData()
1277 def OnPageChanged(self, e):
1278 if e.GetPage().AllowNext():
1279 self.FindWindowById(wx.ID_FORWARD).Enable()
1281 self.FindWindowById(wx.ID_FORWARD).Disable()
1282 self.FindWindowById(wx.ID_BACKWARD).Disable()