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 if self.Ultimaker2Radio.GetValue():
339 profile.putMachineSetting('machine_width', '230')
340 profile.putMachineSetting('machine_depth', '225')
341 profile.putMachineSetting('machine_height', '205')
342 profile.putMachineSetting('machine_name', 'ultimaker2')
343 profile.putMachineSetting('machine_type', 'ultimaker2')
344 profile.putMachineSetting('machine_center_is_zero', 'False')
345 profile.putMachineSetting('has_heated_bed', 'True')
346 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
347 profile.putProfileSetting('nozzle_size', '0.4')
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 elif self.UltimakerRadio.GetValue():
354 profile.putMachineSetting('machine_width', '205')
355 profile.putMachineSetting('machine_depth', '205')
356 profile.putMachineSetting('machine_height', '200')
357 profile.putMachineSetting('machine_name', 'ultimaker')
358 profile.putMachineSetting('machine_type', 'ultimaker')
359 profile.putMachineSetting('machine_center_is_zero', 'False')
360 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
361 profile.putProfileSetting('nozzle_size', '0.4')
362 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
363 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
364 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
365 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
366 profile.putMachineSetting('extruder_head_size_height', '60.0')
368 profile.putMachineSetting('machine_width', '80')
369 profile.putMachineSetting('machine_depth', '80')
370 profile.putMachineSetting('machine_height', '60')
371 profile.putMachineSetting('machine_name', 'reprap')
372 profile.putMachineSetting('machine_type', 'reprap')
373 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
374 profile.putPreference('startMode', 'Normal')
375 profile.putProfileSetting('nozzle_size', '0.5')
376 profile.checkAndUpdateMachineName()
377 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
378 if self.SubmitUserStats.GetValue():
379 profile.putPreference('submit_slice_information', 'True')
381 profile.putPreference('submit_slice_information', 'False')
384 class SelectParts(InfoPage):
385 def __init__(self, parent):
386 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
387 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."))
389 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
390 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
391 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
393 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."))
394 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
395 self.springExtruder.SetValue(True)
398 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
399 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
400 if self.dualExtrusion.GetValue():
401 profile.putMachineSetting('extruder_amount', '2')
402 profile.putMachineSetting('machine_depth', '195')
404 profile.putMachineSetting('extruder_amount', '1')
405 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
406 profile.putProfileSetting('retraction_enable', 'True')
408 profile.putProfileSetting('retraction_enable', 'False')
411 class UltimakerFirmwareUpgradePage(InfoPage):
412 def __init__(self, parent):
413 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
414 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."))
415 self.AddHiddenSeperator()
416 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
417 self.AddHiddenSeperator()
418 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."))
419 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
420 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
421 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
422 self.AddHiddenSeperator()
423 self.AddText(_("Do not upgrade to this firmware if:"))
424 self.AddText(_("* You have an older machine based on ATMega1280"))
425 self.AddText(_("* Have other changes in the firmware"))
426 # button = self.AddButton('Goto this page for a custom firmware')
427 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
432 def OnUpgradeClick(self, e):
433 if firmwareInstall.InstallFirmware():
434 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
436 def OnSkipClick(self, e):
437 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
438 self.GetParent().ShowPage(self.GetNext())
440 def OnUrlClick(self, e):
441 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
443 class UltimakerCheckupPage(InfoPage):
444 def __init__(self, parent):
445 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
447 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
448 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
449 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
450 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
451 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
452 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
453 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
454 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
455 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
456 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
459 _("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."))
460 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
461 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
462 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
464 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
465 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
466 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
468 self.infoBox = self.AddInfoBox()
469 self.machineState = self.AddText("")
470 self.temperatureLabel = self.AddText("")
471 self.errorLogButton = self.AddButton(_("Show error log"))
472 self.errorLogButton.Show(False)
474 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
476 self.xMinStop = False
477 self.xMaxStop = False
478 self.yMinStop = False
479 self.yMaxStop = False
480 self.zMinStop = False
481 self.zMaxStop = False
483 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
486 if self.comm is not None:
490 self.endstopBitmap.Show(False)
493 def OnSkipClick(self, e):
494 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
495 self.GetParent().ShowPage(self.GetNext())
497 def OnCheckClick(self, e=None):
498 self.errorLogButton.Show(False)
499 if self.comm is not None:
503 wx.CallAfter(self.OnCheckClick)
505 self.infoBox.SetBusy(_("Connecting to machine."))
506 self.commState.SetBitmap(self.unknownBitmap)
507 self.tempState.SetBitmap(self.unknownBitmap)
508 self.stopState.SetBitmap(self.unknownBitmap)
509 self.checkupState = 0
510 self.checkExtruderNr = 0
511 self.comm = machineCom.MachineCom(callbackObject=self)
513 def OnErrorLog(self, e):
514 printWindow.LogWindow('\n'.join(self.comm.getLog()))
516 def mcLog(self, message):
519 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
520 if not self.comm.isOperational():
522 if self.checkupState == 0:
523 self.tempCheckTimeout = 20
524 if temp[self.checkExtruderNr] > 70:
525 self.checkupState = 1
526 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
527 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
528 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
530 self.startTemp = temp[self.checkExtruderNr]
531 self.checkupState = 2
532 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
533 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
534 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
535 elif self.checkupState == 1:
537 self.startTemp = temp[self.checkExtruderNr]
538 self.checkupState = 2
539 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
540 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
541 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
542 elif self.checkupState == 2:
543 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
544 if temp[self.checkExtruderNr] > self.startTemp + 40:
545 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
546 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
547 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
548 self.checkExtruderNr = 0
549 self.checkupState = 3
550 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
551 wx.CallAfter(self.endstopBitmap.Show, True)
552 wx.CallAfter(self.Layout)
553 self.comm.sendCommand('M119')
554 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
556 self.checkupState = 0
557 self.checkExtruderNr += 1
559 self.tempCheckTimeout -= 1
560 if self.tempCheckTimeout < 1:
561 self.checkupState = -1
562 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
563 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
564 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
565 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
566 elif self.checkupState >= 3 and self.checkupState < 10:
567 self.comm.sendCommand('M119')
568 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
570 def mcStateChange(self, state):
571 if self.comm is None:
573 if self.comm.isOperational():
574 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
575 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
576 elif self.comm.isError():
577 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
578 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
579 wx.CallAfter(self.endstopBitmap.Show, False)
580 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
581 wx.CallAfter(self.errorLogButton.Show, True)
582 wx.CallAfter(self.Layout)
584 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
586 def mcMessage(self, message):
587 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
588 for data in message.split(' '):
590 tag, value = data.split(':', 1)
592 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
594 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
596 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
598 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
600 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
602 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
604 tag, value = map(str.strip, message.split(':', 1))
606 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
608 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
610 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
612 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
614 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
616 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
617 if 'z_max' in message:
618 self.comm.sendCommand('M119')
620 if self.checkupState == 3:
621 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
622 self.checkupState = 4
623 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
624 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
625 elif self.checkupState == 4:
626 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
627 self.checkupState = 5
628 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
629 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
630 elif self.checkupState == 5:
631 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
632 self.checkupState = 6
633 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
634 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
635 elif self.checkupState == 6:
636 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
637 self.checkupState = 7
638 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
639 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
640 elif self.checkupState == 7:
641 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
642 self.checkupState = 8
643 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
644 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
645 elif self.checkupState == 8:
646 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
647 self.checkupState = 9
648 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
649 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
650 elif self.checkupState == 9:
651 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
652 self.checkupState = 10
654 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
655 wx.CallAfter(self.infoBox.SetReadyIndicator)
656 wx.CallAfter(self.endstopBitmap.Show, False)
657 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
658 wx.CallAfter(self.OnSkipClick, None)
660 def mcProgress(self, lineNr):
663 def mcZChange(self, newZ):
667 class UltimakerCalibrationPage(InfoPage):
668 def __init__(self, parent):
669 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
671 self.AddText("Your Ultimaker requires some calibration.")
672 self.AddText("This calibration is needed for a proper extrusion amount.")
674 self.AddText("The following values are needed:")
675 self.AddText("* Diameter of filament")
676 self.AddText("* Number of steps per mm of filament extrusion")
678 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
680 self.AddText("First we need the diameter of your filament:")
681 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
683 "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.")
684 self.AddText("Note: This value can be changed later at any time.")
687 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
690 class UltimakerCalibrateStepsPerEPage(InfoPage):
691 def __init__(self, parent):
692 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
694 #if profile.getMachineSetting('steps_per_e') == '0':
695 # profile.putMachineSetting('steps_per_e', '865.888')
697 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
698 self.AddText(_("First remove any filament from your machine."))
699 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
700 self.AddText(_("We'll push the filament 100mm"))
701 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
702 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
703 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
704 self.AddText(_("This results in the following steps per E:"))
705 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
706 self.AddText(_("You can repeat these steps to get better calibration."))
709 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
710 self.heatButton = self.AddButton(_("Heatup for filament removal"))
712 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
713 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
714 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
716 def OnSaveLengthClick(self, e):
717 currentEValue = float(self.stepsPerEInput.GetValue())
718 realExtrudeLength = float(self.lengthInput.GetValue())
719 newEValue = currentEValue * 100 / realExtrudeLength
720 self.stepsPerEInput.SetValue(str(newEValue))
721 self.lengthInput.SetValue("100")
723 def OnExtrudeClick(self, e):
724 threading.Thread(target=self.OnExtrudeRun).start()
726 def OnExtrudeRun(self):
727 self.heatButton.Enable(False)
728 self.extrudeButton.Enable(False)
729 currentEValue = float(self.stepsPerEInput.GetValue())
730 self.comm = machineCom.MachineCom()
731 if not self.comm.isOpen():
733 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
734 'Printer error', wx.OK | wx.ICON_INFORMATION)
735 self.heatButton.Enable(True)
736 self.extrudeButton.Enable(True)
739 line = self.comm.readline()
744 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
747 self.sendGCommand('M302') #Disable cold extrusion protection
748 self.sendGCommand("M92 E%f" % (currentEValue))
749 self.sendGCommand("G92 E0")
750 self.sendGCommand("G1 E100 F600")
753 self.extrudeButton.Enable()
754 self.heatButton.Enable()
756 def OnHeatClick(self, e):
757 threading.Thread(target=self.OnHeatRun).start()
760 self.heatButton.Enable(False)
761 self.extrudeButton.Enable(False)
762 self.comm = machineCom.MachineCom()
763 if not self.comm.isOpen():
765 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
766 'Printer error', wx.OK | wx.ICON_INFORMATION)
767 self.heatButton.Enable(True)
768 self.extrudeButton.Enable(True)
771 line = self.comm.readline()
773 self.heatButton.Enable(True)
774 self.extrudeButton.Enable(True)
778 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
781 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
783 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
784 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
785 self.sendGCommand('M104 S0')
788 self.heatButton.Enable(True)
789 self.extrudeButton.Enable(True)
791 def sendGCommand(self, cmd):
792 self.comm.sendCommand(cmd) #Disable cold extrusion protection
794 line = self.comm.readline()
797 if line.startswith('ok'):
801 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
803 class Ultimaker2ReadyPage(InfoPage):
804 def __init__(self, parent):
805 super(Ultimaker2ReadyPage, self).__init__(parent, "Ultimaker2")
806 self.AddText('Congratulations on your the purchase of your brand new Ultimaker2.')
807 self.AddText('Cura is now ready to be used with your Ultimaker2.')
810 class configWizard(wx.wizard.Wizard):
811 def __init__(self, addNew = False):
812 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
814 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
815 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
817 self.firstInfoPage = FirstInfoPage(self, addNew)
818 self.machineSelectPage = MachineSelectPage(self)
819 self.ultimakerSelectParts = SelectParts(self)
820 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
821 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
822 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
823 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
824 self.bedLevelPage = bedLevelWizardMain(self)
825 self.headOffsetCalibration = headOffsetCalibrationPage(self)
826 self.otherMachineSelectPage = OtherMachineSelectPage(self)
827 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
828 self.otherMachineInfoPage = OtherMachineInfoPage(self)
830 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
832 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
833 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
834 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
835 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
836 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
837 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
838 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
839 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
841 self.FitToPage(self.firstInfoPage)
842 self.GetPageAreaSizer().Add(self.firstInfoPage)
844 self.RunWizard(self.firstInfoPage)
847 def OnPageChanging(self, e):
848 e.GetPage().StoreData()
850 def OnPageChanged(self, e):
851 if e.GetPage().AllowNext():
852 self.FindWindowById(wx.ID_FORWARD).Enable()
854 self.FindWindowById(wx.ID_FORWARD).Disable()
855 self.FindWindowById(wx.ID_BACKWARD).Disable()
857 class bedLevelWizardMain(InfoPage):
858 def __init__(self, parent):
859 super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
861 self.AddText('This wizard will help you in leveling your printer bed')
863 self.AddText('It will do the following steps')
864 self.AddText('* Move the printer head to each corner')
865 self.AddText(' and let you adjust the height of the bed to the nozzle')
866 self.AddText('* Print a line around the bed to check if it is level')
869 self.connectButton = self.AddButton('Connect to printer')
872 self.infoBox = self.AddInfoBox()
873 self.resumeButton = self.AddButton('Resume')
874 self.resumeButton.Enable(False)
876 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
877 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
879 def OnConnect(self, e = None):
880 if self.comm is not None:
884 wx.CallAfter(self.OnConnect)
886 self.connectButton.Enable(False)
887 self.comm = machineCom.MachineCom(callbackObject=self)
888 self.infoBox.SetBusy('Connecting to machine.')
889 self._wizardState = 0
892 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
893 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
896 def OnResume(self, e):
897 feedZ = profile.getProfileSettingFloat('print_speed') * 60
898 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
899 if self._wizardState == 2:
900 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
901 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
902 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
903 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
904 self.comm.sendCommand('M400')
905 self._wizardState = 3
906 elif self._wizardState == 4:
907 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
908 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
909 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
910 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
911 self.comm.sendCommand('M400')
912 self._wizardState = 5
913 elif self._wizardState == 6:
914 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
915 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
916 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
917 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
918 self.comm.sendCommand('M400')
919 self._wizardState = 7
920 elif self._wizardState == 8:
921 wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
922 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
923 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
924 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
925 self._wizardState = 9
926 elif self._wizardState == 10:
927 self._wizardState = 11
928 wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
929 feedZ = profile.getProfileSettingFloat('print_speed') * 60
930 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
931 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
932 w = profile.getMachineSettingFloat('machine_width')
933 d = profile.getMachineSettingFloat('machine_depth')
934 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
935 filamentArea = math.pi * filamentRadius * filamentRadius
936 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
940 'G1 Z2 F%d' % (feedZ),
942 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
943 'G1 Z0.3 F%d' % (feedZ)]
945 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
947 for i in xrange(0, 3):
948 dist = 5.0 + 0.4 * float(i)
949 eValue += (d - 2.0*dist) * ePerMM
950 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
951 eValue += (w - 2.0*dist) * ePerMM
952 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
953 eValue += (d - 2.0*dist) * ePerMM
954 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
955 eValue += (w - 2.0*dist) * ePerMM
956 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
958 gcodeList.append('M400')
959 self.comm.printGCode(gcodeList)
960 self.resumeButton.Enable(False)
962 def mcLog(self, message):
963 print 'Log:', message
965 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
966 if self._wizardState == 1:
967 self._wizardState = 2
968 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
969 wx.CallAfter(self.resumeButton.Enable, True)
970 elif self._wizardState == 3:
971 self._wizardState = 4
972 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
973 wx.CallAfter(self.resumeButton.Enable, True)
974 elif self._wizardState == 5:
975 self._wizardState = 6
976 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
977 wx.CallAfter(self.resumeButton.Enable, True)
978 elif self._wizardState == 7:
979 self._wizardState = 8
980 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
981 wx.CallAfter(self.resumeButton.Enable, True)
982 elif self._wizardState == 9:
983 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
984 wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
986 wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
987 wx.CallAfter(self.resumeButton.Enable, True)
988 self._wizardState = 10
990 def mcStateChange(self, state):
991 if self.comm is None:
993 if self.comm.isOperational():
994 if self._wizardState == 0:
995 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
996 self.comm.sendCommand('M105')
997 self.comm.sendCommand('G28')
998 self._wizardState = 1
999 elif self._wizardState == 11 and not self.comm.isPrinting():
1000 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1001 self.comm.sendCommand('G92 E0')
1002 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1003 self.comm.sendCommand('M104 S0')
1004 wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
1005 wx.CallAfter(self.infoBox.SetReadyIndicator)
1006 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1007 wx.CallAfter(self.connectButton.Enable, True)
1008 self._wizardState = 12
1009 elif self.comm.isError():
1010 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1012 def mcMessage(self, message):
1015 def mcProgress(self, lineNr):
1018 def mcZChange(self, newZ):
1021 class headOffsetCalibrationPage(InfoPage):
1022 def __init__(self, parent):
1023 super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
1025 self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
1028 self.connectButton = self.AddButton('Connect to printer')
1031 self.infoBox = self.AddInfoBox()
1032 self.textEntry = self.AddTextCtrl('')
1033 self.textEntry.Enable(False)
1034 self.resumeButton = self.AddButton('Resume')
1035 self.resumeButton.Enable(False)
1037 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1038 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1040 def OnConnect(self, e = None):
1041 if self.comm is not None:
1045 wx.CallAfter(self.OnConnect)
1047 self.connectButton.Enable(False)
1048 self.comm = machineCom.MachineCom(callbackObject=self)
1049 self.infoBox.SetBusy('Connecting to machine.')
1050 self._wizardState = 0
1052 def OnResume(self, e):
1053 if self._wizardState == 2:
1054 self._wizardState = 3
1055 wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
1057 w = profile.getMachineSettingFloat('machine_width')
1058 d = profile.getMachineSettingFloat('machine_depth')
1060 gcode = gcodeGenerator.gcodeGenerator()
1061 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1062 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1069 gcode.addMove(w/2, 5)
1070 gcode.addMove(z=0.2)
1072 gcode.addExtrude(w/2, d-5.0)
1074 gcode.addMove(5, d/2)
1076 gcode.addExtrude(w-5.0, d/2)
1077 gcode.addRetract(15)
1080 gcode.addMove(w/2, 5)
1082 gcode.addExtrude(w/2, d-5.0)
1084 gcode.addMove(5, d/2)
1086 gcode.addExtrude(w-5.0, d/2)
1087 gcode.addRetract(15)
1092 gcode.addCmd('M400')
1094 self.comm.printGCode(gcode.list())
1095 self.resumeButton.Enable(False)
1096 elif self._wizardState == 4:
1098 float(self.textEntry.GetValue())
1101 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1102 self._wizardState = 5
1103 self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
1104 self.textEntry.SetValue('0.0')
1105 self.textEntry.Enable(True)
1106 elif self._wizardState == 5:
1108 float(self.textEntry.GetValue())
1111 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1112 self._wizardState = 6
1113 self.infoBox.SetBusy('Printing the fine calibration lines.')
1114 self.textEntry.SetValue('')
1115 self.textEntry.Enable(False)
1116 self.resumeButton.Enable(False)
1118 x = profile.getMachineSettingFloat('extruder_offset_x1')
1119 y = profile.getMachineSettingFloat('extruder_offset_y1')
1120 gcode = gcodeGenerator.gcodeGenerator()
1121 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1122 gcode.setPrintSpeed(25)
1125 gcode.addMove(50, 40, 0.2)
1127 for n in xrange(0, 10):
1128 gcode.addExtrude(50 + n * 10, 150)
1129 gcode.addExtrude(50 + n * 10 + 5, 150)
1130 gcode.addExtrude(50 + n * 10 + 5, 40)
1131 gcode.addExtrude(50 + n * 10 + 10, 40)
1132 gcode.addMove(40, 50)
1133 for n in xrange(0, 10):
1134 gcode.addExtrude(150, 50 + n * 10)
1135 gcode.addExtrude(150, 50 + n * 10 + 5)
1136 gcode.addExtrude(40, 50 + n * 10 + 5)
1137 gcode.addExtrude(40, 50 + n * 10 + 10)
1138 gcode.addRetract(15)
1141 gcode.addMove(50 - x, 30 - y, 0.2)
1143 for n in xrange(0, 10):
1144 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1145 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1146 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1147 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1148 gcode.addMove(30 - x, 50 - y, 0.2)
1149 for n in xrange(0, 10):
1150 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1151 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1152 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1153 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1154 gcode.addRetract(15)
1156 gcode.addCmd('M400')
1157 gcode.addCmd('M104 T0 S0')
1158 gcode.addCmd('M104 T1 S0')
1159 self.comm.printGCode(gcode.list())
1160 elif self._wizardState == 7:
1162 n = int(self.textEntry.GetValue()) - 1
1165 x = profile.getMachineSettingFloat('extruder_offset_x1')
1167 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1168 self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
1169 self.textEntry.SetValue('10')
1170 self._wizardState = 8
1171 elif self._wizardState == 8:
1173 n = int(self.textEntry.GetValue()) - 1
1176 y = profile.getMachineSettingFloat('extruder_offset_y1')
1178 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1179 self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1180 self.infoBox.SetReadyIndicator()
1181 self._wizardState = 8
1183 self.resumeButton.Enable(False)
1185 def mcLog(self, message):
1186 print 'Log:', message
1188 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1189 if self._wizardState == 1:
1190 if temp[0] >= 210 and temp[1] >= 210:
1191 self._wizardState = 2
1192 wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
1193 wx.CallAfter(self.resumeButton.Enable, True)
1194 wx.CallAfter(self.resumeButton.SetFocus)
1196 def mcStateChange(self, state):
1197 if self.comm is None:
1199 if self.comm.isOperational():
1200 if self._wizardState == 0:
1201 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
1202 self.comm.sendCommand('M105')
1203 self.comm.sendCommand('M104 S220 T0')
1204 self.comm.sendCommand('M104 S220 T1')
1205 self.comm.sendCommand('G28')
1206 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1207 self._wizardState = 1
1208 if not self.comm.isPrinting():
1209 if self._wizardState == 3:
1210 self._wizardState = 4
1211 wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
1212 wx.CallAfter(self.textEntry.SetValue, '0.0')
1213 wx.CallAfter(self.textEntry.Enable, True)
1214 wx.CallAfter(self.resumeButton.Enable, True)
1215 wx.CallAfter(self.resumeButton.SetFocus)
1216 elif self._wizardState == 6:
1217 self._wizardState = 7
1218 wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
1219 wx.CallAfter(self.textEntry.SetValue, '10')
1220 wx.CallAfter(self.textEntry.Enable, True)
1221 wx.CallAfter(self.resumeButton.Enable, True)
1222 wx.CallAfter(self.resumeButton.SetFocus)
1224 elif self.comm.isError():
1225 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1227 def mcMessage(self, message):
1230 def mcProgress(self, lineNr):
1233 def mcZChange(self, newZ):
1236 class bedLevelWizard(wx.wizard.Wizard):
1238 super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
1240 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1241 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1243 self.mainPage = bedLevelWizardMain(self)
1244 self.headOffsetCalibration = None
1246 self.FitToPage(self.mainPage)
1247 self.GetPageAreaSizer().Add(self.mainPage)
1249 self.RunWizard(self.mainPage)
1252 def OnPageChanging(self, e):
1253 e.GetPage().StoreData()
1255 def OnPageChanged(self, e):
1256 if e.GetPage().AllowNext():
1257 self.FindWindowById(wx.ID_FORWARD).Enable()
1259 self.FindWindowById(wx.ID_FORWARD).Disable()
1260 self.FindWindowById(wx.ID_BACKWARD).Disable()
1262 class headOffsetWizard(wx.wizard.Wizard):
1264 super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
1266 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1267 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1269 self.mainPage = headOffsetCalibrationPage(self)
1271 self.FitToPage(self.mainPage)
1272 self.GetPageAreaSizer().Add(self.mainPage)
1274 self.RunWizard(self.mainPage)
1277 def OnPageChanging(self, e):
1278 e.GetPage().StoreData()
1280 def OnPageChanged(self, e):
1281 if e.GetPage().AllowNext():
1282 self.FindWindowById(wx.ID_FORWARD).Enable()
1284 self.FindWindowById(wx.ID_FORWARD).Disable()
1285 self.FindWindowById(wx.ID_BACKWARD).Disable()