1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
12 from Cura.gui import firmwareInstall
13 from Cura.gui import printWindow
14 from Cura.util import machineCom
15 from Cura.util import profile
16 from Cura.util import gcodeGenerator
17 from Cura.util import resources
20 class InfoBox(wx.Panel):
21 def __init__(self, parent):
22 super(InfoBox, self).__init__(parent)
23 self.SetBackgroundColour('#FFFF80')
25 self.sizer = wx.GridBagSizer(5, 5)
26 self.SetSizer(self.sizer)
28 self.attentionBitmap = wx.Bitmap(resources.getPathForImage('attention.png'))
29 self.errorBitmap = wx.Bitmap(resources.getPathForImage('error.png'))
30 self.readyBitmap = wx.Bitmap(resources.getPathForImage('ready.png'))
32 wx.Bitmap(resources.getPathForImage('busy-0.png')),
33 wx.Bitmap(resources.getPathForImage('busy-1.png')),
34 wx.Bitmap(resources.getPathForImage('busy-2.png')),
35 wx.Bitmap(resources.getPathForImage('busy-3.png'))
38 self.bitmap = wx.StaticBitmap(self, -1, wx.EmptyBitmapRGBA(24, 24, red=255, green=255, blue=255, alpha=1))
39 self.text = wx.StaticText(self, -1, '')
40 self.extraInfoButton = wx.Button(self, -1, 'i', style=wx.BU_EXACTFIT)
41 self.sizer.Add(self.bitmap, pos=(0, 0), flag=wx.ALL, border=5)
42 self.sizer.Add(self.text, pos=(0, 1), flag=wx.TOP | wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL, border=5)
43 self.sizer.Add(self.extraInfoButton, pos=(0,2), flag=wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, border=5)
44 self.sizer.AddGrowableCol(1)
46 self.extraInfoButton.Show(False)
48 self.extraInfoUrl = ''
50 self.timer = wx.Timer(self)
51 self.Bind(wx.EVT_TIMER, self.doBusyUpdate, self.timer)
52 self.Bind(wx.EVT_BUTTON, self.doExtraInfo, self.extraInfoButton)
55 def SetInfo(self, info):
56 self.SetBackgroundColour('#FFFF80')
57 self.text.SetLabel(info)
58 self.extraInfoButton.Show(False)
61 def SetError(self, info, extraInfoUrl):
62 self.extraInfoUrl = extraInfoUrl
63 self.SetBackgroundColour('#FF8080')
64 self.text.SetLabel(info)
65 self.extraInfoButton.Show(True)
67 self.SetErrorIndicator()
70 def SetAttention(self, info):
71 self.SetBackgroundColour('#FFFF80')
72 self.text.SetLabel(info)
73 self.extraInfoButton.Show(False)
74 self.SetAttentionIndicator()
78 def SetBusy(self, info):
80 self.SetBusyIndicator()
82 def SetBusyIndicator(self):
84 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
86 def doExtraInfo(self, e):
87 webbrowser.open(self.extraInfoUrl)
89 def doBusyUpdate(self, e):
90 if self.busyState is None:
93 if self.busyState >= len(self.busyBitmap):
95 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
97 def SetReadyIndicator(self):
99 self.bitmap.SetBitmap(self.readyBitmap)
101 def SetErrorIndicator(self):
102 self.busyState = None
103 self.bitmap.SetBitmap(self.errorBitmap)
105 def SetAttentionIndicator(self):
106 self.busyState = None
107 self.bitmap.SetBitmap(self.attentionBitmap)
110 class InfoPage(wx.wizard.WizardPageSimple):
111 def __init__(self, parent, title):
112 wx.wizard.WizardPageSimple.__init__(self, parent)
114 sizer = wx.GridBagSizer(5, 5)
118 title = wx.StaticText(self, -1, title)
119 title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
120 sizer.Add(title, pos=(0, 0), span=(1, 2), flag=wx.ALIGN_CENTRE | wx.ALL)
121 sizer.Add(wx.StaticLine(self, -1), pos=(1, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
122 sizer.AddGrowableCol(1)
126 def AddText(self, info):
127 text = wx.StaticText(self, -1, info)
128 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
132 def AddSeperator(self):
133 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
136 def AddHiddenSeperator(self):
139 def AddInfoBox(self):
140 infoBox = InfoBox(self)
141 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
145 def AddRadioButton(self, label, style=0):
146 radio = wx.RadioButton(self, -1, label, style=style)
147 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
151 def AddCheckbox(self, label, checked=False):
152 check = wx.CheckBox(self, -1)
153 text = wx.StaticText(self, -1, label)
154 check.SetValue(checked)
155 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
156 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 2), flag=wx.ALL)
160 def AddButton(self, label):
161 button = wx.Button(self, -1, label)
162 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
166 def AddDualButton(self, label1, label2):
167 button1 = wx.Button(self, -1, label1)
168 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
169 button2 = wx.Button(self, -1, label2)
170 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
172 return button1, button2
174 def AddTextCtrl(self, value):
175 ret = wx.TextCtrl(self, -1, value)
176 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
180 def AddLabelTextCtrl(self, info, value):
181 text = wx.StaticText(self, -1, info)
182 ret = wx.TextCtrl(self, -1, value)
183 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
184 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
188 def AddTextCtrlButton(self, value, buttonText):
189 text = wx.TextCtrl(self, -1, value)
190 button = wx.Button(self, -1, buttonText)
191 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
192 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
196 def AddBitmap(self, bitmap):
197 bitmap = wx.StaticBitmap(self, -1, bitmap)
198 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
202 def AddCheckmark(self, label, bitmap):
203 check = wx.StaticBitmap(self, -1, bitmap)
204 text = wx.StaticText(self, -1, label)
205 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
206 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 1), flag=wx.ALL)
220 class FirstInfoPage(InfoPage):
221 def __init__(self, parent, addNew):
223 super(FirstInfoPage, self).__init__(parent, _("Add new machine wizard"))
225 super(FirstInfoPage, self).__init__(parent, _("First time run wizard"))
226 self.AddText(_("Welcome, and thanks for trying Cura!"))
228 self.AddText(_("This wizard will help you in setting up Cura for your machine."))
229 # self.AddText(_("This wizard will help you with the following steps:"))
230 # self.AddText(_("* Configure Cura for your machine"))
231 # self.AddText(_("* Optionally upgrade your firmware"))
232 # self.AddText(_("* Optionally check if your machine is working safely"))
233 # self.AddText(_("* Optionally level your printer bed"))
235 #self.AddText('* Calibrate your machine')
236 #self.AddText('* Do your first print')
242 class OtherMachineSelectPage(InfoPage):
243 def __init__(self, parent):
244 super(OtherMachineSelectPage, self).__init__(parent, "Other machine information")
245 self.AddText(_("The following pre-defined machine profiles are available"))
246 self.AddText(_("Note that these profiles are not guaranteed to give good results,\nor work at all. Extra tweaks might be required.\nIf you find issues with the predefined profiles,\nor want an extra profile.\nPlease report it at the github issue tracker."))
248 machines = resources.getDefaultMachineProfiles()
250 for filename in machines:
251 name = os.path.splitext(os.path.basename(filename))[0]
252 item = self.AddRadioButton(name)
253 item.filename = filename
254 item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
255 self.options.append(item)
257 item = self.AddRadioButton('Custom...')
259 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
261 def OnProfileSelect(self, e):
262 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
264 def OnOtherSelect(self, e):
265 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
268 for option in self.options:
269 if option.GetValue():
270 profile.loadProfile(option.filename)
271 profile.loadMachineSettings(option.filename)
273 class OtherMachineInfoPage(InfoPage):
274 def __init__(self, parent):
275 super(OtherMachineInfoPage, self).__init__(parent, "Cura Ready!")
276 self.AddText(_("Cura is now ready to be used!"))
278 class CustomRepRapInfoPage(InfoPage):
279 def __init__(self, parent):
280 super(CustomRepRapInfoPage, self).__init__(parent, "Custom RepRap information")
281 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
282 self.AddText(_("Be sure to review the default profile before running it on your machine."))
283 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
285 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
287 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
288 self.machineWidth = self.AddLabelTextCtrl(_("Machine width (mm)"), "80")
289 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth (mm)"), "80")
290 self.machineHeight = self.AddLabelTextCtrl(_("Machine height (mm)"), "55")
291 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
292 self.heatedBed = self.AddCheckbox(_("Heated bed"))
293 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
296 profile.putMachineSetting('machine_name', self.machineName.GetValue())
297 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
298 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
299 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
300 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
301 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
302 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
303 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
304 profile.putMachineSetting('extruder_head_size_min_x', '0')
305 profile.putMachineSetting('extruder_head_size_min_y', '0')
306 profile.putMachineSetting('extruder_head_size_max_x', '0')
307 profile.putMachineSetting('extruder_head_size_max_y', '0')
308 profile.putMachineSetting('extruder_head_size_height', '0')
309 profile.checkAndUpdateMachineName()
311 class MachineSelectPage(InfoPage):
312 def __init__(self, parent):
313 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
314 self.AddText(_("What kind of machine do you have:"))
316 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2", style=wx.RB_GROUP)
317 self.Ultimaker2Radio.SetValue(True)
318 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
319 self.UltimakerRadio = self.AddRadioButton("Ultimaker Original")
320 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
321 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot)"))
322 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
324 self.AddText(_("The collection of anonymous usage information helps with the continued improvement of Cura."))
325 self.AddText(_("This does NOT submit your models online nor gathers any privacy related information."))
326 self.SubmitUserStats = self.AddCheckbox(_("Submit anonymous usage information:"))
327 self.AddText(_("For full details see: http://wiki.ultimaker.com/Cura:stats"))
328 self.SubmitUserStats.SetValue(True)
330 def OnUltimaker2Select(self, e):
331 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
333 def OnUltimakerSelect(self, e):
334 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
336 def OnOtherSelect(self, e):
337 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
340 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
344 profile.putProfileSetting('retraction_enable', 'True')
345 if self.Ultimaker2Radio.GetValue():
346 profile.putMachineSetting('machine_width', '230')
347 profile.putMachineSetting('machine_depth', '225')
348 profile.putMachineSetting('machine_height', '205')
349 profile.putMachineSetting('machine_name', 'ultimaker2')
350 profile.putMachineSetting('machine_type', 'ultimaker2')
351 profile.putMachineSetting('machine_center_is_zero', 'False')
352 profile.putMachineSetting('has_heated_bed', 'True')
353 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
354 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
355 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
356 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
357 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
358 profile.putMachineSetting('extruder_head_size_height', '55.0')
359 profile.putProfileSetting('nozzle_size', '0.4')
360 profile.putProfileSetting('fan_full_height', '5.0')
361 profile.putMachineSetting('extruder_offset_x1', '18.0')
362 profile.putMachineSetting('extruder_offset_y1', '0.0')
363 elif self.UltimakerRadio.GetValue():
364 profile.putMachineSetting('machine_width', '205')
365 profile.putMachineSetting('machine_depth', '205')
366 profile.putMachineSetting('machine_height', '200')
367 profile.putMachineSetting('machine_name', 'ultimaker original')
368 profile.putMachineSetting('machine_type', 'ultimaker')
369 profile.putMachineSetting('machine_center_is_zero', 'False')
370 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
371 profile.putProfileSetting('nozzle_size', '0.4')
372 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
373 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
374 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
375 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
376 profile.putMachineSetting('extruder_head_size_height', '55.0')
378 profile.putMachineSetting('machine_width', '80')
379 profile.putMachineSetting('machine_depth', '80')
380 profile.putMachineSetting('machine_height', '60')
381 profile.putMachineSetting('machine_name', 'reprap')
382 profile.putMachineSetting('machine_type', 'reprap')
383 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
384 profile.putPreference('startMode', 'Normal')
385 profile.putProfileSetting('nozzle_size', '0.5')
386 profile.checkAndUpdateMachineName()
387 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
388 if self.SubmitUserStats.GetValue():
389 profile.putPreference('submit_slice_information', 'True')
391 profile.putPreference('submit_slice_information', 'False')
394 class SelectParts(InfoPage):
395 def __init__(self, parent):
396 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
397 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."))
399 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
400 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
401 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
402 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
404 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."))
405 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
406 self.springExtruder.SetValue(True)
409 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
410 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
411 profile.putMachineSetting('has_heated_bed', 'True')
413 profile.putMachineSetting('has_heated_bed', 'False')
414 if self.dualExtrusion.GetValue():
415 profile.putMachineSetting('extruder_amount', '2')
416 profile.putMachineSetting('machine_depth', '195')
418 profile.putMachineSetting('extruder_amount', '1')
419 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
420 profile.putProfileSetting('retraction_enable', 'True')
422 profile.putProfileSetting('retraction_enable', 'False')
425 class UltimakerFirmwareUpgradePage(InfoPage):
426 def __init__(self, parent):
427 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
428 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."))
429 self.AddHiddenSeperator()
430 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
431 self.AddHiddenSeperator()
432 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."))
433 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
434 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
435 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
436 self.AddHiddenSeperator()
437 self.AddText(_("Do not upgrade to this firmware if:"))
438 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
439 self.AddText(_("* Have other changes in the firmware"))
440 # button = self.AddButton('Goto this page for a custom firmware')
441 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
446 def OnUpgradeClick(self, e):
447 if firmwareInstall.InstallFirmware():
448 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
450 def OnSkipClick(self, e):
451 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
452 self.GetParent().ShowPage(self.GetNext())
454 def OnUrlClick(self, e):
455 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
457 class UltimakerCheckupPage(InfoPage):
458 def __init__(self, parent):
459 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
461 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
462 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
463 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
464 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
465 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
466 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
467 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
468 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
469 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
470 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
473 _("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."))
474 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
475 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
476 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
478 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
479 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
480 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
482 self.infoBox = self.AddInfoBox()
483 self.machineState = self.AddText("")
484 self.temperatureLabel = self.AddText("")
485 self.errorLogButton = self.AddButton(_("Show error log"))
486 self.errorLogButton.Show(False)
488 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
490 self.xMinStop = False
491 self.xMaxStop = False
492 self.yMinStop = False
493 self.yMaxStop = False
494 self.zMinStop = False
495 self.zMaxStop = False
497 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
500 if self.comm is not None:
504 self.endstopBitmap.Show(False)
507 def OnSkipClick(self, e):
508 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
509 self.GetParent().ShowPage(self.GetNext())
511 def OnCheckClick(self, e=None):
512 self.errorLogButton.Show(False)
513 if self.comm is not None:
517 wx.CallAfter(self.OnCheckClick)
519 self.infoBox.SetBusy(_("Connecting to machine."))
520 self.commState.SetBitmap(self.unknownBitmap)
521 self.tempState.SetBitmap(self.unknownBitmap)
522 self.stopState.SetBitmap(self.unknownBitmap)
523 self.checkupState = 0
524 self.checkExtruderNr = 0
525 self.comm = machineCom.MachineCom(callbackObject=self)
527 def OnErrorLog(self, e):
528 printWindow.LogWindow('\n'.join(self.comm.getLog()))
530 def mcLog(self, message):
533 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
534 if not self.comm.isOperational():
536 if self.checkupState == 0:
537 self.tempCheckTimeout = 20
538 if temp[self.checkExtruderNr] > 70:
539 self.checkupState = 1
540 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
541 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
542 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
544 self.startTemp = temp[self.checkExtruderNr]
545 self.checkupState = 2
546 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
547 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
548 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
549 elif self.checkupState == 1:
551 self.startTemp = temp[self.checkExtruderNr]
552 self.checkupState = 2
553 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
554 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
555 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
556 elif self.checkupState == 2:
557 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
558 if temp[self.checkExtruderNr] > self.startTemp + 40:
559 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
560 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
561 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
562 self.checkExtruderNr = 0
563 self.checkupState = 3
564 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
565 wx.CallAfter(self.endstopBitmap.Show, True)
566 wx.CallAfter(self.Layout)
567 self.comm.sendCommand('M119')
568 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
570 self.checkupState = 0
571 self.checkExtruderNr += 1
573 self.tempCheckTimeout -= 1
574 if self.tempCheckTimeout < 1:
575 self.checkupState = -1
576 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
577 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
578 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
579 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
580 elif self.checkupState >= 3 and self.checkupState < 10:
581 self.comm.sendCommand('M119')
582 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
584 def mcStateChange(self, state):
585 if self.comm is None:
587 if self.comm.isOperational():
588 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
589 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
590 elif self.comm.isError():
591 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
592 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
593 wx.CallAfter(self.endstopBitmap.Show, False)
594 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
595 wx.CallAfter(self.errorLogButton.Show, True)
596 wx.CallAfter(self.Layout)
598 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
600 def mcMessage(self, message):
601 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
602 for data in message.split(' '):
604 tag, value = data.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')
618 tag, value = map(str.strip, message.split(':', 1))
620 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
622 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
624 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
626 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
628 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
630 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
631 if 'z_max' in message:
632 self.comm.sendCommand('M119')
634 if self.checkupState == 3:
635 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
636 self.checkupState = 4
637 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
638 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
639 elif self.checkupState == 4:
640 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
641 self.checkupState = 5
642 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
643 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
644 elif self.checkupState == 5:
645 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
646 self.checkupState = 6
647 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
648 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
649 elif self.checkupState == 6:
650 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
651 self.checkupState = 7
652 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
653 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
654 elif self.checkupState == 7:
655 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
656 self.checkupState = 8
657 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
658 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
659 elif self.checkupState == 8:
660 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
661 self.checkupState = 9
662 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
663 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
664 elif self.checkupState == 9:
665 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
666 self.checkupState = 10
668 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
669 wx.CallAfter(self.infoBox.SetReadyIndicator)
670 wx.CallAfter(self.endstopBitmap.Show, False)
671 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
672 wx.CallAfter(self.OnSkipClick, None)
674 def mcProgress(self, lineNr):
677 def mcZChange(self, newZ):
681 class UltimakerCalibrationPage(InfoPage):
682 def __init__(self, parent):
683 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
685 self.AddText("Your Ultimaker requires some calibration.")
686 self.AddText("This calibration is needed for a proper extrusion amount.")
688 self.AddText("The following values are needed:")
689 self.AddText("* Diameter of filament")
690 self.AddText("* Number of steps per mm of filament extrusion")
692 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
694 self.AddText("First we need the diameter of your filament:")
695 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
697 "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.")
698 self.AddText("Note: This value can be changed later at any time.")
701 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
704 class UltimakerCalibrateStepsPerEPage(InfoPage):
705 def __init__(self, parent):
706 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
708 #if profile.getMachineSetting('steps_per_e') == '0':
709 # profile.putMachineSetting('steps_per_e', '865.888')
711 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
712 self.AddText(_("First remove any filament from your machine."))
713 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
714 self.AddText(_("We'll push the filament 100mm"))
715 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
716 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
717 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
718 self.AddText(_("This results in the following steps per E:"))
719 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
720 self.AddText(_("You can repeat these steps to get better calibration."))
723 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
724 self.heatButton = self.AddButton(_("Heatup for filament removal"))
726 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
727 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
728 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
730 def OnSaveLengthClick(self, e):
731 currentEValue = float(self.stepsPerEInput.GetValue())
732 realExtrudeLength = float(self.lengthInput.GetValue())
733 newEValue = currentEValue * 100 / realExtrudeLength
734 self.stepsPerEInput.SetValue(str(newEValue))
735 self.lengthInput.SetValue("100")
737 def OnExtrudeClick(self, e):
738 t = threading.Thread(target=self.OnExtrudeRun)
742 def OnExtrudeRun(self):
743 self.heatButton.Enable(False)
744 self.extrudeButton.Enable(False)
745 currentEValue = float(self.stepsPerEInput.GetValue())
746 self.comm = machineCom.MachineCom()
747 if not self.comm.isOpen():
749 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
750 'Printer error', wx.OK | wx.ICON_INFORMATION)
751 self.heatButton.Enable(True)
752 self.extrudeButton.Enable(True)
755 line = self.comm.readline()
760 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
763 self.sendGCommand('M302') #Disable cold extrusion protection
764 self.sendGCommand("M92 E%f" % (currentEValue))
765 self.sendGCommand("G92 E0")
766 self.sendGCommand("G1 E100 F600")
769 self.extrudeButton.Enable()
770 self.heatButton.Enable()
772 def OnHeatClick(self, e):
773 t = threading.Thread(target=self.OnHeatRun)
778 self.heatButton.Enable(False)
779 self.extrudeButton.Enable(False)
780 self.comm = machineCom.MachineCom()
781 if not self.comm.isOpen():
783 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
784 'Printer error', wx.OK | wx.ICON_INFORMATION)
785 self.heatButton.Enable(True)
786 self.extrudeButton.Enable(True)
789 line = self.comm.readline()
791 self.heatButton.Enable(True)
792 self.extrudeButton.Enable(True)
796 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
799 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
801 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
802 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
803 self.sendGCommand('M104 S0')
806 self.heatButton.Enable(True)
807 self.extrudeButton.Enable(True)
809 def sendGCommand(self, cmd):
810 self.comm.sendCommand(cmd) #Disable cold extrusion protection
812 line = self.comm.readline()
815 if line.startswith('ok'):
819 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
821 class Ultimaker2ReadyPage(InfoPage):
822 def __init__(self, parent):
823 super(Ultimaker2ReadyPage, self).__init__(parent, "Ultimaker2")
824 self.AddText('Congratulations on your the purchase of your brand new Ultimaker2.')
825 self.AddText('Cura is now ready to be used with your Ultimaker2.')
828 class configWizard(wx.wizard.Wizard):
829 def __init__(self, addNew = False):
830 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
832 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
833 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
835 self.firstInfoPage = FirstInfoPage(self, addNew)
836 self.machineSelectPage = MachineSelectPage(self)
837 self.ultimakerSelectParts = SelectParts(self)
838 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
839 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
840 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
841 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
842 self.bedLevelPage = bedLevelWizardMain(self)
843 self.headOffsetCalibration = headOffsetCalibrationPage(self)
844 self.otherMachineSelectPage = OtherMachineSelectPage(self)
845 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
846 self.otherMachineInfoPage = OtherMachineInfoPage(self)
848 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
850 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
851 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
852 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
853 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
854 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
855 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
856 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
857 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
859 self.FitToPage(self.firstInfoPage)
860 self.GetPageAreaSizer().Add(self.firstInfoPage)
862 self.RunWizard(self.firstInfoPage)
865 def OnPageChanging(self, e):
866 e.GetPage().StoreData()
868 def OnPageChanged(self, e):
869 if e.GetPage().AllowNext():
870 self.FindWindowById(wx.ID_FORWARD).Enable()
872 self.FindWindowById(wx.ID_FORWARD).Disable()
873 if e.GetPage().AllowBack():
874 self.FindWindowById(wx.ID_BACKWARD).Enable()
876 self.FindWindowById(wx.ID_BACKWARD).Disable()
878 class bedLevelWizardMain(InfoPage):
879 def __init__(self, parent):
880 super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
882 self.AddText('This wizard will help you in leveling your printer bed')
884 self.AddText('It will do the following steps')
885 self.AddText('* Move the printer head to each corner')
886 self.AddText(' and let you adjust the height of the bed to the nozzle')
887 self.AddText('* Print a line around the bed to check if it is level')
890 self.connectButton = self.AddButton('Connect to printer')
893 self.infoBox = self.AddInfoBox()
894 self.resumeButton = self.AddButton('Resume')
895 self.upButton, self.downButton = self.AddDualButton('Up 0.2mm', 'Down 0.2mm')
896 self.upButton2, self.downButton2 = self.AddDualButton('Up 10mm', 'Down 10mm')
897 self.resumeButton.Enable(False)
899 self.upButton.Enable(False)
900 self.downButton.Enable(False)
901 self.upButton2.Enable(False)
902 self.downButton2.Enable(False)
904 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
905 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
906 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
907 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
908 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
909 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
911 def OnConnect(self, e = None):
912 if self.comm is not None:
916 wx.CallAfter(self.OnConnect)
918 self.connectButton.Enable(False)
919 self.comm = machineCom.MachineCom(callbackObject=self)
920 self.infoBox.SetBusy('Connecting to machine.')
921 self._wizardState = 0
923 def OnBedUp(self, e):
924 feedZ = profile.getProfileSettingFloat('print_speed') * 60
925 self.comm.sendCommand('G92 Z10')
926 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
927 self.comm.sendCommand('M400')
929 def OnBedDown(self, e):
930 feedZ = profile.getProfileSettingFloat('print_speed') * 60
931 self.comm.sendCommand('G92 Z10')
932 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
933 self.comm.sendCommand('M400')
935 def OnBedUp2(self, e):
936 feedZ = profile.getProfileSettingFloat('print_speed') * 60
937 self.comm.sendCommand('G92 Z10')
938 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
939 self.comm.sendCommand('M400')
941 def OnBedDown2(self, e):
942 feedZ = profile.getProfileSettingFloat('print_speed') * 60
943 self.comm.sendCommand('G92 Z10')
944 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
945 self.comm.sendCommand('M400')
948 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
949 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
952 def OnResume(self, e):
953 feedZ = profile.getProfileSettingFloat('print_speed') * 60
954 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
955 if self._wizardState == -1:
956 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
957 wx.CallAfter(self.upButton.Enable, False)
958 wx.CallAfter(self.downButton.Enable, False)
959 wx.CallAfter(self.upButton2.Enable, False)
960 wx.CallAfter(self.downButton2.Enable, False)
961 self.comm.sendCommand('M105')
962 self.comm.sendCommand('G28')
963 self._wizardState = 1
964 elif self._wizardState == 2:
965 if profile.getMachineSetting('has_heated_bed') == 'True':
966 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back center...')
967 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
968 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
969 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
970 self.comm.sendCommand('M400')
971 self._wizardState = 3
973 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
974 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
975 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
976 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
977 self.comm.sendCommand('M400')
978 self._wizardState = 3
979 elif self._wizardState == 4:
980 if profile.getMachineSetting('has_heated_bed') == 'True':
981 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
982 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
983 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
984 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
985 self.comm.sendCommand('M400')
986 self._wizardState = 7
988 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
989 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
990 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
991 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
992 self.comm.sendCommand('M400')
993 self._wizardState = 5
994 elif self._wizardState == 6:
995 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
996 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
997 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
998 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
999 self.comm.sendCommand('M400')
1000 self._wizardState = 7
1001 elif self._wizardState == 8:
1002 wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
1003 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1004 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1005 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1006 self._wizardState = 9
1007 elif self._wizardState == 10:
1008 self._wizardState = 11
1009 wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
1010 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1011 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1012 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1013 w = profile.getMachineSettingFloat('machine_width') - 10
1014 d = profile.getMachineSettingFloat('machine_depth')
1015 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1016 filamentArea = math.pi * filamentRadius * filamentRadius
1017 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1021 'G1 Z2 F%d' % (feedZ),
1023 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1024 'G1 Z0.3 F%d' % (feedZ)]
1026 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1028 for i in xrange(0, 3):
1029 dist = 5.0 + 0.4 * float(i)
1030 eValue += (d - 2.0*dist) * ePerMM
1031 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1032 eValue += (w - 2.0*dist) * ePerMM
1033 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1034 eValue += (d - 2.0*dist) * ePerMM
1035 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1036 eValue += (w - 2.0*dist) * ePerMM
1037 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1039 gcodeList.append('M400')
1040 self.comm.printGCode(gcodeList)
1041 self.resumeButton.Enable(False)
1043 def mcLog(self, message):
1044 print 'Log:', message
1046 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1047 if self._wizardState == 1:
1048 self._wizardState = 2
1049 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
1050 wx.CallAfter(self.resumeButton.Enable, True)
1051 elif self._wizardState == 3:
1052 self._wizardState = 4
1053 if profile.getMachineSetting('has_heated_bed') == 'True':
1054 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.')
1056 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
1057 wx.CallAfter(self.resumeButton.Enable, True)
1058 elif self._wizardState == 5:
1059 self._wizardState = 6
1060 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
1061 wx.CallAfter(self.resumeButton.Enable, True)
1062 elif self._wizardState == 7:
1063 self._wizardState = 8
1064 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
1065 wx.CallAfter(self.resumeButton.Enable, True)
1066 elif self._wizardState == 9:
1067 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1068 wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1070 wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
1071 wx.CallAfter(self.resumeButton.Enable, True)
1072 self._wizardState = 10
1074 def mcStateChange(self, state):
1075 if self.comm is None:
1077 if self.comm.isOperational():
1078 if self._wizardState == 0:
1079 wx.CallAfter(self.infoBox.SetAttention, 'Use the up/down buttons to move the bed and adjust your Z endstop.')
1080 wx.CallAfter(self.upButton.Enable, True)
1081 wx.CallAfter(self.downButton.Enable, True)
1082 wx.CallAfter(self.upButton2.Enable, True)
1083 wx.CallAfter(self.downButton2.Enable, True)
1084 wx.CallAfter(self.resumeButton.Enable, True)
1085 self._wizardState = -1
1086 elif self._wizardState == 11 and not self.comm.isPrinting():
1087 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1088 self.comm.sendCommand('G92 E0')
1089 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1090 self.comm.sendCommand('M104 S0')
1091 wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
1092 wx.CallAfter(self.infoBox.SetReadyIndicator)
1093 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1094 wx.CallAfter(self.connectButton.Enable, True)
1095 self._wizardState = 12
1096 elif self.comm.isError():
1097 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1099 def mcMessage(self, message):
1102 def mcProgress(self, lineNr):
1105 def mcZChange(self, newZ):
1108 class headOffsetCalibrationPage(InfoPage):
1109 def __init__(self, parent):
1110 super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
1112 self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
1115 self.connectButton = self.AddButton('Connect to printer')
1118 self.infoBox = self.AddInfoBox()
1119 self.textEntry = self.AddTextCtrl('')
1120 self.textEntry.Enable(False)
1121 self.resumeButton = self.AddButton('Resume')
1122 self.resumeButton.Enable(False)
1124 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1125 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1127 def AllowBack(self):
1130 def OnConnect(self, e = None):
1131 if self.comm is not None:
1135 wx.CallAfter(self.OnConnect)
1137 self.connectButton.Enable(False)
1138 self.comm = machineCom.MachineCom(callbackObject=self)
1139 self.infoBox.SetBusy('Connecting to machine.')
1140 self._wizardState = 0
1142 def OnResume(self, e):
1143 if self._wizardState == 2:
1144 self._wizardState = 3
1145 wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
1147 w = profile.getMachineSettingFloat('machine_width')
1148 d = profile.getMachineSettingFloat('machine_depth')
1150 gcode = gcodeGenerator.gcodeGenerator()
1151 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1152 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1159 gcode.addMove(w/2, 5)
1160 gcode.addMove(z=0.2)
1162 gcode.addExtrude(w/2, d-5.0)
1164 gcode.addMove(5, d/2)
1166 gcode.addExtrude(w-5.0, d/2)
1167 gcode.addRetract(15)
1170 gcode.addMove(w/2, 5)
1172 gcode.addExtrude(w/2, d-5.0)
1174 gcode.addMove(5, d/2)
1176 gcode.addExtrude(w-5.0, d/2)
1177 gcode.addRetract(15)
1182 gcode.addCmd('M400')
1184 self.comm.printGCode(gcode.list())
1185 self.resumeButton.Enable(False)
1186 elif self._wizardState == 4:
1188 float(self.textEntry.GetValue())
1191 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1192 self._wizardState = 5
1193 self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
1194 self.textEntry.SetValue('0.0')
1195 self.textEntry.Enable(True)
1196 elif self._wizardState == 5:
1198 float(self.textEntry.GetValue())
1201 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1202 self._wizardState = 6
1203 self.infoBox.SetBusy('Printing the fine calibration lines.')
1204 self.textEntry.SetValue('')
1205 self.textEntry.Enable(False)
1206 self.resumeButton.Enable(False)
1208 x = profile.getMachineSettingFloat('extruder_offset_x1')
1209 y = profile.getMachineSettingFloat('extruder_offset_y1')
1210 gcode = gcodeGenerator.gcodeGenerator()
1211 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1212 gcode.setPrintSpeed(25)
1215 gcode.addMove(50, 40, 0.2)
1217 for n in xrange(0, 10):
1218 gcode.addExtrude(50 + n * 10, 150)
1219 gcode.addExtrude(50 + n * 10 + 5, 150)
1220 gcode.addExtrude(50 + n * 10 + 5, 40)
1221 gcode.addExtrude(50 + n * 10 + 10, 40)
1222 gcode.addMove(40, 50)
1223 for n in xrange(0, 10):
1224 gcode.addExtrude(150, 50 + n * 10)
1225 gcode.addExtrude(150, 50 + n * 10 + 5)
1226 gcode.addExtrude(40, 50 + n * 10 + 5)
1227 gcode.addExtrude(40, 50 + n * 10 + 10)
1228 gcode.addRetract(15)
1231 gcode.addMove(50 - x, 30 - y, 0.2)
1233 for n in xrange(0, 10):
1234 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1235 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1236 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1237 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1238 gcode.addMove(30 - x, 50 - y, 0.2)
1239 for n in xrange(0, 10):
1240 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1241 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1242 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1243 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1244 gcode.addRetract(15)
1246 gcode.addCmd('M400')
1247 gcode.addCmd('M104 T0 S0')
1248 gcode.addCmd('M104 T1 S0')
1249 self.comm.printGCode(gcode.list())
1250 elif self._wizardState == 7:
1252 n = int(self.textEntry.GetValue()) - 1
1255 x = profile.getMachineSettingFloat('extruder_offset_x1')
1257 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1258 self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
1259 self.textEntry.SetValue('10')
1260 self._wizardState = 8
1261 elif self._wizardState == 8:
1263 n = int(self.textEntry.GetValue()) - 1
1266 y = profile.getMachineSettingFloat('extruder_offset_y1')
1268 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1269 self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1270 self.infoBox.SetReadyIndicator()
1271 self._wizardState = 8
1273 self.resumeButton.Enable(False)
1275 def mcLog(self, message):
1276 print 'Log:', message
1278 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1279 if self._wizardState == 1:
1280 if temp[0] >= 210 and temp[1] >= 210:
1281 self._wizardState = 2
1282 wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
1283 wx.CallAfter(self.resumeButton.Enable, True)
1284 wx.CallAfter(self.resumeButton.SetFocus)
1286 def mcStateChange(self, state):
1287 if self.comm is None:
1289 if self.comm.isOperational():
1290 if self._wizardState == 0:
1291 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
1292 self.comm.sendCommand('M105')
1293 self.comm.sendCommand('M104 S220 T0')
1294 self.comm.sendCommand('M104 S220 T1')
1295 self.comm.sendCommand('G28')
1296 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1297 self._wizardState = 1
1298 if not self.comm.isPrinting():
1299 if self._wizardState == 3:
1300 self._wizardState = 4
1301 wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
1302 wx.CallAfter(self.textEntry.SetValue, '0.0')
1303 wx.CallAfter(self.textEntry.Enable, True)
1304 wx.CallAfter(self.resumeButton.Enable, True)
1305 wx.CallAfter(self.resumeButton.SetFocus)
1306 elif self._wizardState == 6:
1307 self._wizardState = 7
1308 wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
1309 wx.CallAfter(self.textEntry.SetValue, '10')
1310 wx.CallAfter(self.textEntry.Enable, True)
1311 wx.CallAfter(self.resumeButton.Enable, True)
1312 wx.CallAfter(self.resumeButton.SetFocus)
1314 elif self.comm.isError():
1315 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1317 def mcMessage(self, message):
1320 def mcProgress(self, lineNr):
1323 def mcZChange(self, newZ):
1326 class bedLevelWizard(wx.wizard.Wizard):
1328 super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
1330 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1331 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1333 self.mainPage = bedLevelWizardMain(self)
1334 self.headOffsetCalibration = None
1336 self.FitToPage(self.mainPage)
1337 self.GetPageAreaSizer().Add(self.mainPage)
1339 self.RunWizard(self.mainPage)
1342 def OnPageChanging(self, e):
1343 e.GetPage().StoreData()
1345 def OnPageChanged(self, e):
1346 if e.GetPage().AllowNext():
1347 self.FindWindowById(wx.ID_FORWARD).Enable()
1349 self.FindWindowById(wx.ID_FORWARD).Disable()
1350 if e.GetPage().AllowBack():
1351 self.FindWindowById(wx.ID_BACKWARD).Enable()
1353 self.FindWindowById(wx.ID_BACKWARD).Disable()
1355 class headOffsetWizard(wx.wizard.Wizard):
1357 super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
1359 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1360 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1362 self.mainPage = headOffsetCalibrationPage(self)
1364 self.FitToPage(self.mainPage)
1365 self.GetPageAreaSizer().Add(self.mainPage)
1367 self.RunWizard(self.mainPage)
1370 def OnPageChanging(self, e):
1371 e.GetPage().StoreData()
1373 def OnPageChanged(self, e):
1374 if e.GetPage().AllowNext():
1375 self.FindWindowById(wx.ID_FORWARD).Enable()
1377 self.FindWindowById(wx.ID_FORWARD).Disable()
1378 if e.GetPage().AllowBack():
1379 self.FindWindowById(wx.ID_BACKWARD).Enable()
1381 self.FindWindowById(wx.ID_BACKWARD).Disable()