1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
12 from Cura.gui import firmwareInstall
13 from Cura.gui import printWindow
14 from Cura.util import machineCom
15 from Cura.util import profile
16 from Cura.util import gcodeGenerator
17 from Cura.util.resources import getPathForImage
19 class InfoBox(wx.Panel):
20 def __init__(self, parent):
21 super(InfoBox, self).__init__(parent)
22 self.SetBackgroundColour('#FFFF80')
24 self.sizer = wx.GridBagSizer(5, 5)
25 self.SetSizer(self.sizer)
27 self.attentionBitmap = wx.Bitmap(getPathForImage('attention.png'))
28 self.errorBitmap = wx.Bitmap(getPathForImage('error.png'))
29 self.readyBitmap = wx.Bitmap(getPathForImage('ready.png'))
31 wx.Bitmap(getPathForImage('busy-0.png')),
32 wx.Bitmap(getPathForImage('busy-1.png')),
33 wx.Bitmap(getPathForImage('busy-2.png')),
34 wx.Bitmap(getPathForImage('busy-3.png'))
37 self.bitmap = wx.StaticBitmap(self, -1, wx.EmptyBitmapRGBA(24, 24, red=255, green=255, blue=255, alpha=1))
38 self.text = wx.StaticText(self, -1, '')
39 self.extraInfoButton = wx.Button(self, -1, 'i', style=wx.BU_EXACTFIT)
40 self.sizer.Add(self.bitmap, pos=(0, 0), flag=wx.ALL, border=5)
41 self.sizer.Add(self.text, pos=(0, 1), flag=wx.TOP | wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL, border=5)
42 self.sizer.Add(self.extraInfoButton, pos=(0,2), flag=wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, border=5)
43 self.sizer.AddGrowableCol(1)
45 self.extraInfoButton.Show(False)
47 self.extraInfoUrl = ''
49 self.timer = wx.Timer(self)
50 self.Bind(wx.EVT_TIMER, self.doBusyUpdate, self.timer)
51 self.Bind(wx.EVT_BUTTON, self.doExtraInfo, self.extraInfoButton)
54 def SetInfo(self, info):
55 self.SetBackgroundColour('#FFFF80')
56 self.text.SetLabel(info)
57 self.extraInfoButton.Show(False)
60 def SetError(self, info, extraInfoUrl):
61 self.extraInfoUrl = extraInfoUrl
62 self.SetBackgroundColour('#FF8080')
63 self.text.SetLabel(info)
64 self.extraInfoButton.Show(True)
66 self.SetErrorIndicator()
69 def SetAttention(self, info):
70 self.SetBackgroundColour('#FFFF80')
71 self.text.SetLabel(info)
72 self.extraInfoButton.Show(False)
73 self.SetAttentionIndicator()
77 def SetBusy(self, info):
79 self.SetBusyIndicator()
81 def SetBusyIndicator(self):
83 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
85 def doExtraInfo(self, e):
86 webbrowser.open(self.extraInfoUrl)
88 def doBusyUpdate(self, e):
89 if self.busyState is None:
92 if self.busyState >= len(self.busyBitmap):
94 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
96 def SetReadyIndicator(self):
98 self.bitmap.SetBitmap(self.readyBitmap)
100 def SetErrorIndicator(self):
101 self.busyState = None
102 self.bitmap.SetBitmap(self.errorBitmap)
104 def SetAttentionIndicator(self):
105 self.busyState = None
106 self.bitmap.SetBitmap(self.attentionBitmap)
109 class InfoPage(wx.wizard.WizardPageSimple):
110 def __init__(self, parent, title):
111 wx.wizard.WizardPageSimple.__init__(self, parent)
113 sizer = wx.GridBagSizer(5, 5)
117 title = wx.StaticText(self, -1, title)
118 title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
119 sizer.Add(title, pos=(0, 0), span=(1, 2), flag=wx.ALIGN_CENTRE | wx.ALL)
120 sizer.Add(wx.StaticLine(self, -1), pos=(1, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
121 sizer.AddGrowableCol(1)
125 def AddText(self, info):
126 text = wx.StaticText(self, -1, info)
127 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
131 def AddSeperator(self):
132 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
135 def AddHiddenSeperator(self):
138 def AddInfoBox(self):
139 infoBox = InfoBox(self)
140 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
144 def AddRadioButton(self, label, style=0):
145 radio = wx.RadioButton(self, -1, label, style=style)
146 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
150 def AddCheckbox(self, label, checked=False):
151 check = wx.CheckBox(self, -1)
152 text = wx.StaticText(self, -1, label)
153 check.SetValue(checked)
154 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
155 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 2), flag=wx.ALL)
159 def AddButton(self, label):
160 button = wx.Button(self, -1, label)
161 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
165 def AddDualButton(self, label1, label2):
166 button1 = wx.Button(self, -1, label1)
167 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
168 button2 = wx.Button(self, -1, label2)
169 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
171 return button1, button2
173 def AddTextCtrl(self, value):
174 ret = wx.TextCtrl(self, -1, value)
175 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
179 def AddLabelTextCtrl(self, info, value):
180 text = wx.StaticText(self, -1, info)
181 ret = wx.TextCtrl(self, -1, value)
182 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
183 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
187 def AddTextCtrlButton(self, value, buttonText):
188 text = wx.TextCtrl(self, -1, value)
189 button = wx.Button(self, -1, buttonText)
190 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
191 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
195 def AddBitmap(self, bitmap):
196 bitmap = wx.StaticBitmap(self, -1, bitmap)
197 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
201 def AddCheckmark(self, label, bitmap):
202 check = wx.StaticBitmap(self, -1, bitmap)
203 text = wx.StaticText(self, -1, label)
204 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
205 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 1), flag=wx.ALL)
216 class FirstInfoPage(InfoPage):
217 def __init__(self, parent):
218 super(FirstInfoPage, self).__init__(parent, _("First time run wizard"))
219 self.AddText(_("Welcome, and thanks for trying Cura!"))
221 self.AddText(_("This wizard will help you with the following steps:"))
222 self.AddText(_("* Configure Cura for your machine"))
223 self.AddText(_("* Upgrade your firmware"))
224 self.AddText(_("* Check if your machine is working safely"))
225 self.AddText(_("* Level your printer bed"))
227 #self.AddText('* Calibrate your machine')
228 #self.AddText('* Do your first print')
231 class RepRapInfoPage(InfoPage):
232 def __init__(self, parent):
233 super(RepRapInfoPage, self).__init__(parent, "RepRap information")
235 _("RepRap machines are vastly different, and there is no\ndefault configuration in Cura for any of them."))
236 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
238 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
240 self.machineWidth = self.AddLabelTextCtrl(_("Machine width (mm)"), "80")
241 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth (mm)"), "80")
242 self.machineHeight = self.AddLabelTextCtrl(_("Machine height (mm)"), "60")
243 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
244 self.heatedBed = self.AddCheckbox(_("Heated bed"))
245 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
248 profile.putPreference('machine_width', self.machineWidth.GetValue())
249 profile.putPreference('machine_depth', self.machineDepth.GetValue())
250 profile.putPreference('machine_height', self.machineHeight.GetValue())
251 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
252 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
253 profile.putPreference('has_heated_bed', str(self.heatedBed.GetValue()))
254 profile.putPreference('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
255 profile.putPreference('extruder_head_size_min_x', '0')
256 profile.putPreference('extruder_head_size_min_y', '0')
257 profile.putPreference('extruder_head_size_max_x', '0')
258 profile.putPreference('extruder_head_size_max_y', '0')
259 profile.putPreference('extruder_head_size_height', '0')
262 class MachineSelectPage(InfoPage):
263 def __init__(self, parent):
264 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
265 self.AddText(_("What kind of machine do you have:"))
267 self.UltimakerRadio = self.AddRadioButton("Ultimaker", style=wx.RB_GROUP)
268 self.UltimakerRadio.SetValue(True)
269 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
270 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap)"))
271 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
273 self.AddText(_("The collection of anonymous usage information helps with the continued improvement of Cura."))
274 self.AddText(_("This does NOT submit your models online nor gathers any privacy related information."))
275 self.SubmitUserStats = self.AddCheckbox(_("Submit anonymous usage information:"))
276 self.AddText(_("For full details see: http://wiki.ultimaker.com/Cura:stats"))
277 self.SubmitUserStats.SetValue(True)
279 def OnUltimakerSelect(self, e):
280 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)
282 def OnOtherSelect(self, e):
283 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().repRapInfoPage)
286 if self.UltimakerRadio.GetValue():
287 profile.putPreference('machine_width', '205')
288 profile.putPreference('machine_depth', '205')
289 profile.putPreference('machine_height', '200')
290 profile.putPreference('machine_type', 'ultimaker')
291 profile.putPreference('machine_center_is_zero', 'False')
292 profile.putProfileSetting('nozzle_size', '0.4')
293 profile.putPreference('extruder_head_size_min_x', '75.0')
294 profile.putPreference('extruder_head_size_min_y', '18.0')
295 profile.putPreference('extruder_head_size_max_x', '18.0')
296 profile.putPreference('extruder_head_size_max_y', '35.0')
297 profile.putPreference('extruder_head_size_height', '60.0')
299 profile.putPreference('machine_width', '80')
300 profile.putPreference('machine_depth', '80')
301 profile.putPreference('machine_height', '60')
302 profile.putPreference('machine_type', 'reprap')
303 profile.putPreference('startMode', 'Normal')
304 profile.putProfileSetting('nozzle_size', '0.5')
305 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
306 if self.SubmitUserStats.GetValue():
307 profile.putPreference('submit_slice_information', 'True')
309 profile.putPreference('submit_slice_information', 'False')
311 class SelectParts(InfoPage):
312 def __init__(self, parent):
313 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
314 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."))
316 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
317 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
318 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
320 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."))
321 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
322 self.springExtruder.SetValue(True)
325 profile.putPreference('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
326 profile.putPreference('has_heated_bed', str(self.heatedBed.GetValue()))
327 if self.dualExtrusion.GetValue():
328 profile.putPreference('extruder_amount', '2')
329 profile.putPreference('machine_depth', '195')
331 profile.putPreference('extruder_amount', '1')
332 if profile.getPreference('ultimaker_extruder_upgrade') == 'True':
333 profile.putProfileSetting('retraction_enable', 'True')
335 profile.putProfileSetting('retraction_enable', 'False')
338 class FirmwareUpgradePage(InfoPage):
339 def __init__(self, parent):
340 super(FirmwareUpgradePage, self).__init__(parent, "Upgrade Ultimaker Firmware")
341 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."))
342 self.AddHiddenSeperator()
343 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
344 self.AddHiddenSeperator()
345 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."))
346 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
347 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
348 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
349 self.AddHiddenSeperator()
350 self.AddText(_("Do not upgrade to this firmware if:"))
351 self.AddText(_("* You have an older machine based on ATMega1280"))
352 self.AddText(_("* Have other changes in the firmware"))
353 # button = self.AddButton('Goto this page for a custom firmware')
354 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
359 def OnUpgradeClick(self, e):
360 if firmwareInstall.InstallFirmware():
361 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
363 def OnSkipClick(self, e):
364 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
365 self.GetParent().ShowPage(self.GetNext())
367 def OnUrlClick(self, e):
368 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
371 class UltimakerCheckupPage(InfoPage):
372 def __init__(self, parent):
373 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
375 self.checkBitmap = wx.Bitmap(getPathForImage('checkmark.png'))
376 self.crossBitmap = wx.Bitmap(getPathForImage('cross.png'))
377 self.unknownBitmap = wx.Bitmap(getPathForImage('question.png'))
378 self.endStopNoneBitmap = wx.Bitmap(getPathForImage('endstop_none.png'))
379 self.endStopXMinBitmap = wx.Bitmap(getPathForImage('endstop_xmin.png'))
380 self.endStopXMaxBitmap = wx.Bitmap(getPathForImage('endstop_xmax.png'))
381 self.endStopYMinBitmap = wx.Bitmap(getPathForImage('endstop_ymin.png'))
382 self.endStopYMaxBitmap = wx.Bitmap(getPathForImage('endstop_ymax.png'))
383 self.endStopZMinBitmap = wx.Bitmap(getPathForImage('endstop_zmin.png'))
384 self.endStopZMaxBitmap = wx.Bitmap(getPathForImage('endstop_zmax.png'))
387 _("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."))
388 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
389 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
390 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
392 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
393 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
394 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
396 self.infoBox = self.AddInfoBox()
397 self.machineState = self.AddText("")
398 self.temperatureLabel = self.AddText("")
399 self.errorLogButton = self.AddButton(_("Show error log"))
400 self.errorLogButton.Show(False)
402 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
404 self.xMinStop = False
405 self.xMaxStop = False
406 self.yMinStop = False
407 self.yMaxStop = False
408 self.zMinStop = False
409 self.zMaxStop = False
411 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
414 if self.comm is not None:
418 self.endstopBitmap.Show(False)
421 def OnSkipClick(self, e):
422 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
423 self.GetParent().ShowPage(self.GetNext())
425 def OnCheckClick(self, e=None):
426 self.errorLogButton.Show(False)
427 if self.comm is not None:
431 wx.CallAfter(self.OnCheckClick)
433 self.infoBox.SetBusy(_("Connecting to machine."))
434 self.commState.SetBitmap(self.unknownBitmap)
435 self.tempState.SetBitmap(self.unknownBitmap)
436 self.stopState.SetBitmap(self.unknownBitmap)
437 self.checkupState = 0
438 self.checkExtruderNr = 0
439 self.comm = machineCom.MachineCom(callbackObject=self)
441 def OnErrorLog(self, e):
442 printWindow.LogWindow('\n'.join(self.comm.getLog()))
444 def mcLog(self, message):
447 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
448 if not self.comm.isOperational():
450 if self.checkupState == 0:
451 self.tempCheckTimeout = 20
452 if temp[self.checkExtruderNr] > 70:
453 self.checkupState = 1
454 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
455 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
456 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
458 self.startTemp = temp[self.checkExtruderNr]
459 self.checkupState = 2
460 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
461 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
462 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
463 elif self.checkupState == 1:
465 self.startTemp = temp[self.checkExtruderNr]
466 self.checkupState = 2
467 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
468 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
469 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
470 elif self.checkupState == 2:
471 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
472 if temp[self.checkExtruderNr] > self.startTemp + 40:
473 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
474 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
475 if self.checkExtruderNr < int(profile.getPreference('extruder_amount')):
476 self.checkExtruderNr = 0
477 self.checkupState = 3
478 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
479 wx.CallAfter(self.endstopBitmap.Show, True)
480 wx.CallAfter(self.Layout)
481 self.comm.sendCommand('M119')
482 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
484 self.checkupState = 0
485 self.checkExtruderNr += 1
487 self.tempCheckTimeout -= 1
488 if self.tempCheckTimeout < 1:
489 self.checkupState = -1
490 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
491 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
492 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
493 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
494 elif self.checkupState >= 3 and self.checkupState < 10:
495 self.comm.sendCommand('M119')
496 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
498 def mcStateChange(self, state):
499 if self.comm is None:
501 if self.comm.isOperational():
502 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
503 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
504 elif self.comm.isError():
505 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
506 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
507 wx.CallAfter(self.endstopBitmap.Show, False)
508 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
509 wx.CallAfter(self.errorLogButton.Show, True)
510 wx.CallAfter(self.Layout)
512 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
514 def mcMessage(self, message):
515 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
516 for data in message.split(' '):
518 tag, value = data.split(':', 1)
520 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
522 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
524 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
526 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
528 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
530 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
532 tag, value = map(str.strip, message.split(':', 1))
534 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
536 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
538 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
540 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
542 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
544 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
545 if 'z_max' in message:
546 self.comm.sendCommand('M119')
548 if self.checkupState == 3:
549 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
550 self.checkupState = 4
551 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
552 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
553 elif self.checkupState == 4:
554 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
555 self.checkupState = 5
556 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
557 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
558 elif self.checkupState == 5:
559 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
560 self.checkupState = 6
561 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
562 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
563 elif self.checkupState == 6:
564 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
565 self.checkupState = 7
566 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
567 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
568 elif self.checkupState == 7:
569 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
570 self.checkupState = 8
571 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
572 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
573 elif self.checkupState == 8:
574 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
575 self.checkupState = 9
576 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
577 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
578 elif self.checkupState == 9:
579 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
580 self.checkupState = 10
582 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
583 wx.CallAfter(self.infoBox.SetReadyIndicator)
584 wx.CallAfter(self.endstopBitmap.Show, False)
585 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
586 wx.CallAfter(self.OnSkipClick, None)
588 def mcProgress(self, lineNr):
591 def mcZChange(self, newZ):
595 class UltimakerCalibrationPage(InfoPage):
596 def __init__(self, parent):
597 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
599 self.AddText("Your Ultimaker requires some calibration.")
600 self.AddText("This calibration is needed for a proper extrusion amount.")
602 self.AddText("The following values are needed:")
603 self.AddText("* Diameter of filament")
604 self.AddText("* Number of steps per mm of filament extrusion")
606 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
608 self.AddText("First we need the diameter of your filament:")
609 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
611 "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.")
612 self.AddText("Note: This value can be changed later at any time.")
615 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
618 class UltimakerCalibrateStepsPerEPage(InfoPage):
619 def __init__(self, parent):
620 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
622 #if profile.getPreference('steps_per_e') == '0':
623 # profile.putPreference('steps_per_e', '865.888')
625 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
626 self.AddText(_("First remove any filament from your machine."))
627 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
628 self.AddText(_("We'll push the filament 100mm"))
629 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
630 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
631 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
632 self.AddText(_("This results in the following steps per E:"))
633 self.stepsPerEInput = self.AddTextCtrl(profile.getPreference('steps_per_e'))
634 self.AddText(_("You can repeat these steps to get better calibration."))
637 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
638 self.heatButton = self.AddButton(_("Heatup for filament removal"))
640 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
641 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
642 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
644 def OnSaveLengthClick(self, e):
645 currentEValue = float(self.stepsPerEInput.GetValue())
646 realExtrudeLength = float(self.lengthInput.GetValue())
647 newEValue = currentEValue * 100 / realExtrudeLength
648 self.stepsPerEInput.SetValue(str(newEValue))
649 self.lengthInput.SetValue("100")
651 def OnExtrudeClick(self, e):
652 threading.Thread(target=self.OnExtrudeRun).start()
654 def OnExtrudeRun(self):
655 self.heatButton.Enable(False)
656 self.extrudeButton.Enable(False)
657 currentEValue = float(self.stepsPerEInput.GetValue())
658 self.comm = machineCom.MachineCom()
659 if not self.comm.isOpen():
661 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
662 'Printer error', wx.OK | wx.ICON_INFORMATION)
663 self.heatButton.Enable(True)
664 self.extrudeButton.Enable(True)
667 line = self.comm.readline()
672 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
675 self.sendGCommand('M302') #Disable cold extrusion protection
676 self.sendGCommand("M92 E%f" % (currentEValue))
677 self.sendGCommand("G92 E0")
678 self.sendGCommand("G1 E100 F600")
681 self.extrudeButton.Enable()
682 self.heatButton.Enable()
684 def OnHeatClick(self, e):
685 threading.Thread(target=self.OnHeatRun).start()
688 self.heatButton.Enable(False)
689 self.extrudeButton.Enable(False)
690 self.comm = machineCom.MachineCom()
691 if not self.comm.isOpen():
693 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
694 'Printer error', wx.OK | wx.ICON_INFORMATION)
695 self.heatButton.Enable(True)
696 self.extrudeButton.Enable(True)
699 line = self.comm.readline()
701 self.heatButton.Enable(True)
702 self.extrudeButton.Enable(True)
706 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
709 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
711 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
712 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
713 self.sendGCommand('M104 S0')
716 self.heatButton.Enable(True)
717 self.extrudeButton.Enable(True)
719 def sendGCommand(self, cmd):
720 self.comm.sendCommand(cmd) #Disable cold extrusion protection
722 line = self.comm.readline()
725 if line.startswith('ok'):
729 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
732 class configWizard(wx.wizard.Wizard):
734 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
736 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
737 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
739 self.firstInfoPage = FirstInfoPage(self)
740 self.machineSelectPage = MachineSelectPage(self)
741 self.ultimakerSelectParts = SelectParts(self)
742 self.ultimakerFirmwareUpgradePage = FirmwareUpgradePage(self)
743 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
744 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
745 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
746 self.bedLevelPage = bedLevelWizardMain(self)
747 self.headOffsetCalibration = headOffsetCalibrationPage(self)
748 self.repRapInfoPage = RepRapInfoPage(self)
750 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
751 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
752 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
753 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
754 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
755 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
757 self.FitToPage(self.firstInfoPage)
758 self.GetPageAreaSizer().Add(self.firstInfoPage)
760 self.RunWizard(self.firstInfoPage)
763 def OnPageChanging(self, e):
764 e.GetPage().StoreData()
766 def OnPageChanged(self, e):
767 if e.GetPage().AllowNext():
768 self.FindWindowById(wx.ID_FORWARD).Enable()
770 self.FindWindowById(wx.ID_FORWARD).Disable()
771 self.FindWindowById(wx.ID_BACKWARD).Disable()
773 class bedLevelWizardMain(InfoPage):
774 def __init__(self, parent):
775 super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
777 self.AddText('This wizard will help you in leveling your printer bed')
779 self.AddText('It will do the following steps')
780 self.AddText('* Move the printer head to each corner')
781 self.AddText(' and let you adjust the height of the bed to the nozzle')
782 self.AddText('* Print a line around the bed to check if it is level')
785 self.connectButton = self.AddButton('Connect to printer')
788 self.infoBox = self.AddInfoBox()
789 self.resumeButton = self.AddButton('Resume')
790 self.resumeButton.Enable(False)
792 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
793 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
795 def OnConnect(self, e = None):
796 if self.comm is not None:
800 wx.CallAfter(self.OnConnect)
802 self.connectButton.Enable(False)
803 self.comm = machineCom.MachineCom(callbackObject=self)
804 self.infoBox.SetBusy('Connecting to machine.')
805 self._wizardState = 0
808 if self.GetParent().headOffsetCalibration is not None and int(profile.getPreference('extruder_amount')) > 1:
809 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
812 def OnResume(self, e):
813 feedZ = profile.getProfileSettingFloat('print_speed') * 60
814 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
815 if self._wizardState == 2:
816 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
817 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
818 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getPreferenceFloat('machine_depth'), feedTravel))
819 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
820 self.comm.sendCommand('M400')
821 self._wizardState = 3
822 elif self._wizardState == 4:
823 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
824 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
825 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getPreferenceFloat('machine_width') - 5.0, profile.getPreferenceFloat('machine_depth') - 25, feedTravel))
826 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
827 self.comm.sendCommand('M400')
828 self._wizardState = 5
829 elif self._wizardState == 6:
830 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
831 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
832 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getPreferenceFloat('machine_width') - 5.0, 20, feedTravel))
833 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
834 self.comm.sendCommand('M400')
835 self._wizardState = 7
836 elif self._wizardState == 8:
837 wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
838 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
839 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
840 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
841 self._wizardState = 9
842 elif self._wizardState == 10:
843 self._wizardState = 11
844 wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
845 feedZ = profile.getProfileSettingFloat('print_speed') * 60
846 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
847 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
848 w = profile.getPreferenceFloat('machine_width')
849 d = profile.getPreferenceFloat('machine_depth')
850 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
851 filamentArea = math.pi * filamentRadius * filamentRadius
852 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
856 'G1 Z2 F%d' % (feedZ),
858 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
859 'G1 Z0.3 F%d' % (feedZ)]
861 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
863 for i in xrange(0, 3):
864 dist = 5.0 + 0.4 * float(i)
865 eValue += (d - 2.0*dist) * ePerMM
866 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
867 eValue += (w - 2.0*dist) * ePerMM
868 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
869 eValue += (d - 2.0*dist) * ePerMM
870 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
871 eValue += (w - 2.0*dist) * ePerMM
872 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
874 gcodeList.append('M400')
875 self.comm.printGCode(gcodeList)
876 self.resumeButton.Enable(False)
878 def mcLog(self, message):
879 print 'Log:', message
881 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
882 if self._wizardState == 1:
883 self._wizardState = 2
884 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
885 wx.CallAfter(self.resumeButton.Enable, True)
886 elif self._wizardState == 3:
887 self._wizardState = 4
888 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
889 wx.CallAfter(self.resumeButton.Enable, True)
890 elif self._wizardState == 5:
891 self._wizardState = 6
892 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
893 wx.CallAfter(self.resumeButton.Enable, True)
894 elif self._wizardState == 7:
895 self._wizardState = 8
896 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
897 wx.CallAfter(self.resumeButton.Enable, True)
898 elif self._wizardState == 9:
899 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
900 wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
902 wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
903 wx.CallAfter(self.resumeButton.Enable, True)
904 self._wizardState = 10
906 def mcStateChange(self, state):
907 if self.comm is None:
909 if self.comm.isOperational():
910 if self._wizardState == 0:
911 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
912 self.comm.sendCommand('M105')
913 self.comm.sendCommand('G28')
914 self._wizardState = 1
915 elif self._wizardState == 11 and not self.comm.isPrinting():
916 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
917 self.comm.sendCommand('G92 E0')
918 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
919 self.comm.sendCommand('M104 S0')
920 wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
921 wx.CallAfter(self.infoBox.SetReadyIndicator)
922 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
923 wx.CallAfter(self.connectButton.Enable, True)
924 self._wizardState = 12
925 elif self.comm.isError():
926 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
928 def mcMessage(self, message):
931 def mcProgress(self, lineNr):
934 def mcZChange(self, newZ):
937 class headOffsetCalibrationPage(InfoPage):
938 def __init__(self, parent):
939 super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
941 self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
944 self.connectButton = self.AddButton('Connect to printer')
947 self.infoBox = self.AddInfoBox()
948 self.textEntry = self.AddTextCtrl('')
949 self.textEntry.Enable(False)
950 self.resumeButton = self.AddButton('Resume')
951 self.resumeButton.Enable(False)
953 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
954 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
956 def OnConnect(self, e = None):
957 if self.comm is not None:
961 wx.CallAfter(self.OnConnect)
963 self.connectButton.Enable(False)
964 self.comm = machineCom.MachineCom(callbackObject=self)
965 self.infoBox.SetBusy('Connecting to machine.')
966 self._wizardState = 0
968 def OnResume(self, e):
969 if self._wizardState == 2:
970 self._wizardState = 3
971 wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
973 w = profile.getPreferenceFloat('machine_width')
974 d = profile.getPreferenceFloat('machine_depth')
976 gcode = gcodeGenerator.gcodeGenerator()
977 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
978 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
985 gcode.addMove(w/2, 5)
988 gcode.addExtrude(w/2, d-5.0)
990 gcode.addMove(5, d/2)
992 gcode.addExtrude(w-5.0, d/2)
996 gcode.addMove(w/2, 5)
998 gcode.addExtrude(w/2, d-5.0)
1000 gcode.addMove(5, d/2)
1002 gcode.addExtrude(w-5.0, d/2)
1003 gcode.addRetract(15)
1008 gcode.addCmd('M400')
1010 self.comm.printGCode(gcode.list())
1011 self.resumeButton.Enable(False)
1012 elif self._wizardState == 4:
1014 float(self.textEntry.GetValue())
1017 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1018 self._wizardState = 5
1019 self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
1020 self.textEntry.SetValue('0.0')
1021 self.textEntry.Enable(True)
1022 elif self._wizardState == 5:
1024 float(self.textEntry.GetValue())
1027 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1028 self._wizardState = 6
1029 self.infoBox.SetBusy('Printing the fine calibration lines.')
1030 self.textEntry.SetValue('')
1031 self.textEntry.Enable(False)
1032 self.resumeButton.Enable(False)
1034 x = profile.getPreferenceFloat('extruder_offset_x1')
1035 y = profile.getPreferenceFloat('extruder_offset_y1')
1036 gcode = gcodeGenerator.gcodeGenerator()
1037 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1038 gcode.setPrintSpeed(25)
1041 gcode.addMove(50, 40, 0.2)
1043 for n in xrange(0, 10):
1044 gcode.addExtrude(50 + n * 10, 150)
1045 gcode.addExtrude(50 + n * 10 + 5, 150)
1046 gcode.addExtrude(50 + n * 10 + 5, 40)
1047 gcode.addExtrude(50 + n * 10 + 10, 40)
1048 gcode.addMove(40, 50)
1049 for n in xrange(0, 10):
1050 gcode.addExtrude(150, 50 + n * 10)
1051 gcode.addExtrude(150, 50 + n * 10 + 5)
1052 gcode.addExtrude(40, 50 + n * 10 + 5)
1053 gcode.addExtrude(40, 50 + n * 10 + 10)
1054 gcode.addRetract(15)
1057 gcode.addMove(50 - x, 30 - y, 0.2)
1059 for n in xrange(0, 10):
1060 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1061 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1062 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1063 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1064 gcode.addMove(30 - x, 50 - y, 0.2)
1065 for n in xrange(0, 10):
1066 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1067 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1068 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1069 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1070 gcode.addRetract(15)
1072 gcode.addCmd('M400')
1073 gcode.addCmd('M104 T0 S0')
1074 gcode.addCmd('M104 T1 S0')
1075 self.comm.printGCode(gcode.list())
1076 elif self._wizardState == 7:
1078 n = int(self.textEntry.GetValue()) - 1
1081 x = profile.getPreferenceFloat('extruder_offset_x1')
1083 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1084 self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
1085 self.textEntry.SetValue('10')
1086 self._wizardState = 8
1087 elif self._wizardState == 8:
1089 n = int(self.textEntry.GetValue()) - 1
1092 y = profile.getPreferenceFloat('extruder_offset_y1')
1094 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1095 self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getPreferenceFloat('extruder_offset_x1'), profile.getPreferenceFloat('extruder_offset_y1')))
1096 self.infoBox.SetReadyIndicator()
1097 self._wizardState = 8
1099 self.resumeButton.Enable(False)
1101 def mcLog(self, message):
1102 print 'Log:', message
1104 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1105 if self._wizardState == 1:
1106 if temp[0] >= 210 and temp[1] >= 210:
1107 self._wizardState = 2
1108 wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
1109 wx.CallAfter(self.resumeButton.Enable, True)
1110 wx.CallAfter(self.resumeButton.SetFocus)
1112 def mcStateChange(self, state):
1113 if self.comm is None:
1115 if self.comm.isOperational():
1116 if self._wizardState == 0:
1117 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
1118 self.comm.sendCommand('M105')
1119 self.comm.sendCommand('M104 S220 T0')
1120 self.comm.sendCommand('M104 S220 T1')
1121 self.comm.sendCommand('G28')
1122 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1123 self._wizardState = 1
1124 if not self.comm.isPrinting():
1125 if self._wizardState == 3:
1126 self._wizardState = 4
1127 wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
1128 wx.CallAfter(self.textEntry.SetValue, '0.0')
1129 wx.CallAfter(self.textEntry.Enable, True)
1130 wx.CallAfter(self.resumeButton.Enable, True)
1131 wx.CallAfter(self.resumeButton.SetFocus)
1132 elif self._wizardState == 6:
1133 self._wizardState = 7
1134 wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
1135 wx.CallAfter(self.textEntry.SetValue, '10')
1136 wx.CallAfter(self.textEntry.Enable, True)
1137 wx.CallAfter(self.resumeButton.Enable, True)
1138 wx.CallAfter(self.resumeButton.SetFocus)
1140 elif self.comm.isError():
1141 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1143 def mcMessage(self, message):
1146 def mcProgress(self, lineNr):
1149 def mcZChange(self, newZ):
1152 class bedLevelWizard(wx.wizard.Wizard):
1154 super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
1156 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1157 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1159 self.mainPage = bedLevelWizardMain(self)
1160 self.headOffsetCalibration = None
1162 self.FitToPage(self.mainPage)
1163 self.GetPageAreaSizer().Add(self.mainPage)
1165 self.RunWizard(self.mainPage)
1168 def OnPageChanging(self, e):
1169 e.GetPage().StoreData()
1171 def OnPageChanged(self, e):
1172 if e.GetPage().AllowNext():
1173 self.FindWindowById(wx.ID_FORWARD).Enable()
1175 self.FindWindowById(wx.ID_FORWARD).Disable()
1176 self.FindWindowById(wx.ID_BACKWARD).Disable()
1178 class headOffsetWizard(wx.wizard.Wizard):
1180 super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
1182 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1183 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1185 self.mainPage = headOffsetCalibrationPage(self)
1187 self.FitToPage(self.mainPage)
1188 self.GetPageAreaSizer().Add(self.mainPage)
1190 self.RunWizard(self.mainPage)
1193 def OnPageChanging(self, e):
1194 e.GetPage().StoreData()
1196 def OnPageChanged(self, e):
1197 if e.GetPage().AllowNext():
1198 self.FindWindowById(wx.ID_FORWARD).Enable()
1200 self.FindWindowById(wx.ID_FORWARD).Disable()
1201 self.FindWindowById(wx.ID_BACKWARD).Disable()