1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
12 from Cura.gui import firmwareInstall
13 from Cura.gui import printWindow
14 from Cura.util import machineCom
15 from Cura.util import profile
16 from Cura.util import gcodeGenerator
17 from Cura.util.resources import getPathForImage
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(getPathForImage('attention.png'))
29 self.errorBitmap = wx.Bitmap(getPathForImage('error.png'))
30 self.readyBitmap = wx.Bitmap(getPathForImage('ready.png'))
32 wx.Bitmap(getPathForImage('busy-0.png')),
33 wx.Bitmap(getPathForImage('busy-1.png')),
34 wx.Bitmap(getPathForImage('busy-2.png')),
35 wx.Bitmap(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)
217 class FirstInfoPage(InfoPage):
218 def __init__(self, parent):
219 super(FirstInfoPage, self).__init__(parent, _("First time run wizard"))
220 self.AddText(_("Welcome, and thanks for trying Cura!"))
222 self.AddText(_("This wizard will help you with the following steps:"))
223 self.AddText(_("* Configure Cura for your machine"))
224 self.AddText(_("* Upgrade your firmware"))
225 self.AddText(_("* Check if your machine is working safely"))
226 self.AddText(_("* Level your printer bed"))
228 #self.AddText('* Calibrate your machine')
229 #self.AddText('* Do your first print')
232 class RepRapInfoPage(InfoPage):
233 def __init__(self, parent):
234 super(RepRapInfoPage, self).__init__(parent, "RepRap information")
236 _("RepRap machines are vastly different, and there is no\ndefault configuration in Cura for any of them."))
237 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
239 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
241 self.machineWidth = self.AddLabelTextCtrl(_("Machine width (mm)"), "80")
242 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth (mm)"), "80")
243 self.machineHeight = self.AddLabelTextCtrl(_("Machine height (mm)"), "60")
244 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
245 self.heatedBed = self.AddCheckbox(_("Heated bed"))
246 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
249 profile.putPreference('machine_width', self.machineWidth.GetValue())
250 profile.putPreference('machine_depth', self.machineDepth.GetValue())
251 profile.putPreference('machine_height', self.machineHeight.GetValue())
252 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
253 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
254 profile.putPreference('has_heated_bed', str(self.heatedBed.GetValue()))
255 profile.putPreference('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
256 profile.putPreference('extruder_head_size_min_x', '0')
257 profile.putPreference('extruder_head_size_min_y', '0')
258 profile.putPreference('extruder_head_size_max_x', '0')
259 profile.putPreference('extruder_head_size_max_y', '0')
260 profile.putPreference('extruder_head_size_height', '0')
263 class MachineSelectPage(InfoPage):
264 def __init__(self, parent):
265 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
266 self.AddText(_("What kind of machine do you have:"))
268 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2", style=wx.RB_GROUP)
269 self.Ultimaker2Radio.SetValue(True)
270 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
271 self.UltimakerRadio = self.AddRadioButton("Ultimaker")
272 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
273 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap)"))
274 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
276 self.AddText(_("The collection of anonymous usage information helps with the continued improvement of Cura."))
277 self.AddText(_("This does NOT submit your models online nor gathers any privacy related information."))
278 self.SubmitUserStats = self.AddCheckbox(_("Submit anonymous usage information:"))
279 self.AddText(_("For full details see: http://wiki.ultimaker.com/Cura:stats"))
280 self.SubmitUserStats.SetValue(True)
282 def OnUltimaker2Select(self, e):
283 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
285 def OnUltimakerSelect(self, e):
286 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
288 def OnOtherSelect(self, e):
289 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().repRapInfoPage)
292 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
296 if self.Ultimaker2Radio.GetValue():
297 profile.putMachineSetting('machine_width', '230')
298 profile.putMachineSetting('machine_depth', '225')
299 profile.putMachineSetting('machine_height', '205')
300 profile.putMachineSetting('machine_type', 'ultimaker2')
301 profile.putMachineSetting('machine_center_is_zero', 'False')
302 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
303 profile.putProfileSetting('nozzle_size', '0.4')
304 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
305 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
306 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
307 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
308 profile.putMachineSetting('extruder_head_size_height', '60.0')
309 elif self.UltimakerRadio.GetValue():
310 profile.putMachineSetting('machine_width', '205')
311 profile.putMachineSetting('machine_depth', '205')
312 profile.putMachineSetting('machine_height', '200')
313 profile.putMachineSetting('machine_type', 'ultimaker')
314 profile.putMachineSetting('machine_center_is_zero', 'False')
315 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
316 profile.putProfileSetting('nozzle_size', '0.4')
317 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
318 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
319 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
320 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
321 profile.putMachineSetting('extruder_head_size_height', '60.0')
323 profile.putMachineSetting('machine_width', '80')
324 profile.putMachineSetting('machine_depth', '80')
325 profile.putMachineSetting('machine_height', '60')
326 profile.putMachineSetting('machine_type', 'reprap')
327 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
328 profile.putPreference('startMode', 'Normal')
329 profile.putProfileSetting('nozzle_size', '0.5')
330 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
331 if self.SubmitUserStats.GetValue():
332 profile.putPreference('submit_slice_information', 'True')
334 profile.putPreference('submit_slice_information', 'False')
337 class SelectParts(InfoPage):
338 def __init__(self, parent):
339 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
340 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."))
342 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
343 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
344 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
346 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."))
347 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
348 self.springExtruder.SetValue(True)
351 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
352 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
353 if self.dualExtrusion.GetValue():
354 profile.putMachineSetting('extruder_amount', '2')
355 profile.putMachineSetting('machine_depth', '195')
357 profile.putMachineSetting('extruder_amount', '1')
358 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
359 profile.putProfileSetting('retraction_enable', 'True')
361 profile.putProfileSetting('retraction_enable', 'False')
364 class UltimakerFirmwareUpgradePage(InfoPage):
365 def __init__(self, parent):
366 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
367 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."))
368 self.AddHiddenSeperator()
369 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
370 self.AddHiddenSeperator()
371 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."))
372 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
373 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
374 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
375 self.AddHiddenSeperator()
376 self.AddText(_("Do not upgrade to this firmware if:"))
377 self.AddText(_("* You have an older machine based on ATMega1280"))
378 self.AddText(_("* Have other changes in the firmware"))
379 # button = self.AddButton('Goto this page for a custom firmware')
380 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
385 def OnUpgradeClick(self, e):
386 if firmwareInstall.InstallFirmware():
387 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
389 def OnSkipClick(self, e):
390 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
391 self.GetParent().ShowPage(self.GetNext())
393 def OnUrlClick(self, e):
394 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
396 class UltimakerCheckupPage(InfoPage):
397 def __init__(self, parent):
398 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
400 self.checkBitmap = wx.Bitmap(getPathForImage('checkmark.png'))
401 self.crossBitmap = wx.Bitmap(getPathForImage('cross.png'))
402 self.unknownBitmap = wx.Bitmap(getPathForImage('question.png'))
403 self.endStopNoneBitmap = wx.Bitmap(getPathForImage('endstop_none.png'))
404 self.endStopXMinBitmap = wx.Bitmap(getPathForImage('endstop_xmin.png'))
405 self.endStopXMaxBitmap = wx.Bitmap(getPathForImage('endstop_xmax.png'))
406 self.endStopYMinBitmap = wx.Bitmap(getPathForImage('endstop_ymin.png'))
407 self.endStopYMaxBitmap = wx.Bitmap(getPathForImage('endstop_ymax.png'))
408 self.endStopZMinBitmap = wx.Bitmap(getPathForImage('endstop_zmin.png'))
409 self.endStopZMaxBitmap = wx.Bitmap(getPathForImage('endstop_zmax.png'))
412 _("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."))
413 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
414 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
415 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
417 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
418 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
419 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
421 self.infoBox = self.AddInfoBox()
422 self.machineState = self.AddText("")
423 self.temperatureLabel = self.AddText("")
424 self.errorLogButton = self.AddButton(_("Show error log"))
425 self.errorLogButton.Show(False)
427 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
429 self.xMinStop = False
430 self.xMaxStop = False
431 self.yMinStop = False
432 self.yMaxStop = False
433 self.zMinStop = False
434 self.zMaxStop = False
436 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
439 if self.comm is not None:
443 self.endstopBitmap.Show(False)
446 def OnSkipClick(self, e):
447 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
448 self.GetParent().ShowPage(self.GetNext())
450 def OnCheckClick(self, e=None):
451 self.errorLogButton.Show(False)
452 if self.comm is not None:
456 wx.CallAfter(self.OnCheckClick)
458 self.infoBox.SetBusy(_("Connecting to machine."))
459 self.commState.SetBitmap(self.unknownBitmap)
460 self.tempState.SetBitmap(self.unknownBitmap)
461 self.stopState.SetBitmap(self.unknownBitmap)
462 self.checkupState = 0
463 self.checkExtruderNr = 0
464 self.comm = machineCom.MachineCom(callbackObject=self)
466 def OnErrorLog(self, e):
467 printWindow.LogWindow('\n'.join(self.comm.getLog()))
469 def mcLog(self, message):
472 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
473 if not self.comm.isOperational():
475 if self.checkupState == 0:
476 self.tempCheckTimeout = 20
477 if temp[self.checkExtruderNr] > 70:
478 self.checkupState = 1
479 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
480 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
481 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
483 self.startTemp = temp[self.checkExtruderNr]
484 self.checkupState = 2
485 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
486 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
487 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
488 elif self.checkupState == 1:
490 self.startTemp = temp[self.checkExtruderNr]
491 self.checkupState = 2
492 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
493 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
494 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
495 elif self.checkupState == 2:
496 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
497 if temp[self.checkExtruderNr] > self.startTemp + 40:
498 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
499 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
500 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
501 self.checkExtruderNr = 0
502 self.checkupState = 3
503 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
504 wx.CallAfter(self.endstopBitmap.Show, True)
505 wx.CallAfter(self.Layout)
506 self.comm.sendCommand('M119')
507 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
509 self.checkupState = 0
510 self.checkExtruderNr += 1
512 self.tempCheckTimeout -= 1
513 if self.tempCheckTimeout < 1:
514 self.checkupState = -1
515 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
516 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
517 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
518 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
519 elif self.checkupState >= 3 and self.checkupState < 10:
520 self.comm.sendCommand('M119')
521 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
523 def mcStateChange(self, state):
524 if self.comm is None:
526 if self.comm.isOperational():
527 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
528 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
529 elif self.comm.isError():
530 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
531 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
532 wx.CallAfter(self.endstopBitmap.Show, False)
533 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
534 wx.CallAfter(self.errorLogButton.Show, True)
535 wx.CallAfter(self.Layout)
537 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
539 def mcMessage(self, message):
540 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
541 for data in message.split(' '):
543 tag, value = data.split(':', 1)
545 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
547 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
549 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
551 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
553 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
555 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
557 tag, value = map(str.strip, message.split(':', 1))
559 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
561 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
563 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
565 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
567 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
569 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
570 if 'z_max' in message:
571 self.comm.sendCommand('M119')
573 if self.checkupState == 3:
574 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
575 self.checkupState = 4
576 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
577 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
578 elif self.checkupState == 4:
579 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
580 self.checkupState = 5
581 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
582 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
583 elif self.checkupState == 5:
584 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
585 self.checkupState = 6
586 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
587 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
588 elif self.checkupState == 6:
589 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
590 self.checkupState = 7
591 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
592 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
593 elif self.checkupState == 7:
594 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
595 self.checkupState = 8
596 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
597 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
598 elif self.checkupState == 8:
599 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
600 self.checkupState = 9
601 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
602 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
603 elif self.checkupState == 9:
604 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
605 self.checkupState = 10
607 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
608 wx.CallAfter(self.infoBox.SetReadyIndicator)
609 wx.CallAfter(self.endstopBitmap.Show, False)
610 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
611 wx.CallAfter(self.OnSkipClick, None)
613 def mcProgress(self, lineNr):
616 def mcZChange(self, newZ):
620 class UltimakerCalibrationPage(InfoPage):
621 def __init__(self, parent):
622 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
624 self.AddText("Your Ultimaker requires some calibration.")
625 self.AddText("This calibration is needed for a proper extrusion amount.")
627 self.AddText("The following values are needed:")
628 self.AddText("* Diameter of filament")
629 self.AddText("* Number of steps per mm of filament extrusion")
631 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
633 self.AddText("First we need the diameter of your filament:")
634 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
636 "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.")
637 self.AddText("Note: This value can be changed later at any time.")
640 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
643 class UltimakerCalibrateStepsPerEPage(InfoPage):
644 def __init__(self, parent):
645 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
647 #if profile.getMachineSetting('steps_per_e') == '0':
648 # profile.putMachineSetting('steps_per_e', '865.888')
650 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
651 self.AddText(_("First remove any filament from your machine."))
652 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
653 self.AddText(_("We'll push the filament 100mm"))
654 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
655 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
656 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
657 self.AddText(_("This results in the following steps per E:"))
658 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
659 self.AddText(_("You can repeat these steps to get better calibration."))
662 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
663 self.heatButton = self.AddButton(_("Heatup for filament removal"))
665 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
666 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
667 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
669 def OnSaveLengthClick(self, e):
670 currentEValue = float(self.stepsPerEInput.GetValue())
671 realExtrudeLength = float(self.lengthInput.GetValue())
672 newEValue = currentEValue * 100 / realExtrudeLength
673 self.stepsPerEInput.SetValue(str(newEValue))
674 self.lengthInput.SetValue("100")
676 def OnExtrudeClick(self, e):
677 threading.Thread(target=self.OnExtrudeRun).start()
679 def OnExtrudeRun(self):
680 self.heatButton.Enable(False)
681 self.extrudeButton.Enable(False)
682 currentEValue = float(self.stepsPerEInput.GetValue())
683 self.comm = machineCom.MachineCom()
684 if not self.comm.isOpen():
686 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
687 'Printer error', wx.OK | wx.ICON_INFORMATION)
688 self.heatButton.Enable(True)
689 self.extrudeButton.Enable(True)
692 line = self.comm.readline()
697 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
700 self.sendGCommand('M302') #Disable cold extrusion protection
701 self.sendGCommand("M92 E%f" % (currentEValue))
702 self.sendGCommand("G92 E0")
703 self.sendGCommand("G1 E100 F600")
706 self.extrudeButton.Enable()
707 self.heatButton.Enable()
709 def OnHeatClick(self, e):
710 threading.Thread(target=self.OnHeatRun).start()
713 self.heatButton.Enable(False)
714 self.extrudeButton.Enable(False)
715 self.comm = machineCom.MachineCom()
716 if not self.comm.isOpen():
718 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
719 'Printer error', wx.OK | wx.ICON_INFORMATION)
720 self.heatButton.Enable(True)
721 self.extrudeButton.Enable(True)
724 line = self.comm.readline()
726 self.heatButton.Enable(True)
727 self.extrudeButton.Enable(True)
731 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
734 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
736 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
737 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
738 self.sendGCommand('M104 S0')
741 self.heatButton.Enable(True)
742 self.extrudeButton.Enable(True)
744 def sendGCommand(self, cmd):
745 self.comm.sendCommand(cmd) #Disable cold extrusion protection
747 line = self.comm.readline()
750 if line.startswith('ok'):
754 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
756 class Ultimaker2ReadyPage(InfoPage):
757 def __init__(self, parent):
758 super(Ultimaker2ReadyPage, self).__init__(parent, "Ultimaker2")
759 self.AddText('Congratulations on your the purchase of your brand new Ultimaker2.')
760 self.AddText('Cura is now ready to be used with your Ultimaker2.')
763 class configWizard(wx.wizard.Wizard):
765 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
767 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
768 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
770 self.firstInfoPage = FirstInfoPage(self)
771 self.machineSelectPage = MachineSelectPage(self)
772 self.ultimakerSelectParts = SelectParts(self)
773 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
774 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
775 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
776 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
777 self.bedLevelPage = bedLevelWizardMain(self)
778 self.headOffsetCalibration = headOffsetCalibrationPage(self)
779 self.repRapInfoPage = RepRapInfoPage(self)
781 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
783 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
784 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
785 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
786 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
787 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
788 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
789 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
791 self.FitToPage(self.firstInfoPage)
792 self.GetPageAreaSizer().Add(self.firstInfoPage)
794 self.RunWizard(self.firstInfoPage)
797 def OnPageChanging(self, e):
798 e.GetPage().StoreData()
800 def OnPageChanged(self, e):
801 if e.GetPage().AllowNext():
802 self.FindWindowById(wx.ID_FORWARD).Enable()
804 self.FindWindowById(wx.ID_FORWARD).Disable()
805 self.FindWindowById(wx.ID_BACKWARD).Disable()
807 class bedLevelWizardMain(InfoPage):
808 def __init__(self, parent):
809 super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
811 self.AddText('This wizard will help you in leveling your printer bed')
813 self.AddText('It will do the following steps')
814 self.AddText('* Move the printer head to each corner')
815 self.AddText(' and let you adjust the height of the bed to the nozzle')
816 self.AddText('* Print a line around the bed to check if it is level')
819 self.connectButton = self.AddButton('Connect to printer')
822 self.infoBox = self.AddInfoBox()
823 self.resumeButton = self.AddButton('Resume')
824 self.resumeButton.Enable(False)
826 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
827 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
829 def OnConnect(self, e = None):
830 if self.comm is not None:
834 wx.CallAfter(self.OnConnect)
836 self.connectButton.Enable(False)
837 self.comm = machineCom.MachineCom(callbackObject=self)
838 self.infoBox.SetBusy('Connecting to machine.')
839 self._wizardState = 0
842 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
843 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
846 def OnResume(self, e):
847 feedZ = profile.getProfileSettingFloat('print_speed') * 60
848 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
849 if self._wizardState == 2:
850 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
851 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
852 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
853 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
854 self.comm.sendCommand('M400')
855 self._wizardState = 3
856 elif self._wizardState == 4:
857 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
858 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
859 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
860 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
861 self.comm.sendCommand('M400')
862 self._wizardState = 5
863 elif self._wizardState == 6:
864 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
865 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
866 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
867 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
868 self.comm.sendCommand('M400')
869 self._wizardState = 7
870 elif self._wizardState == 8:
871 wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
872 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
873 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
874 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
875 self._wizardState = 9
876 elif self._wizardState == 10:
877 self._wizardState = 11
878 wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
879 feedZ = profile.getProfileSettingFloat('print_speed') * 60
880 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
881 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
882 w = profile.getMachineSettingFloat('machine_width')
883 d = profile.getMachineSettingFloat('machine_depth')
884 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
885 filamentArea = math.pi * filamentRadius * filamentRadius
886 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
890 'G1 Z2 F%d' % (feedZ),
892 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
893 'G1 Z0.3 F%d' % (feedZ)]
895 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
897 for i in xrange(0, 3):
898 dist = 5.0 + 0.4 * float(i)
899 eValue += (d - 2.0*dist) * ePerMM
900 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
901 eValue += (w - 2.0*dist) * ePerMM
902 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
903 eValue += (d - 2.0*dist) * ePerMM
904 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
905 eValue += (w - 2.0*dist) * ePerMM
906 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
908 gcodeList.append('M400')
909 self.comm.printGCode(gcodeList)
910 self.resumeButton.Enable(False)
912 def mcLog(self, message):
913 print 'Log:', message
915 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
916 if self._wizardState == 1:
917 self._wizardState = 2
918 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
919 wx.CallAfter(self.resumeButton.Enable, True)
920 elif self._wizardState == 3:
921 self._wizardState = 4
922 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
923 wx.CallAfter(self.resumeButton.Enable, True)
924 elif self._wizardState == 5:
925 self._wizardState = 6
926 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
927 wx.CallAfter(self.resumeButton.Enable, True)
928 elif self._wizardState == 7:
929 self._wizardState = 8
930 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
931 wx.CallAfter(self.resumeButton.Enable, True)
932 elif self._wizardState == 9:
933 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
934 wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
936 wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
937 wx.CallAfter(self.resumeButton.Enable, True)
938 self._wizardState = 10
940 def mcStateChange(self, state):
941 if self.comm is None:
943 if self.comm.isOperational():
944 if self._wizardState == 0:
945 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
946 self.comm.sendCommand('M105')
947 self.comm.sendCommand('G28')
948 self._wizardState = 1
949 elif self._wizardState == 11 and not self.comm.isPrinting():
950 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
951 self.comm.sendCommand('G92 E0')
952 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
953 self.comm.sendCommand('M104 S0')
954 wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
955 wx.CallAfter(self.infoBox.SetReadyIndicator)
956 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
957 wx.CallAfter(self.connectButton.Enable, True)
958 self._wizardState = 12
959 elif self.comm.isError():
960 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
962 def mcMessage(self, message):
965 def mcProgress(self, lineNr):
968 def mcZChange(self, newZ):
971 class headOffsetCalibrationPage(InfoPage):
972 def __init__(self, parent):
973 super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
975 self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
978 self.connectButton = self.AddButton('Connect to printer')
981 self.infoBox = self.AddInfoBox()
982 self.textEntry = self.AddTextCtrl('')
983 self.textEntry.Enable(False)
984 self.resumeButton = self.AddButton('Resume')
985 self.resumeButton.Enable(False)
987 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
988 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
990 def OnConnect(self, e = None):
991 if self.comm is not None:
995 wx.CallAfter(self.OnConnect)
997 self.connectButton.Enable(False)
998 self.comm = machineCom.MachineCom(callbackObject=self)
999 self.infoBox.SetBusy('Connecting to machine.')
1000 self._wizardState = 0
1002 def OnResume(self, e):
1003 if self._wizardState == 2:
1004 self._wizardState = 3
1005 wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
1007 w = profile.getMachineSettingFloat('machine_width')
1008 d = profile.getMachineSettingFloat('machine_depth')
1010 gcode = gcodeGenerator.gcodeGenerator()
1011 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1012 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1019 gcode.addMove(w/2, 5)
1020 gcode.addMove(z=0.2)
1022 gcode.addExtrude(w/2, d-5.0)
1024 gcode.addMove(5, d/2)
1026 gcode.addExtrude(w-5.0, d/2)
1027 gcode.addRetract(15)
1030 gcode.addMove(w/2, 5)
1032 gcode.addExtrude(w/2, d-5.0)
1034 gcode.addMove(5, d/2)
1036 gcode.addExtrude(w-5.0, d/2)
1037 gcode.addRetract(15)
1042 gcode.addCmd('M400')
1044 self.comm.printGCode(gcode.list())
1045 self.resumeButton.Enable(False)
1046 elif self._wizardState == 4:
1048 float(self.textEntry.GetValue())
1051 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1052 self._wizardState = 5
1053 self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
1054 self.textEntry.SetValue('0.0')
1055 self.textEntry.Enable(True)
1056 elif self._wizardState == 5:
1058 float(self.textEntry.GetValue())
1061 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1062 self._wizardState = 6
1063 self.infoBox.SetBusy('Printing the fine calibration lines.')
1064 self.textEntry.SetValue('')
1065 self.textEntry.Enable(False)
1066 self.resumeButton.Enable(False)
1068 x = profile.getMachineSettingFloat('extruder_offset_x1')
1069 y = profile.getMachineSettingFloat('extruder_offset_y1')
1070 gcode = gcodeGenerator.gcodeGenerator()
1071 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1072 gcode.setPrintSpeed(25)
1075 gcode.addMove(50, 40, 0.2)
1077 for n in xrange(0, 10):
1078 gcode.addExtrude(50 + n * 10, 150)
1079 gcode.addExtrude(50 + n * 10 + 5, 150)
1080 gcode.addExtrude(50 + n * 10 + 5, 40)
1081 gcode.addExtrude(50 + n * 10 + 10, 40)
1082 gcode.addMove(40, 50)
1083 for n in xrange(0, 10):
1084 gcode.addExtrude(150, 50 + n * 10)
1085 gcode.addExtrude(150, 50 + n * 10 + 5)
1086 gcode.addExtrude(40, 50 + n * 10 + 5)
1087 gcode.addExtrude(40, 50 + n * 10 + 10)
1088 gcode.addRetract(15)
1091 gcode.addMove(50 - x, 30 - y, 0.2)
1093 for n in xrange(0, 10):
1094 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1095 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1096 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1097 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1098 gcode.addMove(30 - x, 50 - y, 0.2)
1099 for n in xrange(0, 10):
1100 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1101 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1102 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1103 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1104 gcode.addRetract(15)
1106 gcode.addCmd('M400')
1107 gcode.addCmd('M104 T0 S0')
1108 gcode.addCmd('M104 T1 S0')
1109 self.comm.printGCode(gcode.list())
1110 elif self._wizardState == 7:
1112 n = int(self.textEntry.GetValue()) - 1
1115 x = profile.getMachineSettingFloat('extruder_offset_x1')
1117 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1118 self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
1119 self.textEntry.SetValue('10')
1120 self._wizardState = 8
1121 elif self._wizardState == 8:
1123 n = int(self.textEntry.GetValue()) - 1
1126 y = profile.getMachineSettingFloat('extruder_offset_y1')
1128 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1129 self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1130 self.infoBox.SetReadyIndicator()
1131 self._wizardState = 8
1133 self.resumeButton.Enable(False)
1135 def mcLog(self, message):
1136 print 'Log:', message
1138 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1139 if self._wizardState == 1:
1140 if temp[0] >= 210 and temp[1] >= 210:
1141 self._wizardState = 2
1142 wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
1143 wx.CallAfter(self.resumeButton.Enable, True)
1144 wx.CallAfter(self.resumeButton.SetFocus)
1146 def mcStateChange(self, state):
1147 if self.comm is None:
1149 if self.comm.isOperational():
1150 if self._wizardState == 0:
1151 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
1152 self.comm.sendCommand('M105')
1153 self.comm.sendCommand('M104 S220 T0')
1154 self.comm.sendCommand('M104 S220 T1')
1155 self.comm.sendCommand('G28')
1156 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1157 self._wizardState = 1
1158 if not self.comm.isPrinting():
1159 if self._wizardState == 3:
1160 self._wizardState = 4
1161 wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
1162 wx.CallAfter(self.textEntry.SetValue, '0.0')
1163 wx.CallAfter(self.textEntry.Enable, True)
1164 wx.CallAfter(self.resumeButton.Enable, True)
1165 wx.CallAfter(self.resumeButton.SetFocus)
1166 elif self._wizardState == 6:
1167 self._wizardState = 7
1168 wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
1169 wx.CallAfter(self.textEntry.SetValue, '10')
1170 wx.CallAfter(self.textEntry.Enable, True)
1171 wx.CallAfter(self.resumeButton.Enable, True)
1172 wx.CallAfter(self.resumeButton.SetFocus)
1174 elif self.comm.isError():
1175 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1177 def mcMessage(self, message):
1180 def mcProgress(self, lineNr):
1183 def mcZChange(self, newZ):
1186 class bedLevelWizard(wx.wizard.Wizard):
1188 super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
1190 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1191 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1193 self.mainPage = bedLevelWizardMain(self)
1194 self.headOffsetCalibration = None
1196 self.FitToPage(self.mainPage)
1197 self.GetPageAreaSizer().Add(self.mainPage)
1199 self.RunWizard(self.mainPage)
1202 def OnPageChanging(self, e):
1203 e.GetPage().StoreData()
1205 def OnPageChanged(self, e):
1206 if e.GetPage().AllowNext():
1207 self.FindWindowById(wx.ID_FORWARD).Enable()
1209 self.FindWindowById(wx.ID_FORWARD).Disable()
1210 self.FindWindowById(wx.ID_BACKWARD).Disable()
1212 class headOffsetWizard(wx.wizard.Wizard):
1214 super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
1216 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1217 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1219 self.mainPage = headOffsetCalibrationPage(self)
1221 self.FitToPage(self.mainPage)
1222 self.GetPageAreaSizer().Add(self.mainPage)
1224 self.RunWizard(self.mainPage)
1227 def OnPageChanging(self, e):
1228 e.GetPage().StoreData()
1230 def OnPageChanged(self, e):
1231 if e.GetPage().AllowNext():
1232 self.FindWindowById(wx.ID_FORWARD).Enable()
1234 self.FindWindowById(wx.ID_FORWARD).Disable()
1235 self.FindWindowById(wx.ID_BACKWARD).Disable()