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 parent.GetPageAreaSizer().Add(self)
115 sizer = wx.GridBagSizer(5, 5)
119 self.title = wx.StaticText(self, -1, title)
120 font = wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)
121 self.title.SetFont(font)
122 # HACK ALERT: For some reason, the StaticText keeps its same size as if
123 # the font was not modified, this causes the text to wrap and to
124 # get out of bounds of the widgets area and hide other widgets.
125 # The only way I found for the widget to get its right size was to calculate
126 # the new font's extent and set the min size on the widget
129 w,h = dc.GetTextExtent(title)
130 self.title.SetMinSize((w, h))
131 sizer.Add(self.title, pos=(0, 0), span=(1, 2), flag=wx.ALIGN_CENTRE | wx.ALL)
132 sizer.Add(wx.StaticLine(self, -1), pos=(1, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
133 sizer.AddGrowableCol(1)
137 def AddText(self, info):
138 text = wx.StaticText(self, -1, info)
139 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
143 def AddSeperator(self):
144 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
147 def AddHiddenSeperator(self):
150 def AddInfoBox(self):
151 infoBox = InfoBox(self)
152 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
156 def AddRadioButton(self, label, style=0):
157 radio = wx.RadioButton(self, -1, label, style=style)
158 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
162 def AddCheckbox(self, label, checked=False):
163 check = wx.CheckBox(self, -1)
164 text = wx.StaticText(self, -1, label)
165 check.SetValue(checked)
166 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
167 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 2), flag=wx.ALL)
171 def AddButton(self, label):
172 button = wx.Button(self, -1, label)
173 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
177 def AddDualButton(self, label1, label2):
178 button1 = wx.Button(self, -1, label1)
179 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
180 button2 = wx.Button(self, -1, label2)
181 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
183 return button1, button2
185 def AddTextCtrl(self, value):
186 ret = wx.TextCtrl(self, -1, value)
187 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
191 def AddLabelTextCtrl(self, info, value):
192 text = wx.StaticText(self, -1, info)
193 ret = wx.TextCtrl(self, -1, value)
194 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
195 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
199 def AddTextCtrlButton(self, value, buttonText):
200 text = wx.TextCtrl(self, -1, value)
201 button = wx.Button(self, -1, buttonText)
202 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
203 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
207 def AddBitmap(self, bitmap):
208 bitmap = wx.StaticBitmap(self, -1, bitmap)
209 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
213 def AddCheckmark(self, label, bitmap):
214 check = wx.StaticBitmap(self, -1, bitmap)
215 text = wx.StaticText(self, -1, label)
216 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
217 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 1), flag=wx.ALL)
221 def AddCombo(self, label, options):
222 combo = wx.ComboBox(self, -1, options[0], choices=options, style=wx.CB_DROPDOWN|wx.CB_READONLY)
223 text = wx.StaticText(self, -1, label)
224 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER)
225 self.GetSizer().Add(combo, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
238 class PrintrbotPage(InfoPage):
239 def __init__(self, parent):
240 self._printer_info = [
241 # X, Y, Z, Nozzle Size, Filament Diameter, PrintTemperature, Print Speed, Travel Speed, Retract speed, Retract amount, use bed level sensor
242 ("Simple Metal", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, True),
243 ("Metal Plus", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
244 ("Simple Makers Kit", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, True),
245 (":" + _("Older models"),),
246 ("Original", 130, 130, 130, 0.5, 2.95, 208, 40, 70, 30, 1, False),
247 ("Simple Maker's Edition v1", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
248 ("Simple Maker's Edition v2 (2013 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
249 ("Simple Maker's Edition v3 (2014 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
250 ("Jr v1", 115, 120, 80, 0.4, 1.75, 208, 40, 70, 30, 1, False),
251 ("Jr v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
252 ("LC v1", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
253 ("LC v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
254 ("Plus v1", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
255 ("Plus v2", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
256 ("Plus v2.1", 185, 220, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
257 ("Plus v2.2 (Model 1404/140422/140501/140507)", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
258 ("Go v2 Large", 505, 306, 310, 0.4, 1.75, 208, 35, 70, 30, 1, True),
261 super(PrintrbotPage, self).__init__(parent, _("Printrbot Selection"))
262 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Printrbot_logo.png')))
263 self.AddText(_("Select which Printrbot machine you have:"))
265 for printer in self._printer_info:
266 if printer[0].startswith(":"):
268 self.AddText(printer[0][1:])
270 item = self.AddRadioButton(printer[0])
271 item.data = printer[1:]
272 self._items.append(item)
275 profile.putMachineSetting('machine_name', 'Printrbot ???')
276 for item in self._items:
279 profile.putMachineSetting('machine_name', 'Printrbot ' + item.GetLabel())
280 profile.putMachineSetting('machine_width', data[0])
281 profile.putMachineSetting('machine_depth', data[1])
282 profile.putMachineSetting('machine_height', data[2])
283 profile.putProfileSetting('nozzle_size', data[3])
284 profile.putProfileSetting('filament_diameter', data[4])
285 profile.putProfileSetting('print_temperature', data[5])
286 profile.putProfileSetting('print_speed', data[6])
287 profile.putProfileSetting('travel_speed', data[7])
288 profile.putProfileSetting('retraction_speed', data[8])
289 profile.putProfileSetting('retraction_amount', data[9])
290 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
291 profile.putMachineSetting('has_heated_bed', 'False')
292 profile.putMachineSetting('machine_center_is_zero', 'False')
293 profile.putMachineSetting('extruder_head_size_min_x', '0')
294 profile.putMachineSetting('extruder_head_size_min_y', '0')
295 profile.putMachineSetting('extruder_head_size_max_x', '0')
296 profile.putMachineSetting('extruder_head_size_max_y', '0')
297 profile.putMachineSetting('extruder_head_size_height', '0')
299 profile.setAlterationFile('start.gcode', """;Sliced at: {day} {date} {time}
300 ;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {fill_density}
301 ;Print time: {print_time}
302 ;Filament used: {filament_amount}m {filament_weight}g
303 ;Filament cost: {filament_cost}
304 ;M190 S{print_bed_temperature} ;Uncomment to add your own bed temperature line
305 ;M109 S{print_temperature} ;Uncomment to add your own temperature line
307 G90 ;absolute positioning
308 M82 ;set extruder to absolute mode
309 M107 ;start with the fan off
310 G28 X0 Y0 ;move X/Y to min endstops
311 G28 Z0 ;move Z to min endstops
312 G29 ;Run the auto bed leveling
313 G1 Z15.0 F{travel_speed} ;move the platform down 15mm
314 G92 E0 ;zero the extruded length
315 G1 F200 E3 ;extrude 3mm of feed stock
316 G92 E0 ;zero the extruded length again
318 ;Put printing message on LCD screen
322 class OtherMachineSelectPage(InfoPage):
323 def __init__(self, parent):
324 super(OtherMachineSelectPage, self).__init__(parent, _("Other machine information"))
325 self.AddText(_("The following pre-defined machine profiles are available"))
326 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."))
328 machines = resources.getDefaultMachineProfiles()
330 for filename in machines:
331 name = os.path.splitext(os.path.basename(filename))[0]
332 item = self.AddRadioButton(name)
333 item.filename = filename
334 item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
335 self.options.append(item)
337 item = self.AddRadioButton(_('Custom...'))
339 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
341 def OnProfileSelect(self, e):
342 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
344 def OnOtherSelect(self, e):
345 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
348 for option in self.options:
349 if option.GetValue():
350 profile.loadProfile(option.filename)
351 profile.loadMachineSettings(option.filename)
353 class OtherMachineInfoPage(InfoPage):
354 def __init__(self, parent):
355 super(OtherMachineInfoPage, self).__init__(parent, _("Cura Ready!"))
356 self.AddText(_("Cura is now ready to be used!"))
358 class CustomRepRapInfoPage(InfoPage):
359 def __init__(self, parent):
360 super(CustomRepRapInfoPage, self).__init__(parent, _("Custom RepRap information"))
361 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
362 self.AddText(_("Be sure to review the default profile before running it on your machine."))
363 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
365 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
367 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
368 self.machineWidth = self.AddLabelTextCtrl(_("Machine width X (mm)"), "80")
369 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth Y (mm)"), "80")
370 self.machineHeight = self.AddLabelTextCtrl(_("Machine height Z (mm)"), "55")
371 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
372 self.heatedBed = self.AddCheckbox(_("Heated bed"))
373 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
376 profile.putMachineSetting('machine_name', self.machineName.GetValue())
377 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
378 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
379 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
380 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
381 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
382 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
383 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
384 profile.putMachineSetting('extruder_head_size_min_x', '0')
385 profile.putMachineSetting('extruder_head_size_min_y', '0')
386 profile.putMachineSetting('extruder_head_size_max_x', '0')
387 profile.putMachineSetting('extruder_head_size_max_y', '0')
388 profile.putMachineSetting('extruder_head_size_height', '0')
389 profile.checkAndUpdateMachineName()
391 class MachineSelectPage(InfoPage):
392 def __init__(self, parent):
393 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
394 self.AddText(_("What kind of machine do you have:"))
396 self.LulzbotMiniRadio = self.AddRadioButton("LulzBot Mini", style=wx.RB_GROUP)
397 self.LulzbotMiniRadio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
398 self.LulzbotMiniRadio.SetValue(True)
399 self.LulzbotTaz5Radio = self.AddRadioButton("LulzBot TAZ 5")
400 self.LulzbotTaz5Radio.Bind(wx.EVT_RADIOBUTTON, self.OnTaz5Select)
401 self.LulzbotTaz4Radio = self.AddRadioButton("LulzBot TAZ 4")
402 self.LulzbotTaz4Radio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
403 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2")
404 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
405 self.Ultimaker2ExtRadio = self.AddRadioButton("Ultimaker2extended")
406 self.Ultimaker2ExtRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
407 self.Ultimaker2GoRadio = self.AddRadioButton("Ultimaker2go")
408 self.Ultimaker2GoRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
409 self.UltimakerRadio = self.AddRadioButton("Ultimaker Original")
410 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
411 self.UltimakerOPRadio = self.AddRadioButton("Ultimaker Original+")
412 self.UltimakerOPRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerOPSelect)
413 self.PrintrbotRadio = self.AddRadioButton("Printrbot")
414 self.PrintrbotRadio.Bind(wx.EVT_RADIOBUTTON, self.OnPrintrbotSelect)
415 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot, Witbox)"))
416 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
418 def OnUltimaker2Select(self, e):
419 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
421 def OnUltimakerSelect(self, e):
422 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
424 def OnUltimakerOPSelect(self, e):
425 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)
427 def OnPrintrbotSelect(self, e):
428 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().printrbotSelectType)
430 def OnLulzbotSelect(self, e):
431 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotToolheadPage)
433 def OnTaz5Select(self, e):
434 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().taz5NozzleSelectPage)
435 wx.wizard.WizardPageSimple.Chain(self.GetParent().taz5NozzleSelectPage, self.GetParent().lulzbotToolheadPage)
437 def OnOtherSelect(self, e):
438 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
447 profile.putProfileSetting('retraction_enable', 'True')
448 if self.Ultimaker2Radio.GetValue() or self.Ultimaker2GoRadio.GetValue() or self.Ultimaker2ExtRadio.GetValue():
449 if self.Ultimaker2Radio.GetValue():
450 profile.putMachineSetting('machine_width', '230')
451 profile.putMachineSetting('machine_depth', '225')
452 profile.putMachineSetting('machine_height', '205')
453 profile.putMachineSetting('machine_name', 'ultimaker2')
454 profile.putMachineSetting('machine_type', 'ultimaker2')
455 profile.putMachineSetting('has_heated_bed', 'True')
456 if self.Ultimaker2GoRadio.GetValue():
457 profile.putMachineSetting('machine_width', '120')
458 profile.putMachineSetting('machine_depth', '120')
459 profile.putMachineSetting('machine_height', '115')
460 profile.putMachineSetting('machine_name', 'ultimaker2go')
461 profile.putMachineSetting('machine_type', 'ultimaker2go')
462 profile.putMachineSetting('has_heated_bed', 'False')
463 if self.Ultimaker2ExtRadio.GetValue():
464 profile.putMachineSetting('machine_width', '230')
465 profile.putMachineSetting('machine_depth', '225')
466 profile.putMachineSetting('machine_height', '315')
467 profile.putMachineSetting('machine_name', 'ultimaker2extended')
468 profile.putMachineSetting('machine_type', 'ultimaker2extended')
469 profile.putMachineSetting('has_heated_bed', 'False')
470 profile.putMachineSetting('machine_center_is_zero', 'False')
471 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
472 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
473 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
474 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
475 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
476 profile.putMachineSetting('extruder_head_size_height', '48.0')
477 profile.putProfileSetting('nozzle_size', '0.4')
478 profile.putProfileSetting('fan_full_height', '5.0')
479 profile.putMachineSetting('extruder_offset_x1', '18.0')
480 profile.putMachineSetting('extruder_offset_y1', '0.0')
481 elif self.UltimakerRadio.GetValue():
482 profile.putMachineSetting('machine_width', '205')
483 profile.putMachineSetting('machine_depth', '205')
484 profile.putMachineSetting('machine_height', '200')
485 profile.putMachineSetting('machine_name', 'ultimaker original')
486 profile.putMachineSetting('machine_type', 'ultimaker')
487 profile.putMachineSetting('machine_center_is_zero', 'False')
488 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
489 profile.putProfileSetting('nozzle_size', '0.4')
490 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
491 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
492 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
493 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
494 profile.putMachineSetting('extruder_head_size_height', '55.0')
495 elif self.UltimakerOPRadio.GetValue():
496 profile.putMachineSetting('machine_width', '205')
497 profile.putMachineSetting('machine_depth', '205')
498 profile.putMachineSetting('machine_height', '200')
499 profile.putMachineSetting('machine_name', 'ultimaker original+')
500 profile.putMachineSetting('machine_type', 'ultimaker_plus')
501 profile.putMachineSetting('machine_center_is_zero', 'False')
502 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
503 profile.putProfileSetting('nozzle_size', '0.4')
504 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
505 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
506 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
507 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
508 profile.putMachineSetting('extruder_head_size_height', '55.0')
509 profile.putMachineSetting('has_heated_bed', 'True')
510 profile.putMachineSetting('extruder_amount', '1')
511 profile.putProfileSetting('retraction_enable', 'True')
512 elif self.LulzbotTaz4Radio.GetValue() or self.LulzbotTaz5Radio.GetValue() or self.LulzbotMiniRadio.GetValue():
513 if self.LulzbotTaz4Radio.GetValue():
514 profile.putMachineSetting('machine_width', '290')
515 profile.putMachineSetting('machine_depth', '275')
516 profile.putMachineSetting('machine_height', '250')
517 profile.putProfileSetting('nozzle_size', '0.35')
518 profile.putMachineSetting('machine_name', 'LulzBot TAZ 4')
519 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_4')
520 profile.putMachineSetting('serial_baud', '115200')
521 elif self.LulzbotTaz5Radio.GetValue():
522 profile.putMachineSetting('machine_width', '290')
523 profile.putMachineSetting('machine_depth', '275')
524 profile.putMachineSetting('machine_height', '250')
525 profile.putMachineSetting('serial_baud', '115200')
526 # Machine type and name are set in the nozzle select page
528 profile.putMachineSetting('machine_width', '155')
529 profile.putMachineSetting('machine_depth', '155')
530 profile.putMachineSetting('machine_height', '163')
531 profile.putProfileSetting('nozzle_size', '0.5')
532 profile.putMachineSetting('machine_name', 'LulzBot Mini')
533 profile.putMachineSetting('machine_type', 'lulzbot_mini')
534 profile.putMachineSetting('serial_baud', '115200')
535 profile.putMachineSetting('extruder_head_size_min_x', '40')
536 profile.putMachineSetting('extruder_head_size_max_x', '75')
537 profile.putMachineSetting('extruder_head_size_min_y', '25')
538 profile.putMachineSetting('extruder_head_size_max_y', '55')
539 profile.putMachineSetting('extruder_head_size_height', '17')
541 profile.putMachineSetting('machine_center_is_zero', 'False')
542 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
543 profile.putMachineSetting('has_heated_bed', 'True')
544 profile.putMachineSetting('extruder_head_size_min_x', '0.0')
545 profile.putMachineSetting('extruder_head_size_min_y', '0.0')
546 profile.putMachineSetting('extruder_head_size_max_x', '0.0')
547 profile.putMachineSetting('extruder_head_size_max_y', '0.0')
548 profile.putMachineSetting('extruder_head_size_height', '0.0')
549 profile.putPreference('startMode', 'Simple')
551 profile.putMachineSetting('machine_width', '80')
552 profile.putMachineSetting('machine_depth', '80')
553 profile.putMachineSetting('machine_height', '60')
554 profile.putMachineSetting('machine_name', 'reprap')
555 profile.putMachineSetting('machine_type', 'reprap')
556 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
557 profile.putPreference('startMode', 'Normal')
558 profile.putProfileSetting('nozzle_size', '0.5')
559 profile.checkAndUpdateMachineName()
560 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
562 class SelectParts(InfoPage):
563 def __init__(self, parent):
564 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
565 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."))
567 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
568 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
569 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
570 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
572 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."))
573 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
574 self.springExtruder.SetValue(True)
577 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
578 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
579 profile.putMachineSetting('has_heated_bed', 'True')
581 profile.putMachineSetting('has_heated_bed', 'False')
582 if self.dualExtrusion.GetValue():
583 profile.putMachineSetting('extruder_amount', '2')
584 profile.putMachineSetting('machine_depth', '195')
586 profile.putMachineSetting('extruder_amount', '1')
587 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
588 profile.putProfileSetting('retraction_enable', 'True')
590 profile.putProfileSetting('retraction_enable', 'False')
593 class UltimakerFirmwareUpgradePage(InfoPage):
594 def __init__(self, parent):
595 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
596 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."))
597 self.AddHiddenSeperator()
598 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
599 self.AddHiddenSeperator()
600 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."))
601 upgradeButton, skipUpgradeButton = self.AddDualButton(_('Upgrade to Marlin firmware'), _('Skip upgrade'))
602 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
603 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
604 self.AddHiddenSeperator()
605 if profile.getMachineSetting('machine_type') == 'ultimaker':
606 self.AddText(_("Do not upgrade to this firmware if:"))
607 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
608 self.AddText(_("* Build your own heated bed"))
609 self.AddText(_("* Have other changes in the firmware"))
610 # button = self.AddButton('Goto this page for a custom firmware')
611 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
616 def OnUpgradeClick(self, e):
617 if firmwareInstall.InstallFirmware():
618 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
620 def OnSkipClick(self, e):
621 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
622 self.GetParent().ShowPage(self.GetNext())
624 def OnUrlClick(self, e):
625 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
627 class UltimakerCheckupPage(InfoPage):
628 def __init__(self, parent):
629 super(UltimakerCheckupPage, self).__init__(parent, _("Ultimaker Checkup"))
631 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
632 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
633 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
634 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
635 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
636 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
637 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
638 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
639 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
640 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
643 _("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."))
644 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
645 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
646 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
648 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
649 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
650 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
652 self.infoBox = self.AddInfoBox()
653 self.machineState = self.AddText("")
654 self.temperatureLabel = self.AddText("")
655 self.errorLogButton = self.AddButton(_("Show error log"))
656 self.errorLogButton.Show(False)
658 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
660 self.xMinStop = False
661 self.xMaxStop = False
662 self.yMinStop = False
663 self.yMaxStop = False
664 self.zMinStop = False
665 self.zMaxStop = False
667 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
670 if self.comm is not None:
674 self.endstopBitmap.Show(False)
677 def OnSkipClick(self, e):
678 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
679 self.GetParent().ShowPage(self.GetNext())
681 def OnCheckClick(self, e=None):
682 self.errorLogButton.Show(False)
683 if self.comm is not None:
687 wx.CallAfter(self.OnCheckClick)
689 self.infoBox.SetBusy(_("Connecting to machine."))
690 self.commState.SetBitmap(self.unknownBitmap)
691 self.tempState.SetBitmap(self.unknownBitmap)
692 self.stopState.SetBitmap(self.unknownBitmap)
693 self.checkupState = 0
694 self.checkExtruderNr = 0
695 self.comm = machineCom.MachineCom(callbackObject=self)
697 def OnErrorLog(self, e):
698 printWindow.LogWindow('\n'.join(self.comm.getLog()))
700 def mcLog(self, message):
703 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
704 if not self.comm.isOperational():
706 if self.checkupState == 0:
707 self.tempCheckTimeout = 20
708 if temp[self.checkExtruderNr] > 70:
709 self.checkupState = 1
710 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
711 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
712 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
714 self.startTemp = temp[self.checkExtruderNr]
715 self.checkupState = 2
716 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
717 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
718 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
719 elif self.checkupState == 1:
720 if temp[self.checkExtruderNr] < 60:
721 self.startTemp = temp[self.checkExtruderNr]
722 self.checkupState = 2
723 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
724 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
725 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
726 elif self.checkupState == 2:
727 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
728 if temp[self.checkExtruderNr] > self.startTemp + 40:
729 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
730 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
731 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
732 self.checkExtruderNr = 0
733 self.checkupState = 3
734 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
735 wx.CallAfter(self.endstopBitmap.Show, True)
736 wx.CallAfter(self.Layout)
737 self.comm.sendCommand('M119')
738 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
740 self.checkupState = 0
741 self.checkExtruderNr += 1
743 self.tempCheckTimeout -= 1
744 if self.tempCheckTimeout < 1:
745 self.checkupState = -1
746 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
747 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
748 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
749 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
750 elif self.checkupState >= 3 and self.checkupState < 10:
751 self.comm.sendCommand('M119')
752 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
754 def mcStateChange(self, state):
755 if self.comm is None:
757 if self.comm.isOperational():
758 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
759 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
760 elif self.comm.isError():
761 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
762 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
763 wx.CallAfter(self.endstopBitmap.Show, False)
764 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
765 wx.CallAfter(self.errorLogButton.Show, True)
766 wx.CallAfter(self.Layout)
768 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
770 def mcMessage(self, message):
771 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
772 for data in message.split(' '):
774 tag, value = data.split(':', 1)
776 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
778 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
780 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
782 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
784 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
786 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
788 tag, value = map(str.strip, message.split(':', 1))
790 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
792 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
794 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
796 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
798 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
800 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
801 if 'z_max' in message:
802 self.comm.sendCommand('M119')
804 if self.checkupState == 3:
805 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
806 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
807 self.checkupState = 5
808 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
809 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
811 self.checkupState = 4
812 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
813 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
814 elif self.checkupState == 4:
815 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
816 self.checkupState = 5
817 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
818 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
819 elif self.checkupState == 5:
820 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
821 self.checkupState = 6
822 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
823 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
824 elif self.checkupState == 6:
825 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
826 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
827 self.checkupState = 8
828 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
829 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
831 self.checkupState = 7
832 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
833 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
834 elif self.checkupState == 7:
835 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
836 self.checkupState = 8
837 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
838 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
839 elif self.checkupState == 8:
840 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
841 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
842 self.checkupState = 10
844 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
845 wx.CallAfter(self.infoBox.SetReadyIndicator)
846 wx.CallAfter(self.endstopBitmap.Show, False)
847 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
848 wx.CallAfter(self.OnSkipClick, None)
850 self.checkupState = 9
851 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
852 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
853 elif self.checkupState == 9:
854 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
855 self.checkupState = 10
857 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
858 wx.CallAfter(self.infoBox.SetReadyIndicator)
859 wx.CallAfter(self.endstopBitmap.Show, False)
860 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
861 wx.CallAfter(self.OnSkipClick, None)
863 def mcProgress(self, lineNr):
866 def mcZChange(self, newZ):
870 class UltimakerCalibrationPage(InfoPage):
871 def __init__(self, parent):
872 super(UltimakerCalibrationPage, self).__init__(parent, _("Ultimaker Calibration"))
874 self.AddText("Your Ultimaker requires some calibration.")
875 self.AddText("This calibration is needed for a proper extrusion amount.")
877 self.AddText("The following values are needed:")
878 self.AddText("* Diameter of filament")
879 self.AddText("* Number of steps per mm of filament extrusion")
881 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
883 self.AddText("First we need the diameter of your filament:")
884 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
886 "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.")
887 self.AddText("Note: This value can be changed later at any time.")
890 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
893 class UltimakerCalibrateStepsPerEPage(InfoPage):
894 def __init__(self, parent):
895 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, _("Ultimaker Calibration"))
897 #if profile.getMachineSetting('steps_per_e') == '0':
898 # profile.putMachineSetting('steps_per_e', '865.888')
900 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
901 self.AddText(_("First remove any filament from your machine."))
902 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
903 self.AddText(_("We'll push the filament 100mm"))
904 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
905 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
906 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
907 self.AddText(_("This results in the following steps per E:"))
908 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
909 self.AddText(_("You can repeat these steps to get better calibration."))
912 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
913 self.heatButton = self.AddButton(_("Heatup for filament removal"))
915 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
916 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
917 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
919 def OnSaveLengthClick(self, e):
920 currentEValue = float(self.stepsPerEInput.GetValue())
921 realExtrudeLength = float(self.lengthInput.GetValue())
922 newEValue = currentEValue * 100 / realExtrudeLength
923 self.stepsPerEInput.SetValue(str(newEValue))
924 self.lengthInput.SetValue("100")
926 def OnExtrudeClick(self, e):
927 t = threading.Thread(target=self.OnExtrudeRun)
931 def OnExtrudeRun(self):
932 self.heatButton.Enable(False)
933 self.extrudeButton.Enable(False)
934 currentEValue = float(self.stepsPerEInput.GetValue())
935 self.comm = machineCom.MachineCom()
936 if not self.comm.isOpen():
938 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
939 'Printer error', wx.OK | wx.ICON_INFORMATION)
940 self.heatButton.Enable(True)
941 self.extrudeButton.Enable(True)
944 line = self.comm.readline()
949 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
952 self.sendGCommand('M302') #Disable cold extrusion protection
953 self.sendGCommand("M92 E%f" % (currentEValue))
954 self.sendGCommand("G92 E0")
955 self.sendGCommand("G1 E100 F600")
958 self.extrudeButton.Enable()
959 self.heatButton.Enable()
961 def OnHeatClick(self, e):
962 t = threading.Thread(target=self.OnHeatRun)
967 self.heatButton.Enable(False)
968 self.extrudeButton.Enable(False)
969 self.comm = machineCom.MachineCom()
970 if not self.comm.isOpen():
972 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
973 'Printer error', wx.OK | wx.ICON_INFORMATION)
974 self.heatButton.Enable(True)
975 self.extrudeButton.Enable(True)
978 line = self.comm.readline()
980 self.heatButton.Enable(True)
981 self.extrudeButton.Enable(True)
985 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
988 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
990 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
991 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
992 self.sendGCommand('M104 S0')
995 self.heatButton.Enable(True)
996 self.extrudeButton.Enable(True)
998 def sendGCommand(self, cmd):
999 self.comm.sendCommand(cmd) #Disable cold extrusion protection
1001 line = self.comm.readline()
1004 if line.startswith('ok'):
1007 def StoreData(self):
1008 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
1010 class Ultimaker2ReadyPage(InfoPage):
1011 def __init__(self, parent):
1012 super(Ultimaker2ReadyPage, self).__init__(parent, _("Ultimaker2"))
1013 self.AddText(_('Congratulations on your the purchase of your brand new Ultimaker2.'))
1014 self.AddText(_('Cura is now ready to be used with your Ultimaker2.'))
1017 class LulzbotReadyPage(InfoPage):
1018 def __init__(self, parent):
1019 super(LulzbotReadyPage, self).__init__(parent, _("LulzBot TAZ/Mini"))
1020 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Lulzbot_logo.png')))
1021 self.AddText(_('Cura is now ready to be used with your LulzBot 3D printer.'))
1023 self.AddText(_('For more information about using Cura with your LulzBot'))
1024 self.AddText(_('3D printer, please visit www.LulzBot.com/cura'))
1027 class LulzbotToolheadSelectPage(InfoPage):
1028 url='http://lulzbot.com/toolhead-identification'
1030 def __init__(self, parent):
1031 super(LulzbotToolheadSelectPage, self).__init__(parent, _("LulzBot Toolhead Selection"))
1033 self.mini_choices = [_('Standard'), _('Flexystruder')]
1034 self.taz_choices = [_('Standard v1'),
1035 _('Standard v2 0.35 mm nozzle'), _('Standard v2 0.5 mm nozzle'),
1036 _('Flexystruder v1'), _('Flexystruder v2'),
1037 _('Dually v1'), _('Dually v2'),
1038 _('FlexyDually v1'), _('FlexyDually v2')]
1039 self.description_map = {
1040 _('Standard'): _('This is the standard toolhead that comes with the Lulzbot Mini'),
1041 _('Flexystruder'): _('This is the Flexystruder for the Lulzbot Mini\nIt is used for printing Flexible materials'),
1042 _('Standard v1'): _('This is the standard toolhead that comes with the Lulzbot TAZ 1-2-3 and TAZ 4.\nIt uses the Budaschnozzle for the hotend'),
1043 _('Standard v2 0.35 mm nozzle'): _('This is the standard toolhead that comes with the Lulzbot TAZ 5.\nIt uses the Hexagon hotend and a 0.35 mm nozzle'),
1044 _('Standard v2 0.5 mm nozzle'): _('This is the standard toolhead that comes with the Lulzbot TAZ 5.\nIt uses the Hexagon hotend and a 0.5 mm nozzle'),
1045 _('Flexystruder v1'): _('It\'s the flexy!'),
1046 _('Flexystruder v2'): _('It\'s the flexy v2!'),
1047 _('Dually v1'): _('It\'s the dualy v1!'),
1048 _('Dually v2'): _('It\'s the dual v2!'),
1049 _('FlexyDually v1'): _('It\'s the flexy dually v1!'),
1050 _('FlexyDually v2'): _('It\'s the flexy dual v2!')
1053 _('Standard'): 'Lulzbot_Toolhead_Mini_Standard.jpg',
1054 _('Flexystruder'): 'Lulzbot_logo.png',
1055 _('Standard v1'): 'Lulzbot_logo.png',
1056 _('Standard v2 0.35 mm nozzle'): 'Lulzbot_Toolhead_TAZ_Single_v2.jpg',
1057 _('Standard v2 0.5 mm nozzle'): 'Lulzbot_Toolhead_TAZ_Single_v2.jpg',
1058 _('Flexystruder v1'): 'Lulzbot_Toolhead_TAZ_Flexystruder_v1.jpg',
1059 _('Flexystruder v2'): 'Lulzbot_logo.png',
1060 _('Dually v1'): 'Lulzbot_Toolhead_TAZ_Dually_v1.jpg',
1061 _('Dually v2'): 'Lulzbot_logo.png',
1062 _('FlexyDually v1'): 'Lulzbot_logo.png',
1063 _('FlexyDually v2'): 'Lulzbot_logo.png'
1065 self.AddBitmap(wx.Bitmap(resources.getPathForImage('LulzBot_logo.png')))
1066 printer_name = profile.getMachineSetting('machine_type')
1067 self.Bind(wx.wizard.EVT_WIZARD_PAGE_SHOWN, self.OnPageShown)
1069 self.AddText(_('Please select your currently installed Tool Head'))
1070 txt = self.AddText(_('It is important to select the correct Tool head for your printer.\n' +
1071 'Flashing the wrong firmware on your printer can cause damage to your printer and to your toolhead\n' +
1072 'If you are not sure which toolhead you have, please refer to this webpage for more information: '))
1073 txt.SetForegroundColour(wx.RED)
1074 button = self.AddButton(self.url)
1075 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1078 self.combo = self.AddCombo(_('Currently installed Toolhead'), [''])
1079 self.combo.SetEditable(False)
1080 self.combo.Bind(wx.EVT_COMBOBOX, self.OnToolheadSelected)
1081 self.description = self.AddText('\n\n')
1082 self.description.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.BOLD))
1083 self.image = self.AddBitmap(wx.Bitmap(resources.getPathForImage(self.image_map[self.mini_choices[0]])))
1085 def OnPageShown(self, e):
1086 printer_name = profile.getMachineSetting('machine_type')
1087 if printer_name == 'lulzbot_mini':
1088 choices = self.mini_choices
1091 choices = self.taz_choices
1092 if printer_name == 'lulzbot_TAZ_4':
1094 elif printer_name == 'lulzbot_TAZ_5':
1100 self.combo.AppendItems(choices)
1101 self.combo.SetValue(choices[default])
1102 self.OnToolheadSelected(e)
1104 def OnUrlClick(self, e):
1105 webbrowser.open(LulzbotToolheadSelectPage.url)
1107 def OnToolheadSelected(self, e):
1108 toolhead = self.combo.GetValue()
1109 if self.description_map.has_key(toolhead):
1110 self.image.SetBitmap(wx.Bitmap(resources.getPathForImage(self.image_map[toolhead])))
1111 self.description.SetLabel(self.description_map[toolhead])
1113 self.image.SetBitmap(wx.NullBitmap)
1114 self.description.SetLabel('\n\n')
1119 class Taz5NozzleSelectPage(InfoPage):
1120 url='http://lulzbot.com/printer-identification'
1122 def __init__(self, parent):
1123 super(Taz5NozzleSelectPage, self).__init__(parent, _("LulzBot TAZ5"))
1124 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Lulzbot_logo.png')))
1126 self.AddText(_(' '))
1127 self.AddText(_('Please select nozzle size:'))
1128 self.Nozzle35Radio = self.AddRadioButton("0.35 mm", style=wx.RB_GROUP)
1129 self.Nozzle35Radio.SetValue(True)
1130 self.Nozzle50Radio = self.AddRadioButton("0.5 mm")
1131 self.AddText(_(' '))
1134 self.AddText(_('If you are not sure which nozzle size you have'))
1135 self.AddText(_('please check this webpage: '))
1136 button = self.AddButton(Taz5NozzleSelectPage.url)
1137 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1139 def OnUrlClick(self, e):
1140 webbrowser.open(Taz5NozzleSelectPage.url)
1142 def StoreData(self):
1143 if self.Nozzle35Radio.GetValue():
1144 profile.putProfileSetting('nozzle_size', '0.35')
1145 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.35 nozzle)')
1146 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5')
1149 profile.putProfileSetting('nozzle_size', '0.5')
1150 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.5 nozzle)')
1151 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5_05nozzle')
1153 class ConfigWizard(wx.wizard.Wizard):
1154 def __init__(self, addNew = False):
1155 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
1157 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1159 profile.setActiveMachine(profile.getMachineCount())
1161 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1162 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1163 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1165 self.machineSelectPage = MachineSelectPage(self)
1166 self.ultimakerSelectParts = SelectParts(self)
1167 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
1168 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
1169 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
1170 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
1171 self.bedLevelPage = bedLevelWizardMain(self)
1172 self.headOffsetCalibration = headOffsetCalibrationPage(self)
1173 self.printrbotSelectType = PrintrbotPage(self)
1174 self.otherMachineSelectPage = OtherMachineSelectPage(self)
1175 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
1176 self.otherMachineInfoPage = OtherMachineInfoPage(self)
1178 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
1179 self.lulzbotReadyPage = LulzbotReadyPage(self)
1180 self.lulzbotToolheadPage = LulzbotToolheadSelectPage(self)
1181 self.taz5NozzleSelectPage = Taz5NozzleSelectPage(self)
1183 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
1184 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
1185 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
1186 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
1187 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
1188 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
1189 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
1190 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
1191 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.lulzbotToolheadPage)
1192 wx.wizard.WizardPageSimple.Chain(self.lulzbotToolheadPage, self.lulzbotReadyPage)
1194 self.RunWizard(self.machineSelectPage)
1197 def OnPageChanging(self, e):
1198 e.GetPage().StoreData()
1200 def OnPageChanged(self, e):
1201 if e.GetPage().AllowNext():
1202 self.FindWindowById(wx.ID_FORWARD).Enable()
1204 self.FindWindowById(wx.ID_FORWARD).Disable()
1205 if e.GetPage().AllowBack():
1206 self.FindWindowById(wx.ID_BACKWARD).Enable()
1208 self.FindWindowById(wx.ID_BACKWARD).Disable()
1210 def OnCancel(self, e):
1211 new_machine_index = int(profile.getPreferenceFloat('active_machine'))
1212 profile.setActiveMachine(self._old_machine_index)
1213 profile.removeMachine(new_machine_index)
1215 class bedLevelWizardMain(InfoPage):
1216 def __init__(self, parent):
1217 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1219 self.AddText(_('This wizard will help you in leveling your printer bed'))
1221 self.AddText(_('It will do the following steps'))
1222 self.AddText(_('* Move the printer head to each corner'))
1223 self.AddText(_(' and let you adjust the height of the bed to the nozzle'))
1224 self.AddText(_('* Print a line around the bed to check if it is level'))
1227 self.connectButton = self.AddButton(_('Connect to printer'))
1230 self.infoBox = self.AddInfoBox()
1231 self.resumeButton = self.AddButton(_('Resume'))
1232 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1233 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1234 self.resumeButton.Enable(False)
1236 self.upButton.Enable(False)
1237 self.downButton.Enable(False)
1238 self.upButton2.Enable(False)
1239 self.downButton2.Enable(False)
1241 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1242 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1243 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1244 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1245 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1246 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1248 def OnConnect(self, e = None):
1249 if self.comm is not None:
1253 wx.CallAfter(self.OnConnect)
1255 self.connectButton.Enable(False)
1256 self.comm = machineCom.MachineCom(callbackObject=self)
1257 self.infoBox.SetBusy(_('Connecting to machine.'))
1258 self._wizardState = 0
1260 def OnBedUp(self, e):
1261 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1262 self.comm.sendCommand('G92 Z10')
1263 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1264 self.comm.sendCommand('M400')
1266 def OnBedDown(self, e):
1267 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1268 self.comm.sendCommand('G92 Z10')
1269 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1270 self.comm.sendCommand('M400')
1272 def OnBedUp2(self, e):
1273 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1274 self.comm.sendCommand('G92 Z10')
1275 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1276 self.comm.sendCommand('M400')
1278 def OnBedDown2(self, e):
1279 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1280 self.comm.sendCommand('G92 Z10')
1281 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1282 self.comm.sendCommand('M400')
1284 def AllowNext(self):
1285 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1286 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1289 def OnResume(self, e):
1290 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1291 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1292 if self._wizardState == -1:
1293 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1294 wx.CallAfter(self.upButton.Enable, False)
1295 wx.CallAfter(self.downButton.Enable, False)
1296 wx.CallAfter(self.upButton2.Enable, False)
1297 wx.CallAfter(self.downButton2.Enable, False)
1298 self.comm.sendCommand('M105')
1299 self.comm.sendCommand('G28')
1300 self._wizardState = 1
1301 elif self._wizardState == 2:
1302 if profile.getMachineSetting('has_heated_bed') == 'True':
1303 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1304 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1305 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1306 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1307 self.comm.sendCommand('M400')
1308 self._wizardState = 3
1310 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1311 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1312 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1313 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1314 self.comm.sendCommand('M400')
1315 self._wizardState = 3
1316 elif self._wizardState == 4:
1317 if profile.getMachineSetting('has_heated_bed') == 'True':
1318 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1319 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1320 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1321 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1322 self.comm.sendCommand('M400')
1323 self._wizardState = 7
1325 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1326 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1327 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1328 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1329 self.comm.sendCommand('M400')
1330 self._wizardState = 5
1331 elif self._wizardState == 6:
1332 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1333 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1334 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1335 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1336 self.comm.sendCommand('M400')
1337 self._wizardState = 7
1338 elif self._wizardState == 8:
1339 wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1340 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1341 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1342 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1343 self._wizardState = 9
1344 elif self._wizardState == 10:
1345 self._wizardState = 11
1346 wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1347 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1348 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1349 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1350 w = profile.getMachineSettingFloat('machine_width') - 10
1351 d = profile.getMachineSettingFloat('machine_depth')
1352 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1353 filamentArea = math.pi * filamentRadius * filamentRadius
1354 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1358 'G1 Z2 F%d' % (feedZ),
1360 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1361 'G1 Z0.3 F%d' % (feedZ)]
1363 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1365 for i in xrange(0, 3):
1366 dist = 5.0 + 0.4 * float(i)
1367 eValue += (d - 2.0*dist) * ePerMM
1368 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1369 eValue += (w - 2.0*dist) * ePerMM
1370 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1371 eValue += (d - 2.0*dist) * ePerMM
1372 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1373 eValue += (w - 2.0*dist) * ePerMM
1374 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1376 gcodeList.append('M400')
1377 self.comm.printGCode(gcodeList)
1378 self.resumeButton.Enable(False)
1380 def mcLog(self, message):
1381 print 'Log:', message
1383 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1384 if self._wizardState == 1:
1385 self._wizardState = 2
1386 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1387 wx.CallAfter(self.resumeButton.Enable, True)
1388 elif self._wizardState == 3:
1389 self._wizardState = 4
1390 if profile.getMachineSetting('has_heated_bed') == 'True':
1391 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1393 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1394 wx.CallAfter(self.resumeButton.Enable, True)
1395 elif self._wizardState == 5:
1396 self._wizardState = 6
1397 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1398 wx.CallAfter(self.resumeButton.Enable, True)
1399 elif self._wizardState == 7:
1400 self._wizardState = 8
1401 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1402 wx.CallAfter(self.resumeButton.Enable, True)
1403 elif self._wizardState == 9:
1404 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1405 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1407 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1408 wx.CallAfter(self.resumeButton.Enable, True)
1409 self._wizardState = 10
1411 def mcStateChange(self, state):
1412 if self.comm is None:
1414 if self.comm.isOperational():
1415 if self._wizardState == 0:
1416 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1417 wx.CallAfter(self.upButton.Enable, True)
1418 wx.CallAfter(self.downButton.Enable, True)
1419 wx.CallAfter(self.upButton2.Enable, True)
1420 wx.CallAfter(self.downButton2.Enable, True)
1421 wx.CallAfter(self.resumeButton.Enable, True)
1422 self._wizardState = -1
1423 elif self._wizardState == 11 and not self.comm.isPrinting():
1424 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1425 self.comm.sendCommand('G92 E0')
1426 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1427 self.comm.sendCommand('M104 S0')
1428 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1429 wx.CallAfter(self.infoBox.SetReadyIndicator)
1430 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1431 wx.CallAfter(self.connectButton.Enable, True)
1432 self._wizardState = 12
1433 elif self.comm.isError():
1434 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1436 def mcMessage(self, message):
1439 def mcProgress(self, lineNr):
1442 def mcZChange(self, newZ):
1445 class headOffsetCalibrationPage(InfoPage):
1446 def __init__(self, parent):
1447 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1449 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1452 self.connectButton = self.AddButton(_('Connect to printer'))
1455 self.infoBox = self.AddInfoBox()
1456 self.textEntry = self.AddTextCtrl('')
1457 self.textEntry.Enable(False)
1458 self.resumeButton = self.AddButton(_('Resume'))
1459 self.resumeButton.Enable(False)
1461 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1462 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1464 def AllowBack(self):
1467 def OnConnect(self, e = None):
1468 if self.comm is not None:
1472 wx.CallAfter(self.OnConnect)
1474 self.connectButton.Enable(False)
1475 self.comm = machineCom.MachineCom(callbackObject=self)
1476 self.infoBox.SetBusy(_('Connecting to machine.'))
1477 self._wizardState = 0
1479 def OnResume(self, e):
1480 if self._wizardState == 2:
1481 self._wizardState = 3
1482 wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1484 w = profile.getMachineSettingFloat('machine_width')
1485 d = profile.getMachineSettingFloat('machine_depth')
1487 gcode = gcodeGenerator.gcodeGenerator()
1488 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1489 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1496 gcode.addMove(w/2, 5)
1497 gcode.addMove(z=0.2)
1499 gcode.addExtrude(w/2, d-5.0)
1501 gcode.addMove(5, d/2)
1503 gcode.addExtrude(w-5.0, d/2)
1504 gcode.addRetract(15)
1507 gcode.addMove(w/2, 5)
1509 gcode.addExtrude(w/2, d-5.0)
1511 gcode.addMove(5, d/2)
1513 gcode.addExtrude(w-5.0, d/2)
1514 gcode.addRetract(15)
1519 gcode.addCmd('M400')
1521 self.comm.printGCode(gcode.list())
1522 self.resumeButton.Enable(False)
1523 elif self._wizardState == 4:
1525 float(self.textEntry.GetValue())
1528 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1529 self._wizardState = 5
1530 self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1531 self.textEntry.SetValue('0.0')
1532 self.textEntry.Enable(True)
1533 elif self._wizardState == 5:
1535 float(self.textEntry.GetValue())
1538 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1539 self._wizardState = 6
1540 self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1541 self.textEntry.SetValue('')
1542 self.textEntry.Enable(False)
1543 self.resumeButton.Enable(False)
1545 x = profile.getMachineSettingFloat('extruder_offset_x1')
1546 y = profile.getMachineSettingFloat('extruder_offset_y1')
1547 gcode = gcodeGenerator.gcodeGenerator()
1548 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1549 gcode.setPrintSpeed(25)
1552 gcode.addMove(50, 40, 0.2)
1554 for n in xrange(0, 10):
1555 gcode.addExtrude(50 + n * 10, 150)
1556 gcode.addExtrude(50 + n * 10 + 5, 150)
1557 gcode.addExtrude(50 + n * 10 + 5, 40)
1558 gcode.addExtrude(50 + n * 10 + 10, 40)
1559 gcode.addMove(40, 50)
1560 for n in xrange(0, 10):
1561 gcode.addExtrude(150, 50 + n * 10)
1562 gcode.addExtrude(150, 50 + n * 10 + 5)
1563 gcode.addExtrude(40, 50 + n * 10 + 5)
1564 gcode.addExtrude(40, 50 + n * 10 + 10)
1565 gcode.addRetract(15)
1568 gcode.addMove(50 - x, 30 - y, 0.2)
1570 for n in xrange(0, 10):
1571 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1572 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1573 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1574 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1575 gcode.addMove(30 - x, 50 - y, 0.2)
1576 for n in xrange(0, 10):
1577 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1578 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1579 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1580 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1581 gcode.addRetract(15)
1583 gcode.addCmd('M400')
1584 gcode.addCmd('M104 T0 S0')
1585 gcode.addCmd('M104 T1 S0')
1586 self.comm.printGCode(gcode.list())
1587 elif self._wizardState == 7:
1589 n = int(self.textEntry.GetValue()) - 1
1592 x = profile.getMachineSettingFloat('extruder_offset_x1')
1594 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1595 self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1596 self.textEntry.SetValue('10')
1597 self._wizardState = 8
1598 elif self._wizardState == 8:
1600 n = int(self.textEntry.GetValue()) - 1
1603 y = profile.getMachineSettingFloat('extruder_offset_y1')
1605 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1606 self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1607 self.infoBox.SetReadyIndicator()
1608 self._wizardState = 8
1610 self.resumeButton.Enable(False)
1612 def mcLog(self, message):
1613 print 'Log:', message
1615 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1616 if self._wizardState == 1:
1617 if temp[0] >= 210 and temp[1] >= 210:
1618 self._wizardState = 2
1619 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1620 wx.CallAfter(self.resumeButton.Enable, True)
1621 wx.CallAfter(self.resumeButton.SetFocus)
1623 def mcStateChange(self, state):
1624 if self.comm is None:
1626 if self.comm.isOperational():
1627 if self._wizardState == 0:
1628 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1629 self.comm.sendCommand('M105')
1630 self.comm.sendCommand('M104 S220 T0')
1631 self.comm.sendCommand('M104 S220 T1')
1632 self.comm.sendCommand('G28')
1633 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1634 self._wizardState = 1
1635 if not self.comm.isPrinting():
1636 if self._wizardState == 3:
1637 self._wizardState = 4
1638 wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1639 wx.CallAfter(self.textEntry.SetValue, '0.0')
1640 wx.CallAfter(self.textEntry.Enable, True)
1641 wx.CallAfter(self.resumeButton.Enable, True)
1642 wx.CallAfter(self.resumeButton.SetFocus)
1643 elif self._wizardState == 6:
1644 self._wizardState = 7
1645 wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1646 wx.CallAfter(self.textEntry.SetValue, '10')
1647 wx.CallAfter(self.textEntry.Enable, True)
1648 wx.CallAfter(self.resumeButton.Enable, True)
1649 wx.CallAfter(self.resumeButton.SetFocus)
1651 elif self.comm.isError():
1652 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1654 def mcMessage(self, message):
1657 def mcProgress(self, lineNr):
1660 def mcZChange(self, newZ):
1663 class bedLevelWizard(wx.wizard.Wizard):
1665 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1667 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1668 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1670 self.mainPage = bedLevelWizardMain(self)
1671 self.headOffsetCalibration = None
1673 self.RunWizard(self.mainPage)
1676 def OnPageChanging(self, e):
1677 e.GetPage().StoreData()
1679 def OnPageChanged(self, e):
1680 if e.GetPage().AllowNext():
1681 self.FindWindowById(wx.ID_FORWARD).Enable()
1683 self.FindWindowById(wx.ID_FORWARD).Disable()
1684 if e.GetPage().AllowBack():
1685 self.FindWindowById(wx.ID_BACKWARD).Enable()
1687 self.FindWindowById(wx.ID_BACKWARD).Disable()
1689 class headOffsetWizard(wx.wizard.Wizard):
1691 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1693 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1694 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1696 self.mainPage = headOffsetCalibrationPage(self)
1698 self.RunWizard(self.mainPage)
1701 def OnPageChanging(self, e):
1702 e.GetPage().StoreData()
1704 def OnPageChanged(self, e):
1705 if e.GetPage().AllowNext():
1706 self.FindWindowById(wx.ID_FORWARD).Enable()
1708 self.FindWindowById(wx.ID_FORWARD).Disable()
1709 if e.GetPage().AllowBack():
1710 self.FindWindowById(wx.ID_BACKWARD).Enable()
1712 self.FindWindowById(wx.ID_BACKWARD).Disable()