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.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
245 self.machineWidth = self.AddLabelTextCtrl(_("Machine width (mm)"), "80")
246 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth (mm)"), "80")
247 self.machineHeight = self.AddLabelTextCtrl(_("Machine height (mm)"), "60")
248 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
249 self.heatedBed = self.AddCheckbox(_("Heated bed"))
250 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
253 profile.putMachineSetting('machine_name', self.machineName.GetValue())
254 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
255 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
256 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
257 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
258 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
259 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
260 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
261 profile.putMachineSetting('extruder_head_size_min_x', '0')
262 profile.putMachineSetting('extruder_head_size_min_y', '0')
263 profile.putMachineSetting('extruder_head_size_max_x', '0')
264 profile.putMachineSetting('extruder_head_size_max_y', '0')
265 profile.putMachineSetting('extruder_head_size_height', '0')
266 profile.checkAndUpdateMachineName()
268 class MachineSelectPage(InfoPage):
269 def __init__(self, parent):
270 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
271 self.AddText(_("What kind of machine do you have:"))
273 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2", style=wx.RB_GROUP)
274 self.Ultimaker2Radio.SetValue(True)
275 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
276 self.UltimakerRadio = self.AddRadioButton("Ultimaker")
277 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
278 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap)"))
279 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
281 self.AddText(_("The collection of anonymous usage information helps with the continued improvement of Cura."))
282 self.AddText(_("This does NOT submit your models online nor gathers any privacy related information."))
283 self.SubmitUserStats = self.AddCheckbox(_("Submit anonymous usage information:"))
284 self.AddText(_("For full details see: http://wiki.ultimaker.com/Cura:stats"))
285 self.SubmitUserStats.SetValue(True)
287 def OnUltimaker2Select(self, e):
288 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
290 def OnUltimakerSelect(self, e):
291 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
293 def OnOtherSelect(self, e):
294 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().repRapInfoPage)
297 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
301 if self.Ultimaker2Radio.GetValue():
302 profile.putMachineSetting('machine_width', '230')
303 profile.putMachineSetting('machine_depth', '225')
304 profile.putMachineSetting('machine_height', '205')
305 profile.putMachineSetting('machine_type', 'ultimaker2')
306 profile.putMachineSetting('machine_center_is_zero', 'False')
307 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
308 profile.putProfileSetting('nozzle_size', '0.4')
309 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
310 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
311 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
312 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
313 profile.putMachineSetting('extruder_head_size_height', '60.0')
314 elif self.UltimakerRadio.GetValue():
315 profile.putMachineSetting('machine_width', '205')
316 profile.putMachineSetting('machine_depth', '205')
317 profile.putMachineSetting('machine_height', '200')
318 profile.putMachineSetting('machine_type', 'ultimaker')
319 profile.putMachineSetting('machine_center_is_zero', 'False')
320 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
321 profile.putProfileSetting('nozzle_size', '0.4')
322 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
323 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
324 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
325 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
326 profile.putMachineSetting('extruder_head_size_height', '60.0')
328 profile.putMachineSetting('machine_width', '80')
329 profile.putMachineSetting('machine_depth', '80')
330 profile.putMachineSetting('machine_height', '60')
331 profile.putMachineSetting('machine_type', 'reprap')
332 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
333 profile.putPreference('startMode', 'Normal')
334 profile.putProfileSetting('nozzle_size', '0.5')
335 profile.checkAndUpdateMachineName()
336 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
337 if self.SubmitUserStats.GetValue():
338 profile.putPreference('submit_slice_information', 'True')
340 profile.putPreference('submit_slice_information', 'False')
343 class SelectParts(InfoPage):
344 def __init__(self, parent):
345 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
346 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."))
348 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
349 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
350 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
352 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."))
353 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
354 self.springExtruder.SetValue(True)
357 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
358 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
359 if self.dualExtrusion.GetValue():
360 profile.putMachineSetting('extruder_amount', '2')
361 profile.putMachineSetting('machine_depth', '195')
363 profile.putMachineSetting('extruder_amount', '1')
364 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
365 profile.putProfileSetting('retraction_enable', 'True')
367 profile.putProfileSetting('retraction_enable', 'False')
370 class UltimakerFirmwareUpgradePage(InfoPage):
371 def __init__(self, parent):
372 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
373 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."))
374 self.AddHiddenSeperator()
375 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
376 self.AddHiddenSeperator()
377 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."))
378 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
379 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
380 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
381 self.AddHiddenSeperator()
382 self.AddText(_("Do not upgrade to this firmware if:"))
383 self.AddText(_("* You have an older machine based on ATMega1280"))
384 self.AddText(_("* Have other changes in the firmware"))
385 # button = self.AddButton('Goto this page for a custom firmware')
386 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
391 def OnUpgradeClick(self, e):
392 if firmwareInstall.InstallFirmware():
393 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
395 def OnSkipClick(self, e):
396 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
397 self.GetParent().ShowPage(self.GetNext())
399 def OnUrlClick(self, e):
400 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
402 class UltimakerCheckupPage(InfoPage):
403 def __init__(self, parent):
404 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
406 self.checkBitmap = wx.Bitmap(getPathForImage('checkmark.png'))
407 self.crossBitmap = wx.Bitmap(getPathForImage('cross.png'))
408 self.unknownBitmap = wx.Bitmap(getPathForImage('question.png'))
409 self.endStopNoneBitmap = wx.Bitmap(getPathForImage('endstop_none.png'))
410 self.endStopXMinBitmap = wx.Bitmap(getPathForImage('endstop_xmin.png'))
411 self.endStopXMaxBitmap = wx.Bitmap(getPathForImage('endstop_xmax.png'))
412 self.endStopYMinBitmap = wx.Bitmap(getPathForImage('endstop_ymin.png'))
413 self.endStopYMaxBitmap = wx.Bitmap(getPathForImage('endstop_ymax.png'))
414 self.endStopZMinBitmap = wx.Bitmap(getPathForImage('endstop_zmin.png'))
415 self.endStopZMaxBitmap = wx.Bitmap(getPathForImage('endstop_zmax.png'))
418 _("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."))
419 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
420 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
421 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
423 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
424 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
425 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
427 self.infoBox = self.AddInfoBox()
428 self.machineState = self.AddText("")
429 self.temperatureLabel = self.AddText("")
430 self.errorLogButton = self.AddButton(_("Show error log"))
431 self.errorLogButton.Show(False)
433 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
435 self.xMinStop = False
436 self.xMaxStop = False
437 self.yMinStop = False
438 self.yMaxStop = False
439 self.zMinStop = False
440 self.zMaxStop = False
442 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
445 if self.comm is not None:
449 self.endstopBitmap.Show(False)
452 def OnSkipClick(self, e):
453 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
454 self.GetParent().ShowPage(self.GetNext())
456 def OnCheckClick(self, e=None):
457 self.errorLogButton.Show(False)
458 if self.comm is not None:
462 wx.CallAfter(self.OnCheckClick)
464 self.infoBox.SetBusy(_("Connecting to machine."))
465 self.commState.SetBitmap(self.unknownBitmap)
466 self.tempState.SetBitmap(self.unknownBitmap)
467 self.stopState.SetBitmap(self.unknownBitmap)
468 self.checkupState = 0
469 self.checkExtruderNr = 0
470 self.comm = machineCom.MachineCom(callbackObject=self)
472 def OnErrorLog(self, e):
473 printWindow.LogWindow('\n'.join(self.comm.getLog()))
475 def mcLog(self, message):
478 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
479 if not self.comm.isOperational():
481 if self.checkupState == 0:
482 self.tempCheckTimeout = 20
483 if temp[self.checkExtruderNr] > 70:
484 self.checkupState = 1
485 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
486 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
487 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
489 self.startTemp = temp[self.checkExtruderNr]
490 self.checkupState = 2
491 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
492 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
493 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
494 elif self.checkupState == 1:
496 self.startTemp = temp[self.checkExtruderNr]
497 self.checkupState = 2
498 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
499 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
500 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
501 elif self.checkupState == 2:
502 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
503 if temp[self.checkExtruderNr] > self.startTemp + 40:
504 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
505 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
506 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
507 self.checkExtruderNr = 0
508 self.checkupState = 3
509 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
510 wx.CallAfter(self.endstopBitmap.Show, True)
511 wx.CallAfter(self.Layout)
512 self.comm.sendCommand('M119')
513 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
515 self.checkupState = 0
516 self.checkExtruderNr += 1
518 self.tempCheckTimeout -= 1
519 if self.tempCheckTimeout < 1:
520 self.checkupState = -1
521 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
522 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
523 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
524 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
525 elif self.checkupState >= 3 and self.checkupState < 10:
526 self.comm.sendCommand('M119')
527 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
529 def mcStateChange(self, state):
530 if self.comm is None:
532 if self.comm.isOperational():
533 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
534 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
535 elif self.comm.isError():
536 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
537 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
538 wx.CallAfter(self.endstopBitmap.Show, False)
539 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
540 wx.CallAfter(self.errorLogButton.Show, True)
541 wx.CallAfter(self.Layout)
543 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
545 def mcMessage(self, message):
546 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
547 for data in message.split(' '):
549 tag, value = data.split(':', 1)
551 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
553 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
555 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
557 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
559 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
561 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
563 tag, value = map(str.strip, message.split(':', 1))
565 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
567 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
569 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
571 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
573 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
575 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
576 if 'z_max' in message:
577 self.comm.sendCommand('M119')
579 if self.checkupState == 3:
580 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
581 self.checkupState = 4
582 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
583 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
584 elif self.checkupState == 4:
585 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
586 self.checkupState = 5
587 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
588 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
589 elif self.checkupState == 5:
590 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
591 self.checkupState = 6
592 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
593 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
594 elif self.checkupState == 6:
595 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
596 self.checkupState = 7
597 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
598 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
599 elif self.checkupState == 7:
600 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
601 self.checkupState = 8
602 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
603 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
604 elif self.checkupState == 8:
605 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
606 self.checkupState = 9
607 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
608 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
609 elif self.checkupState == 9:
610 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
611 self.checkupState = 10
613 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
614 wx.CallAfter(self.infoBox.SetReadyIndicator)
615 wx.CallAfter(self.endstopBitmap.Show, False)
616 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
617 wx.CallAfter(self.OnSkipClick, None)
619 def mcProgress(self, lineNr):
622 def mcZChange(self, newZ):
626 class UltimakerCalibrationPage(InfoPage):
627 def __init__(self, parent):
628 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
630 self.AddText("Your Ultimaker requires some calibration.")
631 self.AddText("This calibration is needed for a proper extrusion amount.")
633 self.AddText("The following values are needed:")
634 self.AddText("* Diameter of filament")
635 self.AddText("* Number of steps per mm of filament extrusion")
637 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
639 self.AddText("First we need the diameter of your filament:")
640 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
642 "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.")
643 self.AddText("Note: This value can be changed later at any time.")
646 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
649 class UltimakerCalibrateStepsPerEPage(InfoPage):
650 def __init__(self, parent):
651 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
653 #if profile.getMachineSetting('steps_per_e') == '0':
654 # profile.putMachineSetting('steps_per_e', '865.888')
656 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
657 self.AddText(_("First remove any filament from your machine."))
658 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
659 self.AddText(_("We'll push the filament 100mm"))
660 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
661 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
662 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
663 self.AddText(_("This results in the following steps per E:"))
664 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
665 self.AddText(_("You can repeat these steps to get better calibration."))
668 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
669 self.heatButton = self.AddButton(_("Heatup for filament removal"))
671 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
672 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
673 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
675 def OnSaveLengthClick(self, e):
676 currentEValue = float(self.stepsPerEInput.GetValue())
677 realExtrudeLength = float(self.lengthInput.GetValue())
678 newEValue = currentEValue * 100 / realExtrudeLength
679 self.stepsPerEInput.SetValue(str(newEValue))
680 self.lengthInput.SetValue("100")
682 def OnExtrudeClick(self, e):
683 threading.Thread(target=self.OnExtrudeRun).start()
685 def OnExtrudeRun(self):
686 self.heatButton.Enable(False)
687 self.extrudeButton.Enable(False)
688 currentEValue = float(self.stepsPerEInput.GetValue())
689 self.comm = machineCom.MachineCom()
690 if not self.comm.isOpen():
692 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
693 'Printer error', wx.OK | wx.ICON_INFORMATION)
694 self.heatButton.Enable(True)
695 self.extrudeButton.Enable(True)
698 line = self.comm.readline()
703 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
706 self.sendGCommand('M302') #Disable cold extrusion protection
707 self.sendGCommand("M92 E%f" % (currentEValue))
708 self.sendGCommand("G92 E0")
709 self.sendGCommand("G1 E100 F600")
712 self.extrudeButton.Enable()
713 self.heatButton.Enable()
715 def OnHeatClick(self, e):
716 threading.Thread(target=self.OnHeatRun).start()
719 self.heatButton.Enable(False)
720 self.extrudeButton.Enable(False)
721 self.comm = machineCom.MachineCom()
722 if not self.comm.isOpen():
724 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
725 'Printer error', wx.OK | wx.ICON_INFORMATION)
726 self.heatButton.Enable(True)
727 self.extrudeButton.Enable(True)
730 line = self.comm.readline()
732 self.heatButton.Enable(True)
733 self.extrudeButton.Enable(True)
737 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
740 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
742 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
743 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
744 self.sendGCommand('M104 S0')
747 self.heatButton.Enable(True)
748 self.extrudeButton.Enable(True)
750 def sendGCommand(self, cmd):
751 self.comm.sendCommand(cmd) #Disable cold extrusion protection
753 line = self.comm.readline()
756 if line.startswith('ok'):
760 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
762 class Ultimaker2ReadyPage(InfoPage):
763 def __init__(self, parent):
764 super(Ultimaker2ReadyPage, self).__init__(parent, "Ultimaker2")
765 self.AddText('Congratulations on your the purchase of your brand new Ultimaker2.')
766 self.AddText('Cura is now ready to be used with your Ultimaker2.')
769 class configWizard(wx.wizard.Wizard):
770 def __init__(self, addNew = False):
771 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
773 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
774 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
776 self.firstInfoPage = FirstInfoPage(self, addNew)
777 self.machineSelectPage = MachineSelectPage(self)
778 self.ultimakerSelectParts = SelectParts(self)
779 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
780 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
781 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
782 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
783 self.bedLevelPage = bedLevelWizardMain(self)
784 self.headOffsetCalibration = headOffsetCalibrationPage(self)
785 self.repRapInfoPage = RepRapInfoPage(self)
787 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
789 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
790 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
791 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
792 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
793 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
794 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
795 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
797 self.FitToPage(self.firstInfoPage)
798 self.GetPageAreaSizer().Add(self.firstInfoPage)
800 self.RunWizard(self.firstInfoPage)
803 def OnPageChanging(self, e):
804 e.GetPage().StoreData()
806 def OnPageChanged(self, e):
807 if e.GetPage().AllowNext():
808 self.FindWindowById(wx.ID_FORWARD).Enable()
810 self.FindWindowById(wx.ID_FORWARD).Disable()
811 self.FindWindowById(wx.ID_BACKWARD).Disable()
813 class bedLevelWizardMain(InfoPage):
814 def __init__(self, parent):
815 super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
817 self.AddText('This wizard will help you in leveling your printer bed')
819 self.AddText('It will do the following steps')
820 self.AddText('* Move the printer head to each corner')
821 self.AddText(' and let you adjust the height of the bed to the nozzle')
822 self.AddText('* Print a line around the bed to check if it is level')
825 self.connectButton = self.AddButton('Connect to printer')
828 self.infoBox = self.AddInfoBox()
829 self.resumeButton = self.AddButton('Resume')
830 self.resumeButton.Enable(False)
832 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
833 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
835 def OnConnect(self, e = None):
836 if self.comm is not None:
840 wx.CallAfter(self.OnConnect)
842 self.connectButton.Enable(False)
843 self.comm = machineCom.MachineCom(callbackObject=self)
844 self.infoBox.SetBusy('Connecting to machine.')
845 self._wizardState = 0
848 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
849 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
852 def OnResume(self, e):
853 feedZ = profile.getProfileSettingFloat('print_speed') * 60
854 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
855 if self._wizardState == 2:
856 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
857 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
858 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
859 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
860 self.comm.sendCommand('M400')
861 self._wizardState = 3
862 elif self._wizardState == 4:
863 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
864 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
865 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
866 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
867 self.comm.sendCommand('M400')
868 self._wizardState = 5
869 elif self._wizardState == 6:
870 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
871 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
872 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
873 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
874 self.comm.sendCommand('M400')
875 self._wizardState = 7
876 elif self._wizardState == 8:
877 wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
878 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
879 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
880 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
881 self._wizardState = 9
882 elif self._wizardState == 10:
883 self._wizardState = 11
884 wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
885 feedZ = profile.getProfileSettingFloat('print_speed') * 60
886 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
887 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
888 w = profile.getMachineSettingFloat('machine_width')
889 d = profile.getMachineSettingFloat('machine_depth')
890 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
891 filamentArea = math.pi * filamentRadius * filamentRadius
892 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
896 'G1 Z2 F%d' % (feedZ),
898 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
899 'G1 Z0.3 F%d' % (feedZ)]
901 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
903 for i in xrange(0, 3):
904 dist = 5.0 + 0.4 * float(i)
905 eValue += (d - 2.0*dist) * ePerMM
906 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
907 eValue += (w - 2.0*dist) * ePerMM
908 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
909 eValue += (d - 2.0*dist) * ePerMM
910 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
911 eValue += (w - 2.0*dist) * ePerMM
912 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
914 gcodeList.append('M400')
915 self.comm.printGCode(gcodeList)
916 self.resumeButton.Enable(False)
918 def mcLog(self, message):
919 print 'Log:', message
921 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
922 if self._wizardState == 1:
923 self._wizardState = 2
924 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
925 wx.CallAfter(self.resumeButton.Enable, True)
926 elif self._wizardState == 3:
927 self._wizardState = 4
928 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
929 wx.CallAfter(self.resumeButton.Enable, True)
930 elif self._wizardState == 5:
931 self._wizardState = 6
932 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
933 wx.CallAfter(self.resumeButton.Enable, True)
934 elif self._wizardState == 7:
935 self._wizardState = 8
936 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
937 wx.CallAfter(self.resumeButton.Enable, True)
938 elif self._wizardState == 9:
939 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
940 wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
942 wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
943 wx.CallAfter(self.resumeButton.Enable, True)
944 self._wizardState = 10
946 def mcStateChange(self, state):
947 if self.comm is None:
949 if self.comm.isOperational():
950 if self._wizardState == 0:
951 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
952 self.comm.sendCommand('M105')
953 self.comm.sendCommand('G28')
954 self._wizardState = 1
955 elif self._wizardState == 11 and not self.comm.isPrinting():
956 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
957 self.comm.sendCommand('G92 E0')
958 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
959 self.comm.sendCommand('M104 S0')
960 wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
961 wx.CallAfter(self.infoBox.SetReadyIndicator)
962 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
963 wx.CallAfter(self.connectButton.Enable, True)
964 self._wizardState = 12
965 elif self.comm.isError():
966 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
968 def mcMessage(self, message):
971 def mcProgress(self, lineNr):
974 def mcZChange(self, newZ):
977 class headOffsetCalibrationPage(InfoPage):
978 def __init__(self, parent):
979 super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
981 self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
984 self.connectButton = self.AddButton('Connect to printer')
987 self.infoBox = self.AddInfoBox()
988 self.textEntry = self.AddTextCtrl('')
989 self.textEntry.Enable(False)
990 self.resumeButton = self.AddButton('Resume')
991 self.resumeButton.Enable(False)
993 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
994 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
996 def OnConnect(self, e = None):
997 if self.comm is not None:
1001 wx.CallAfter(self.OnConnect)
1003 self.connectButton.Enable(False)
1004 self.comm = machineCom.MachineCom(callbackObject=self)
1005 self.infoBox.SetBusy('Connecting to machine.')
1006 self._wizardState = 0
1008 def OnResume(self, e):
1009 if self._wizardState == 2:
1010 self._wizardState = 3
1011 wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
1013 w = profile.getMachineSettingFloat('machine_width')
1014 d = profile.getMachineSettingFloat('machine_depth')
1016 gcode = gcodeGenerator.gcodeGenerator()
1017 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1018 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1025 gcode.addMove(w/2, 5)
1026 gcode.addMove(z=0.2)
1028 gcode.addExtrude(w/2, d-5.0)
1030 gcode.addMove(5, d/2)
1032 gcode.addExtrude(w-5.0, d/2)
1033 gcode.addRetract(15)
1036 gcode.addMove(w/2, 5)
1038 gcode.addExtrude(w/2, d-5.0)
1040 gcode.addMove(5, d/2)
1042 gcode.addExtrude(w-5.0, d/2)
1043 gcode.addRetract(15)
1048 gcode.addCmd('M400')
1050 self.comm.printGCode(gcode.list())
1051 self.resumeButton.Enable(False)
1052 elif self._wizardState == 4:
1054 float(self.textEntry.GetValue())
1057 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1058 self._wizardState = 5
1059 self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
1060 self.textEntry.SetValue('0.0')
1061 self.textEntry.Enable(True)
1062 elif self._wizardState == 5:
1064 float(self.textEntry.GetValue())
1067 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1068 self._wizardState = 6
1069 self.infoBox.SetBusy('Printing the fine calibration lines.')
1070 self.textEntry.SetValue('')
1071 self.textEntry.Enable(False)
1072 self.resumeButton.Enable(False)
1074 x = profile.getMachineSettingFloat('extruder_offset_x1')
1075 y = profile.getMachineSettingFloat('extruder_offset_y1')
1076 gcode = gcodeGenerator.gcodeGenerator()
1077 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1078 gcode.setPrintSpeed(25)
1081 gcode.addMove(50, 40, 0.2)
1083 for n in xrange(0, 10):
1084 gcode.addExtrude(50 + n * 10, 150)
1085 gcode.addExtrude(50 + n * 10 + 5, 150)
1086 gcode.addExtrude(50 + n * 10 + 5, 40)
1087 gcode.addExtrude(50 + n * 10 + 10, 40)
1088 gcode.addMove(40, 50)
1089 for n in xrange(0, 10):
1090 gcode.addExtrude(150, 50 + n * 10)
1091 gcode.addExtrude(150, 50 + n * 10 + 5)
1092 gcode.addExtrude(40, 50 + n * 10 + 5)
1093 gcode.addExtrude(40, 50 + n * 10 + 10)
1094 gcode.addRetract(15)
1097 gcode.addMove(50 - x, 30 - y, 0.2)
1099 for n in xrange(0, 10):
1100 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1101 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1102 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1103 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1104 gcode.addMove(30 - x, 50 - y, 0.2)
1105 for n in xrange(0, 10):
1106 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1107 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1108 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1109 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1110 gcode.addRetract(15)
1112 gcode.addCmd('M400')
1113 gcode.addCmd('M104 T0 S0')
1114 gcode.addCmd('M104 T1 S0')
1115 self.comm.printGCode(gcode.list())
1116 elif self._wizardState == 7:
1118 n = int(self.textEntry.GetValue()) - 1
1121 x = profile.getMachineSettingFloat('extruder_offset_x1')
1123 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1124 self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
1125 self.textEntry.SetValue('10')
1126 self._wizardState = 8
1127 elif self._wizardState == 8:
1129 n = int(self.textEntry.GetValue()) - 1
1132 y = profile.getMachineSettingFloat('extruder_offset_y1')
1134 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1135 self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1136 self.infoBox.SetReadyIndicator()
1137 self._wizardState = 8
1139 self.resumeButton.Enable(False)
1141 def mcLog(self, message):
1142 print 'Log:', message
1144 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1145 if self._wizardState == 1:
1146 if temp[0] >= 210 and temp[1] >= 210:
1147 self._wizardState = 2
1148 wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
1149 wx.CallAfter(self.resumeButton.Enable, True)
1150 wx.CallAfter(self.resumeButton.SetFocus)
1152 def mcStateChange(self, state):
1153 if self.comm is None:
1155 if self.comm.isOperational():
1156 if self._wizardState == 0:
1157 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
1158 self.comm.sendCommand('M105')
1159 self.comm.sendCommand('M104 S220 T0')
1160 self.comm.sendCommand('M104 S220 T1')
1161 self.comm.sendCommand('G28')
1162 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1163 self._wizardState = 1
1164 if not self.comm.isPrinting():
1165 if self._wizardState == 3:
1166 self._wizardState = 4
1167 wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
1168 wx.CallAfter(self.textEntry.SetValue, '0.0')
1169 wx.CallAfter(self.textEntry.Enable, True)
1170 wx.CallAfter(self.resumeButton.Enable, True)
1171 wx.CallAfter(self.resumeButton.SetFocus)
1172 elif self._wizardState == 6:
1173 self._wizardState = 7
1174 wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
1175 wx.CallAfter(self.textEntry.SetValue, '10')
1176 wx.CallAfter(self.textEntry.Enable, True)
1177 wx.CallAfter(self.resumeButton.Enable, True)
1178 wx.CallAfter(self.resumeButton.SetFocus)
1180 elif self.comm.isError():
1181 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1183 def mcMessage(self, message):
1186 def mcProgress(self, lineNr):
1189 def mcZChange(self, newZ):
1192 class bedLevelWizard(wx.wizard.Wizard):
1194 super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
1196 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1197 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1199 self.mainPage = bedLevelWizardMain(self)
1200 self.headOffsetCalibration = None
1202 self.FitToPage(self.mainPage)
1203 self.GetPageAreaSizer().Add(self.mainPage)
1205 self.RunWizard(self.mainPage)
1208 def OnPageChanging(self, e):
1209 e.GetPage().StoreData()
1211 def OnPageChanged(self, e):
1212 if e.GetPage().AllowNext():
1213 self.FindWindowById(wx.ID_FORWARD).Enable()
1215 self.FindWindowById(wx.ID_FORWARD).Disable()
1216 self.FindWindowById(wx.ID_BACKWARD).Disable()
1218 class headOffsetWizard(wx.wizard.Wizard):
1220 super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
1222 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1223 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1225 self.mainPage = headOffsetCalibrationPage(self)
1227 self.FitToPage(self.mainPage)
1228 self.GetPageAreaSizer().Add(self.mainPage)
1230 self.RunWizard(self.mainPage)
1233 def OnPageChanging(self, e):
1234 e.GetPage().StoreData()
1236 def OnPageChanged(self, e):
1237 if e.GetPage().AllowNext():
1238 self.FindWindowById(wx.ID_FORWARD).Enable()
1240 self.FindWindowById(wx.ID_FORWARD).Disable()
1241 self.FindWindowById(wx.ID_BACKWARD).Disable()