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, addNew):
220 super(FirstInfoPage, self).__init__(parent, _("Add new machine wizard"))
222 super(FirstInfoPage, self).__init__(parent, _("First time run wizard"))
223 self.AddText(_("Welcome, and thanks for trying Cura!"))
225 self.AddText(_("This wizard will help you with the following steps:"))
226 self.AddText(_("* Configure Cura for your machine"))
227 self.AddText(_("* Optionally upgrade your firmware"))
228 self.AddText(_("* Optionally check if your machine is working safely"))
229 self.AddText(_("* Optionally level your printer bed"))
231 #self.AddText('* Calibrate your machine')
232 #self.AddText('* Do your first print')
235 class RepRapInfoPage(InfoPage):
236 def __init__(self, parent):
237 super(RepRapInfoPage, self).__init__(parent, "RepRap information")
239 _("RepRap machines are vastly different, and there is no\ndefault configuration in Cura for any of them."))
240 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
242 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
244 self.machineWidth = self.AddLabelTextCtrl(_("Machine width (mm)"), "80")
245 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth (mm)"), "80")
246 self.machineHeight = self.AddLabelTextCtrl(_("Machine height (mm)"), "60")
247 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
248 self.heatedBed = self.AddCheckbox(_("Heated bed"))
249 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
252 profile.putPreference('machine_width', self.machineWidth.GetValue())
253 profile.putPreference('machine_depth', self.machineDepth.GetValue())
254 profile.putPreference('machine_height', self.machineHeight.GetValue())
255 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
256 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
257 profile.putPreference('has_heated_bed', str(self.heatedBed.GetValue()))
258 profile.putPreference('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
259 profile.putPreference('extruder_head_size_min_x', '0')
260 profile.putPreference('extruder_head_size_min_y', '0')
261 profile.putPreference('extruder_head_size_max_x', '0')
262 profile.putPreference('extruder_head_size_max_y', '0')
263 profile.putPreference('extruder_head_size_height', '0')
266 class MachineSelectPage(InfoPage):
267 def __init__(self, parent):
268 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
269 self.AddText(_("What kind of machine do you have:"))
271 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2", style=wx.RB_GROUP)
272 self.Ultimaker2Radio.SetValue(True)
273 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
274 self.UltimakerRadio = self.AddRadioButton("Ultimaker")
275 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
276 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap)"))
277 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
279 self.AddText(_("The collection of anonymous usage information helps with the continued improvement of Cura."))
280 self.AddText(_("This does NOT submit your models online nor gathers any privacy related information."))
281 self.SubmitUserStats = self.AddCheckbox(_("Submit anonymous usage information:"))
282 self.AddText(_("For full details see: http://wiki.ultimaker.com/Cura:stats"))
283 self.SubmitUserStats.SetValue(True)
285 def OnUltimaker2Select(self, e):
286 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
288 def OnUltimakerSelect(self, e):
289 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
291 def OnOtherSelect(self, e):
292 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().repRapInfoPage)
295 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
299 if self.Ultimaker2Radio.GetValue():
300 profile.putMachineSetting('machine_width', '230')
301 profile.putMachineSetting('machine_depth', '225')
302 profile.putMachineSetting('machine_height', '205')
303 profile.putMachineSetting('machine_type', 'ultimaker2')
304 profile.putMachineSetting('machine_center_is_zero', 'False')
305 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
306 profile.putProfileSetting('nozzle_size', '0.4')
307 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
308 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
309 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
310 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
311 profile.putMachineSetting('extruder_head_size_height', '60.0')
312 elif self.UltimakerRadio.GetValue():
313 profile.putMachineSetting('machine_width', '205')
314 profile.putMachineSetting('machine_depth', '205')
315 profile.putMachineSetting('machine_height', '200')
316 profile.putMachineSetting('machine_type', 'ultimaker')
317 profile.putMachineSetting('machine_center_is_zero', 'False')
318 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
319 profile.putProfileSetting('nozzle_size', '0.4')
320 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
321 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
322 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
323 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
324 profile.putMachineSetting('extruder_head_size_height', '60.0')
326 profile.putMachineSetting('machine_width', '80')
327 profile.putMachineSetting('machine_depth', '80')
328 profile.putMachineSetting('machine_height', '60')
329 profile.putMachineSetting('machine_type', 'reprap')
330 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
331 profile.putPreference('startMode', 'Normal')
332 profile.putProfileSetting('nozzle_size', '0.5')
333 profile.checkAndUpdateMachineName()
334 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
335 if self.SubmitUserStats.GetValue():
336 profile.putPreference('submit_slice_information', 'True')
338 profile.putPreference('submit_slice_information', 'False')
341 class SelectParts(InfoPage):
342 def __init__(self, parent):
343 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
344 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."))
346 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
347 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
348 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
350 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."))
351 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
352 self.springExtruder.SetValue(True)
355 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
356 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
357 if self.dualExtrusion.GetValue():
358 profile.putMachineSetting('extruder_amount', '2')
359 profile.putMachineSetting('machine_depth', '195')
361 profile.putMachineSetting('extruder_amount', '1')
362 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
363 profile.putProfileSetting('retraction_enable', 'True')
365 profile.putProfileSetting('retraction_enable', 'False')
368 class UltimakerFirmwareUpgradePage(InfoPage):
369 def __init__(self, parent):
370 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
371 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."))
372 self.AddHiddenSeperator()
373 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
374 self.AddHiddenSeperator()
375 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."))
376 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
377 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
378 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
379 self.AddHiddenSeperator()
380 self.AddText(_("Do not upgrade to this firmware if:"))
381 self.AddText(_("* You have an older machine based on ATMega1280"))
382 self.AddText(_("* Have other changes in the firmware"))
383 # button = self.AddButton('Goto this page for a custom firmware')
384 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
389 def OnUpgradeClick(self, e):
390 if firmwareInstall.InstallFirmware():
391 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
393 def OnSkipClick(self, e):
394 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
395 self.GetParent().ShowPage(self.GetNext())
397 def OnUrlClick(self, e):
398 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
400 class UltimakerCheckupPage(InfoPage):
401 def __init__(self, parent):
402 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
404 self.checkBitmap = wx.Bitmap(getPathForImage('checkmark.png'))
405 self.crossBitmap = wx.Bitmap(getPathForImage('cross.png'))
406 self.unknownBitmap = wx.Bitmap(getPathForImage('question.png'))
407 self.endStopNoneBitmap = wx.Bitmap(getPathForImage('endstop_none.png'))
408 self.endStopXMinBitmap = wx.Bitmap(getPathForImage('endstop_xmin.png'))
409 self.endStopXMaxBitmap = wx.Bitmap(getPathForImage('endstop_xmax.png'))
410 self.endStopYMinBitmap = wx.Bitmap(getPathForImage('endstop_ymin.png'))
411 self.endStopYMaxBitmap = wx.Bitmap(getPathForImage('endstop_ymax.png'))
412 self.endStopZMinBitmap = wx.Bitmap(getPathForImage('endstop_zmin.png'))
413 self.endStopZMaxBitmap = wx.Bitmap(getPathForImage('endstop_zmax.png'))
416 _("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."))
417 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
418 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
419 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
421 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
422 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
423 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
425 self.infoBox = self.AddInfoBox()
426 self.machineState = self.AddText("")
427 self.temperatureLabel = self.AddText("")
428 self.errorLogButton = self.AddButton(_("Show error log"))
429 self.errorLogButton.Show(False)
431 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
433 self.xMinStop = False
434 self.xMaxStop = False
435 self.yMinStop = False
436 self.yMaxStop = False
437 self.zMinStop = False
438 self.zMaxStop = False
440 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
443 if self.comm is not None:
447 self.endstopBitmap.Show(False)
450 def OnSkipClick(self, e):
451 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
452 self.GetParent().ShowPage(self.GetNext())
454 def OnCheckClick(self, e=None):
455 self.errorLogButton.Show(False)
456 if self.comm is not None:
460 wx.CallAfter(self.OnCheckClick)
462 self.infoBox.SetBusy(_("Connecting to machine."))
463 self.commState.SetBitmap(self.unknownBitmap)
464 self.tempState.SetBitmap(self.unknownBitmap)
465 self.stopState.SetBitmap(self.unknownBitmap)
466 self.checkupState = 0
467 self.checkExtruderNr = 0
468 self.comm = machineCom.MachineCom(callbackObject=self)
470 def OnErrorLog(self, e):
471 printWindow.LogWindow('\n'.join(self.comm.getLog()))
473 def mcLog(self, message):
476 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
477 if not self.comm.isOperational():
479 if self.checkupState == 0:
480 self.tempCheckTimeout = 20
481 if temp[self.checkExtruderNr] > 70:
482 self.checkupState = 1
483 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
484 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
485 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
487 self.startTemp = temp[self.checkExtruderNr]
488 self.checkupState = 2
489 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
490 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
491 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
492 elif self.checkupState == 1:
494 self.startTemp = temp[self.checkExtruderNr]
495 self.checkupState = 2
496 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
497 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
498 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
499 elif self.checkupState == 2:
500 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
501 if temp[self.checkExtruderNr] > self.startTemp + 40:
502 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
503 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
504 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
505 self.checkExtruderNr = 0
506 self.checkupState = 3
507 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
508 wx.CallAfter(self.endstopBitmap.Show, True)
509 wx.CallAfter(self.Layout)
510 self.comm.sendCommand('M119')
511 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
513 self.checkupState = 0
514 self.checkExtruderNr += 1
516 self.tempCheckTimeout -= 1
517 if self.tempCheckTimeout < 1:
518 self.checkupState = -1
519 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
520 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
521 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
522 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
523 elif self.checkupState >= 3 and self.checkupState < 10:
524 self.comm.sendCommand('M119')
525 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
527 def mcStateChange(self, state):
528 if self.comm is None:
530 if self.comm.isOperational():
531 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
532 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
533 elif self.comm.isError():
534 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
535 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
536 wx.CallAfter(self.endstopBitmap.Show, False)
537 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
538 wx.CallAfter(self.errorLogButton.Show, True)
539 wx.CallAfter(self.Layout)
541 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
543 def mcMessage(self, message):
544 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
545 for data in message.split(' '):
547 tag, value = data.split(':', 1)
549 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
551 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
553 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
555 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
557 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
559 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
561 tag, value = map(str.strip, message.split(':', 1))
563 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
565 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
567 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
569 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
571 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
573 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
574 if 'z_max' in message:
575 self.comm.sendCommand('M119')
577 if self.checkupState == 3:
578 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
579 self.checkupState = 4
580 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
581 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
582 elif self.checkupState == 4:
583 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
584 self.checkupState = 5
585 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
586 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
587 elif self.checkupState == 5:
588 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
589 self.checkupState = 6
590 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
591 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
592 elif self.checkupState == 6:
593 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
594 self.checkupState = 7
595 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
596 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
597 elif self.checkupState == 7:
598 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
599 self.checkupState = 8
600 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
601 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
602 elif self.checkupState == 8:
603 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
604 self.checkupState = 9
605 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
606 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
607 elif self.checkupState == 9:
608 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
609 self.checkupState = 10
611 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
612 wx.CallAfter(self.infoBox.SetReadyIndicator)
613 wx.CallAfter(self.endstopBitmap.Show, False)
614 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
615 wx.CallAfter(self.OnSkipClick, None)
617 def mcProgress(self, lineNr):
620 def mcZChange(self, newZ):
624 class UltimakerCalibrationPage(InfoPage):
625 def __init__(self, parent):
626 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
628 self.AddText("Your Ultimaker requires some calibration.")
629 self.AddText("This calibration is needed for a proper extrusion amount.")
631 self.AddText("The following values are needed:")
632 self.AddText("* Diameter of filament")
633 self.AddText("* Number of steps per mm of filament extrusion")
635 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
637 self.AddText("First we need the diameter of your filament:")
638 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
640 "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.")
641 self.AddText("Note: This value can be changed later at any time.")
644 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
647 class UltimakerCalibrateStepsPerEPage(InfoPage):
648 def __init__(self, parent):
649 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
651 #if profile.getMachineSetting('steps_per_e') == '0':
652 # profile.putMachineSetting('steps_per_e', '865.888')
654 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
655 self.AddText(_("First remove any filament from your machine."))
656 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
657 self.AddText(_("We'll push the filament 100mm"))
658 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
659 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
660 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
661 self.AddText(_("This results in the following steps per E:"))
662 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
663 self.AddText(_("You can repeat these steps to get better calibration."))
666 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
667 self.heatButton = self.AddButton(_("Heatup for filament removal"))
669 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
670 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
671 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
673 def OnSaveLengthClick(self, e):
674 currentEValue = float(self.stepsPerEInput.GetValue())
675 realExtrudeLength = float(self.lengthInput.GetValue())
676 newEValue = currentEValue * 100 / realExtrudeLength
677 self.stepsPerEInput.SetValue(str(newEValue))
678 self.lengthInput.SetValue("100")
680 def OnExtrudeClick(self, e):
681 threading.Thread(target=self.OnExtrudeRun).start()
683 def OnExtrudeRun(self):
684 self.heatButton.Enable(False)
685 self.extrudeButton.Enable(False)
686 currentEValue = float(self.stepsPerEInput.GetValue())
687 self.comm = machineCom.MachineCom()
688 if not self.comm.isOpen():
690 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
691 'Printer error', wx.OK | wx.ICON_INFORMATION)
692 self.heatButton.Enable(True)
693 self.extrudeButton.Enable(True)
696 line = self.comm.readline()
701 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
704 self.sendGCommand('M302') #Disable cold extrusion protection
705 self.sendGCommand("M92 E%f" % (currentEValue))
706 self.sendGCommand("G92 E0")
707 self.sendGCommand("G1 E100 F600")
710 self.extrudeButton.Enable()
711 self.heatButton.Enable()
713 def OnHeatClick(self, e):
714 threading.Thread(target=self.OnHeatRun).start()
717 self.heatButton.Enable(False)
718 self.extrudeButton.Enable(False)
719 self.comm = machineCom.MachineCom()
720 if not self.comm.isOpen():
722 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
723 'Printer error', wx.OK | wx.ICON_INFORMATION)
724 self.heatButton.Enable(True)
725 self.extrudeButton.Enable(True)
728 line = self.comm.readline()
730 self.heatButton.Enable(True)
731 self.extrudeButton.Enable(True)
735 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
738 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
740 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
741 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
742 self.sendGCommand('M104 S0')
745 self.heatButton.Enable(True)
746 self.extrudeButton.Enable(True)
748 def sendGCommand(self, cmd):
749 self.comm.sendCommand(cmd) #Disable cold extrusion protection
751 line = self.comm.readline()
754 if line.startswith('ok'):
758 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
760 class Ultimaker2ReadyPage(InfoPage):
761 def __init__(self, parent):
762 super(Ultimaker2ReadyPage, self).__init__(parent, "Ultimaker2")
763 self.AddText('Congratulations on your the purchase of your brand new Ultimaker2.')
764 self.AddText('Cura is now ready to be used with your Ultimaker2.')
767 class configWizard(wx.wizard.Wizard):
768 def __init__(self, addNew = False):
769 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
771 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
772 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
774 self.firstInfoPage = FirstInfoPage(self, addNew)
775 self.machineSelectPage = MachineSelectPage(self)
776 self.ultimakerSelectParts = SelectParts(self)
777 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
778 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
779 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
780 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
781 self.bedLevelPage = bedLevelWizardMain(self)
782 self.headOffsetCalibration = headOffsetCalibrationPage(self)
783 self.repRapInfoPage = RepRapInfoPage(self)
785 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
787 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
788 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
789 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
790 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
791 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
792 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
793 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
795 self.FitToPage(self.firstInfoPage)
796 self.GetPageAreaSizer().Add(self.firstInfoPage)
798 self.RunWizard(self.firstInfoPage)
801 def OnPageChanging(self, e):
802 e.GetPage().StoreData()
804 def OnPageChanged(self, e):
805 if e.GetPage().AllowNext():
806 self.FindWindowById(wx.ID_FORWARD).Enable()
808 self.FindWindowById(wx.ID_FORWARD).Disable()
809 self.FindWindowById(wx.ID_BACKWARD).Disable()
811 class bedLevelWizardMain(InfoPage):
812 def __init__(self, parent):
813 super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
815 self.AddText('This wizard will help you in leveling your printer bed')
817 self.AddText('It will do the following steps')
818 self.AddText('* Move the printer head to each corner')
819 self.AddText(' and let you adjust the height of the bed to the nozzle')
820 self.AddText('* Print a line around the bed to check if it is level')
823 self.connectButton = self.AddButton('Connect to printer')
826 self.infoBox = self.AddInfoBox()
827 self.resumeButton = self.AddButton('Resume')
828 self.resumeButton.Enable(False)
830 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
831 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
833 def OnConnect(self, e = None):
834 if self.comm is not None:
838 wx.CallAfter(self.OnConnect)
840 self.connectButton.Enable(False)
841 self.comm = machineCom.MachineCom(callbackObject=self)
842 self.infoBox.SetBusy('Connecting to machine.')
843 self._wizardState = 0
846 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
847 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
850 def OnResume(self, e):
851 feedZ = profile.getProfileSettingFloat('print_speed') * 60
852 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
853 if self._wizardState == 2:
854 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
855 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
856 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
857 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
858 self.comm.sendCommand('M400')
859 self._wizardState = 3
860 elif self._wizardState == 4:
861 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
862 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
863 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
864 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
865 self.comm.sendCommand('M400')
866 self._wizardState = 5
867 elif self._wizardState == 6:
868 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
869 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
870 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
871 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
872 self.comm.sendCommand('M400')
873 self._wizardState = 7
874 elif self._wizardState == 8:
875 wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
876 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
877 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
878 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
879 self._wizardState = 9
880 elif self._wizardState == 10:
881 self._wizardState = 11
882 wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
883 feedZ = profile.getProfileSettingFloat('print_speed') * 60
884 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
885 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
886 w = profile.getMachineSettingFloat('machine_width')
887 d = profile.getMachineSettingFloat('machine_depth')
888 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
889 filamentArea = math.pi * filamentRadius * filamentRadius
890 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
894 'G1 Z2 F%d' % (feedZ),
896 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
897 'G1 Z0.3 F%d' % (feedZ)]
899 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
901 for i in xrange(0, 3):
902 dist = 5.0 + 0.4 * float(i)
903 eValue += (d - 2.0*dist) * ePerMM
904 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
905 eValue += (w - 2.0*dist) * ePerMM
906 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
907 eValue += (d - 2.0*dist) * ePerMM
908 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
909 eValue += (w - 2.0*dist) * ePerMM
910 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
912 gcodeList.append('M400')
913 self.comm.printGCode(gcodeList)
914 self.resumeButton.Enable(False)
916 def mcLog(self, message):
917 print 'Log:', message
919 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
920 if self._wizardState == 1:
921 self._wizardState = 2
922 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
923 wx.CallAfter(self.resumeButton.Enable, True)
924 elif self._wizardState == 3:
925 self._wizardState = 4
926 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
927 wx.CallAfter(self.resumeButton.Enable, True)
928 elif self._wizardState == 5:
929 self._wizardState = 6
930 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
931 wx.CallAfter(self.resumeButton.Enable, True)
932 elif self._wizardState == 7:
933 self._wizardState = 8
934 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
935 wx.CallAfter(self.resumeButton.Enable, True)
936 elif self._wizardState == 9:
937 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
938 wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
940 wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
941 wx.CallAfter(self.resumeButton.Enable, True)
942 self._wizardState = 10
944 def mcStateChange(self, state):
945 if self.comm is None:
947 if self.comm.isOperational():
948 if self._wizardState == 0:
949 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
950 self.comm.sendCommand('M105')
951 self.comm.sendCommand('G28')
952 self._wizardState = 1
953 elif self._wizardState == 11 and not self.comm.isPrinting():
954 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
955 self.comm.sendCommand('G92 E0')
956 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
957 self.comm.sendCommand('M104 S0')
958 wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
959 wx.CallAfter(self.infoBox.SetReadyIndicator)
960 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
961 wx.CallAfter(self.connectButton.Enable, True)
962 self._wizardState = 12
963 elif self.comm.isError():
964 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
966 def mcMessage(self, message):
969 def mcProgress(self, lineNr):
972 def mcZChange(self, newZ):
975 class headOffsetCalibrationPage(InfoPage):
976 def __init__(self, parent):
977 super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
979 self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
982 self.connectButton = self.AddButton('Connect to printer')
985 self.infoBox = self.AddInfoBox()
986 self.textEntry = self.AddTextCtrl('')
987 self.textEntry.Enable(False)
988 self.resumeButton = self.AddButton('Resume')
989 self.resumeButton.Enable(False)
991 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
992 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
994 def OnConnect(self, e = None):
995 if self.comm is not None:
999 wx.CallAfter(self.OnConnect)
1001 self.connectButton.Enable(False)
1002 self.comm = machineCom.MachineCom(callbackObject=self)
1003 self.infoBox.SetBusy('Connecting to machine.')
1004 self._wizardState = 0
1006 def OnResume(self, e):
1007 if self._wizardState == 2:
1008 self._wizardState = 3
1009 wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
1011 w = profile.getMachineSettingFloat('machine_width')
1012 d = profile.getMachineSettingFloat('machine_depth')
1014 gcode = gcodeGenerator.gcodeGenerator()
1015 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1016 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1023 gcode.addMove(w/2, 5)
1024 gcode.addMove(z=0.2)
1026 gcode.addExtrude(w/2, d-5.0)
1028 gcode.addMove(5, d/2)
1030 gcode.addExtrude(w-5.0, d/2)
1031 gcode.addRetract(15)
1034 gcode.addMove(w/2, 5)
1036 gcode.addExtrude(w/2, d-5.0)
1038 gcode.addMove(5, d/2)
1040 gcode.addExtrude(w-5.0, d/2)
1041 gcode.addRetract(15)
1046 gcode.addCmd('M400')
1048 self.comm.printGCode(gcode.list())
1049 self.resumeButton.Enable(False)
1050 elif self._wizardState == 4:
1052 float(self.textEntry.GetValue())
1055 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1056 self._wizardState = 5
1057 self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
1058 self.textEntry.SetValue('0.0')
1059 self.textEntry.Enable(True)
1060 elif self._wizardState == 5:
1062 float(self.textEntry.GetValue())
1065 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1066 self._wizardState = 6
1067 self.infoBox.SetBusy('Printing the fine calibration lines.')
1068 self.textEntry.SetValue('')
1069 self.textEntry.Enable(False)
1070 self.resumeButton.Enable(False)
1072 x = profile.getMachineSettingFloat('extruder_offset_x1')
1073 y = profile.getMachineSettingFloat('extruder_offset_y1')
1074 gcode = gcodeGenerator.gcodeGenerator()
1075 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1076 gcode.setPrintSpeed(25)
1079 gcode.addMove(50, 40, 0.2)
1081 for n in xrange(0, 10):
1082 gcode.addExtrude(50 + n * 10, 150)
1083 gcode.addExtrude(50 + n * 10 + 5, 150)
1084 gcode.addExtrude(50 + n * 10 + 5, 40)
1085 gcode.addExtrude(50 + n * 10 + 10, 40)
1086 gcode.addMove(40, 50)
1087 for n in xrange(0, 10):
1088 gcode.addExtrude(150, 50 + n * 10)
1089 gcode.addExtrude(150, 50 + n * 10 + 5)
1090 gcode.addExtrude(40, 50 + n * 10 + 5)
1091 gcode.addExtrude(40, 50 + n * 10 + 10)
1092 gcode.addRetract(15)
1095 gcode.addMove(50 - x, 30 - y, 0.2)
1097 for n in xrange(0, 10):
1098 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1099 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1100 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1101 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1102 gcode.addMove(30 - x, 50 - y, 0.2)
1103 for n in xrange(0, 10):
1104 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1105 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1106 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1107 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1108 gcode.addRetract(15)
1110 gcode.addCmd('M400')
1111 gcode.addCmd('M104 T0 S0')
1112 gcode.addCmd('M104 T1 S0')
1113 self.comm.printGCode(gcode.list())
1114 elif self._wizardState == 7:
1116 n = int(self.textEntry.GetValue()) - 1
1119 x = profile.getMachineSettingFloat('extruder_offset_x1')
1121 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1122 self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
1123 self.textEntry.SetValue('10')
1124 self._wizardState = 8
1125 elif self._wizardState == 8:
1127 n = int(self.textEntry.GetValue()) - 1
1130 y = profile.getMachineSettingFloat('extruder_offset_y1')
1132 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1133 self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1134 self.infoBox.SetReadyIndicator()
1135 self._wizardState = 8
1137 self.resumeButton.Enable(False)
1139 def mcLog(self, message):
1140 print 'Log:', message
1142 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1143 if self._wizardState == 1:
1144 if temp[0] >= 210 and temp[1] >= 210:
1145 self._wizardState = 2
1146 wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
1147 wx.CallAfter(self.resumeButton.Enable, True)
1148 wx.CallAfter(self.resumeButton.SetFocus)
1150 def mcStateChange(self, state):
1151 if self.comm is None:
1153 if self.comm.isOperational():
1154 if self._wizardState == 0:
1155 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
1156 self.comm.sendCommand('M105')
1157 self.comm.sendCommand('M104 S220 T0')
1158 self.comm.sendCommand('M104 S220 T1')
1159 self.comm.sendCommand('G28')
1160 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1161 self._wizardState = 1
1162 if not self.comm.isPrinting():
1163 if self._wizardState == 3:
1164 self._wizardState = 4
1165 wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
1166 wx.CallAfter(self.textEntry.SetValue, '0.0')
1167 wx.CallAfter(self.textEntry.Enable, True)
1168 wx.CallAfter(self.resumeButton.Enable, True)
1169 wx.CallAfter(self.resumeButton.SetFocus)
1170 elif self._wizardState == 6:
1171 self._wizardState = 7
1172 wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
1173 wx.CallAfter(self.textEntry.SetValue, '10')
1174 wx.CallAfter(self.textEntry.Enable, True)
1175 wx.CallAfter(self.resumeButton.Enable, True)
1176 wx.CallAfter(self.resumeButton.SetFocus)
1178 elif self.comm.isError():
1179 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1181 def mcMessage(self, message):
1184 def mcProgress(self, lineNr):
1187 def mcZChange(self, newZ):
1190 class bedLevelWizard(wx.wizard.Wizard):
1192 super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
1194 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1195 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1197 self.mainPage = bedLevelWizardMain(self)
1198 self.headOffsetCalibration = None
1200 self.FitToPage(self.mainPage)
1201 self.GetPageAreaSizer().Add(self.mainPage)
1203 self.RunWizard(self.mainPage)
1206 def OnPageChanging(self, e):
1207 e.GetPage().StoreData()
1209 def OnPageChanged(self, e):
1210 if e.GetPage().AllowNext():
1211 self.FindWindowById(wx.ID_FORWARD).Enable()
1213 self.FindWindowById(wx.ID_FORWARD).Disable()
1214 self.FindWindowById(wx.ID_BACKWARD).Disable()
1216 class headOffsetWizard(wx.wizard.Wizard):
1218 super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
1220 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1221 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1223 self.mainPage = headOffsetCalibrationPage(self)
1225 self.FitToPage(self.mainPage)
1226 self.GetPageAreaSizer().Add(self.mainPage)
1228 self.RunWizard(self.mainPage)
1231 def OnPageChanging(self, e):
1232 e.GetPage().StoreData()
1234 def OnPageChanged(self, e):
1235 if e.GetPage().AllowNext():
1236 self.FindWindowById(wx.ID_FORWARD).Enable()
1238 self.FindWindowById(wx.ID_FORWARD).Disable()
1239 self.FindWindowById(wx.ID_BACKWARD).Disable()