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.putProfileSetting('nozzle_size', '0.4')
349 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
350 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
351 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
352 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
353 profile.putMachineSetting('extruder_head_size_height', '60.0')
354 elif self.UltimakerRadio.GetValue():
355 profile.putMachineSetting('machine_width', '205')
356 profile.putMachineSetting('machine_depth', '205')
357 profile.putMachineSetting('machine_height', '200')
358 profile.putMachineSetting('machine_name', 'ultimaker')
359 profile.putMachineSetting('machine_type', 'ultimaker')
360 profile.putMachineSetting('machine_center_is_zero', 'False')
361 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
362 profile.putProfileSetting('nozzle_size', '0.4')
363 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
364 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
365 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
366 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
367 profile.putMachineSetting('extruder_head_size_height', '60.0')
369 profile.putMachineSetting('machine_width', '80')
370 profile.putMachineSetting('machine_depth', '80')
371 profile.putMachineSetting('machine_height', '60')
372 profile.putMachineSetting('machine_name', 'reprap')
373 profile.putMachineSetting('machine_type', 'reprap')
374 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
375 profile.putPreference('startMode', 'Normal')
376 profile.putProfileSetting('nozzle_size', '0.5')
377 profile.checkAndUpdateMachineName()
378 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
379 if self.SubmitUserStats.GetValue():
380 profile.putPreference('submit_slice_information', 'True')
382 profile.putPreference('submit_slice_information', 'False')
385 class SelectParts(InfoPage):
386 def __init__(self, parent):
387 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
388 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."))
390 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
391 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
392 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
394 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."))
395 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
396 self.springExtruder.SetValue(True)
399 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
400 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
401 if self.dualExtrusion.GetValue():
402 profile.putMachineSetting('extruder_amount', '2')
403 profile.putMachineSetting('machine_depth', '195')
405 profile.putMachineSetting('extruder_amount', '1')
406 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
407 profile.putProfileSetting('retraction_enable', 'True')
409 profile.putProfileSetting('retraction_enable', 'False')
412 class UltimakerFirmwareUpgradePage(InfoPage):
413 def __init__(self, parent):
414 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
415 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."))
416 self.AddHiddenSeperator()
417 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
418 self.AddHiddenSeperator()
419 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."))
420 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
421 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
422 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
423 self.AddHiddenSeperator()
424 self.AddText(_("Do not upgrade to this firmware if:"))
425 self.AddText(_("* You have an older machine based on ATMega1280"))
426 self.AddText(_("* Have other changes in the firmware"))
427 # button = self.AddButton('Goto this page for a custom firmware')
428 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
433 def OnUpgradeClick(self, e):
434 if firmwareInstall.InstallFirmware():
435 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
437 def OnSkipClick(self, e):
438 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
439 self.GetParent().ShowPage(self.GetNext())
441 def OnUrlClick(self, e):
442 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
444 class UltimakerCheckupPage(InfoPage):
445 def __init__(self, parent):
446 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
448 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
449 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
450 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
451 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
452 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
453 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
454 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
455 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
456 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
457 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
460 _("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."))
461 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
462 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
463 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
465 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
466 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
467 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
469 self.infoBox = self.AddInfoBox()
470 self.machineState = self.AddText("")
471 self.temperatureLabel = self.AddText("")
472 self.errorLogButton = self.AddButton(_("Show error log"))
473 self.errorLogButton.Show(False)
475 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
477 self.xMinStop = False
478 self.xMaxStop = False
479 self.yMinStop = False
480 self.yMaxStop = False
481 self.zMinStop = False
482 self.zMaxStop = False
484 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
487 if self.comm is not None:
491 self.endstopBitmap.Show(False)
494 def OnSkipClick(self, e):
495 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
496 self.GetParent().ShowPage(self.GetNext())
498 def OnCheckClick(self, e=None):
499 self.errorLogButton.Show(False)
500 if self.comm is not None:
504 wx.CallAfter(self.OnCheckClick)
506 self.infoBox.SetBusy(_("Connecting to machine."))
507 self.commState.SetBitmap(self.unknownBitmap)
508 self.tempState.SetBitmap(self.unknownBitmap)
509 self.stopState.SetBitmap(self.unknownBitmap)
510 self.checkupState = 0
511 self.checkExtruderNr = 0
512 self.comm = machineCom.MachineCom(callbackObject=self)
514 def OnErrorLog(self, e):
515 printWindow.LogWindow('\n'.join(self.comm.getLog()))
517 def mcLog(self, message):
520 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
521 if not self.comm.isOperational():
523 if self.checkupState == 0:
524 self.tempCheckTimeout = 20
525 if temp[self.checkExtruderNr] > 70:
526 self.checkupState = 1
527 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
528 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
529 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
531 self.startTemp = temp[self.checkExtruderNr]
532 self.checkupState = 2
533 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
534 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
535 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
536 elif self.checkupState == 1:
538 self.startTemp = temp[self.checkExtruderNr]
539 self.checkupState = 2
540 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
541 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
542 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
543 elif self.checkupState == 2:
544 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
545 if temp[self.checkExtruderNr] > self.startTemp + 40:
546 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
547 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
548 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
549 self.checkExtruderNr = 0
550 self.checkupState = 3
551 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
552 wx.CallAfter(self.endstopBitmap.Show, True)
553 wx.CallAfter(self.Layout)
554 self.comm.sendCommand('M119')
555 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
557 self.checkupState = 0
558 self.checkExtruderNr += 1
560 self.tempCheckTimeout -= 1
561 if self.tempCheckTimeout < 1:
562 self.checkupState = -1
563 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
564 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
565 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
566 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
567 elif self.checkupState >= 3 and self.checkupState < 10:
568 self.comm.sendCommand('M119')
569 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
571 def mcStateChange(self, state):
572 if self.comm is None:
574 if self.comm.isOperational():
575 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
576 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
577 elif self.comm.isError():
578 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
579 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
580 wx.CallAfter(self.endstopBitmap.Show, False)
581 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
582 wx.CallAfter(self.errorLogButton.Show, True)
583 wx.CallAfter(self.Layout)
585 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
587 def mcMessage(self, message):
588 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
589 for data in message.split(' '):
591 tag, value = data.split(':', 1)
593 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
595 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
597 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
599 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
601 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
603 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
605 tag, value = map(str.strip, message.split(':', 1))
607 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
609 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
611 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
613 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
615 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
617 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
618 if 'z_max' in message:
619 self.comm.sendCommand('M119')
621 if self.checkupState == 3:
622 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
623 self.checkupState = 4
624 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
625 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
626 elif self.checkupState == 4:
627 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
628 self.checkupState = 5
629 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
630 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
631 elif self.checkupState == 5:
632 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
633 self.checkupState = 6
634 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
635 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
636 elif self.checkupState == 6:
637 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
638 self.checkupState = 7
639 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
640 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
641 elif self.checkupState == 7:
642 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
643 self.checkupState = 8
644 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
645 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
646 elif self.checkupState == 8:
647 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
648 self.checkupState = 9
649 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
650 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
651 elif self.checkupState == 9:
652 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
653 self.checkupState = 10
655 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
656 wx.CallAfter(self.infoBox.SetReadyIndicator)
657 wx.CallAfter(self.endstopBitmap.Show, False)
658 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
659 wx.CallAfter(self.OnSkipClick, None)
661 def mcProgress(self, lineNr):
664 def mcZChange(self, newZ):
668 class UltimakerCalibrationPage(InfoPage):
669 def __init__(self, parent):
670 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
672 self.AddText("Your Ultimaker requires some calibration.")
673 self.AddText("This calibration is needed for a proper extrusion amount.")
675 self.AddText("The following values are needed:")
676 self.AddText("* Diameter of filament")
677 self.AddText("* Number of steps per mm of filament extrusion")
679 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
681 self.AddText("First we need the diameter of your filament:")
682 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
684 "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.")
685 self.AddText("Note: This value can be changed later at any time.")
688 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
691 class UltimakerCalibrateStepsPerEPage(InfoPage):
692 def __init__(self, parent):
693 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
695 #if profile.getMachineSetting('steps_per_e') == '0':
696 # profile.putMachineSetting('steps_per_e', '865.888')
698 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
699 self.AddText(_("First remove any filament from your machine."))
700 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
701 self.AddText(_("We'll push the filament 100mm"))
702 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
703 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
704 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
705 self.AddText(_("This results in the following steps per E:"))
706 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
707 self.AddText(_("You can repeat these steps to get better calibration."))
710 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
711 self.heatButton = self.AddButton(_("Heatup for filament removal"))
713 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
714 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
715 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
717 def OnSaveLengthClick(self, e):
718 currentEValue = float(self.stepsPerEInput.GetValue())
719 realExtrudeLength = float(self.lengthInput.GetValue())
720 newEValue = currentEValue * 100 / realExtrudeLength
721 self.stepsPerEInput.SetValue(str(newEValue))
722 self.lengthInput.SetValue("100")
724 def OnExtrudeClick(self, e):
725 threading.Thread(target=self.OnExtrudeRun).start()
727 def OnExtrudeRun(self):
728 self.heatButton.Enable(False)
729 self.extrudeButton.Enable(False)
730 currentEValue = float(self.stepsPerEInput.GetValue())
731 self.comm = machineCom.MachineCom()
732 if not self.comm.isOpen():
734 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
735 'Printer error', wx.OK | wx.ICON_INFORMATION)
736 self.heatButton.Enable(True)
737 self.extrudeButton.Enable(True)
740 line = self.comm.readline()
745 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
748 self.sendGCommand('M302') #Disable cold extrusion protection
749 self.sendGCommand("M92 E%f" % (currentEValue))
750 self.sendGCommand("G92 E0")
751 self.sendGCommand("G1 E100 F600")
754 self.extrudeButton.Enable()
755 self.heatButton.Enable()
757 def OnHeatClick(self, e):
758 threading.Thread(target=self.OnHeatRun).start()
761 self.heatButton.Enable(False)
762 self.extrudeButton.Enable(False)
763 self.comm = machineCom.MachineCom()
764 if not self.comm.isOpen():
766 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
767 'Printer error', wx.OK | wx.ICON_INFORMATION)
768 self.heatButton.Enable(True)
769 self.extrudeButton.Enable(True)
772 line = self.comm.readline()
774 self.heatButton.Enable(True)
775 self.extrudeButton.Enable(True)
779 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
782 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
784 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
785 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
786 self.sendGCommand('M104 S0')
789 self.heatButton.Enable(True)
790 self.extrudeButton.Enable(True)
792 def sendGCommand(self, cmd):
793 self.comm.sendCommand(cmd) #Disable cold extrusion protection
795 line = self.comm.readline()
798 if line.startswith('ok'):
802 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
804 class Ultimaker2ReadyPage(InfoPage):
805 def __init__(self, parent):
806 super(Ultimaker2ReadyPage, self).__init__(parent, "Ultimaker2")
807 self.AddText('Congratulations on your the purchase of your brand new Ultimaker2.')
808 self.AddText('Cura is now ready to be used with your Ultimaker2.')
811 class configWizard(wx.wizard.Wizard):
812 def __init__(self, addNew = False):
813 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
815 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
816 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
818 self.firstInfoPage = FirstInfoPage(self, addNew)
819 self.machineSelectPage = MachineSelectPage(self)
820 self.ultimakerSelectParts = SelectParts(self)
821 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
822 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
823 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
824 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
825 self.bedLevelPage = bedLevelWizardMain(self)
826 self.headOffsetCalibration = headOffsetCalibrationPage(self)
827 self.otherMachineSelectPage = OtherMachineSelectPage(self)
828 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
829 self.otherMachineInfoPage = OtherMachineInfoPage(self)
831 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
833 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
834 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
835 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
836 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
837 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
838 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
839 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
840 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
842 self.FitToPage(self.firstInfoPage)
843 self.GetPageAreaSizer().Add(self.firstInfoPage)
845 self.RunWizard(self.firstInfoPage)
848 def OnPageChanging(self, e):
849 e.GetPage().StoreData()
851 def OnPageChanged(self, e):
852 if e.GetPage().AllowNext():
853 self.FindWindowById(wx.ID_FORWARD).Enable()
855 self.FindWindowById(wx.ID_FORWARD).Disable()
856 self.FindWindowById(wx.ID_BACKWARD).Disable()
858 class bedLevelWizardMain(InfoPage):
859 def __init__(self, parent):
860 super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
862 self.AddText('This wizard will help you in leveling your printer bed')
864 self.AddText('It will do the following steps')
865 self.AddText('* Move the printer head to each corner')
866 self.AddText(' and let you adjust the height of the bed to the nozzle')
867 self.AddText('* Print a line around the bed to check if it is level')
870 self.connectButton = self.AddButton('Connect to printer')
873 self.infoBox = self.AddInfoBox()
874 self.resumeButton = self.AddButton('Resume')
875 self.resumeButton.Enable(False)
877 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
878 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
880 def OnConnect(self, e = None):
881 if self.comm is not None:
885 wx.CallAfter(self.OnConnect)
887 self.connectButton.Enable(False)
888 self.comm = machineCom.MachineCom(callbackObject=self)
889 self.infoBox.SetBusy('Connecting to machine.')
890 self._wizardState = 0
893 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
894 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
897 def OnResume(self, e):
898 feedZ = profile.getProfileSettingFloat('print_speed') * 60
899 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
900 if self._wizardState == 2:
901 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
902 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
903 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
904 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
905 self.comm.sendCommand('M400')
906 self._wizardState = 3
907 elif self._wizardState == 4:
908 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
909 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
910 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
911 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
912 self.comm.sendCommand('M400')
913 self._wizardState = 5
914 elif self._wizardState == 6:
915 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
916 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
917 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
918 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
919 self.comm.sendCommand('M400')
920 self._wizardState = 7
921 elif self._wizardState == 8:
922 wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
923 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
924 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
925 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
926 self._wizardState = 9
927 elif self._wizardState == 10:
928 self._wizardState = 11
929 wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
930 feedZ = profile.getProfileSettingFloat('print_speed') * 60
931 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
932 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
933 w = profile.getMachineSettingFloat('machine_width')
934 d = profile.getMachineSettingFloat('machine_depth')
935 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
936 filamentArea = math.pi * filamentRadius * filamentRadius
937 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
941 'G1 Z2 F%d' % (feedZ),
943 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
944 'G1 Z0.3 F%d' % (feedZ)]
946 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
948 for i in xrange(0, 3):
949 dist = 5.0 + 0.4 * float(i)
950 eValue += (d - 2.0*dist) * ePerMM
951 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
952 eValue += (w - 2.0*dist) * ePerMM
953 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
954 eValue += (d - 2.0*dist) * ePerMM
955 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
956 eValue += (w - 2.0*dist) * ePerMM
957 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
959 gcodeList.append('M400')
960 self.comm.printGCode(gcodeList)
961 self.resumeButton.Enable(False)
963 def mcLog(self, message):
964 print 'Log:', message
966 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
967 if self._wizardState == 1:
968 self._wizardState = 2
969 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
970 wx.CallAfter(self.resumeButton.Enable, True)
971 elif self._wizardState == 3:
972 self._wizardState = 4
973 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
974 wx.CallAfter(self.resumeButton.Enable, True)
975 elif self._wizardState == 5:
976 self._wizardState = 6
977 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
978 wx.CallAfter(self.resumeButton.Enable, True)
979 elif self._wizardState == 7:
980 self._wizardState = 8
981 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
982 wx.CallAfter(self.resumeButton.Enable, True)
983 elif self._wizardState == 9:
984 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
985 wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
987 wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
988 wx.CallAfter(self.resumeButton.Enable, True)
989 self._wizardState = 10
991 def mcStateChange(self, state):
992 if self.comm is None:
994 if self.comm.isOperational():
995 if self._wizardState == 0:
996 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
997 self.comm.sendCommand('M105')
998 self.comm.sendCommand('G28')
999 self._wizardState = 1
1000 elif self._wizardState == 11 and not self.comm.isPrinting():
1001 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1002 self.comm.sendCommand('G92 E0')
1003 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1004 self.comm.sendCommand('M104 S0')
1005 wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
1006 wx.CallAfter(self.infoBox.SetReadyIndicator)
1007 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1008 wx.CallAfter(self.connectButton.Enable, True)
1009 self._wizardState = 12
1010 elif self.comm.isError():
1011 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1013 def mcMessage(self, message):
1016 def mcProgress(self, lineNr):
1019 def mcZChange(self, newZ):
1022 class headOffsetCalibrationPage(InfoPage):
1023 def __init__(self, parent):
1024 super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
1026 self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
1029 self.connectButton = self.AddButton('Connect to printer')
1032 self.infoBox = self.AddInfoBox()
1033 self.textEntry = self.AddTextCtrl('')
1034 self.textEntry.Enable(False)
1035 self.resumeButton = self.AddButton('Resume')
1036 self.resumeButton.Enable(False)
1038 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1039 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1041 def OnConnect(self, e = None):
1042 if self.comm is not None:
1046 wx.CallAfter(self.OnConnect)
1048 self.connectButton.Enable(False)
1049 self.comm = machineCom.MachineCom(callbackObject=self)
1050 self.infoBox.SetBusy('Connecting to machine.')
1051 self._wizardState = 0
1053 def OnResume(self, e):
1054 if self._wizardState == 2:
1055 self._wizardState = 3
1056 wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
1058 w = profile.getMachineSettingFloat('machine_width')
1059 d = profile.getMachineSettingFloat('machine_depth')
1061 gcode = gcodeGenerator.gcodeGenerator()
1062 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1063 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1070 gcode.addMove(w/2, 5)
1071 gcode.addMove(z=0.2)
1073 gcode.addExtrude(w/2, d-5.0)
1075 gcode.addMove(5, d/2)
1077 gcode.addExtrude(w-5.0, d/2)
1078 gcode.addRetract(15)
1081 gcode.addMove(w/2, 5)
1083 gcode.addExtrude(w/2, d-5.0)
1085 gcode.addMove(5, d/2)
1087 gcode.addExtrude(w-5.0, d/2)
1088 gcode.addRetract(15)
1093 gcode.addCmd('M400')
1095 self.comm.printGCode(gcode.list())
1096 self.resumeButton.Enable(False)
1097 elif self._wizardState == 4:
1099 float(self.textEntry.GetValue())
1102 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1103 self._wizardState = 5
1104 self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
1105 self.textEntry.SetValue('0.0')
1106 self.textEntry.Enable(True)
1107 elif self._wizardState == 5:
1109 float(self.textEntry.GetValue())
1112 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1113 self._wizardState = 6
1114 self.infoBox.SetBusy('Printing the fine calibration lines.')
1115 self.textEntry.SetValue('')
1116 self.textEntry.Enable(False)
1117 self.resumeButton.Enable(False)
1119 x = profile.getMachineSettingFloat('extruder_offset_x1')
1120 y = profile.getMachineSettingFloat('extruder_offset_y1')
1121 gcode = gcodeGenerator.gcodeGenerator()
1122 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1123 gcode.setPrintSpeed(25)
1126 gcode.addMove(50, 40, 0.2)
1128 for n in xrange(0, 10):
1129 gcode.addExtrude(50 + n * 10, 150)
1130 gcode.addExtrude(50 + n * 10 + 5, 150)
1131 gcode.addExtrude(50 + n * 10 + 5, 40)
1132 gcode.addExtrude(50 + n * 10 + 10, 40)
1133 gcode.addMove(40, 50)
1134 for n in xrange(0, 10):
1135 gcode.addExtrude(150, 50 + n * 10)
1136 gcode.addExtrude(150, 50 + n * 10 + 5)
1137 gcode.addExtrude(40, 50 + n * 10 + 5)
1138 gcode.addExtrude(40, 50 + n * 10 + 10)
1139 gcode.addRetract(15)
1142 gcode.addMove(50 - x, 30 - y, 0.2)
1144 for n in xrange(0, 10):
1145 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1146 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1147 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1148 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1149 gcode.addMove(30 - x, 50 - y, 0.2)
1150 for n in xrange(0, 10):
1151 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1152 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1153 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1154 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1155 gcode.addRetract(15)
1157 gcode.addCmd('M400')
1158 gcode.addCmd('M104 T0 S0')
1159 gcode.addCmd('M104 T1 S0')
1160 self.comm.printGCode(gcode.list())
1161 elif self._wizardState == 7:
1163 n = int(self.textEntry.GetValue()) - 1
1166 x = profile.getMachineSettingFloat('extruder_offset_x1')
1168 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1169 self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
1170 self.textEntry.SetValue('10')
1171 self._wizardState = 8
1172 elif self._wizardState == 8:
1174 n = int(self.textEntry.GetValue()) - 1
1177 y = profile.getMachineSettingFloat('extruder_offset_y1')
1179 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1180 self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1181 self.infoBox.SetReadyIndicator()
1182 self._wizardState = 8
1184 self.resumeButton.Enable(False)
1186 def mcLog(self, message):
1187 print 'Log:', message
1189 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1190 if self._wizardState == 1:
1191 if temp[0] >= 210 and temp[1] >= 210:
1192 self._wizardState = 2
1193 wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
1194 wx.CallAfter(self.resumeButton.Enable, True)
1195 wx.CallAfter(self.resumeButton.SetFocus)
1197 def mcStateChange(self, state):
1198 if self.comm is None:
1200 if self.comm.isOperational():
1201 if self._wizardState == 0:
1202 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
1203 self.comm.sendCommand('M105')
1204 self.comm.sendCommand('M104 S220 T0')
1205 self.comm.sendCommand('M104 S220 T1')
1206 self.comm.sendCommand('G28')
1207 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1208 self._wizardState = 1
1209 if not self.comm.isPrinting():
1210 if self._wizardState == 3:
1211 self._wizardState = 4
1212 wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
1213 wx.CallAfter(self.textEntry.SetValue, '0.0')
1214 wx.CallAfter(self.textEntry.Enable, True)
1215 wx.CallAfter(self.resumeButton.Enable, True)
1216 wx.CallAfter(self.resumeButton.SetFocus)
1217 elif self._wizardState == 6:
1218 self._wizardState = 7
1219 wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
1220 wx.CallAfter(self.textEntry.SetValue, '10')
1221 wx.CallAfter(self.textEntry.Enable, True)
1222 wx.CallAfter(self.resumeButton.Enable, True)
1223 wx.CallAfter(self.resumeButton.SetFocus)
1225 elif self.comm.isError():
1226 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1228 def mcMessage(self, message):
1231 def mcProgress(self, lineNr):
1234 def mcZChange(self, newZ):
1237 class bedLevelWizard(wx.wizard.Wizard):
1239 super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
1241 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1242 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1244 self.mainPage = bedLevelWizardMain(self)
1245 self.headOffsetCalibration = None
1247 self.FitToPage(self.mainPage)
1248 self.GetPageAreaSizer().Add(self.mainPage)
1250 self.RunWizard(self.mainPage)
1253 def OnPageChanging(self, e):
1254 e.GetPage().StoreData()
1256 def OnPageChanged(self, e):
1257 if e.GetPage().AllowNext():
1258 self.FindWindowById(wx.ID_FORWARD).Enable()
1260 self.FindWindowById(wx.ID_FORWARD).Disable()
1261 self.FindWindowById(wx.ID_BACKWARD).Disable()
1263 class headOffsetWizard(wx.wizard.Wizard):
1265 super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
1267 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1268 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1270 self.mainPage = headOffsetCalibrationPage(self)
1272 self.FitToPage(self.mainPage)
1273 self.GetPageAreaSizer().Add(self.mainPage)
1275 self.RunWizard(self.mainPage)
1278 def OnPageChanging(self, e):
1279 e.GetPage().StoreData()
1281 def OnPageChanged(self, e):
1282 if e.GetPage().AllowNext():
1283 self.FindWindowById(wx.ID_FORWARD).Enable()
1285 self.FindWindowById(wx.ID_FORWARD).Disable()
1286 self.FindWindowById(wx.ID_BACKWARD).Disable()