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)
210 def AddCombo(self, label, options):
211 combo = wx.ComboBox(self, -1, options[0], choices=options, style=wx.CB_DROPDOWN|wx.CB_READONLY)
212 text = wx.StaticText(self, -1, label)
213 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
214 self.GetSizer().Add(combo, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
228 class FirstInfoPage(InfoPage):
229 def __init__(self, parent, addNew):
231 super(FirstInfoPage, self).__init__(parent, _("Add new machine wizard"))
233 super(FirstInfoPage, self).__init__(parent, _("First time run wizard"))
234 self.AddText(_("Welcome, and thanks for trying Cura!"))
236 self.AddText(_("This wizard will help you in setting up Cura for your machine."))
239 self._language_option = self.AddCombo(_("Select your language:"), map(lambda o: o[1], resources.getLanguageOptions()))
241 self._language_option = None
242 # self.AddText(_("This wizard will help you with the following steps:"))
243 # self.AddText(_("* Configure Cura for your machine"))
244 # self.AddText(_("* Optionally upgrade your firmware"))
245 # self.AddText(_("* Optionally check if your machine is working safely"))
246 # self.AddText(_("* Optionally level your printer bed"))
248 #self.AddText('* Calibrate your machine')
249 #self.AddText('* Do your first print')
255 if self._language_option is not None:
256 profile.putPreference('language', self._language_option.GetValue())
257 resources.setupLocalization(self._language_option.GetValue())
259 class PrintrbotPage(InfoPage):
260 def __init__(self, parent):
261 self._printer_info = {
262 # X, Y, Z, Filament Diameter, PrintTemperature, Print Speed, Travel Speed, Retract speed, Retract amount
263 "Original": (130, 130, 130, 2.95, 208, 40, 70, 30, 1),
264 "Simple Maker's Edition v1": (100, 100, 100, 1.75, 208, 40, 70, 30, 1),
265 "Simple Maker's Edition v2 (2013 Printrbot Simple)": (100, 100, 100, 1.75, 208, 40, 70, 30, 1),
266 "Simple Maker's Edition v3 (2014 Printrbot Simple)": (100, 100, 100, 1.75, 208, 40, 70, 30, 1),
267 "Simple Maker's Edition v4 (Model 1405)": (100, 100, 100, 1.75, 208, 40, 70, 30, 1),
268 "Simple Metal": (150, 150, 150, 1.75, 208, 40, 70, 30, 1),
269 "Jr v1": (150, 100, 80, 1.75, 208, 40, 70, 30, 1),
270 "Jr v2": (150, 150, 150, 1.75, 208, 40, 70, 30, 1),
271 "LC v2": (150, 150, 150, 1.75, 208, 40, 70, 30, 1),
272 "Plus v2": (200, 200, 200, 1.75, 208, 40, 70, 30, 1),
273 "Plus v2.1": (200, 200, 200, 1.75, 208, 40, 70, 30, 1),
274 "Plus v2.2 (Model 1404/140422)": (250, 250, 250, 1.75, 208, 40, 70, 30, 1),
275 "Plus v2.3 (Model 140501)": (250, 250, 250, 1.75, 208, 40, 70, 30, 1),
276 "Plus v2.4 (Model 140507)": (250, 250, 250, 1.75, 208, 40, 70, 30, 1),
279 super(PrintrbotPage, self).__init__(parent, "Printrbot Selection")
280 self.AddText(_("Select which Printrbot machine you have:"))
281 keys = self._printer_info.keys()
285 item = self.AddRadioButton(name)
286 item.data = self._printer_info[name]
287 self._items.append(item)
290 profile.putMachineSetting('machine_name', 'Printrbot ???')
291 for item in self._items:
294 profile.putMachineSetting('machine_name', 'Printrbot ' + item.GetLabel())
295 profile.putMachineSetting('machine_width', data[0])
296 profile.putMachineSetting('machine_depth', data[1])
297 profile.putMachineSetting('machine_height', data[2])
298 profile.putProfileSetting('nozzle_size', '0.5')
299 profile.putProfileSetting('filament_diameter', data[3])
300 profile.putProfileSetting('print_temperature', data[4])
301 profile.putProfileSetting('print_speed', data[5])
302 profile.putProfileSetting('travel_speed', data[6])
303 profile.putProfileSetting('retraction_speed', data[7])
304 profile.putProfileSetting('retraction_amount', data[8])
305 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
306 profile.putMachineSetting('has_heated_bed', 'False')
307 profile.putMachineSetting('machine_center_is_zero', 'False')
308 profile.putMachineSetting('extruder_head_size_min_x', '0')
309 profile.putMachineSetting('extruder_head_size_min_y', '0')
310 profile.putMachineSetting('extruder_head_size_max_x', '0')
311 profile.putMachineSetting('extruder_head_size_max_y', '0')
312 profile.putMachineSetting('extruder_head_size_height', '0')
314 class OtherMachineSelectPage(InfoPage):
315 def __init__(self, parent):
316 super(OtherMachineSelectPage, self).__init__(parent, "Other machine information")
317 self.AddText(_("The following pre-defined machine profiles are available"))
318 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."))
320 machines = resources.getDefaultMachineProfiles()
322 for filename in machines:
323 name = os.path.splitext(os.path.basename(filename))[0]
324 item = self.AddRadioButton(name)
325 item.filename = filename
326 item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
327 self.options.append(item)
329 item = self.AddRadioButton('Custom...')
331 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
333 def OnProfileSelect(self, e):
334 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
336 def OnOtherSelect(self, e):
337 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
340 for option in self.options:
341 if option.GetValue():
342 profile.loadProfile(option.filename)
343 profile.loadMachineSettings(option.filename)
345 class OtherMachineInfoPage(InfoPage):
346 def __init__(self, parent):
347 super(OtherMachineInfoPage, self).__init__(parent, "Cura Ready!")
348 self.AddText(_("Cura is now ready to be used!"))
350 class CustomRepRapInfoPage(InfoPage):
351 def __init__(self, parent):
352 super(CustomRepRapInfoPage, self).__init__(parent, "Custom RepRap information")
353 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
354 self.AddText(_("Be sure to review the default profile before running it on your machine."))
355 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
357 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
359 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
360 self.machineWidth = self.AddLabelTextCtrl(_("Machine width (mm)"), "80")
361 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth (mm)"), "80")
362 self.machineHeight = self.AddLabelTextCtrl(_("Machine height (mm)"), "55")
363 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
364 self.heatedBed = self.AddCheckbox(_("Heated bed"))
365 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
368 profile.putMachineSetting('machine_name', self.machineName.GetValue())
369 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
370 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
371 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
372 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
373 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
374 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
375 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
376 profile.putMachineSetting('extruder_head_size_min_x', '0')
377 profile.putMachineSetting('extruder_head_size_min_y', '0')
378 profile.putMachineSetting('extruder_head_size_max_x', '0')
379 profile.putMachineSetting('extruder_head_size_max_y', '0')
380 profile.putMachineSetting('extruder_head_size_height', '0')
381 profile.checkAndUpdateMachineName()
383 class MachineSelectPage(InfoPage):
384 def __init__(self, parent):
385 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
386 self.AddText(_("What kind of machine do you have:"))
388 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2", style=wx.RB_GROUP)
389 self.Ultimaker2Radio.SetValue(True)
390 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
391 self.UltimakerRadio = self.AddRadioButton("Ultimaker Original")
392 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
393 self.PrintrbotRadio = self.AddRadioButton("Printrbot")
394 self.PrintrbotRadio.Bind(wx.EVT_RADIOBUTTON, self.OnPrintrbotSelect)
395 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot, Witbox)"))
396 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
398 self.AddText(_("The collection of anonymous usage information helps with the continued improvement of Cura."))
399 self.AddText(_("This does NOT submit your models online nor gathers any privacy related information."))
400 self.SubmitUserStats = self.AddCheckbox(_("Submit anonymous usage information:"))
401 self.AddText(_("For full details see: http://wiki.ultimaker.com/Cura:stats"))
402 self.SubmitUserStats.SetValue(True)
404 def OnUltimaker2Select(self, e):
405 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
407 def OnUltimakerSelect(self, e):
408 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
410 def OnPrintrbotSelect(self, e):
411 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().printrbotSelectType)
413 def OnOtherSelect(self, e):
414 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
417 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
421 profile.putProfileSetting('retraction_enable', 'True')
422 if self.Ultimaker2Radio.GetValue():
423 profile.putMachineSetting('machine_width', '230')
424 profile.putMachineSetting('machine_depth', '225')
425 profile.putMachineSetting('machine_height', '205')
426 profile.putMachineSetting('machine_name', 'ultimaker2')
427 profile.putMachineSetting('machine_type', 'ultimaker2')
428 profile.putMachineSetting('machine_center_is_zero', 'False')
429 profile.putMachineSetting('has_heated_bed', 'True')
430 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
431 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
432 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
433 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
434 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
435 profile.putMachineSetting('extruder_head_size_height', '55.0')
436 profile.putProfileSetting('nozzle_size', '0.4')
437 profile.putProfileSetting('fan_full_height', '5.0')
438 profile.putMachineSetting('extruder_offset_x1', '18.0')
439 profile.putMachineSetting('extruder_offset_y1', '0.0')
440 elif self.UltimakerRadio.GetValue():
441 profile.putMachineSetting('machine_width', '205')
442 profile.putMachineSetting('machine_depth', '205')
443 profile.putMachineSetting('machine_height', '200')
444 profile.putMachineSetting('machine_name', 'ultimaker original')
445 profile.putMachineSetting('machine_type', 'ultimaker')
446 profile.putMachineSetting('machine_center_is_zero', 'False')
447 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
448 profile.putProfileSetting('nozzle_size', '0.4')
449 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
450 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
451 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
452 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
453 profile.putMachineSetting('extruder_head_size_height', '55.0')
455 profile.putMachineSetting('machine_width', '80')
456 profile.putMachineSetting('machine_depth', '80')
457 profile.putMachineSetting('machine_height', '60')
458 profile.putMachineSetting('machine_name', 'reprap')
459 profile.putMachineSetting('machine_type', 'reprap')
460 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
461 profile.putPreference('startMode', 'Normal')
462 profile.putProfileSetting('nozzle_size', '0.5')
463 profile.checkAndUpdateMachineName()
464 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
465 if self.SubmitUserStats.GetValue():
466 profile.putPreference('submit_slice_information', 'True')
468 profile.putPreference('submit_slice_information', 'False')
471 class SelectParts(InfoPage):
472 def __init__(self, parent):
473 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
474 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."))
476 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
477 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
478 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
479 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
481 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."))
482 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
483 self.springExtruder.SetValue(True)
486 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
487 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
488 profile.putMachineSetting('has_heated_bed', 'True')
490 profile.putMachineSetting('has_heated_bed', 'False')
491 if self.dualExtrusion.GetValue():
492 profile.putMachineSetting('extruder_amount', '2')
493 profile.putMachineSetting('machine_depth', '195')
495 profile.putMachineSetting('extruder_amount', '1')
496 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
497 profile.putProfileSetting('retraction_enable', 'True')
499 profile.putProfileSetting('retraction_enable', 'False')
502 class UltimakerFirmwareUpgradePage(InfoPage):
503 def __init__(self, parent):
504 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
505 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."))
506 self.AddHiddenSeperator()
507 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
508 self.AddHiddenSeperator()
509 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."))
510 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
511 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
512 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
513 self.AddHiddenSeperator()
514 self.AddText(_("Do not upgrade to this firmware if:"))
515 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
516 self.AddText(_("* Have other changes in the firmware"))
517 # button = self.AddButton('Goto this page for a custom firmware')
518 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
523 def OnUpgradeClick(self, e):
524 if firmwareInstall.InstallFirmware():
525 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
527 def OnSkipClick(self, e):
528 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
529 self.GetParent().ShowPage(self.GetNext())
531 def OnUrlClick(self, e):
532 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
534 class UltimakerCheckupPage(InfoPage):
535 def __init__(self, parent):
536 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
538 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
539 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
540 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
541 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
542 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
543 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
544 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
545 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
546 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
547 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
550 _("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."))
551 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
552 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
553 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
555 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
556 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
557 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
559 self.infoBox = self.AddInfoBox()
560 self.machineState = self.AddText("")
561 self.temperatureLabel = self.AddText("")
562 self.errorLogButton = self.AddButton(_("Show error log"))
563 self.errorLogButton.Show(False)
565 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
567 self.xMinStop = False
568 self.xMaxStop = False
569 self.yMinStop = False
570 self.yMaxStop = False
571 self.zMinStop = False
572 self.zMaxStop = False
574 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
577 if self.comm is not None:
581 self.endstopBitmap.Show(False)
584 def OnSkipClick(self, e):
585 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
586 self.GetParent().ShowPage(self.GetNext())
588 def OnCheckClick(self, e=None):
589 self.errorLogButton.Show(False)
590 if self.comm is not None:
594 wx.CallAfter(self.OnCheckClick)
596 self.infoBox.SetBusy(_("Connecting to machine."))
597 self.commState.SetBitmap(self.unknownBitmap)
598 self.tempState.SetBitmap(self.unknownBitmap)
599 self.stopState.SetBitmap(self.unknownBitmap)
600 self.checkupState = 0
601 self.checkExtruderNr = 0
602 self.comm = machineCom.MachineCom(callbackObject=self)
604 def OnErrorLog(self, e):
605 printWindow.LogWindow('\n'.join(self.comm.getLog()))
607 def mcLog(self, message):
610 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
611 if not self.comm.isOperational():
613 if self.checkupState == 0:
614 self.tempCheckTimeout = 20
615 if temp[self.checkExtruderNr] > 70:
616 self.checkupState = 1
617 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
618 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
619 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
621 self.startTemp = temp[self.checkExtruderNr]
622 self.checkupState = 2
623 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
624 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
625 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
626 elif self.checkupState == 1:
628 self.startTemp = temp[self.checkExtruderNr]
629 self.checkupState = 2
630 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
631 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
632 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
633 elif self.checkupState == 2:
634 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
635 if temp[self.checkExtruderNr] > self.startTemp + 40:
636 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
637 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
638 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
639 self.checkExtruderNr = 0
640 self.checkupState = 3
641 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
642 wx.CallAfter(self.endstopBitmap.Show, True)
643 wx.CallAfter(self.Layout)
644 self.comm.sendCommand('M119')
645 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
647 self.checkupState = 0
648 self.checkExtruderNr += 1
650 self.tempCheckTimeout -= 1
651 if self.tempCheckTimeout < 1:
652 self.checkupState = -1
653 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
654 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
655 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
656 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
657 elif self.checkupState >= 3 and self.checkupState < 10:
658 self.comm.sendCommand('M119')
659 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
661 def mcStateChange(self, state):
662 if self.comm is None:
664 if self.comm.isOperational():
665 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
666 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
667 elif self.comm.isError():
668 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
669 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
670 wx.CallAfter(self.endstopBitmap.Show, False)
671 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
672 wx.CallAfter(self.errorLogButton.Show, True)
673 wx.CallAfter(self.Layout)
675 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
677 def mcMessage(self, message):
678 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
679 for data in message.split(' '):
681 tag, value = data.split(':', 1)
683 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
685 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
687 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
689 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
691 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
693 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
695 tag, value = map(str.strip, message.split(':', 1))
697 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
699 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
701 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
703 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
705 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
707 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
708 if 'z_max' in message:
709 self.comm.sendCommand('M119')
711 if self.checkupState == 3:
712 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
713 self.checkupState = 4
714 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
715 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
716 elif self.checkupState == 4:
717 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
718 self.checkupState = 5
719 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
720 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
721 elif self.checkupState == 5:
722 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
723 self.checkupState = 6
724 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
725 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
726 elif self.checkupState == 6:
727 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
728 self.checkupState = 7
729 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
730 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
731 elif self.checkupState == 7:
732 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
733 self.checkupState = 8
734 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
735 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
736 elif self.checkupState == 8:
737 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
738 self.checkupState = 9
739 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
740 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
741 elif self.checkupState == 9:
742 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
743 self.checkupState = 10
745 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
746 wx.CallAfter(self.infoBox.SetReadyIndicator)
747 wx.CallAfter(self.endstopBitmap.Show, False)
748 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
749 wx.CallAfter(self.OnSkipClick, None)
751 def mcProgress(self, lineNr):
754 def mcZChange(self, newZ):
758 class UltimakerCalibrationPage(InfoPage):
759 def __init__(self, parent):
760 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
762 self.AddText("Your Ultimaker requires some calibration.")
763 self.AddText("This calibration is needed for a proper extrusion amount.")
765 self.AddText("The following values are needed:")
766 self.AddText("* Diameter of filament")
767 self.AddText("* Number of steps per mm of filament extrusion")
769 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
771 self.AddText("First we need the diameter of your filament:")
772 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
774 "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.")
775 self.AddText("Note: This value can be changed later at any time.")
778 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
781 class UltimakerCalibrateStepsPerEPage(InfoPage):
782 def __init__(self, parent):
783 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
785 #if profile.getMachineSetting('steps_per_e') == '0':
786 # profile.putMachineSetting('steps_per_e', '865.888')
788 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
789 self.AddText(_("First remove any filament from your machine."))
790 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
791 self.AddText(_("We'll push the filament 100mm"))
792 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
793 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
794 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
795 self.AddText(_("This results in the following steps per E:"))
796 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
797 self.AddText(_("You can repeat these steps to get better calibration."))
800 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
801 self.heatButton = self.AddButton(_("Heatup for filament removal"))
803 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
804 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
805 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
807 def OnSaveLengthClick(self, e):
808 currentEValue = float(self.stepsPerEInput.GetValue())
809 realExtrudeLength = float(self.lengthInput.GetValue())
810 newEValue = currentEValue * 100 / realExtrudeLength
811 self.stepsPerEInput.SetValue(str(newEValue))
812 self.lengthInput.SetValue("100")
814 def OnExtrudeClick(self, e):
815 t = threading.Thread(target=self.OnExtrudeRun)
819 def OnExtrudeRun(self):
820 self.heatButton.Enable(False)
821 self.extrudeButton.Enable(False)
822 currentEValue = float(self.stepsPerEInput.GetValue())
823 self.comm = machineCom.MachineCom()
824 if not self.comm.isOpen():
826 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
827 'Printer error', wx.OK | wx.ICON_INFORMATION)
828 self.heatButton.Enable(True)
829 self.extrudeButton.Enable(True)
832 line = self.comm.readline()
837 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
840 self.sendGCommand('M302') #Disable cold extrusion protection
841 self.sendGCommand("M92 E%f" % (currentEValue))
842 self.sendGCommand("G92 E0")
843 self.sendGCommand("G1 E100 F600")
846 self.extrudeButton.Enable()
847 self.heatButton.Enable()
849 def OnHeatClick(self, e):
850 t = threading.Thread(target=self.OnHeatRun)
855 self.heatButton.Enable(False)
856 self.extrudeButton.Enable(False)
857 self.comm = machineCom.MachineCom()
858 if not self.comm.isOpen():
860 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
861 'Printer error', wx.OK | wx.ICON_INFORMATION)
862 self.heatButton.Enable(True)
863 self.extrudeButton.Enable(True)
866 line = self.comm.readline()
868 self.heatButton.Enable(True)
869 self.extrudeButton.Enable(True)
873 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
876 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
878 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
879 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
880 self.sendGCommand('M104 S0')
883 self.heatButton.Enable(True)
884 self.extrudeButton.Enable(True)
886 def sendGCommand(self, cmd):
887 self.comm.sendCommand(cmd) #Disable cold extrusion protection
889 line = self.comm.readline()
892 if line.startswith('ok'):
896 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
898 class Ultimaker2ReadyPage(InfoPage):
899 def __init__(self, parent):
900 super(Ultimaker2ReadyPage, self).__init__(parent, "Ultimaker2")
901 self.AddText('Congratulations on your the purchase of your brand new Ultimaker2.')
902 self.AddText('Cura is now ready to be used with your Ultimaker2.')
905 class configWizard(wx.wizard.Wizard):
906 def __init__(self, addNew = False):
907 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
909 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
910 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
912 self.firstInfoPage = FirstInfoPage(self, addNew)
913 self.machineSelectPage = MachineSelectPage(self)
914 self.ultimakerSelectParts = SelectParts(self)
915 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
916 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
917 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
918 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
919 self.bedLevelPage = bedLevelWizardMain(self)
920 self.headOffsetCalibration = headOffsetCalibrationPage(self)
921 self.printrbotSelectType = PrintrbotPage(self)
922 self.otherMachineSelectPage = OtherMachineSelectPage(self)
923 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
924 self.otherMachineInfoPage = OtherMachineInfoPage(self)
926 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
928 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
929 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
930 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
931 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
932 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
933 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
934 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
935 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
936 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
938 self.FitToPage(self.firstInfoPage)
939 self.GetPageAreaSizer().Add(self.firstInfoPage)
941 self.RunWizard(self.firstInfoPage)
944 def OnPageChanging(self, e):
945 e.GetPage().StoreData()
947 def OnPageChanged(self, e):
948 if e.GetPage().AllowNext():
949 self.FindWindowById(wx.ID_FORWARD).Enable()
951 self.FindWindowById(wx.ID_FORWARD).Disable()
952 if e.GetPage().AllowBack():
953 self.FindWindowById(wx.ID_BACKWARD).Enable()
955 self.FindWindowById(wx.ID_BACKWARD).Disable()
957 class bedLevelWizardMain(InfoPage):
958 def __init__(self, parent):
959 super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
961 self.AddText('This wizard will help you in leveling your printer bed')
963 self.AddText('It will do the following steps')
964 self.AddText('* Move the printer head to each corner')
965 self.AddText(' and let you adjust the height of the bed to the nozzle')
966 self.AddText('* Print a line around the bed to check if it is level')
969 self.connectButton = self.AddButton('Connect to printer')
972 self.infoBox = self.AddInfoBox()
973 self.resumeButton = self.AddButton('Resume')
974 self.upButton, self.downButton = self.AddDualButton('Up 0.2mm', 'Down 0.2mm')
975 self.upButton2, self.downButton2 = self.AddDualButton('Up 10mm', 'Down 10mm')
976 self.resumeButton.Enable(False)
978 self.upButton.Enable(False)
979 self.downButton.Enable(False)
980 self.upButton2.Enable(False)
981 self.downButton2.Enable(False)
983 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
984 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
985 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
986 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
987 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
988 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
990 def OnConnect(self, e = None):
991 if self.comm is not None:
995 wx.CallAfter(self.OnConnect)
997 self.connectButton.Enable(False)
998 self.comm = machineCom.MachineCom(callbackObject=self)
999 self.infoBox.SetBusy('Connecting to machine.')
1000 self._wizardState = 0
1002 def OnBedUp(self, e):
1003 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1004 self.comm.sendCommand('G92 Z10')
1005 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1006 self.comm.sendCommand('M400')
1008 def OnBedDown(self, e):
1009 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1010 self.comm.sendCommand('G92 Z10')
1011 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1012 self.comm.sendCommand('M400')
1014 def OnBedUp2(self, e):
1015 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1016 self.comm.sendCommand('G92 Z10')
1017 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1018 self.comm.sendCommand('M400')
1020 def OnBedDown2(self, e):
1021 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1022 self.comm.sendCommand('G92 Z10')
1023 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1024 self.comm.sendCommand('M400')
1026 def AllowNext(self):
1027 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1028 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1031 def OnResume(self, e):
1032 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1033 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1034 if self._wizardState == -1:
1035 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
1036 wx.CallAfter(self.upButton.Enable, False)
1037 wx.CallAfter(self.downButton.Enable, False)
1038 wx.CallAfter(self.upButton2.Enable, False)
1039 wx.CallAfter(self.downButton2.Enable, False)
1040 self.comm.sendCommand('M105')
1041 self.comm.sendCommand('G28')
1042 self._wizardState = 1
1043 elif self._wizardState == 2:
1044 if profile.getMachineSetting('has_heated_bed') == 'True':
1045 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back center...')
1046 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1047 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1048 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1049 self.comm.sendCommand('M400')
1050 self._wizardState = 3
1052 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
1053 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1054 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1055 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1056 self.comm.sendCommand('M400')
1057 self._wizardState = 3
1058 elif self._wizardState == 4:
1059 if profile.getMachineSetting('has_heated_bed') == 'True':
1060 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
1061 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1062 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1063 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1064 self.comm.sendCommand('M400')
1065 self._wizardState = 7
1067 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
1068 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1069 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1070 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1071 self.comm.sendCommand('M400')
1072 self._wizardState = 5
1073 elif self._wizardState == 6:
1074 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
1075 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1076 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1077 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1078 self.comm.sendCommand('M400')
1079 self._wizardState = 7
1080 elif self._wizardState == 8:
1081 wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
1082 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1083 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1084 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1085 self._wizardState = 9
1086 elif self._wizardState == 10:
1087 self._wizardState = 11
1088 wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
1089 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1090 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1091 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1092 w = profile.getMachineSettingFloat('machine_width') - 10
1093 d = profile.getMachineSettingFloat('machine_depth')
1094 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1095 filamentArea = math.pi * filamentRadius * filamentRadius
1096 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1100 'G1 Z2 F%d' % (feedZ),
1102 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1103 'G1 Z0.3 F%d' % (feedZ)]
1105 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1107 for i in xrange(0, 3):
1108 dist = 5.0 + 0.4 * float(i)
1109 eValue += (d - 2.0*dist) * ePerMM
1110 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1111 eValue += (w - 2.0*dist) * ePerMM
1112 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1113 eValue += (d - 2.0*dist) * ePerMM
1114 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1115 eValue += (w - 2.0*dist) * ePerMM
1116 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1118 gcodeList.append('M400')
1119 self.comm.printGCode(gcodeList)
1120 self.resumeButton.Enable(False)
1122 def mcLog(self, message):
1123 print 'Log:', message
1125 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1126 if self._wizardState == 1:
1127 self._wizardState = 2
1128 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
1129 wx.CallAfter(self.resumeButton.Enable, True)
1130 elif self._wizardState == 3:
1131 self._wizardState = 4
1132 if profile.getMachineSetting('has_heated_bed') == 'True':
1133 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.')
1135 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
1136 wx.CallAfter(self.resumeButton.Enable, True)
1137 elif self._wizardState == 5:
1138 self._wizardState = 6
1139 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
1140 wx.CallAfter(self.resumeButton.Enable, True)
1141 elif self._wizardState == 7:
1142 self._wizardState = 8
1143 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
1144 wx.CallAfter(self.resumeButton.Enable, True)
1145 elif self._wizardState == 9:
1146 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1147 wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1149 wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
1150 wx.CallAfter(self.resumeButton.Enable, True)
1151 self._wizardState = 10
1153 def mcStateChange(self, state):
1154 if self.comm is None:
1156 if self.comm.isOperational():
1157 if self._wizardState == 0:
1158 wx.CallAfter(self.infoBox.SetAttention, 'Use the up/down buttons to move the bed and adjust your Z endstop.')
1159 wx.CallAfter(self.upButton.Enable, True)
1160 wx.CallAfter(self.downButton.Enable, True)
1161 wx.CallAfter(self.upButton2.Enable, True)
1162 wx.CallAfter(self.downButton2.Enable, True)
1163 wx.CallAfter(self.resumeButton.Enable, True)
1164 self._wizardState = -1
1165 elif self._wizardState == 11 and not self.comm.isPrinting():
1166 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1167 self.comm.sendCommand('G92 E0')
1168 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1169 self.comm.sendCommand('M104 S0')
1170 wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
1171 wx.CallAfter(self.infoBox.SetReadyIndicator)
1172 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1173 wx.CallAfter(self.connectButton.Enable, True)
1174 self._wizardState = 12
1175 elif self.comm.isError():
1176 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1178 def mcMessage(self, message):
1181 def mcProgress(self, lineNr):
1184 def mcZChange(self, newZ):
1187 class headOffsetCalibrationPage(InfoPage):
1188 def __init__(self, parent):
1189 super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
1191 self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
1194 self.connectButton = self.AddButton('Connect to printer')
1197 self.infoBox = self.AddInfoBox()
1198 self.textEntry = self.AddTextCtrl('')
1199 self.textEntry.Enable(False)
1200 self.resumeButton = self.AddButton('Resume')
1201 self.resumeButton.Enable(False)
1203 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1204 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1206 def AllowBack(self):
1209 def OnConnect(self, e = None):
1210 if self.comm is not None:
1214 wx.CallAfter(self.OnConnect)
1216 self.connectButton.Enable(False)
1217 self.comm = machineCom.MachineCom(callbackObject=self)
1218 self.infoBox.SetBusy('Connecting to machine.')
1219 self._wizardState = 0
1221 def OnResume(self, e):
1222 if self._wizardState == 2:
1223 self._wizardState = 3
1224 wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
1226 w = profile.getMachineSettingFloat('machine_width')
1227 d = profile.getMachineSettingFloat('machine_depth')
1229 gcode = gcodeGenerator.gcodeGenerator()
1230 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1231 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1238 gcode.addMove(w/2, 5)
1239 gcode.addMove(z=0.2)
1241 gcode.addExtrude(w/2, d-5.0)
1243 gcode.addMove(5, d/2)
1245 gcode.addExtrude(w-5.0, d/2)
1246 gcode.addRetract(15)
1249 gcode.addMove(w/2, 5)
1251 gcode.addExtrude(w/2, d-5.0)
1253 gcode.addMove(5, d/2)
1255 gcode.addExtrude(w-5.0, d/2)
1256 gcode.addRetract(15)
1261 gcode.addCmd('M400')
1263 self.comm.printGCode(gcode.list())
1264 self.resumeButton.Enable(False)
1265 elif self._wizardState == 4:
1267 float(self.textEntry.GetValue())
1270 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1271 self._wizardState = 5
1272 self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
1273 self.textEntry.SetValue('0.0')
1274 self.textEntry.Enable(True)
1275 elif self._wizardState == 5:
1277 float(self.textEntry.GetValue())
1280 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1281 self._wizardState = 6
1282 self.infoBox.SetBusy('Printing the fine calibration lines.')
1283 self.textEntry.SetValue('')
1284 self.textEntry.Enable(False)
1285 self.resumeButton.Enable(False)
1287 x = profile.getMachineSettingFloat('extruder_offset_x1')
1288 y = profile.getMachineSettingFloat('extruder_offset_y1')
1289 gcode = gcodeGenerator.gcodeGenerator()
1290 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1291 gcode.setPrintSpeed(25)
1294 gcode.addMove(50, 40, 0.2)
1296 for n in xrange(0, 10):
1297 gcode.addExtrude(50 + n * 10, 150)
1298 gcode.addExtrude(50 + n * 10 + 5, 150)
1299 gcode.addExtrude(50 + n * 10 + 5, 40)
1300 gcode.addExtrude(50 + n * 10 + 10, 40)
1301 gcode.addMove(40, 50)
1302 for n in xrange(0, 10):
1303 gcode.addExtrude(150, 50 + n * 10)
1304 gcode.addExtrude(150, 50 + n * 10 + 5)
1305 gcode.addExtrude(40, 50 + n * 10 + 5)
1306 gcode.addExtrude(40, 50 + n * 10 + 10)
1307 gcode.addRetract(15)
1310 gcode.addMove(50 - x, 30 - y, 0.2)
1312 for n in xrange(0, 10):
1313 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1314 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1315 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1316 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1317 gcode.addMove(30 - x, 50 - y, 0.2)
1318 for n in xrange(0, 10):
1319 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1320 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1321 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1322 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1323 gcode.addRetract(15)
1325 gcode.addCmd('M400')
1326 gcode.addCmd('M104 T0 S0')
1327 gcode.addCmd('M104 T1 S0')
1328 self.comm.printGCode(gcode.list())
1329 elif self._wizardState == 7:
1331 n = int(self.textEntry.GetValue()) - 1
1334 x = profile.getMachineSettingFloat('extruder_offset_x1')
1336 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1337 self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
1338 self.textEntry.SetValue('10')
1339 self._wizardState = 8
1340 elif self._wizardState == 8:
1342 n = int(self.textEntry.GetValue()) - 1
1345 y = profile.getMachineSettingFloat('extruder_offset_y1')
1347 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1348 self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1349 self.infoBox.SetReadyIndicator()
1350 self._wizardState = 8
1352 self.resumeButton.Enable(False)
1354 def mcLog(self, message):
1355 print 'Log:', message
1357 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1358 if self._wizardState == 1:
1359 if temp[0] >= 210 and temp[1] >= 210:
1360 self._wizardState = 2
1361 wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
1362 wx.CallAfter(self.resumeButton.Enable, True)
1363 wx.CallAfter(self.resumeButton.SetFocus)
1365 def mcStateChange(self, state):
1366 if self.comm is None:
1368 if self.comm.isOperational():
1369 if self._wizardState == 0:
1370 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
1371 self.comm.sendCommand('M105')
1372 self.comm.sendCommand('M104 S220 T0')
1373 self.comm.sendCommand('M104 S220 T1')
1374 self.comm.sendCommand('G28')
1375 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1376 self._wizardState = 1
1377 if not self.comm.isPrinting():
1378 if self._wizardState == 3:
1379 self._wizardState = 4
1380 wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
1381 wx.CallAfter(self.textEntry.SetValue, '0.0')
1382 wx.CallAfter(self.textEntry.Enable, True)
1383 wx.CallAfter(self.resumeButton.Enable, True)
1384 wx.CallAfter(self.resumeButton.SetFocus)
1385 elif self._wizardState == 6:
1386 self._wizardState = 7
1387 wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
1388 wx.CallAfter(self.textEntry.SetValue, '10')
1389 wx.CallAfter(self.textEntry.Enable, True)
1390 wx.CallAfter(self.resumeButton.Enable, True)
1391 wx.CallAfter(self.resumeButton.SetFocus)
1393 elif self.comm.isError():
1394 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1396 def mcMessage(self, message):
1399 def mcProgress(self, lineNr):
1402 def mcZChange(self, newZ):
1405 class bedLevelWizard(wx.wizard.Wizard):
1407 super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
1409 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1410 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1412 self.mainPage = bedLevelWizardMain(self)
1413 self.headOffsetCalibration = None
1415 self.FitToPage(self.mainPage)
1416 self.GetPageAreaSizer().Add(self.mainPage)
1418 self.RunWizard(self.mainPage)
1421 def OnPageChanging(self, e):
1422 e.GetPage().StoreData()
1424 def OnPageChanged(self, e):
1425 if e.GetPage().AllowNext():
1426 self.FindWindowById(wx.ID_FORWARD).Enable()
1428 self.FindWindowById(wx.ID_FORWARD).Disable()
1429 if e.GetPage().AllowBack():
1430 self.FindWindowById(wx.ID_BACKWARD).Enable()
1432 self.FindWindowById(wx.ID_BACKWARD).Disable()
1434 class headOffsetWizard(wx.wizard.Wizard):
1436 super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
1438 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1439 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1441 self.mainPage = headOffsetCalibrationPage(self)
1443 self.FitToPage(self.mainPage)
1444 self.GetPageAreaSizer().Add(self.mainPage)
1446 self.RunWizard(self.mainPage)
1449 def OnPageChanging(self, e):
1450 e.GetPage().StoreData()
1452 def OnPageChanged(self, e):
1453 if e.GetPage().AllowNext():
1454 self.FindWindowById(wx.ID_FORWARD).Enable()
1456 self.FindWindowById(wx.ID_FORWARD).Disable()
1457 if e.GetPage().AllowBack():
1458 self.FindWindowById(wx.ID_BACKWARD).Enable()
1460 self.FindWindowById(wx.ID_BACKWARD).Disable()