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.LulzbotTazRadio = self.AddRadioButton("Lulzbot TAZ")
396 self.LulzbotTazRadio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
397 self.LulzbotMiniRadio = self.AddRadioButton("Lulzbot Mini")
398 self.LulzbotMiniRadio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
399 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot, Witbox)"))
400 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
402 self.AddText(_("The collection of anonymous usage information helps with the continued improvement of Cura."))
403 self.AddText(_("This does NOT submit your models online nor gathers any privacy related information."))
404 self.SubmitUserStats = self.AddCheckbox(_("Submit anonymous usage information:"))
405 self.AddText(_("For full details see: http://wiki.ultimaker.com/Cura:stats"))
406 self.SubmitUserStats.SetValue(True)
408 def OnUltimaker2Select(self, e):
409 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
411 def OnUltimakerSelect(self, e):
412 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
414 def OnPrintrbotSelect(self, e):
415 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().printrbotSelectType)
417 def OnLulzbotSelect(self, e):
418 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
420 def OnOtherSelect(self, e):
421 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
424 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
428 profile.putProfileSetting('retraction_enable', 'True')
429 if self.Ultimaker2Radio.GetValue():
430 profile.putMachineSetting('machine_width', '230')
431 profile.putMachineSetting('machine_depth', '225')
432 profile.putMachineSetting('machine_height', '205')
433 profile.putMachineSetting('machine_name', 'ultimaker2')
434 profile.putMachineSetting('machine_type', 'ultimaker2')
435 profile.putMachineSetting('machine_center_is_zero', 'False')
436 profile.putMachineSetting('has_heated_bed', 'True')
437 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
438 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
439 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
440 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
441 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
442 profile.putMachineSetting('extruder_head_size_height', '55.0')
443 profile.putProfileSetting('nozzle_size', '0.4')
444 profile.putProfileSetting('fan_full_height', '5.0')
445 profile.putMachineSetting('extruder_offset_x1', '18.0')
446 profile.putMachineSetting('extruder_offset_y1', '0.0')
447 elif self.UltimakerRadio.GetValue():
448 profile.putMachineSetting('machine_width', '205')
449 profile.putMachineSetting('machine_depth', '205')
450 profile.putMachineSetting('machine_height', '200')
451 profile.putMachineSetting('machine_name', 'ultimaker original')
452 profile.putMachineSetting('machine_type', 'ultimaker')
453 profile.putMachineSetting('machine_center_is_zero', 'False')
454 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
455 profile.putProfileSetting('nozzle_size', '0.4')
456 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
457 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
458 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
459 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
460 profile.putMachineSetting('extruder_head_size_height', '55.0')
461 elif self.LulzbotTazRadio.GetValue() or self.LulzbotMiniRadio.GetValue():
462 if self.LulzbotTazRadio.GetValue():
463 profile.putMachineSetting('machine_width', '298')
464 profile.putMachineSetting('machine_depth', '275')
465 profile.putMachineSetting('machine_height', '250')
466 profile.putMachineSetting('machine_name', 'Lulzbot TAZ')
468 profile.putMachineSetting('machine_width', '160')
469 profile.putMachineSetting('machine_depth', '160')
470 profile.putMachineSetting('machine_height', '160')
471 profile.putMachineSetting('machine_name', 'Lulzbot Mini')
472 profile.putMachineSetting('machine_type', 'Aleph Objects')
473 profile.putMachineSetting('machine_center_is_zero', 'False')
474 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
475 profile.putMachineSetting('has_heated_bed', 'True')
476 profile.putProfileSetting('nozzle_size', '0.5')
477 profile.putMachineSetting('extruder_head_size_min_x', '0.0')
478 profile.putMachineSetting('extruder_head_size_min_y', '0.0')
479 profile.putMachineSetting('extruder_head_size_max_x', '0.0')
480 profile.putMachineSetting('extruder_head_size_max_y', '0.0')
481 profile.putMachineSetting('extruder_head_size_height', '0.0')
483 profile.putMachineSetting('machine_width', '80')
484 profile.putMachineSetting('machine_depth', '80')
485 profile.putMachineSetting('machine_height', '60')
486 profile.putMachineSetting('machine_name', 'reprap')
487 profile.putMachineSetting('machine_type', 'reprap')
488 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
489 profile.putPreference('startMode', 'Normal')
490 profile.putProfileSetting('nozzle_size', '0.5')
491 profile.checkAndUpdateMachineName()
492 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
493 if self.SubmitUserStats.GetValue():
494 profile.putPreference('submit_slice_information', 'True')
496 profile.putPreference('submit_slice_information', 'False')
499 class SelectParts(InfoPage):
500 def __init__(self, parent):
501 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
502 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."))
504 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
505 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
506 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
507 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
509 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."))
510 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
511 self.springExtruder.SetValue(True)
514 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
515 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
516 profile.putMachineSetting('has_heated_bed', 'True')
518 profile.putMachineSetting('has_heated_bed', 'False')
519 if self.dualExtrusion.GetValue():
520 profile.putMachineSetting('extruder_amount', '2')
521 profile.putMachineSetting('machine_depth', '195')
523 profile.putMachineSetting('extruder_amount', '1')
524 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
525 profile.putProfileSetting('retraction_enable', 'True')
527 profile.putProfileSetting('retraction_enable', 'False')
530 class UltimakerFirmwareUpgradePage(InfoPage):
531 def __init__(self, parent):
532 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
533 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."))
534 self.AddHiddenSeperator()
535 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
536 self.AddHiddenSeperator()
537 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."))
538 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
539 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
540 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
541 self.AddHiddenSeperator()
542 self.AddText(_("Do not upgrade to this firmware if:"))
543 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
544 self.AddText(_("* Have other changes in the firmware"))
545 # button = self.AddButton('Goto this page for a custom firmware')
546 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
551 def OnUpgradeClick(self, e):
552 if firmwareInstall.InstallFirmware():
553 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
555 def OnSkipClick(self, e):
556 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
557 self.GetParent().ShowPage(self.GetNext())
559 def OnUrlClick(self, e):
560 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
562 class UltimakerCheckupPage(InfoPage):
563 def __init__(self, parent):
564 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
566 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
567 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
568 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
569 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
570 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
571 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
572 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
573 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
574 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
575 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
578 _("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."))
579 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
580 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
581 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
583 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
584 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
585 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
587 self.infoBox = self.AddInfoBox()
588 self.machineState = self.AddText("")
589 self.temperatureLabel = self.AddText("")
590 self.errorLogButton = self.AddButton(_("Show error log"))
591 self.errorLogButton.Show(False)
593 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
595 self.xMinStop = False
596 self.xMaxStop = False
597 self.yMinStop = False
598 self.yMaxStop = False
599 self.zMinStop = False
600 self.zMaxStop = False
602 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
605 if self.comm is not None:
609 self.endstopBitmap.Show(False)
612 def OnSkipClick(self, e):
613 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
614 self.GetParent().ShowPage(self.GetNext())
616 def OnCheckClick(self, e=None):
617 self.errorLogButton.Show(False)
618 if self.comm is not None:
622 wx.CallAfter(self.OnCheckClick)
624 self.infoBox.SetBusy(_("Connecting to machine."))
625 self.commState.SetBitmap(self.unknownBitmap)
626 self.tempState.SetBitmap(self.unknownBitmap)
627 self.stopState.SetBitmap(self.unknownBitmap)
628 self.checkupState = 0
629 self.checkExtruderNr = 0
630 self.comm = machineCom.MachineCom(callbackObject=self)
632 def OnErrorLog(self, e):
633 printWindow.LogWindow('\n'.join(self.comm.getLog()))
635 def mcLog(self, message):
638 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
639 if not self.comm.isOperational():
641 if self.checkupState == 0:
642 self.tempCheckTimeout = 20
643 if temp[self.checkExtruderNr] > 70:
644 self.checkupState = 1
645 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
646 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
647 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
649 self.startTemp = temp[self.checkExtruderNr]
650 self.checkupState = 2
651 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
652 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
653 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
654 elif self.checkupState == 1:
656 self.startTemp = temp[self.checkExtruderNr]
657 self.checkupState = 2
658 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
659 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
660 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
661 elif self.checkupState == 2:
662 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
663 if temp[self.checkExtruderNr] > self.startTemp + 40:
664 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
665 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
666 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
667 self.checkExtruderNr = 0
668 self.checkupState = 3
669 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
670 wx.CallAfter(self.endstopBitmap.Show, True)
671 wx.CallAfter(self.Layout)
672 self.comm.sendCommand('M119')
673 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
675 self.checkupState = 0
676 self.checkExtruderNr += 1
678 self.tempCheckTimeout -= 1
679 if self.tempCheckTimeout < 1:
680 self.checkupState = -1
681 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
682 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
683 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
684 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
685 elif self.checkupState >= 3 and self.checkupState < 10:
686 self.comm.sendCommand('M119')
687 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
689 def mcStateChange(self, state):
690 if self.comm is None:
692 if self.comm.isOperational():
693 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
694 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
695 elif self.comm.isError():
696 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
697 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
698 wx.CallAfter(self.endstopBitmap.Show, False)
699 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
700 wx.CallAfter(self.errorLogButton.Show, True)
701 wx.CallAfter(self.Layout)
703 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
705 def mcMessage(self, message):
706 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
707 for data in message.split(' '):
709 tag, value = data.split(':', 1)
711 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
713 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
715 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
717 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
719 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
721 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
723 tag, value = map(str.strip, message.split(':', 1))
725 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
727 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
729 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
731 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
733 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
735 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
736 if 'z_max' in message:
737 self.comm.sendCommand('M119')
739 if self.checkupState == 3:
740 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
741 self.checkupState = 4
742 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
743 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
744 elif self.checkupState == 4:
745 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
746 self.checkupState = 5
747 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
748 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
749 elif self.checkupState == 5:
750 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
751 self.checkupState = 6
752 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
753 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
754 elif self.checkupState == 6:
755 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
756 self.checkupState = 7
757 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
758 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
759 elif self.checkupState == 7:
760 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
761 self.checkupState = 8
762 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
763 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
764 elif self.checkupState == 8:
765 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
766 self.checkupState = 9
767 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
768 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
769 elif self.checkupState == 9:
770 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
771 self.checkupState = 10
773 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
774 wx.CallAfter(self.infoBox.SetReadyIndicator)
775 wx.CallAfter(self.endstopBitmap.Show, False)
776 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
777 wx.CallAfter(self.OnSkipClick, None)
779 def mcProgress(self, lineNr):
782 def mcZChange(self, newZ):
786 class UltimakerCalibrationPage(InfoPage):
787 def __init__(self, parent):
788 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
790 self.AddText("Your Ultimaker requires some calibration.")
791 self.AddText("This calibration is needed for a proper extrusion amount.")
793 self.AddText("The following values are needed:")
794 self.AddText("* Diameter of filament")
795 self.AddText("* Number of steps per mm of filament extrusion")
797 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
799 self.AddText("First we need the diameter of your filament:")
800 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
802 "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.")
803 self.AddText("Note: This value can be changed later at any time.")
806 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
809 class UltimakerCalibrateStepsPerEPage(InfoPage):
810 def __init__(self, parent):
811 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
813 #if profile.getMachineSetting('steps_per_e') == '0':
814 # profile.putMachineSetting('steps_per_e', '865.888')
816 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
817 self.AddText(_("First remove any filament from your machine."))
818 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
819 self.AddText(_("We'll push the filament 100mm"))
820 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
821 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
822 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
823 self.AddText(_("This results in the following steps per E:"))
824 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
825 self.AddText(_("You can repeat these steps to get better calibration."))
828 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
829 self.heatButton = self.AddButton(_("Heatup for filament removal"))
831 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
832 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
833 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
835 def OnSaveLengthClick(self, e):
836 currentEValue = float(self.stepsPerEInput.GetValue())
837 realExtrudeLength = float(self.lengthInput.GetValue())
838 newEValue = currentEValue * 100 / realExtrudeLength
839 self.stepsPerEInput.SetValue(str(newEValue))
840 self.lengthInput.SetValue("100")
842 def OnExtrudeClick(self, e):
843 t = threading.Thread(target=self.OnExtrudeRun)
847 def OnExtrudeRun(self):
848 self.heatButton.Enable(False)
849 self.extrudeButton.Enable(False)
850 currentEValue = float(self.stepsPerEInput.GetValue())
851 self.comm = machineCom.MachineCom()
852 if not self.comm.isOpen():
854 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
855 'Printer error', wx.OK | wx.ICON_INFORMATION)
856 self.heatButton.Enable(True)
857 self.extrudeButton.Enable(True)
860 line = self.comm.readline()
865 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
868 self.sendGCommand('M302') #Disable cold extrusion protection
869 self.sendGCommand("M92 E%f" % (currentEValue))
870 self.sendGCommand("G92 E0")
871 self.sendGCommand("G1 E100 F600")
874 self.extrudeButton.Enable()
875 self.heatButton.Enable()
877 def OnHeatClick(self, e):
878 t = threading.Thread(target=self.OnHeatRun)
883 self.heatButton.Enable(False)
884 self.extrudeButton.Enable(False)
885 self.comm = machineCom.MachineCom()
886 if not self.comm.isOpen():
888 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
889 'Printer error', wx.OK | wx.ICON_INFORMATION)
890 self.heatButton.Enable(True)
891 self.extrudeButton.Enable(True)
894 line = self.comm.readline()
896 self.heatButton.Enable(True)
897 self.extrudeButton.Enable(True)
901 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
904 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
906 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
907 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
908 self.sendGCommand('M104 S0')
911 self.heatButton.Enable(True)
912 self.extrudeButton.Enable(True)
914 def sendGCommand(self, cmd):
915 self.comm.sendCommand(cmd) #Disable cold extrusion protection
917 line = self.comm.readline()
920 if line.startswith('ok'):
924 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
926 class Ultimaker2ReadyPage(InfoPage):
927 def __init__(self, parent):
928 super(Ultimaker2ReadyPage, self).__init__(parent, "Ultimaker2")
929 self.AddText('Congratulations on your the purchase of your brand new Ultimaker2.')
930 self.AddText('Cura is now ready to be used with your Ultimaker2.')
933 class LulzbotReadyPage(InfoPage):
934 def __init__(self, parent):
935 super(LulzbotReadyPage, self).__init__(parent, "Lulzbot TAZ/Mini")
936 self.AddText('Cura is now ready to be used with your Lulzbot.')
939 class configWizard(wx.wizard.Wizard):
940 def __init__(self, addNew = False):
941 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
943 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
944 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
946 self.firstInfoPage = FirstInfoPage(self, addNew)
947 self.machineSelectPage = MachineSelectPage(self)
948 self.ultimakerSelectParts = SelectParts(self)
949 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
950 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
951 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
952 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
953 self.bedLevelPage = bedLevelWizardMain(self)
954 self.headOffsetCalibration = headOffsetCalibrationPage(self)
955 self.printrbotSelectType = PrintrbotPage(self)
956 self.otherMachineSelectPage = OtherMachineSelectPage(self)
957 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
958 self.otherMachineInfoPage = OtherMachineInfoPage(self)
960 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
961 self.lulzbotReadyPage = LulzbotReadyPage(self)
963 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
964 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
965 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
966 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
967 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
968 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
969 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
970 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
971 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
973 self.FitToPage(self.firstInfoPage)
974 self.GetPageAreaSizer().Add(self.firstInfoPage)
976 self.RunWizard(self.firstInfoPage)
979 def OnPageChanging(self, e):
980 e.GetPage().StoreData()
982 def OnPageChanged(self, e):
983 if e.GetPage().AllowNext():
984 self.FindWindowById(wx.ID_FORWARD).Enable()
986 self.FindWindowById(wx.ID_FORWARD).Disable()
987 if e.GetPage().AllowBack():
988 self.FindWindowById(wx.ID_BACKWARD).Enable()
990 self.FindWindowById(wx.ID_BACKWARD).Disable()
992 class bedLevelWizardMain(InfoPage):
993 def __init__(self, parent):
994 super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
996 self.AddText('This wizard will help you in leveling your printer bed')
998 self.AddText('It will do the following steps')
999 self.AddText('* Move the printer head to each corner')
1000 self.AddText(' and let you adjust the height of the bed to the nozzle')
1001 self.AddText('* Print a line around the bed to check if it is level')
1004 self.connectButton = self.AddButton('Connect to printer')
1007 self.infoBox = self.AddInfoBox()
1008 self.resumeButton = self.AddButton('Resume')
1009 self.upButton, self.downButton = self.AddDualButton('Up 0.2mm', 'Down 0.2mm')
1010 self.upButton2, self.downButton2 = self.AddDualButton('Up 10mm', 'Down 10mm')
1011 self.resumeButton.Enable(False)
1013 self.upButton.Enable(False)
1014 self.downButton.Enable(False)
1015 self.upButton2.Enable(False)
1016 self.downButton2.Enable(False)
1018 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1019 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1020 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1021 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1022 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1023 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1025 def OnConnect(self, e = None):
1026 if self.comm is not None:
1030 wx.CallAfter(self.OnConnect)
1032 self.connectButton.Enable(False)
1033 self.comm = machineCom.MachineCom(callbackObject=self)
1034 self.infoBox.SetBusy('Connecting to machine.')
1035 self._wizardState = 0
1037 def OnBedUp(self, e):
1038 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1039 self.comm.sendCommand('G92 Z10')
1040 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1041 self.comm.sendCommand('M400')
1043 def OnBedDown(self, e):
1044 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1045 self.comm.sendCommand('G92 Z10')
1046 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1047 self.comm.sendCommand('M400')
1049 def OnBedUp2(self, e):
1050 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1051 self.comm.sendCommand('G92 Z10')
1052 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1053 self.comm.sendCommand('M400')
1055 def OnBedDown2(self, e):
1056 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1057 self.comm.sendCommand('G92 Z10')
1058 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1059 self.comm.sendCommand('M400')
1061 def AllowNext(self):
1062 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1063 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1066 def OnResume(self, e):
1067 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1068 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1069 if self._wizardState == -1:
1070 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
1071 wx.CallAfter(self.upButton.Enable, False)
1072 wx.CallAfter(self.downButton.Enable, False)
1073 wx.CallAfter(self.upButton2.Enable, False)
1074 wx.CallAfter(self.downButton2.Enable, False)
1075 self.comm.sendCommand('M105')
1076 self.comm.sendCommand('G28')
1077 self._wizardState = 1
1078 elif self._wizardState == 2:
1079 if profile.getMachineSetting('has_heated_bed') == 'True':
1080 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back center...')
1081 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1082 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1083 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1084 self.comm.sendCommand('M400')
1085 self._wizardState = 3
1087 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
1088 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1089 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1090 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1091 self.comm.sendCommand('M400')
1092 self._wizardState = 3
1093 elif self._wizardState == 4:
1094 if profile.getMachineSetting('has_heated_bed') == 'True':
1095 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
1096 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1097 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1098 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1099 self.comm.sendCommand('M400')
1100 self._wizardState = 7
1102 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
1103 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1104 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1105 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1106 self.comm.sendCommand('M400')
1107 self._wizardState = 5
1108 elif self._wizardState == 6:
1109 wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
1110 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1111 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1112 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1113 self.comm.sendCommand('M400')
1114 self._wizardState = 7
1115 elif self._wizardState == 8:
1116 wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
1117 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1118 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1119 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1120 self._wizardState = 9
1121 elif self._wizardState == 10:
1122 self._wizardState = 11
1123 wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
1124 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1125 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1126 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1127 w = profile.getMachineSettingFloat('machine_width') - 10
1128 d = profile.getMachineSettingFloat('machine_depth')
1129 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1130 filamentArea = math.pi * filamentRadius * filamentRadius
1131 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1135 'G1 Z2 F%d' % (feedZ),
1137 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1138 'G1 Z0.3 F%d' % (feedZ)]
1140 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1142 for i in xrange(0, 3):
1143 dist = 5.0 + 0.4 * float(i)
1144 eValue += (d - 2.0*dist) * ePerMM
1145 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1146 eValue += (w - 2.0*dist) * ePerMM
1147 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1148 eValue += (d - 2.0*dist) * ePerMM
1149 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1150 eValue += (w - 2.0*dist) * ePerMM
1151 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1153 gcodeList.append('M400')
1154 self.comm.printGCode(gcodeList)
1155 self.resumeButton.Enable(False)
1157 def mcLog(self, message):
1158 print 'Log:', message
1160 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1161 if self._wizardState == 1:
1162 self._wizardState = 2
1163 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
1164 wx.CallAfter(self.resumeButton.Enable, True)
1165 elif self._wizardState == 3:
1166 self._wizardState = 4
1167 if profile.getMachineSetting('has_heated_bed') == 'True':
1168 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.')
1170 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
1171 wx.CallAfter(self.resumeButton.Enable, True)
1172 elif self._wizardState == 5:
1173 self._wizardState = 6
1174 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
1175 wx.CallAfter(self.resumeButton.Enable, True)
1176 elif self._wizardState == 7:
1177 self._wizardState = 8
1178 wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
1179 wx.CallAfter(self.resumeButton.Enable, True)
1180 elif self._wizardState == 9:
1181 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1182 wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1184 wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
1185 wx.CallAfter(self.resumeButton.Enable, True)
1186 self._wizardState = 10
1188 def mcStateChange(self, state):
1189 if self.comm is None:
1191 if self.comm.isOperational():
1192 if self._wizardState == 0:
1193 wx.CallAfter(self.infoBox.SetAttention, 'Use the up/down buttons to move the bed and adjust your Z endstop.')
1194 wx.CallAfter(self.upButton.Enable, True)
1195 wx.CallAfter(self.downButton.Enable, True)
1196 wx.CallAfter(self.upButton2.Enable, True)
1197 wx.CallAfter(self.downButton2.Enable, True)
1198 wx.CallAfter(self.resumeButton.Enable, True)
1199 self._wizardState = -1
1200 elif self._wizardState == 11 and not self.comm.isPrinting():
1201 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1202 self.comm.sendCommand('G92 E0')
1203 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1204 self.comm.sendCommand('M104 S0')
1205 wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
1206 wx.CallAfter(self.infoBox.SetReadyIndicator)
1207 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1208 wx.CallAfter(self.connectButton.Enable, True)
1209 self._wizardState = 12
1210 elif self.comm.isError():
1211 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1213 def mcMessage(self, message):
1216 def mcProgress(self, lineNr):
1219 def mcZChange(self, newZ):
1222 class headOffsetCalibrationPage(InfoPage):
1223 def __init__(self, parent):
1224 super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
1226 self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
1229 self.connectButton = self.AddButton('Connect to printer')
1232 self.infoBox = self.AddInfoBox()
1233 self.textEntry = self.AddTextCtrl('')
1234 self.textEntry.Enable(False)
1235 self.resumeButton = self.AddButton('Resume')
1236 self.resumeButton.Enable(False)
1238 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1239 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1241 def AllowBack(self):
1244 def OnConnect(self, e = None):
1245 if self.comm is not None:
1249 wx.CallAfter(self.OnConnect)
1251 self.connectButton.Enable(False)
1252 self.comm = machineCom.MachineCom(callbackObject=self)
1253 self.infoBox.SetBusy('Connecting to machine.')
1254 self._wizardState = 0
1256 def OnResume(self, e):
1257 if self._wizardState == 2:
1258 self._wizardState = 3
1259 wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
1261 w = profile.getMachineSettingFloat('machine_width')
1262 d = profile.getMachineSettingFloat('machine_depth')
1264 gcode = gcodeGenerator.gcodeGenerator()
1265 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1266 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1273 gcode.addMove(w/2, 5)
1274 gcode.addMove(z=0.2)
1276 gcode.addExtrude(w/2, d-5.0)
1278 gcode.addMove(5, d/2)
1280 gcode.addExtrude(w-5.0, d/2)
1281 gcode.addRetract(15)
1284 gcode.addMove(w/2, 5)
1286 gcode.addExtrude(w/2, d-5.0)
1288 gcode.addMove(5, d/2)
1290 gcode.addExtrude(w-5.0, d/2)
1291 gcode.addRetract(15)
1296 gcode.addCmd('M400')
1298 self.comm.printGCode(gcode.list())
1299 self.resumeButton.Enable(False)
1300 elif self._wizardState == 4:
1302 float(self.textEntry.GetValue())
1305 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1306 self._wizardState = 5
1307 self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
1308 self.textEntry.SetValue('0.0')
1309 self.textEntry.Enable(True)
1310 elif self._wizardState == 5:
1312 float(self.textEntry.GetValue())
1315 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1316 self._wizardState = 6
1317 self.infoBox.SetBusy('Printing the fine calibration lines.')
1318 self.textEntry.SetValue('')
1319 self.textEntry.Enable(False)
1320 self.resumeButton.Enable(False)
1322 x = profile.getMachineSettingFloat('extruder_offset_x1')
1323 y = profile.getMachineSettingFloat('extruder_offset_y1')
1324 gcode = gcodeGenerator.gcodeGenerator()
1325 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1326 gcode.setPrintSpeed(25)
1329 gcode.addMove(50, 40, 0.2)
1331 for n in xrange(0, 10):
1332 gcode.addExtrude(50 + n * 10, 150)
1333 gcode.addExtrude(50 + n * 10 + 5, 150)
1334 gcode.addExtrude(50 + n * 10 + 5, 40)
1335 gcode.addExtrude(50 + n * 10 + 10, 40)
1336 gcode.addMove(40, 50)
1337 for n in xrange(0, 10):
1338 gcode.addExtrude(150, 50 + n * 10)
1339 gcode.addExtrude(150, 50 + n * 10 + 5)
1340 gcode.addExtrude(40, 50 + n * 10 + 5)
1341 gcode.addExtrude(40, 50 + n * 10 + 10)
1342 gcode.addRetract(15)
1345 gcode.addMove(50 - x, 30 - y, 0.2)
1347 for n in xrange(0, 10):
1348 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1349 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1350 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1351 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1352 gcode.addMove(30 - x, 50 - y, 0.2)
1353 for n in xrange(0, 10):
1354 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1355 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1356 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1357 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1358 gcode.addRetract(15)
1360 gcode.addCmd('M400')
1361 gcode.addCmd('M104 T0 S0')
1362 gcode.addCmd('M104 T1 S0')
1363 self.comm.printGCode(gcode.list())
1364 elif self._wizardState == 7:
1366 n = int(self.textEntry.GetValue()) - 1
1369 x = profile.getMachineSettingFloat('extruder_offset_x1')
1371 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1372 self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
1373 self.textEntry.SetValue('10')
1374 self._wizardState = 8
1375 elif self._wizardState == 8:
1377 n = int(self.textEntry.GetValue()) - 1
1380 y = profile.getMachineSettingFloat('extruder_offset_y1')
1382 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1383 self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1384 self.infoBox.SetReadyIndicator()
1385 self._wizardState = 8
1387 self.resumeButton.Enable(False)
1389 def mcLog(self, message):
1390 print 'Log:', message
1392 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1393 if self._wizardState == 1:
1394 if temp[0] >= 210 and temp[1] >= 210:
1395 self._wizardState = 2
1396 wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
1397 wx.CallAfter(self.resumeButton.Enable, True)
1398 wx.CallAfter(self.resumeButton.SetFocus)
1400 def mcStateChange(self, state):
1401 if self.comm is None:
1403 if self.comm.isOperational():
1404 if self._wizardState == 0:
1405 wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
1406 self.comm.sendCommand('M105')
1407 self.comm.sendCommand('M104 S220 T0')
1408 self.comm.sendCommand('M104 S220 T1')
1409 self.comm.sendCommand('G28')
1410 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1411 self._wizardState = 1
1412 if not self.comm.isPrinting():
1413 if self._wizardState == 3:
1414 self._wizardState = 4
1415 wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
1416 wx.CallAfter(self.textEntry.SetValue, '0.0')
1417 wx.CallAfter(self.textEntry.Enable, True)
1418 wx.CallAfter(self.resumeButton.Enable, True)
1419 wx.CallAfter(self.resumeButton.SetFocus)
1420 elif self._wizardState == 6:
1421 self._wizardState = 7
1422 wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
1423 wx.CallAfter(self.textEntry.SetValue, '10')
1424 wx.CallAfter(self.textEntry.Enable, True)
1425 wx.CallAfter(self.resumeButton.Enable, True)
1426 wx.CallAfter(self.resumeButton.SetFocus)
1428 elif self.comm.isError():
1429 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1431 def mcMessage(self, message):
1434 def mcProgress(self, lineNr):
1437 def mcZChange(self, newZ):
1440 class bedLevelWizard(wx.wizard.Wizard):
1442 super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
1444 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1445 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1447 self.mainPage = bedLevelWizardMain(self)
1448 self.headOffsetCalibration = None
1450 self.FitToPage(self.mainPage)
1451 self.GetPageAreaSizer().Add(self.mainPage)
1453 self.RunWizard(self.mainPage)
1456 def OnPageChanging(self, e):
1457 e.GetPage().StoreData()
1459 def OnPageChanged(self, e):
1460 if e.GetPage().AllowNext():
1461 self.FindWindowById(wx.ID_FORWARD).Enable()
1463 self.FindWindowById(wx.ID_FORWARD).Disable()
1464 if e.GetPage().AllowBack():
1465 self.FindWindowById(wx.ID_BACKWARD).Enable()
1467 self.FindWindowById(wx.ID_BACKWARD).Disable()
1469 class headOffsetWizard(wx.wizard.Wizard):
1471 super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
1473 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1474 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1476 self.mainPage = headOffsetCalibrationPage(self)
1478 self.FitToPage(self.mainPage)
1479 self.GetPageAreaSizer().Add(self.mainPage)
1481 self.RunWizard(self.mainPage)
1484 def OnPageChanging(self, e):
1485 e.GetPage().StoreData()
1487 def OnPageChanged(self, e):
1488 if e.GetPage().AllowNext():
1489 self.FindWindowById(wx.ID_FORWARD).Enable()
1491 self.FindWindowById(wx.ID_FORWARD).Disable()
1492 if e.GetPage().AllowBack():
1493 self.FindWindowById(wx.ID_BACKWARD).Enable()
1495 self.FindWindowById(wx.ID_BACKWARD).Disable()