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')
241 class PrintrbotPage(InfoPage):
242 def __init__(self, parent):
243 self._printer_info = {
244 # X, Y, Z, Filament Diameter, PrintTemperature, Print Speed, Travel Speed, Retract speed, Retract amount
245 "Original": (130, 130, 130, 2.95, 208, 40, 70, 30, 1),
246 "Simple Maker's Edition v1": (100, 100, 100, 1.75, 208, 40, 70, 30, 1),
247 "Simple Maker's Edition v2 (2013 Printrbot Simple)": (100, 100, 100, 1.75, 208, 40, 70, 30, 1),
248 "Simple Maker's Edition v3 (2014 Printrbot Simple)": (100, 100, 100, 1.75, 208, 40, 70, 30, 1),
249 "Simple Maker's Edition v4 (Model 1405)": (100, 100, 100, 1.75, 208, 40, 70, 30, 1),
250 "Simple Metal": (150, 150, 150, 1.75, 208, 40, 70, 30, 1),
251 "Jr v1": (150, 100, 80, 1.75, 208, 40, 70, 30, 1),
252 "Jr v2": (150, 150, 150, 1.75, 208, 40, 70, 30, 1),
253 "LC v2": (150, 150, 150, 1.75, 208, 40, 70, 30, 1),
254 "Plus v2": (200, 200, 200, 1.75, 208, 40, 70, 30, 1),
255 "Plus v2.1": (200, 200, 200, 1.75, 208, 40, 70, 30, 1),
256 "Plus v2.2 (Model 1404/140422)": (250, 250, 250, 1.75, 208, 40, 70, 30, 1),
257 "Plus v2.3 (Model 140501)": (250, 250, 250, 1.75, 208, 40, 70, 30, 1),
258 "Plus v2.4 (Model 140507)": (250, 250, 250, 1.75, 208, 40, 70, 30, 1),
261 super(PrintrbotPage, self).__init__(parent, "Printrbot Selection")
262 self.AddText(_("Select which Printrbot machine you have:"))
263 keys = self._printer_info.keys()
267 item = self.AddRadioButton(name)
268 item.data = self._printer_info[name]
269 self._items.append(item)
272 profile.putMachineSetting('machine_name', 'Printrbot ???')
273 for item in self._items:
276 profile.putMachineSetting('machine_name', 'Printrbot ' + item.GetLabel())
277 profile.putMachineSetting('machine_width', data[0])
278 profile.putMachineSetting('machine_depth', data[1])
279 profile.putMachineSetting('machine_height', data[2])
280 profile.putProfileSetting('nozzle_size', '0.5')
281 profile.putProfileSetting('filament_diameter', data[3])
282 profile.putProfileSetting('print_temperature', data[4])
283 profile.putProfileSetting('print_speed', data[5])
284 profile.putProfileSetting('travel_speed', data[6])
285 profile.putProfileSetting('retraction_speed', data[7])
286 profile.putProfileSetting('retraction_amount', data[8])
287 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
288 profile.putMachineSetting('has_heated_bed', 'False')
289 profile.putMachineSetting('machine_center_is_zero', 'False')
290 profile.putMachineSetting('extruder_head_size_min_x', '0')
291 profile.putMachineSetting('extruder_head_size_min_y', '0')
292 profile.putMachineSetting('extruder_head_size_max_x', '0')
293 profile.putMachineSetting('extruder_head_size_max_y', '0')
294 profile.putMachineSetting('extruder_head_size_height', '0')
296 class OtherMachineSelectPage(InfoPage):
297 def __init__(self, parent):
298 super(OtherMachineSelectPage, self).__init__(parent, "Other machine information")
299 self.AddText(_("The following pre-defined machine profiles are available"))
300 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."))
302 machines = resources.getDefaultMachineProfiles()
304 for filename in machines:
305 name = os.path.splitext(os.path.basename(filename))[0]
306 item = self.AddRadioButton(name)
307 item.filename = filename
308 item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
309 self.options.append(item)
311 item = self.AddRadioButton('Custom...')
313 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
315 def OnProfileSelect(self, e):
316 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
318 def OnOtherSelect(self, e):
319 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
322 for option in self.options:
323 if option.GetValue():
324 profile.loadProfile(option.filename)
325 profile.loadMachineSettings(option.filename)
327 class OtherMachineInfoPage(InfoPage):
328 def __init__(self, parent):
329 super(OtherMachineInfoPage, self).__init__(parent, "Cura Ready!")
330 self.AddText(_("Cura is now ready to be used!"))
332 class CustomRepRapInfoPage(InfoPage):
333 def __init__(self, parent):
334 super(CustomRepRapInfoPage, self).__init__(parent, "Custom RepRap information")
335 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
336 self.AddText(_("Be sure to review the default profile before running it on your machine."))
337 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
339 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
341 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
342 self.machineWidth = self.AddLabelTextCtrl(_("Machine width (mm)"), "80")
343 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth (mm)"), "80")
344 self.machineHeight = self.AddLabelTextCtrl(_("Machine height (mm)"), "55")
345 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
346 self.heatedBed = self.AddCheckbox(_("Heated bed"))
347 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
350 profile.putMachineSetting('machine_name', self.machineName.GetValue())
351 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
352 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
353 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
354 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
355 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
356 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
357 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
358 profile.putMachineSetting('extruder_head_size_min_x', '0')
359 profile.putMachineSetting('extruder_head_size_min_y', '0')
360 profile.putMachineSetting('extruder_head_size_max_x', '0')
361 profile.putMachineSetting('extruder_head_size_max_y', '0')
362 profile.putMachineSetting('extruder_head_size_height', '0')
363 profile.checkAndUpdateMachineName()
365 class MachineSelectPage(InfoPage):
366 def __init__(self, parent):
367 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
368 self.AddText(_("What kind of machine do you have:"))
370 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2", style=wx.RB_GROUP)
371 self.Ultimaker2Radio.SetValue(True)
372 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
373 self.UltimakerRadio = self.AddRadioButton("Ultimaker Original")
374 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
375 self.PrintrbotRadio = self.AddRadioButton("Printrbot")
376 self.PrintrbotRadio.Bind(wx.EVT_RADIOBUTTON, self.OnPrintrbotSelect)
377 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot)"))
378 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
380 self.AddText(_("The collection of anonymous usage information helps with the continued improvement of Cura."))
381 self.AddText(_("This does NOT submit your models online nor gathers any privacy related information."))
382 self.SubmitUserStats = self.AddCheckbox(_("Submit anonymous usage information:"))
383 self.AddText(_("For full details see: http://wiki.ultimaker.com/Cura:stats"))
384 self.SubmitUserStats.SetValue(True)
386 def OnUltimaker2Select(self, e):
387 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
389 def OnUltimakerSelect(self, e):
390 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
392 def OnPrintrbotSelect(self, e):
393 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().printrbotSelectType)
395 def OnOtherSelect(self, e):
396 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
399 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
403 profile.putProfileSetting('retraction_enable', 'True')
404 if self.Ultimaker2Radio.GetValue():
405 profile.putMachineSetting('machine_width', '230')
406 profile.putMachineSetting('machine_depth', '225')
407 profile.putMachineSetting('machine_height', '205')
408 profile.putMachineSetting('machine_name', 'ultimaker2')
409 profile.putMachineSetting('machine_type', 'ultimaker2')
410 profile.putMachineSetting('machine_center_is_zero', 'False')
411 profile.putMachineSetting('has_heated_bed', 'True')
412 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
413 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
414 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
415 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
416 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
417 profile.putMachineSetting('extruder_head_size_height', '55.0')
418 profile.putProfileSetting('nozzle_size', '0.4')
419 profile.putProfileSetting('fan_full_height', '5.0')
420 profile.putMachineSetting('extruder_offset_x1', '18.0')
421 profile.putMachineSetting('extruder_offset_y1', '0.0')
422 elif self.UltimakerRadio.GetValue():
423 profile.putMachineSetting('machine_width', '205')
424 profile.putMachineSetting('machine_depth', '205')
425 profile.putMachineSetting('machine_height', '200')
426 profile.putMachineSetting('machine_name', 'ultimaker original')
427 profile.putMachineSetting('machine_type', 'ultimaker')
428 profile.putMachineSetting('machine_center_is_zero', 'False')
429 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
430 profile.putProfileSetting('nozzle_size', '0.4')
431 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
432 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
433 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
434 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
435 profile.putMachineSetting('extruder_head_size_height', '55.0')
437 profile.putMachineSetting('machine_width', '80')
438 profile.putMachineSetting('machine_depth', '80')
439 profile.putMachineSetting('machine_height', '60')
440 profile.putMachineSetting('machine_name', 'reprap')
441 profile.putMachineSetting('machine_type', 'reprap')
442 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
443 profile.putPreference('startMode', 'Normal')
444 profile.putProfileSetting('nozzle_size', '0.5')
445 profile.checkAndUpdateMachineName()
446 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
447 if self.SubmitUserStats.GetValue():
448 profile.putPreference('submit_slice_information', 'True')
450 profile.putPreference('submit_slice_information', 'False')
453 class SelectParts(InfoPage):
454 def __init__(self, parent):
455 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
456 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."))
458 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
459 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
460 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
461 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
463 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."))
464 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
465 self.springExtruder.SetValue(True)
468 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
469 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
470 profile.putMachineSetting('has_heated_bed', 'True')
472 profile.putMachineSetting('has_heated_bed', 'False')
473 if self.dualExtrusion.GetValue():
474 profile.putMachineSetting('extruder_amount', '2')
475 profile.putMachineSetting('machine_depth', '195')
477 profile.putMachineSetting('extruder_amount', '1')
478 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
479 profile.putProfileSetting('retraction_enable', 'True')
481 profile.putProfileSetting('retraction_enable', 'False')
484 class UltimakerFirmwareUpgradePage(InfoPage):
485 def __init__(self, parent):
486 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
487 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."))
488 self.AddHiddenSeperator()
489 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
490 self.AddHiddenSeperator()
491 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."))
492 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
493 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
494 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
495 self.AddHiddenSeperator()
496 self.AddText(_("Do not upgrade to this firmware if:"))
497 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
498 self.AddText(_("* Have other changes in the firmware"))
499 # button = self.AddButton('Goto this page for a custom firmware')
500 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
505 def OnUpgradeClick(self, e):
506 if firmwareInstall.InstallFirmware():
507 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
509 def OnSkipClick(self, e):
510 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
511 self.GetParent().ShowPage(self.GetNext())
513 def OnUrlClick(self, e):
514 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
516 class UltimakerCheckupPage(InfoPage):
517 def __init__(self, parent):
518 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
520 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
521 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
522 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
523 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
524 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
525 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
526 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
527 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
528 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
529 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
532 _("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."))
533 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
534 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
535 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
537 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
538 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
539 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
541 self.infoBox = self.AddInfoBox()
542 self.machineState = self.AddText("")
543 self.temperatureLabel = self.AddText("")
544 self.errorLogButton = self.AddButton(_("Show error log"))
545 self.errorLogButton.Show(False)
547 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
549 self.xMinStop = False
550 self.xMaxStop = False
551 self.yMinStop = False
552 self.yMaxStop = False
553 self.zMinStop = False
554 self.zMaxStop = False
556 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
559 if self.comm is not None:
563 self.endstopBitmap.Show(False)
566 def OnSkipClick(self, e):
567 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
568 self.GetParent().ShowPage(self.GetNext())
570 def OnCheckClick(self, e=None):
571 self.errorLogButton.Show(False)
572 if self.comm is not None:
576 wx.CallAfter(self.OnCheckClick)
578 self.infoBox.SetBusy(_("Connecting to machine."))
579 self.commState.SetBitmap(self.unknownBitmap)
580 self.tempState.SetBitmap(self.unknownBitmap)
581 self.stopState.SetBitmap(self.unknownBitmap)
582 self.checkupState = 0
583 self.checkExtruderNr = 0
584 self.comm = machineCom.MachineCom(callbackObject=self)
586 def OnErrorLog(self, e):
587 printWindow.LogWindow('\n'.join(self.comm.getLog()))
589 def mcLog(self, message):
592 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
593 if not self.comm.isOperational():
595 if self.checkupState == 0:
596 self.tempCheckTimeout = 20
597 if temp[self.checkExtruderNr] > 70:
598 self.checkupState = 1
599 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
600 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
601 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
603 self.startTemp = temp[self.checkExtruderNr]
604 self.checkupState = 2
605 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
606 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
607 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
608 elif self.checkupState == 1:
610 self.startTemp = temp[self.checkExtruderNr]
611 self.checkupState = 2
612 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
613 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
614 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
615 elif self.checkupState == 2:
616 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
617 if temp[self.checkExtruderNr] > self.startTemp + 40:
618 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
619 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
620 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
621 self.checkExtruderNr = 0
622 self.checkupState = 3
623 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
624 wx.CallAfter(self.endstopBitmap.Show, True)
625 wx.CallAfter(self.Layout)
626 self.comm.sendCommand('M119')
627 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
629 self.checkupState = 0
630 self.checkExtruderNr += 1
632 self.tempCheckTimeout -= 1
633 if self.tempCheckTimeout < 1:
634 self.checkupState = -1
635 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
636 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
637 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
638 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
639 elif self.checkupState >= 3 and self.checkupState < 10:
640 self.comm.sendCommand('M119')
641 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
643 def mcStateChange(self, state):
644 if self.comm is None:
646 if self.comm.isOperational():
647 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
648 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
649 elif self.comm.isError():
650 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
651 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
652 wx.CallAfter(self.endstopBitmap.Show, False)
653 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
654 wx.CallAfter(self.errorLogButton.Show, True)
655 wx.CallAfter(self.Layout)
657 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
659 def mcMessage(self, message):
660 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
661 for data in message.split(' '):
663 tag, value = data.split(':', 1)
665 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
667 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
669 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
671 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
673 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
675 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
677 tag, value = map(str.strip, message.split(':', 1))
679 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
681 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
683 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
685 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
687 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
689 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
690 if 'z_max' in message:
691 self.comm.sendCommand('M119')
693 if self.checkupState == 3:
694 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
695 self.checkupState = 4
696 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
697 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
698 elif self.checkupState == 4:
699 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
700 self.checkupState = 5
701 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
702 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
703 elif self.checkupState == 5:
704 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
705 self.checkupState = 6
706 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
707 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
708 elif self.checkupState == 6:
709 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
710 self.checkupState = 7
711 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
712 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
713 elif self.checkupState == 7:
714 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
715 self.checkupState = 8
716 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
717 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
718 elif self.checkupState == 8:
719 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
720 self.checkupState = 9
721 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
722 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
723 elif self.checkupState == 9:
724 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
725 self.checkupState = 10
727 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
728 wx.CallAfter(self.infoBox.SetReadyIndicator)
729 wx.CallAfter(self.endstopBitmap.Show, False)
730 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
731 wx.CallAfter(self.OnSkipClick, None)
733 def mcProgress(self, lineNr):
736 def mcZChange(self, newZ):
740 class UltimakerCalibrationPage(InfoPage):
741 def __init__(self, parent):
742 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
744 self.AddText("Your Ultimaker requires some calibration.")
745 self.AddText("This calibration is needed for a proper extrusion amount.")
747 self.AddText("The following values are needed:")
748 self.AddText("* Diameter of filament")
749 self.AddText("* Number of steps per mm of filament extrusion")
751 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
753 self.AddText("First we need the diameter of your filament:")
754 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
756 "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.")
757 self.AddText("Note: This value can be changed later at any time.")
760 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
763 class UltimakerCalibrateStepsPerEPage(InfoPage):
764 def __init__(self, parent):
765 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
767 #if profile.getMachineSetting('steps_per_e') == '0':
768 # profile.putMachineSetting('steps_per_e', '865.888')
770 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
771 self.AddText(_("First remove any filament from your machine."))
772 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
773 self.AddText(_("We'll push the filament 100mm"))
774 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
775 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
776 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
777 self.AddText(_("This results in the following steps per E:"))
778 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
779 self.AddText(_("You can repeat these steps to get better calibration."))
782 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
783 self.heatButton = self.AddButton(_("Heatup for filament removal"))
785 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
786 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
787 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
789 def OnSaveLengthClick(self, e):
790 currentEValue = float(self.stepsPerEInput.GetValue())
791 realExtrudeLength = float(self.lengthInput.GetValue())
792 newEValue = currentEValue * 100 / realExtrudeLength
793 self.stepsPerEInput.SetValue(str(newEValue))
794 self.lengthInput.SetValue("100")
796 def OnExtrudeClick(self, e):
797 t = threading.Thread(target=self.OnExtrudeRun)
801 def OnExtrudeRun(self):
802 self.heatButton.Enable(False)
803 self.extrudeButton.Enable(False)
804 currentEValue = float(self.stepsPerEInput.GetValue())
805 self.comm = machineCom.MachineCom()
806 if not self.comm.isOpen():
808 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
809 'Printer error', wx.OK | wx.ICON_INFORMATION)
810 self.heatButton.Enable(True)
811 self.extrudeButton.Enable(True)
814 line = self.comm.readline()
819 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
822 self.sendGCommand('M302') #Disable cold extrusion protection
823 self.sendGCommand("M92 E%f" % (currentEValue))
824 self.sendGCommand("G92 E0")
825 self.sendGCommand("G1 E100 F600")
828 self.extrudeButton.Enable()
829 self.heatButton.Enable()
831 def OnHeatClick(self, e):
832 t = threading.Thread(target=self.OnHeatRun)
837 self.heatButton.Enable(False)
838 self.extrudeButton.Enable(False)
839 self.comm = machineCom.MachineCom()
840 if not self.comm.isOpen():
842 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
843 'Printer error', wx.OK | wx.ICON_INFORMATION)
844 self.heatButton.Enable(True)
845 self.extrudeButton.Enable(True)
848 line = self.comm.readline()
850 self.heatButton.Enable(True)
851 self.extrudeButton.Enable(True)
855 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
858 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
860 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
861 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
862 self.sendGCommand('M104 S0')
865 self.heatButton.Enable(True)
866 self.extrudeButton.Enable(True)
868 def sendGCommand(self, cmd):
869 self.comm.sendCommand(cmd) #Disable cold extrusion protection
871 line = self.comm.readline()
874 if line.startswith('ok'):
878 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
880 class Ultimaker2ReadyPage(InfoPage):
881 def __init__(self, parent):
882 super(Ultimaker2ReadyPage, self).__init__(parent, "Ultimaker2")
883 self.AddText('Congratulations on your the purchase of your brand new Ultimaker2.')
884 self.AddText('Cura is now ready to be used with your Ultimaker2.')
887 class configWizard(wx.wizard.Wizard):
888 def __init__(self, addNew = False):
889 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
891 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
892 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
894 self.firstInfoPage = FirstInfoPage(self, addNew)
895 self.machineSelectPage = MachineSelectPage(self)
896 self.ultimakerSelectParts = SelectParts(self)
897 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
898 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
899 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
900 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
901 self.bedLevelPage = bedLevelWizardMain(self)
902 self.headOffsetCalibration = headOffsetCalibrationPage(self)
903 self.printrbotSelectType = PrintrbotPage(self)
904 self.otherMachineSelectPage = OtherMachineSelectPage(self)
905 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
906 self.otherMachineInfoPage = OtherMachineInfoPage(self)
908 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
910 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
911 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
912 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
913 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
914 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
915 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
916 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
917 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
918 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
920 self.FitToPage(self.firstInfoPage)
921 self.GetPageAreaSizer().Add(self.firstInfoPage)
923 self.RunWizard(self.firstInfoPage)
926 def OnPageChanging(self, e):
927 e.GetPage().StoreData()
929 def OnPageChanged(self, e):
930 if e.GetPage().AllowNext():
931 self.FindWindowById(wx.ID_FORWARD).Enable()
933 self.FindWindowById(wx.ID_FORWARD).Disable()
934 if e.GetPage().AllowBack():
935 self.FindWindowById(wx.ID_BACKWARD).Enable()
937 self.FindWindowById(wx.ID_BACKWARD).Disable()
939 class bedLevelWizardMain(InfoPage):
940 def __init__(self, parent):
941 super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
943 self.AddText('This wizard will help you in leveling your printer bed')
945 self.AddText('It will do the following steps')
946 self.AddText('* Move the printer head to each corner')
947 self.AddText(' and let you adjust the height of the bed to the nozzle')
948 self.AddText('* Print a line around the bed to check if it is level')
951 self.connectButton = self.AddButton('Connect to printer')
954 self.infoBox = self.AddInfoBox()
955 self.resumeButton = self.AddButton('Resume')
956 self.upButton, self.downButton = self.AddDualButton('Up 0.2mm', 'Down 0.2mm')
957 self.upButton2, self.downButton2 = self.AddDualButton('Up 10mm', 'Down 10mm')
958 self.resumeButton.Enable(False)
960 self.upButton.Enable(False)
961 self.downButton.Enable(False)
962 self.upButton2.Enable(False)
963 self.downButton2.Enable(False)
965 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
966 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
967 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
968 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
969 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
970 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
972 def OnConnect(self, e = None):
973 if self.comm is not None:
977 wx.CallAfter(self.OnConnect)
979 self.connectButton.Enable(False)
980 self.comm = machineCom.MachineCom(callbackObject=self)
981 self.infoBox.SetBusy('Connecting to machine.')
982 self._wizardState = 0
984 def OnBedUp(self, e):
985 feedZ = profile.getProfileSettingFloat('print_speed') * 60
986 self.comm.sendCommand('G92 Z10')
987 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
988 self.comm.sendCommand('M400')
990 def OnBedDown(self, e):
991 feedZ = profile.getProfileSettingFloat('print_speed') * 60
992 self.comm.sendCommand('G92 Z10')
993 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
994 self.comm.sendCommand('M400')
996 def OnBedUp2(self, e):
997 feedZ = profile.getProfileSettingFloat('print_speed') * 60
998 self.comm.sendCommand('G92 Z10')
999 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1000 self.comm.sendCommand('M400')
1002 def OnBedDown2(self, e):
1003 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1004 self.comm.sendCommand('G92 Z10')
1005 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1006 self.comm.sendCommand('M400')
1008 def AllowNext(self):
1009 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1010 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1013 def OnResume(self, e):
1014 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1015 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1016 if self._wizardState == -1:
1017 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
1018 wx.CallAfter(self.upButton.Enable, False)
1019 wx.CallAfter(self.downButton.Enable, False)
1020 wx.CallAfter(self.upButton2.Enable, False)
1021 wx.CallAfter(self.downButton2.Enable, False)
1022 self.comm.sendCommand('M105')
1023 self.comm.sendCommand('G28')
1024 self._wizardState = 1
1025 elif self._wizardState == 2:
1026 if profile.getMachineSetting('has_heated_bed') == 'True':
1027 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back center...')
1028 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1029 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1030 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1031 self.comm.sendCommand('M400')
1032 self._wizardState = 3
1034 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
1035 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1036 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1037 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1038 self.comm.sendCommand('M400')
1039 self._wizardState = 3
1040 elif self._wizardState == 4:
1041 if profile.getMachineSetting('has_heated_bed') == 'True':
1042 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
1043 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1044 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1045 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1046 self.comm.sendCommand('M400')
1047 self._wizardState = 7
1049 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
1050 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1051 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1052 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1053 self.comm.sendCommand('M400')
1054 self._wizardState = 5
1055 elif self._wizardState == 6:
1056 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
1057 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1058 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1059 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1060 self.comm.sendCommand('M400')
1061 self._wizardState = 7
1062 elif self._wizardState == 8:
1063 wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
1064 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1065 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1066 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1067 self._wizardState = 9
1068 elif self._wizardState == 10:
1069 self._wizardState = 11
1070 wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
1071 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1072 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1073 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1074 w = profile.getMachineSettingFloat('machine_width') - 10
1075 d = profile.getMachineSettingFloat('machine_depth')
1076 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1077 filamentArea = math.pi * filamentRadius * filamentRadius
1078 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1082 'G1 Z2 F%d' % (feedZ),
1084 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1085 'G1 Z0.3 F%d' % (feedZ)]
1087 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1089 for i in xrange(0, 3):
1090 dist = 5.0 + 0.4 * float(i)
1091 eValue += (d - 2.0*dist) * ePerMM
1092 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1093 eValue += (w - 2.0*dist) * ePerMM
1094 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1095 eValue += (d - 2.0*dist) * ePerMM
1096 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1097 eValue += (w - 2.0*dist) * ePerMM
1098 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1100 gcodeList.append('M400')
1101 self.comm.printGCode(gcodeList)
1102 self.resumeButton.Enable(False)
1104 def mcLog(self, message):
1105 print 'Log:', message
1107 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1108 if self._wizardState == 1:
1109 self._wizardState = 2
1110 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
1111 wx.CallAfter(self.resumeButton.Enable, True)
1112 elif self._wizardState == 3:
1113 self._wizardState = 4
1114 if profile.getMachineSetting('has_heated_bed') == 'True':
1115 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.')
1117 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
1118 wx.CallAfter(self.resumeButton.Enable, True)
1119 elif self._wizardState == 5:
1120 self._wizardState = 6
1121 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
1122 wx.CallAfter(self.resumeButton.Enable, True)
1123 elif self._wizardState == 7:
1124 self._wizardState = 8
1125 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
1126 wx.CallAfter(self.resumeButton.Enable, True)
1127 elif self._wizardState == 9:
1128 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1129 wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1131 wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
1132 wx.CallAfter(self.resumeButton.Enable, True)
1133 self._wizardState = 10
1135 def mcStateChange(self, state):
1136 if self.comm is None:
1138 if self.comm.isOperational():
1139 if self._wizardState == 0:
1140 wx.CallAfter(self.infoBox.SetAttention, 'Use the up/down buttons to move the bed and adjust your Z endstop.')
1141 wx.CallAfter(self.upButton.Enable, True)
1142 wx.CallAfter(self.downButton.Enable, True)
1143 wx.CallAfter(self.upButton2.Enable, True)
1144 wx.CallAfter(self.downButton2.Enable, True)
1145 wx.CallAfter(self.resumeButton.Enable, True)
1146 self._wizardState = -1
1147 elif self._wizardState == 11 and not self.comm.isPrinting():
1148 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1149 self.comm.sendCommand('G92 E0')
1150 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1151 self.comm.sendCommand('M104 S0')
1152 wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
1153 wx.CallAfter(self.infoBox.SetReadyIndicator)
1154 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1155 wx.CallAfter(self.connectButton.Enable, True)
1156 self._wizardState = 12
1157 elif self.comm.isError():
1158 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1160 def mcMessage(self, message):
1163 def mcProgress(self, lineNr):
1166 def mcZChange(self, newZ):
1169 class headOffsetCalibrationPage(InfoPage):
1170 def __init__(self, parent):
1171 super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
1173 self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
1176 self.connectButton = self.AddButton('Connect to printer')
1179 self.infoBox = self.AddInfoBox()
1180 self.textEntry = self.AddTextCtrl('')
1181 self.textEntry.Enable(False)
1182 self.resumeButton = self.AddButton('Resume')
1183 self.resumeButton.Enable(False)
1185 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1186 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1188 def AllowBack(self):
1191 def OnConnect(self, e = None):
1192 if self.comm is not None:
1196 wx.CallAfter(self.OnConnect)
1198 self.connectButton.Enable(False)
1199 self.comm = machineCom.MachineCom(callbackObject=self)
1200 self.infoBox.SetBusy('Connecting to machine.')
1201 self._wizardState = 0
1203 def OnResume(self, e):
1204 if self._wizardState == 2:
1205 self._wizardState = 3
1206 wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
1208 w = profile.getMachineSettingFloat('machine_width')
1209 d = profile.getMachineSettingFloat('machine_depth')
1211 gcode = gcodeGenerator.gcodeGenerator()
1212 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1213 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1220 gcode.addMove(w/2, 5)
1221 gcode.addMove(z=0.2)
1223 gcode.addExtrude(w/2, d-5.0)
1225 gcode.addMove(5, d/2)
1227 gcode.addExtrude(w-5.0, d/2)
1228 gcode.addRetract(15)
1231 gcode.addMove(w/2, 5)
1233 gcode.addExtrude(w/2, d-5.0)
1235 gcode.addMove(5, d/2)
1237 gcode.addExtrude(w-5.0, d/2)
1238 gcode.addRetract(15)
1243 gcode.addCmd('M400')
1245 self.comm.printGCode(gcode.list())
1246 self.resumeButton.Enable(False)
1247 elif self._wizardState == 4:
1249 float(self.textEntry.GetValue())
1252 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1253 self._wizardState = 5
1254 self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
1255 self.textEntry.SetValue('0.0')
1256 self.textEntry.Enable(True)
1257 elif self._wizardState == 5:
1259 float(self.textEntry.GetValue())
1262 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1263 self._wizardState = 6
1264 self.infoBox.SetBusy('Printing the fine calibration lines.')
1265 self.textEntry.SetValue('')
1266 self.textEntry.Enable(False)
1267 self.resumeButton.Enable(False)
1269 x = profile.getMachineSettingFloat('extruder_offset_x1')
1270 y = profile.getMachineSettingFloat('extruder_offset_y1')
1271 gcode = gcodeGenerator.gcodeGenerator()
1272 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1273 gcode.setPrintSpeed(25)
1276 gcode.addMove(50, 40, 0.2)
1278 for n in xrange(0, 10):
1279 gcode.addExtrude(50 + n * 10, 150)
1280 gcode.addExtrude(50 + n * 10 + 5, 150)
1281 gcode.addExtrude(50 + n * 10 + 5, 40)
1282 gcode.addExtrude(50 + n * 10 + 10, 40)
1283 gcode.addMove(40, 50)
1284 for n in xrange(0, 10):
1285 gcode.addExtrude(150, 50 + n * 10)
1286 gcode.addExtrude(150, 50 + n * 10 + 5)
1287 gcode.addExtrude(40, 50 + n * 10 + 5)
1288 gcode.addExtrude(40, 50 + n * 10 + 10)
1289 gcode.addRetract(15)
1292 gcode.addMove(50 - x, 30 - y, 0.2)
1294 for n in xrange(0, 10):
1295 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1296 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1297 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1298 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1299 gcode.addMove(30 - x, 50 - y, 0.2)
1300 for n in xrange(0, 10):
1301 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1302 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1303 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1304 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1305 gcode.addRetract(15)
1307 gcode.addCmd('M400')
1308 gcode.addCmd('M104 T0 S0')
1309 gcode.addCmd('M104 T1 S0')
1310 self.comm.printGCode(gcode.list())
1311 elif self._wizardState == 7:
1313 n = int(self.textEntry.GetValue()) - 1
1316 x = profile.getMachineSettingFloat('extruder_offset_x1')
1318 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1319 self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
1320 self.textEntry.SetValue('10')
1321 self._wizardState = 8
1322 elif self._wizardState == 8:
1324 n = int(self.textEntry.GetValue()) - 1
1327 y = profile.getMachineSettingFloat('extruder_offset_y1')
1329 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1330 self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1331 self.infoBox.SetReadyIndicator()
1332 self._wizardState = 8
1334 self.resumeButton.Enable(False)
1336 def mcLog(self, message):
1337 print 'Log:', message
1339 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1340 if self._wizardState == 1:
1341 if temp[0] >= 210 and temp[1] >= 210:
1342 self._wizardState = 2
1343 wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
1344 wx.CallAfter(self.resumeButton.Enable, True)
1345 wx.CallAfter(self.resumeButton.SetFocus)
1347 def mcStateChange(self, state):
1348 if self.comm is None:
1350 if self.comm.isOperational():
1351 if self._wizardState == 0:
1352 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
1353 self.comm.sendCommand('M105')
1354 self.comm.sendCommand('M104 S220 T0')
1355 self.comm.sendCommand('M104 S220 T1')
1356 self.comm.sendCommand('G28')
1357 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1358 self._wizardState = 1
1359 if not self.comm.isPrinting():
1360 if self._wizardState == 3:
1361 self._wizardState = 4
1362 wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
1363 wx.CallAfter(self.textEntry.SetValue, '0.0')
1364 wx.CallAfter(self.textEntry.Enable, True)
1365 wx.CallAfter(self.resumeButton.Enable, True)
1366 wx.CallAfter(self.resumeButton.SetFocus)
1367 elif self._wizardState == 6:
1368 self._wizardState = 7
1369 wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
1370 wx.CallAfter(self.textEntry.SetValue, '10')
1371 wx.CallAfter(self.textEntry.Enable, True)
1372 wx.CallAfter(self.resumeButton.Enable, True)
1373 wx.CallAfter(self.resumeButton.SetFocus)
1375 elif self.comm.isError():
1376 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1378 def mcMessage(self, message):
1381 def mcProgress(self, lineNr):
1384 def mcZChange(self, newZ):
1387 class bedLevelWizard(wx.wizard.Wizard):
1389 super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
1391 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1392 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1394 self.mainPage = bedLevelWizardMain(self)
1395 self.headOffsetCalibration = None
1397 self.FitToPage(self.mainPage)
1398 self.GetPageAreaSizer().Add(self.mainPage)
1400 self.RunWizard(self.mainPage)
1403 def OnPageChanging(self, e):
1404 e.GetPage().StoreData()
1406 def OnPageChanged(self, e):
1407 if e.GetPage().AllowNext():
1408 self.FindWindowById(wx.ID_FORWARD).Enable()
1410 self.FindWindowById(wx.ID_FORWARD).Disable()
1411 if e.GetPage().AllowBack():
1412 self.FindWindowById(wx.ID_BACKWARD).Enable()
1414 self.FindWindowById(wx.ID_BACKWARD).Disable()
1416 class headOffsetWizard(wx.wizard.Wizard):
1418 super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
1420 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1421 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1423 self.mainPage = headOffsetCalibrationPage(self)
1425 self.FitToPage(self.mainPage)
1426 self.GetPageAreaSizer().Add(self.mainPage)
1428 self.RunWizard(self.mainPage)
1431 def OnPageChanging(self, e):
1432 e.GetPage().StoreData()
1434 def OnPageChanged(self, e):
1435 if e.GetPage().AllowNext():
1436 self.FindWindowById(wx.ID_FORWARD).Enable()
1438 self.FindWindowById(wx.ID_FORWARD).Disable()
1439 if e.GetPage().AllowBack():
1440 self.FindWindowById(wx.ID_BACKWARD).Enable()
1442 self.FindWindowById(wx.ID_BACKWARD).Disable()