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