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)
109 class ImageButton(wx.Panel):
110 DefaultOverlay = wx.Bitmap(resources.getPathForImage('ImageButton_Overlay.png'))
113 __last_group__ = None
114 def __init__(self, parent, label, bitmap, extra_label=None, overlay=DefaultOverlay, style=None):
115 super(ImageButton, self).__init__(parent)
117 if style is ImageButton.IB_GROUP:
118 ImageButton.__last_group__ = self
119 ImageButton.__groups__[self] = [self]
122 if ImageButton.__last_group__:
123 ImageButton.__groups__[ImageButton.__last_group__].append(self)
124 self.group = ImageButton.__last_group__
127 self.sizer = wx.StaticBoxSizer(wx.StaticBox(self), wx.VERTICAL)
128 self.SetSizer(self.sizer)
130 self.original_overlay = overlay
131 self.overlay = self.createOverlay(bitmap, overlay)
132 self.text = wx.StaticText(self, -1, label)
133 self.bmp = wx.StaticBitmap(self, -1, self.bitmap)
135 self.extra_text = wx.StaticText(self, -1, extra_label)
137 self.extra_text = None
138 self.selected = False
141 self.sizer.Add(self.text, 0, flag=wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER, border=5)
142 self.sizer.Add(self.bmp, 1, flag=wx.ALL|wx.ALIGN_CENTER|wx.EXPAND, border=5)
144 self.sizer.Add(self.extra_text, 0, flag=wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER, border=5)
145 self.bmp.Bind(wx.EVT_LEFT_UP, self.OnLeftClick)
149 ImageButton.__groups__[self.group].remove(self)
150 if self == self.group:
151 for ib in ImageButton.__groups__[self.group]:
153 del ImageButton.__groups__[self.group]
154 if ImageButton.__last_group__ == self:
155 ImageButton.__last_group__ = None
157 def OnLeftClick(self, e):
163 def SetValue(self, value):
164 old_value = self.selected
165 self.selected = bool(value)
166 self.bmp.SetBitmap(self.overlay if self.GetValue() else self.bitmap)
167 if self.selected and self.group:
168 for ib in ImageButton.__groups__[self.group]:
173 if self.callback and not old_value and self.selected:
176 def SetLabel(self, label):
177 self.text.SetLabel(label)
180 def SetExtraLabel(self, label):
182 self.extra_text.SetLabel(label)
184 self.extra_text = wx.StaticText(self, -1, label)
185 self.sizer.Add(self.extra_text, 0, flag=wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER, border=5)
188 def SetBitmap(self, bitmap):
190 self.overlay = self.createOverlay(bitmap, self.original_overlay)
191 self.bmp.SetBitmap(self.overlay if self.GetValue() else self.bitmap)
194 def SetOverlay(self, overlay):
195 self.original_overlay = overlay
196 self.overlay = self.createOverlay(self.bitmap, self.original_overlay)
197 self.bmp.SetBitmap(self.overlay if self.GetValue() else self.bitmap)
200 def OnSelected(self, callback):
201 self.callback = callback
203 def createOverlay(self, bitmap, overlay):
204 result = bitmap.GetSubBitmap(wx.Rect(0, 0, *bitmap.Size))
205 (width, height) = bitmap.GetSize()
206 overlay_image = wx.ImageFromBitmap(overlay)
207 overlay_image = overlay_image.Scale(width, height, wx.IMAGE_QUALITY_HIGH)
208 overlay_scaled = wx.BitmapFromImage(overlay_image)
210 dc.SelectObject(result)
211 dc.DrawBitmap(overlay_scaled, 0, 0)
212 dc.SelectObject(wx.NullBitmap)
216 class InfoPage(wx.wizard.WizardPageSimple):
217 def __init__(self, parent, title):
218 wx.wizard.WizardPageSimple.__init__(self, parent)
220 parent.GetPageAreaSizer().Add(self)
221 sizer = wx.GridBagSizer(5, 5)
225 self.title = wx.StaticText(self, -1, title)
226 font = wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)
227 self.title.SetFont(font)
228 # HACK ALERT: For some reason, the StaticText keeps its same size as if
229 # the font was not modified, this causes the text to wrap and to
230 # get out of bounds of the widgets area and hide other widgets.
231 # The only way I found for the widget to get its right size was to calculate
232 # the new font's extent and set the min size on the widget
233 self.title.SetMinSize(self.GetTextExtent(font, title))
234 sizer.Add(self.title, pos=(0, 0), span=(1, 2), flag=wx.ALIGN_CENTRE | wx.ALL)
235 sizer.Add(wx.StaticLine(self, -1), pos=(1, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
236 sizer.AddGrowableCol(1)
240 def GetTextExtent(self, font, text):
243 w,h = dc.GetTextExtent(text)
246 def AddText(self, info):
247 text = wx.StaticText(self, -1, info)
248 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
252 def AddSeperator(self):
253 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
256 def AddHiddenSeperator(self):
259 def AddInfoBox(self):
260 infoBox = InfoBox(self)
261 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
265 def AddRadioButton(self, label, style=0):
266 radio = wx.RadioButton(self, -1, label, style=style)
267 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
271 def AddCheckbox(self, label, checked=False):
272 check = wx.CheckBox(self, -1)
273 text = wx.StaticText(self, -1, label)
274 check.SetValue(checked)
275 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
276 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 2), flag=wx.ALL)
280 def AddButton(self, label):
281 button = wx.Button(self, -1, label)
282 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
286 def AddDualButton(self, label1, label2):
287 button1 = wx.Button(self, -1, label1)
288 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
289 button2 = wx.Button(self, -1, label2)
290 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
292 return button1, button2
294 def AddTextCtrl(self, value):
295 ret = wx.TextCtrl(self, -1, value)
296 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
300 def AddLabelTextCtrl(self, info, value):
301 text = wx.StaticText(self, -1, info)
302 ret = wx.TextCtrl(self, -1, value)
303 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
304 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
308 def AddTextCtrlButton(self, value, buttonText):
309 text = wx.TextCtrl(self, -1, value)
310 button = wx.Button(self, -1, buttonText)
311 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
312 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
316 def AddBitmap(self, bitmap):
317 bitmap = wx.StaticBitmap(self, -1, bitmap)
318 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
323 panel = wx.Panel(self, -1)
324 sizer = wx.GridBagSizer(2, 2)
325 panel.SetSizer(sizer)
326 self.GetSizer().Add(panel, pos=(self.rowNr, 0), span=(1, 2), flag=wx.ALL | wx.EXPAND)
330 def AddCheckmark(self, label, bitmap):
331 check = wx.StaticBitmap(self, -1, bitmap)
332 text = wx.StaticText(self, -1, label)
333 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
334 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 1), flag=wx.ALL)
338 def AddCombo(self, label, options):
339 combo = wx.ComboBox(self, -1, options[0], choices=options, style=wx.CB_DROPDOWN|wx.CB_READONLY)
340 text = wx.StaticText(self, -1, label)
341 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER)
342 self.GetSizer().Add(combo, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
346 def AddImageButton(self, panel, x, y, label, filename, image_size=None,
347 extra_label=None, overlay=ImageButton.DefaultOverlay, style=None):
348 ib = ImageButton(panel, label, self.GetBitmap(filename, image_size), extra_label, overlay, style)
349 panel.GetSizer().Add(ib, pos=(x, y), flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=10)
352 def GetBitmap(self, filename, image_size):
353 if image_size == None:
354 return wx.Bitmap(resources.getPathForImage(filename))
356 image = wx.Image(resources.getPathForImage(filename))
357 image_scaled = image.Scale(image_size[0], image_size[1], wx.IMAGE_QUALITY_HIGH)
358 return wx.BitmapFromImage(image_scaled)
369 class PrintrbotPage(InfoPage):
370 def __init__(self, parent):
371 self._printer_info = [
372 # X, Y, Z, Nozzle Size, Filament Diameter, PrintTemperature, Print Speed, Travel Speed, Retract speed, Retract amount, use bed level sensor
373 ("Simple Metal", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, True),
374 ("Metal Plus", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
375 ("Simple Makers Kit", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, True),
376 (":" + _("Older models"),),
377 ("Original", 130, 130, 130, 0.5, 2.95, 208, 40, 70, 30, 1, False),
378 ("Simple Maker's Edition v1", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
379 ("Simple Maker's Edition v2 (2013 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
380 ("Simple Maker's Edition v3 (2014 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
381 ("Jr v1", 115, 120, 80, 0.4, 1.75, 208, 40, 70, 30, 1, False),
382 ("Jr v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
383 ("LC v1", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
384 ("LC v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
385 ("Plus v1", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
386 ("Plus v2", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
387 ("Plus v2.1", 185, 220, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
388 ("Plus v2.2 (Model 1404/140422/140501/140507)", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
389 ("Go v2 Large", 505, 306, 310, 0.4, 1.75, 208, 35, 70, 30, 1, True),
392 super(PrintrbotPage, self).__init__(parent, _("Printrbot Selection"))
393 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Printrbot_logo.png')))
394 self.AddText(_("Select which Printrbot machine you have:"))
396 for printer in self._printer_info:
397 if printer[0].startswith(":"):
399 self.AddText(printer[0][1:])
401 item = self.AddRadioButton(printer[0])
402 item.data = printer[1:]
403 self._items.append(item)
406 profile.putMachineSetting('machine_name', 'Printrbot ???')
407 for item in self._items:
410 profile.putMachineSetting('machine_name', 'Printrbot ' + item.GetLabel())
411 profile.putMachineSetting('machine_width', data[0])
412 profile.putMachineSetting('machine_depth', data[1])
413 profile.putMachineSetting('machine_height', data[2])
414 profile.putProfileSetting('nozzle_size', data[3])
415 profile.putProfileSetting('filament_diameter', data[4])
416 profile.putProfileSetting('print_temperature', data[5])
417 profile.putProfileSetting('print_speed', data[6])
418 profile.putProfileSetting('travel_speed', data[7])
419 profile.putProfileSetting('retraction_speed', data[8])
420 profile.putProfileSetting('retraction_amount', data[9])
421 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
422 profile.putMachineSetting('has_heated_bed', 'False')
423 profile.putMachineSetting('machine_center_is_zero', 'False')
424 profile.putMachineSetting('extruder_head_size_min_x', '0')
425 profile.putMachineSetting('extruder_head_size_min_y', '0')
426 profile.putMachineSetting('extruder_head_size_max_x', '0')
427 profile.putMachineSetting('extruder_head_size_max_y', '0')
428 profile.putMachineSetting('extruder_head_size_height', '0')
430 profile.setAlterationFile('start.gcode', """;Sliced at: {day} {date} {time}
431 ;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {fill_density}
432 ;Print time: {print_time}
433 ;Filament used: {filament_amount}m {filament_weight}g
434 ;Filament cost: {filament_cost}
435 ;M190 S{print_bed_temperature} ;Uncomment to add your own bed temperature line
436 ;M109 S{print_temperature} ;Uncomment to add your own temperature line
438 G90 ;absolute positioning
439 M82 ;set extruder to absolute mode
440 M107 ;start with the fan off
441 G28 X0 Y0 ;move X/Y to min endstops
442 G28 Z0 ;move Z to min endstops
443 G29 ;Run the auto bed leveling
444 G1 Z15.0 F{travel_speed} ;move the platform down 15mm
445 G92 E0 ;zero the extruded length
446 G1 F200 E3 ;extrude 3mm of feed stock
447 G92 E0 ;zero the extruded length again
449 ;Put printing message on LCD screen
453 class OtherMachineSelectPage(InfoPage):
454 def __init__(self, parent):
455 super(OtherMachineSelectPage, self).__init__(parent, _("Other machine information"))
456 self.AddText(_("The following pre-defined machine profiles are available"))
457 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."))
459 machines = resources.getDefaultMachineProfiles()
461 for filename in machines:
462 name = os.path.splitext(os.path.basename(filename))[0]
463 item = self.AddRadioButton(name)
464 item.filename = filename
465 item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
466 self.options.append(item)
468 item = self.AddRadioButton(_('Custom...'))
470 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
472 def OnProfileSelect(self, e):
473 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
475 def OnOtherSelect(self, e):
476 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
479 for option in self.options:
480 if option.GetValue():
481 profile.loadProfile(option.filename)
482 profile.loadMachineSettings(option.filename)
484 class OtherMachineInfoPage(InfoPage):
485 def __init__(self, parent):
486 super(OtherMachineInfoPage, self).__init__(parent, _("Cura Ready!"))
487 self.AddText(_("Cura is now ready to be used!"))
489 class CustomRepRapInfoPage(InfoPage):
490 def __init__(self, parent):
491 super(CustomRepRapInfoPage, self).__init__(parent, _("Custom RepRap information"))
492 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
493 self.AddText(_("Be sure to review the default profile before running it on your machine."))
494 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
496 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
498 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
499 self.machineWidth = self.AddLabelTextCtrl(_("Machine width X (mm)"), "80")
500 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth Y (mm)"), "80")
501 self.machineHeight = self.AddLabelTextCtrl(_("Machine height Z (mm)"), "55")
502 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
503 self.heatedBed = self.AddCheckbox(_("Heated bed"))
504 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
507 profile.putMachineSetting('machine_name', self.machineName.GetValue())
508 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
509 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
510 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
511 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
512 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
513 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
514 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
515 profile.putMachineSetting('extruder_head_size_min_x', '0')
516 profile.putMachineSetting('extruder_head_size_min_y', '0')
517 profile.putMachineSetting('extruder_head_size_max_x', '0')
518 profile.putMachineSetting('extruder_head_size_max_y', '0')
519 profile.putMachineSetting('extruder_head_size_height', '0')
520 profile.checkAndUpdateMachineName()
522 class MachineSelectPage(InfoPage):
523 def __init__(self, parent):
524 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
525 self.AddText(_("What kind of machine do you have:"))
527 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2")
528 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
529 self.Ultimaker2ExtRadio = self.AddRadioButton("Ultimaker2extended")
530 self.Ultimaker2ExtRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
531 self.Ultimaker2GoRadio = self.AddRadioButton("Ultimaker2go")
532 self.Ultimaker2GoRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
533 self.UltimakerRadio = self.AddRadioButton("Ultimaker Original")
534 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
535 self.UltimakerOPRadio = self.AddRadioButton("Ultimaker Original+")
536 self.UltimakerOPRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerOPSelect)
537 self.PrintrbotRadio = self.AddRadioButton("Printrbot")
538 self.PrintrbotRadio.Bind(wx.EVT_RADIOBUTTON, self.OnPrintrbotSelect)
539 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot, Witbox)"))
540 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
542 def OnUltimaker2Select(self, e):
543 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
545 def OnUltimakerSelect(self, e):
546 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
548 def OnUltimakerOPSelect(self, e):
549 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)
551 def OnPrintrbotSelect(self, e):
552 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().printrbotSelectType)
554 def OnOtherSelect(self, e):
555 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
558 profile.putProfileSetting('retraction_enable', 'True')
559 if self.Ultimaker2Radio.GetValue() or self.Ultimaker2GoRadio.GetValue() or self.Ultimaker2ExtRadio.GetValue():
560 if self.Ultimaker2Radio.GetValue():
561 profile.putMachineSetting('machine_width', '230')
562 profile.putMachineSetting('machine_depth', '225')
563 profile.putMachineSetting('machine_height', '205')
564 profile.putMachineSetting('machine_name', 'ultimaker2')
565 profile.putMachineSetting('machine_type', 'ultimaker2')
566 profile.putMachineSetting('has_heated_bed', 'True')
567 if self.Ultimaker2GoRadio.GetValue():
568 profile.putMachineSetting('machine_width', '120')
569 profile.putMachineSetting('machine_depth', '120')
570 profile.putMachineSetting('machine_height', '115')
571 profile.putMachineSetting('machine_name', 'ultimaker2go')
572 profile.putMachineSetting('machine_type', 'ultimaker2go')
573 profile.putMachineSetting('has_heated_bed', 'False')
574 if self.Ultimaker2ExtRadio.GetValue():
575 profile.putMachineSetting('machine_width', '230')
576 profile.putMachineSetting('machine_depth', '225')
577 profile.putMachineSetting('machine_height', '315')
578 profile.putMachineSetting('machine_name', 'ultimaker2extended')
579 profile.putMachineSetting('machine_type', 'ultimaker2extended')
580 profile.putMachineSetting('has_heated_bed', 'False')
581 profile.putMachineSetting('machine_center_is_zero', 'False')
582 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
583 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
584 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
585 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
586 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
587 profile.putMachineSetting('extruder_head_size_height', '48.0')
588 profile.putProfileSetting('nozzle_size', '0.4')
589 profile.putProfileSetting('fan_full_height', '5.0')
590 profile.putMachineSetting('extruder_offset_x1', '18.0')
591 profile.putMachineSetting('extruder_offset_y1', '0.0')
592 elif self.UltimakerRadio.GetValue():
593 profile.putMachineSetting('machine_width', '205')
594 profile.putMachineSetting('machine_depth', '205')
595 profile.putMachineSetting('machine_height', '200')
596 profile.putMachineSetting('machine_name', 'ultimaker original')
597 profile.putMachineSetting('machine_type', 'ultimaker')
598 profile.putMachineSetting('machine_center_is_zero', 'False')
599 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
600 profile.putProfileSetting('nozzle_size', '0.4')
601 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
602 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
603 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
604 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
605 profile.putMachineSetting('extruder_head_size_height', '55.0')
606 elif self.UltimakerOPRadio.GetValue():
607 profile.putMachineSetting('machine_width', '205')
608 profile.putMachineSetting('machine_depth', '205')
609 profile.putMachineSetting('machine_height', '200')
610 profile.putMachineSetting('machine_name', 'ultimaker original+')
611 profile.putMachineSetting('machine_type', 'ultimaker_plus')
612 profile.putMachineSetting('machine_center_is_zero', 'False')
613 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
614 profile.putProfileSetting('nozzle_size', '0.4')
615 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
616 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
617 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
618 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
619 profile.putMachineSetting('extruder_head_size_height', '55.0')
620 profile.putMachineSetting('has_heated_bed', 'True')
621 profile.putMachineSetting('extruder_amount', '1')
622 profile.putProfileSetting('retraction_enable', 'True')
624 profile.putMachineSetting('machine_width', '80')
625 profile.putMachineSetting('machine_depth', '80')
626 profile.putMachineSetting('machine_height', '60')
627 profile.putMachineSetting('machine_name', 'reprap')
628 profile.putMachineSetting('machine_type', 'reprap')
629 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
630 profile.putPreference('startMode', 'Normal')
631 profile.putProfileSetting('nozzle_size', '0.5')
632 profile.checkAndUpdateMachineName()
633 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
635 class SelectParts(InfoPage):
636 def __init__(self, parent):
637 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
638 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."))
640 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
641 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
642 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
643 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
645 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."))
646 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
647 self.springExtruder.SetValue(True)
650 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
651 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
652 profile.putMachineSetting('has_heated_bed', 'True')
654 profile.putMachineSetting('has_heated_bed', 'False')
655 if self.dualExtrusion.GetValue():
656 profile.putMachineSetting('extruder_amount', '2')
657 profile.putMachineSetting('machine_depth', '195')
659 profile.putMachineSetting('extruder_amount', '1')
660 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
661 profile.putProfileSetting('retraction_enable', 'True')
663 profile.putProfileSetting('retraction_enable', 'False')
666 class UltimakerFirmwareUpgradePage(InfoPage):
667 def __init__(self, parent):
668 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
669 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."))
670 self.AddHiddenSeperator()
671 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
672 self.AddHiddenSeperator()
673 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."))
674 upgradeButton, skipUpgradeButton = self.AddDualButton(_('Upgrade to Marlin firmware'), _('Skip upgrade'))
675 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
676 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
677 self.AddHiddenSeperator()
678 if profile.getMachineSetting('machine_type') == 'ultimaker':
679 self.AddText(_("Do not upgrade to this firmware if:"))
680 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
681 self.AddText(_("* Build your own heated bed"))
682 self.AddText(_("* Have other changes in the firmware"))
683 # button = self.AddButton('Goto this page for a custom firmware')
684 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
689 def OnUpgradeClick(self, e):
690 if firmwareInstall.InstallFirmware():
691 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
693 def OnSkipClick(self, e):
694 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
695 self.GetParent().ShowPage(self.GetNext())
697 def OnUrlClick(self, e):
698 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
700 class UltimakerCheckupPage(InfoPage):
701 def __init__(self, parent):
702 super(UltimakerCheckupPage, self).__init__(parent, _("Ultimaker Checkup"))
704 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
705 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
706 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
707 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
708 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
709 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
710 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
711 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
712 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
713 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
716 _("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."))
717 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
718 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
719 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
721 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
722 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
723 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
725 self.infoBox = self.AddInfoBox()
726 self.machineState = self.AddText("")
727 self.temperatureLabel = self.AddText("")
728 self.errorLogButton = self.AddButton(_("Show error log"))
729 self.errorLogButton.Show(False)
731 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
733 self.xMinStop = False
734 self.xMaxStop = False
735 self.yMinStop = False
736 self.yMaxStop = False
737 self.zMinStop = False
738 self.zMaxStop = False
740 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
743 if self.comm is not None:
747 self.endstopBitmap.Show(False)
750 def OnSkipClick(self, e):
751 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
752 self.GetParent().ShowPage(self.GetNext())
754 def OnCheckClick(self, e=None):
755 self.errorLogButton.Show(False)
756 if self.comm is not None:
760 wx.CallAfter(self.OnCheckClick)
762 self.infoBox.SetBusy(_("Connecting to machine."))
763 self.commState.SetBitmap(self.unknownBitmap)
764 self.tempState.SetBitmap(self.unknownBitmap)
765 self.stopState.SetBitmap(self.unknownBitmap)
766 self.checkupState = 0
767 self.checkExtruderNr = 0
768 self.comm = machineCom.MachineCom(callbackObject=self)
770 def OnErrorLog(self, e):
771 printWindow.LogWindow('\n'.join(self.comm.getLog()))
773 def mcLog(self, message):
776 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
777 if not self.comm.isOperational():
779 if self.checkupState == 0:
780 self.tempCheckTimeout = 20
781 if temp[self.checkExtruderNr] > 70:
782 self.checkupState = 1
783 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
784 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
785 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
787 self.startTemp = temp[self.checkExtruderNr]
788 self.checkupState = 2
789 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
790 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
791 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
792 elif self.checkupState == 1:
793 if temp[self.checkExtruderNr] < 60:
794 self.startTemp = temp[self.checkExtruderNr]
795 self.checkupState = 2
796 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
797 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
798 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
799 elif self.checkupState == 2:
800 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
801 if temp[self.checkExtruderNr] > self.startTemp + 40:
802 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
803 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
804 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
805 self.checkExtruderNr = 0
806 self.checkupState = 3
807 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
808 wx.CallAfter(self.endstopBitmap.Show, True)
809 wx.CallAfter(self.Layout)
810 self.comm.sendCommand('M119')
811 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
813 self.checkupState = 0
814 self.checkExtruderNr += 1
816 self.tempCheckTimeout -= 1
817 if self.tempCheckTimeout < 1:
818 self.checkupState = -1
819 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
820 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
821 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
822 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
823 elif self.checkupState >= 3 and self.checkupState < 10:
824 self.comm.sendCommand('M119')
825 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
827 def mcStateChange(self, state):
828 if self.comm is None:
830 if self.comm.isOperational():
831 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
832 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
833 elif self.comm.isError():
834 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
835 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
836 wx.CallAfter(self.endstopBitmap.Show, False)
837 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
838 wx.CallAfter(self.errorLogButton.Show, True)
839 wx.CallAfter(self.Layout)
841 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
843 def mcMessage(self, message):
844 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
845 for data in message.split(' '):
847 tag, value = data.split(':', 1)
849 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
851 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
853 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
855 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
857 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
859 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
861 tag, value = map(str.strip, message.split(':', 1))
863 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
865 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
867 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
869 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
871 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
873 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
874 if 'z_max' in message:
875 self.comm.sendCommand('M119')
877 if self.checkupState == 3:
878 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
879 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
880 self.checkupState = 5
881 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
882 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
884 self.checkupState = 4
885 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
886 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
887 elif self.checkupState == 4:
888 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
889 self.checkupState = 5
890 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
891 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
892 elif self.checkupState == 5:
893 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
894 self.checkupState = 6
895 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
896 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
897 elif self.checkupState == 6:
898 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
899 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
900 self.checkupState = 8
901 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
902 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
904 self.checkupState = 7
905 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
906 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
907 elif self.checkupState == 7:
908 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
909 self.checkupState = 8
910 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
911 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
912 elif self.checkupState == 8:
913 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
914 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
915 self.checkupState = 10
917 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
918 wx.CallAfter(self.infoBox.SetReadyIndicator)
919 wx.CallAfter(self.endstopBitmap.Show, False)
920 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
921 wx.CallAfter(self.OnSkipClick, None)
923 self.checkupState = 9
924 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
925 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
926 elif self.checkupState == 9:
927 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
928 self.checkupState = 10
930 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
931 wx.CallAfter(self.infoBox.SetReadyIndicator)
932 wx.CallAfter(self.endstopBitmap.Show, False)
933 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
934 wx.CallAfter(self.OnSkipClick, None)
936 def mcProgress(self, lineNr):
939 def mcZChange(self, newZ):
943 class UltimakerCalibrationPage(InfoPage):
944 def __init__(self, parent):
945 super(UltimakerCalibrationPage, self).__init__(parent, _("Ultimaker Calibration"))
947 self.AddText("Your Ultimaker requires some calibration.")
948 self.AddText("This calibration is needed for a proper extrusion amount.")
950 self.AddText("The following values are needed:")
951 self.AddText("* Diameter of filament")
952 self.AddText("* Number of steps per mm of filament extrusion")
954 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
956 self.AddText("First we need the diameter of your filament:")
957 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
959 "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.")
960 self.AddText("Note: This value can be changed later at any time.")
963 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
966 class UltimakerCalibrateStepsPerEPage(InfoPage):
967 def __init__(self, parent):
968 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, _("Ultimaker Calibration"))
970 #if profile.getMachineSetting('steps_per_e') == '0':
971 # profile.putMachineSetting('steps_per_e', '865.888')
973 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
974 self.AddText(_("First remove any filament from your machine."))
975 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
976 self.AddText(_("We'll push the filament 100mm"))
977 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
978 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
979 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
980 self.AddText(_("This results in the following steps per E:"))
981 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
982 self.AddText(_("You can repeat these steps to get better calibration."))
985 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
986 self.heatButton = self.AddButton(_("Heatup for filament removal"))
988 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
989 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
990 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
992 def OnSaveLengthClick(self, e):
993 currentEValue = float(self.stepsPerEInput.GetValue())
994 realExtrudeLength = float(self.lengthInput.GetValue())
995 newEValue = currentEValue * 100 / realExtrudeLength
996 self.stepsPerEInput.SetValue(str(newEValue))
997 self.lengthInput.SetValue("100")
999 def OnExtrudeClick(self, e):
1000 t = threading.Thread(target=self.OnExtrudeRun)
1004 def OnExtrudeRun(self):
1005 self.heatButton.Enable(False)
1006 self.extrudeButton.Enable(False)
1007 currentEValue = float(self.stepsPerEInput.GetValue())
1008 self.comm = machineCom.MachineCom()
1009 if not self.comm.isOpen():
1011 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
1012 'Printer error', wx.OK | wx.ICON_INFORMATION)
1013 self.heatButton.Enable(True)
1014 self.extrudeButton.Enable(True)
1017 line = self.comm.readline()
1022 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
1025 self.sendGCommand('M302') #Disable cold extrusion protection
1026 self.sendGCommand("M92 E%f" % (currentEValue))
1027 self.sendGCommand("G92 E0")
1028 self.sendGCommand("G1 E100 F600")
1031 self.extrudeButton.Enable()
1032 self.heatButton.Enable()
1034 def OnHeatClick(self, e):
1035 t = threading.Thread(target=self.OnHeatRun)
1039 def OnHeatRun(self):
1040 self.heatButton.Enable(False)
1041 self.extrudeButton.Enable(False)
1042 self.comm = machineCom.MachineCom()
1043 if not self.comm.isOpen():
1045 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
1046 'Printer error', wx.OK | wx.ICON_INFORMATION)
1047 self.heatButton.Enable(True)
1048 self.extrudeButton.Enable(True)
1051 line = self.comm.readline()
1053 self.heatButton.Enable(True)
1054 self.extrudeButton.Enable(True)
1058 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
1061 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
1063 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
1064 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
1065 self.sendGCommand('M104 S0')
1068 self.heatButton.Enable(True)
1069 self.extrudeButton.Enable(True)
1071 def sendGCommand(self, cmd):
1072 self.comm.sendCommand(cmd) #Disable cold extrusion protection
1074 line = self.comm.readline()
1077 if line.startswith('ok'):
1080 def StoreData(self):
1081 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
1083 class Ultimaker2ReadyPage(InfoPage):
1084 def __init__(self, parent):
1085 super(Ultimaker2ReadyPage, self).__init__(parent, _("Ultimaker2"))
1086 self.AddText(_('Congratulations on your the purchase of your brand new Ultimaker2.'))
1087 self.AddText(_('Cura is now ready to be used with your Ultimaker2.'))
1090 class LulzbotMachineSelectPage(InfoPage):
1094 def __init__(self, parent):
1095 super(LulzbotMachineSelectPage, self).__init__(parent, _("Select your machine"))
1096 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Lulzbot_logo.png')))
1097 self.AddText(_("Select your printer :"))
1099 self.panel = self.AddPanel()
1101 image_size=(LulzbotMachineSelectPage.IMAGE_WIDTH, LulzbotMachineSelectPage.IMAGE_HEIGHT)
1102 self.LulzbotMini = self.AddImageButton(self.panel, 0, 0, _("LulzBot Mini"),
1103 'Lulzbot_mini.jpg', image_size, style=ImageButton.IB_GROUP)
1104 self.LulzbotMini.OnSelected(self.OnLulzbotMiniSelected)
1105 self.LulzbotMini.SetValue(True)
1106 self.LulzbotTaz5 = self.AddImageButton(self.panel, 0, 1, _("LulzBot TAZ 5"),
1107 'Lulzbot_TAZ5.jpg', image_size)
1108 self.LulzbotTaz5.OnSelected(self.OnLulzbotTazSelected)
1109 self.LulzbotTaz4 = self.AddImageButton(self.panel, 1, 0, _("LulzBot TAZ 4"),
1110 'Lulzbot_TAZ4.jpg', image_size)
1111 self.LulzbotTaz4.OnSelected(self.OnLulzbotTazSelected)
1112 self.OtherPrinters = self.AddImageButton(self.panel, 1, 1, _("Other Printers"),
1113 'Other_Printers.jpg', image_size)
1114 self.OtherPrinters.OnSelected(self.OnOthersSelected)
1116 def OnOthersSelected(self):
1117 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().machineSelectPage)
1119 def OnLulzbotMiniSelected(self):
1120 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotMiniToolheadPage)
1121 wx.wizard.WizardPageSimple.Chain(self.GetParent().lulzbotMiniToolheadPage,
1122 self.GetParent().lulzbotReadyPage)
1124 def OnLulzbotTazSelected(self):
1125 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotTazHotendPage)
1127 def AllowNext(self):
1130 def AllowBack(self):
1133 def StoreData(self):
1134 if self.LulzbotTaz4.GetValue() or self.LulzbotTaz5.GetValue() or self.LulzbotMini.GetValue():
1135 if self.LulzbotTaz4.GetValue():
1136 # Nozzle size will be set in the toolhead selection page
1137 # We set the machine_type here so later pages can differenciate between TAZ 4 and 5
1138 profile.putMachineSetting('machine_width', '290')
1139 profile.putMachineSetting('machine_depth', '275')
1140 profile.putMachineSetting('machine_height', '250')
1141 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_4')
1142 profile.putMachineSetting('serial_baud', '115200')
1143 elif self.LulzbotTaz5.GetValue():
1144 # Nozzle size will be set in the toolhead selection page
1145 # We set the machine_type here so later pages can differenciate between TAZ 4 and 5
1146 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5')
1147 profile.putMachineSetting('machine_width', '290')
1148 profile.putMachineSetting('machine_depth', '275')
1149 profile.putMachineSetting('machine_height', '250')
1150 profile.putMachineSetting('serial_baud', '115200')
1152 # Nozzle size and machine name/type will be set in the toolhead selection page
1153 profile.putMachineSetting('machine_width', '155')
1154 profile.putMachineSetting('machine_depth', '155')
1155 profile.putMachineSetting('machine_height', '163')
1156 profile.putMachineSetting('serial_baud', '115200')
1157 profile.putMachineSetting('extruder_head_size_min_x', '40')
1158 profile.putMachineSetting('extruder_head_size_max_x', '75')
1159 profile.putMachineSetting('extruder_head_size_min_y', '25')
1160 profile.putMachineSetting('extruder_head_size_max_y', '55')
1161 profile.putMachineSetting('extruder_head_size_height', '17')
1163 profile.putMachineSetting('machine_center_is_zero', 'False')
1164 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
1165 profile.putMachineSetting('has_heated_bed', 'True')
1166 profile.putMachineSetting('extruder_head_size_min_x', '0.0')
1167 profile.putMachineSetting('extruder_head_size_min_y', '0.0')
1168 profile.putMachineSetting('extruder_head_size_max_x', '0.0')
1169 profile.putMachineSetting('extruder_head_size_max_y', '0.0')
1170 profile.putMachineSetting('extruder_head_size_height', '0.0')
1171 profile.putProfileSetting('retraction_enable', 'True')
1172 profile.putPreference('startMode', 'Simple')
1173 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
1174 profile.checkAndUpdateMachineName()
1176 class LulzbotReadyPage(InfoPage):
1177 def __init__(self, parent):
1178 super(LulzbotReadyPage, self).__init__(parent, _("LulzBot TAZ/Mini"))
1179 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Lulzbot_logo.png')))
1180 self.AddText(_('Cura is now ready to be used with your LulzBot 3D printer.'))
1182 self.AddText(_('For more information about using Cura with your LulzBot'))
1183 self.AddText(_('3D printer, please visit www.LulzBot.com/cura'))
1186 class LulzbotToolheadSelectPage(InfoPage):
1187 url='http://lulzbot.com/toolhead-identification'
1189 def __init__(self, parent, title):
1190 super(LulzbotToolheadSelectPage, self).__init__(parent, title)
1192 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Lulzbot_logo.png')))
1194 self.AddText(_('Please select your currently installed Tool Head'))
1195 txt = self.AddText(_('WARNING: Carefully select the right Tool Head.\nFlashing the firmware with the wrong Tool Head can damage your LulzBot printer. Learn more here :'))
1196 txt.SetForegroundColour(wx.RED)
1197 button = self.AddButton(self.url)
1198 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1202 def OnUrlClick(self, e):
1203 webbrowser.open(LulzbotMiniToolheadSelectPage.url)
1205 class LulzbotMiniToolheadSelectPage(LulzbotToolheadSelectPage):
1206 def __init__(self, parent):
1207 super(LulzbotMiniToolheadSelectPage, self).__init__(parent, _("LulzBot Mini Toolhead Selection"))
1209 self.panel = self.AddPanel()
1210 image_size=(LulzbotMachineSelectPage.IMAGE_WIDTH, LulzbotMachineSelectPage.IMAGE_HEIGHT)
1211 self.standard = self.AddImageButton(self.panel, 0, 0, _('Single Extruder v2'),
1212 'Lulzbot_Toolhead_Mini_Standard.jpg', image_size,
1213 style=ImageButton.IB_GROUP)
1214 self.flexy = self.AddImageButton(self.panel, 0, 1, _('Flexystruder v2'),
1215 'Lulzbot_Toolhead_Mini_Flexystruder.jpg', image_size)
1216 self.standard.SetValue(True)
1218 def StoreData(self):
1219 if self.standard.GetValue():
1220 profile.putProfileSetting('nozzle_size', '0.5')
1221 profile.putMachineSetting('extruder_amount', '1')
1222 profile.putMachineSetting('toolhead', 'Single Extruder V2')
1223 profile.putMachineSetting('machine_name', 'LulzBot Mini')
1224 profile.putMachineSetting('machine_type', 'lulzbot_mini')
1226 profile.putProfileSetting('nozzle_size', '0.6')
1227 profile.putMachineSetting('extruder_amount', '1')
1228 profile.putMachineSetting('toolhead', 'Flexystruder V2')
1229 profile.putMachineSetting('machine_name', 'LulzBot Mini (Flexy)')
1230 profile.putMachineSetting('machine_type', 'lulzbot_mini_flexy')
1233 class LulzbotTazToolheadSelectPage(LulzbotToolheadSelectPage):
1234 def __init__(self, parent):
1235 super(LulzbotTazToolheadSelectPage, self).__init__(parent, _("LulzBot TAZ Toolhead Selection"))
1237 self.panel = self.AddPanel()
1238 image_size=(LulzbotMachineSelectPage.IMAGE_WIDTH, LulzbotMachineSelectPage.IMAGE_HEIGHT)
1239 self.single = self.AddImageButton(self.panel, 0, 0, _('Single Extruder v1'),
1240 'Lulzbot_Toolhead_TAZ_Single_v1.jpg', image_size,
1241 style=ImageButton.IB_GROUP)
1242 self.flexy = self.AddImageButton(self.panel, 0, 1, _('Flexystruder v1'),
1243 'Lulzbot_Toolhead_TAZ_Flexystruder_v1.jpg', image_size)
1244 self.dually = self.AddImageButton(self.panel, 1, 0, _('Dual Extruder v1'),
1245 'Lulzbot_Toolhead_TAZ_Dually_v1.jpg', image_size)
1246 self.flexydually = self.AddImageButton(self.panel, 1, 1, _('FlexyDually v1'),
1247 'Lulzbot_Toolhead_TAZ_FlexyDually_v1.jpg', image_size)
1249 self.single.SetValue(True)
1251 def SetVersion(self, version):
1252 image_size=(LulzbotMachineSelectPage.IMAGE_WIDTH, LulzbotMachineSelectPage.IMAGE_HEIGHT)
1253 self.single.SetBitmap(self.GetBitmap('Lulzbot_Toolhead_TAZ_Single_v%d.jpg' % version, image_size))
1254 self.single.SetLabel(_('Single Extruder v%d' % version))
1255 self.flexy.SetBitmap(self.GetBitmap('Lulzbot_Toolhead_TAZ_Flexystruder_v%d.jpg' % version, image_size))
1256 self.flexy.SetLabel(_('Flexystruder v%d' % version))
1257 self.dually.SetBitmap(self.GetBitmap('Lulzbot_Toolhead_TAZ_Dually_v%d.jpg' % version, image_size))
1258 self.dually.SetLabel(_('Dual Extruder v%d' % version))
1259 self.flexydually.SetBitmap(self.GetBitmap('Lulzbot_Toolhead_TAZ_FlexyDually_v%d.jpg' % version, image_size))
1260 self.flexydually.SetLabel(_('FlexyDually v%d' % version))
1261 self.version = version
1263 self.single.OnSelected(None)
1264 self.flexy.OnSelected(None)
1265 self.dually.OnSelected(None)
1266 self.flexydually.OnSelected(None)
1267 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
1269 self.single.OnSelected(self.OnSingleV2)
1270 self.flexy.OnSelected(self.OnNonSingle)
1271 self.dually.OnSelected(self.OnNonSingle)
1272 self.flexydually.OnSelected(self.OnNonSingle)
1273 if self.single.GetValue():
1274 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotTaz5NozzleSelectPage)
1275 wx.wizard.WizardPageSimple.Chain(self.GetParent().lulzbotTaz5NozzleSelectPage, self.GetParent().lulzbotReadyPage)
1277 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
1279 def OnSingleV2(self):
1280 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotTaz5NozzleSelectPage)
1281 wx.wizard.WizardPageSimple.Chain(self.GetParent().lulzbotTaz5NozzleSelectPage, self.GetParent().lulzbotReadyPage)
1283 def OnNonSingle(self):
1284 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
1286 def StoreData(self):
1287 if profile.getMachineSetting('machine_type').startswith('lulzbot_TAZ_4'):
1291 version = (taz_version, self.version)
1292 if self.single.GetValue():
1293 profile.putProfileSetting('nozzle_size', '0.5' if self.version == 2 else '0.35')
1294 profile.putMachineSetting('extruder_amount', '1')
1295 profile.putMachineSetting('toolhead', 'Single Extruder V%d' % self.version)
1296 profile.putMachineSetting('machine_name', 'LulzBot TAZ %d' % taz_version)
1297 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_%d_SingleV%d' % version)
1298 elif self.flexy.GetValue():
1299 profile.putProfileSetting('nozzle_size', '0.6')
1300 profile.putMachineSetting('extruder_amount', '1')
1301 profile.putMachineSetting('toolhead', 'Flexystruder V%d' % self.version)
1302 profile.putMachineSetting('machine_name', 'LulzBot TAZ %d (Flexy v%d)' % version)
1303 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_%d_flexyV%d' % version)
1304 elif self.dually.GetValue():
1305 profile.putMachineSetting('extruder_amount', '2')
1306 profile.putProfileSetting('nozzle_size', '0.5')
1307 profile.putMachineSetting('toolhead', 'Dual Extruder V%d' % self.version)
1308 profile.putMachineSetting('machine_name', 'LulzBot TAZ %d (Dually v%d)' % version)
1309 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_%d_DuallyV%d' % version)
1310 elif self.flexydually.GetValue():
1311 profile.putProfileSetting('nozzle_size', '0.6')
1312 profile.putMachineSetting('extruder_amount', '2')
1313 profile.putMachineSetting('toolhead', 'FlexyDually V%d' % self.version)
1314 profile.putMachineSetting('machine_name', 'LulzBot TAZ %d (FlexyDually v%d)' % version)
1315 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_%d_FlexyDuallyV%d' % version)
1318 class LulzbotHotendSelectPage(LulzbotToolheadSelectPage):
1319 def __init__(self, parent):
1320 super(LulzbotHotendSelectPage, self).__init__(parent, _("LulzBot Toolhead Hotend Selection"))
1322 self.panel = self.AddPanel()
1323 image_size=(LulzbotMachineSelectPage.IMAGE_WIDTH, LulzbotMachineSelectPage.IMAGE_HEIGHT)
1324 self.v1 = self.AddImageButton(self.panel, 0, 0, _('v1 (Budaschnozzle Hotends)'),
1325 'Lulzbot_Toolhead_v1.jpg', image_size,
1326 style=ImageButton.IB_GROUP)
1327 self.v2 = self.AddImageButton(self.panel, 0, 1, _('v2 (Hexagon Hotends)'),
1328 'Lulzbot_Toolhead_v2.jpg', image_size)
1329 self.v1.SetValue(True)
1331 def StoreData(self):
1332 self.GetParent().lulzbotTazToolheadPage.SetVersion(1 if self.v1.GetValue() else 2)
1335 class LulzbotTaz5NozzleSelectPage(LulzbotToolheadSelectPage):
1336 url2='http://lulzbot.com/printer-identification'
1338 def __init__(self, parent):
1339 super(LulzbotTaz5NozzleSelectPage, self).__init__(parent, _("LulzBot TAZ Single V2 Nozzle Selection"))
1341 self.AddText(_('Please select your Hexagon hotend\'s nozzle size:'))
1342 self.Nozzle35Radio = self.AddRadioButton("0.35 mm", style=wx.RB_GROUP)
1343 self.Nozzle35Radio.SetValue(True)
1344 self.Nozzle50Radio = self.AddRadioButton("0.5 mm")
1345 self.AddText(_(' '))
1348 self.AddText(_('If you are not sure which nozzle size you have'))
1349 self.AddText(_('please check this webpage: '))
1350 button = self.AddButton(LulzbotTaz5NozzleSelectPage.url2)
1351 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1353 def OnUrlClick(self, e):
1354 webbrowser.open(LulzbotTaz5NozzleSelectPage.url2)
1356 def StoreData(self):
1357 if self.Nozzle35Radio.GetValue():
1358 profile.putProfileSetting('nozzle_size', '0.35')
1359 profile.putMachineSetting('toolhead', 'Single Extruder V2 (0.35 nozzle)')
1360 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.35 nozzle)')
1361 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5_035nozzle')
1364 profile.putProfileSetting('nozzle_size', '0.5')
1365 profile.putMachineSetting('toolhead', 'Single Extruder V2 (0.5 nozzle)')
1366 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.5 nozzle)')
1367 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5_05nozzle')
1369 class ConfigWizard(wx.wizard.Wizard):
1370 def __init__(self, addNew = False):
1371 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
1373 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1375 profile.setActiveMachine(profile.getMachineCount())
1377 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1378 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1379 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1381 self.machineSelectPage = MachineSelectPage(self)
1382 self.ultimakerSelectParts = SelectParts(self)
1383 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
1384 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
1385 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
1386 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
1387 self.bedLevelPage = bedLevelWizardMain(self)
1388 self.headOffsetCalibration = headOffsetCalibrationPage(self)
1389 self.printrbotSelectType = PrintrbotPage(self)
1390 self.otherMachineSelectPage = OtherMachineSelectPage(self)
1391 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
1392 self.otherMachineInfoPage = OtherMachineInfoPage(self)
1394 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
1395 self.lulzbotReadyPage = LulzbotReadyPage(self)
1396 self.lulzbotMiniToolheadPage = LulzbotMiniToolheadSelectPage(self)
1397 self.lulzbotTazToolheadPage = LulzbotTazToolheadSelectPage(self)
1398 self.lulzbotTazHotendPage = LulzbotHotendSelectPage(self)
1399 self.lulzbotTaz5NozzleSelectPage = LulzbotTaz5NozzleSelectPage(self)
1400 self.lulzbotMachineSelectPage = LulzbotMachineSelectPage(self)
1402 wx.wizard.WizardPageSimple.Chain(self.lulzbotMachineSelectPage, self.lulzbotMiniToolheadPage)
1403 wx.wizard.WizardPageSimple.Chain(self.lulzbotMiniToolheadPage, self.lulzbotReadyPage)
1404 wx.wizard.WizardPageSimple.Chain(self.lulzbotTazHotendPage, self.lulzbotTazToolheadPage)
1405 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
1406 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
1407 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
1408 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
1409 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
1410 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
1412 self.RunWizard(self.lulzbotMachineSelectPage)
1415 def OnPageChanging(self, e):
1416 e.GetPage().StoreData()
1418 def OnPageChanged(self, e):
1419 if e.GetPage().AllowNext():
1420 self.FindWindowById(wx.ID_FORWARD).Enable()
1422 self.FindWindowById(wx.ID_FORWARD).Disable()
1423 if e.GetPage().AllowBack():
1424 self.FindWindowById(wx.ID_BACKWARD).Enable()
1426 self.FindWindowById(wx.ID_BACKWARD).Disable()
1428 def OnCancel(self, e):
1429 new_machine_index = int(profile.getPreferenceFloat('active_machine'))
1430 profile.setActiveMachine(self._old_machine_index)
1431 profile.removeMachine(new_machine_index)
1433 class bedLevelWizardMain(InfoPage):
1434 def __init__(self, parent):
1435 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1437 self.AddText(_('This wizard will help you in leveling your printer bed'))
1439 self.AddText(_('It will do the following steps'))
1440 self.AddText(_('* Move the printer head to each corner'))
1441 self.AddText(_(' and let you adjust the height of the bed to the nozzle'))
1442 self.AddText(_('* Print a line around the bed to check if it is level'))
1445 self.connectButton = self.AddButton(_('Connect to printer'))
1448 self.infoBox = self.AddInfoBox()
1449 self.resumeButton = self.AddButton(_('Resume'))
1450 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1451 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1452 self.resumeButton.Enable(False)
1454 self.upButton.Enable(False)
1455 self.downButton.Enable(False)
1456 self.upButton2.Enable(False)
1457 self.downButton2.Enable(False)
1459 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1460 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1461 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1462 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1463 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1464 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1466 def OnConnect(self, e = None):
1467 if self.comm is not None:
1471 wx.CallAfter(self.OnConnect)
1473 self.connectButton.Enable(False)
1474 self.comm = machineCom.MachineCom(callbackObject=self)
1475 self.infoBox.SetBusy(_('Connecting to machine.'))
1476 self._wizardState = 0
1478 def OnBedUp(self, e):
1479 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1480 self.comm.sendCommand('G92 Z10')
1481 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1482 self.comm.sendCommand('M400')
1484 def OnBedDown(self, e):
1485 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1486 self.comm.sendCommand('G92 Z10')
1487 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1488 self.comm.sendCommand('M400')
1490 def OnBedUp2(self, e):
1491 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1492 self.comm.sendCommand('G92 Z10')
1493 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1494 self.comm.sendCommand('M400')
1496 def OnBedDown2(self, e):
1497 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1498 self.comm.sendCommand('G92 Z10')
1499 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1500 self.comm.sendCommand('M400')
1502 def AllowNext(self):
1503 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1504 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1507 def OnResume(self, e):
1508 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1509 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1510 if self._wizardState == -1:
1511 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1512 wx.CallAfter(self.upButton.Enable, False)
1513 wx.CallAfter(self.downButton.Enable, False)
1514 wx.CallAfter(self.upButton2.Enable, False)
1515 wx.CallAfter(self.downButton2.Enable, False)
1516 self.comm.sendCommand('M105')
1517 self.comm.sendCommand('G28')
1518 self._wizardState = 1
1519 elif self._wizardState == 2:
1520 if profile.getMachineSetting('has_heated_bed') == 'True':
1521 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1522 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1523 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1524 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1525 self.comm.sendCommand('M400')
1526 self._wizardState = 3
1528 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1529 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1530 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1531 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1532 self.comm.sendCommand('M400')
1533 self._wizardState = 3
1534 elif self._wizardState == 4:
1535 if profile.getMachineSetting('has_heated_bed') == 'True':
1536 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1537 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1538 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1539 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1540 self.comm.sendCommand('M400')
1541 self._wizardState = 7
1543 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1544 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1545 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1546 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1547 self.comm.sendCommand('M400')
1548 self._wizardState = 5
1549 elif self._wizardState == 6:
1550 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1551 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1552 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1553 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1554 self.comm.sendCommand('M400')
1555 self._wizardState = 7
1556 elif self._wizardState == 8:
1557 wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1558 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1559 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1560 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1561 self._wizardState = 9
1562 elif self._wizardState == 10:
1563 self._wizardState = 11
1564 wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1565 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1566 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1567 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1568 w = profile.getMachineSettingFloat('machine_width') - 10
1569 d = profile.getMachineSettingFloat('machine_depth')
1570 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1571 filamentArea = math.pi * filamentRadius * filamentRadius
1572 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1576 'G1 Z2 F%d' % (feedZ),
1578 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1579 'G1 Z0.3 F%d' % (feedZ)]
1581 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1583 for i in xrange(0, 3):
1584 dist = 5.0 + 0.4 * float(i)
1585 eValue += (d - 2.0*dist) * ePerMM
1586 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1587 eValue += (w - 2.0*dist) * ePerMM
1588 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1589 eValue += (d - 2.0*dist) * ePerMM
1590 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1591 eValue += (w - 2.0*dist) * ePerMM
1592 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1594 gcodeList.append('M400')
1595 self.comm.printGCode(gcodeList)
1596 self.resumeButton.Enable(False)
1598 def mcLog(self, message):
1599 print 'Log:', message
1601 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1602 if self._wizardState == 1:
1603 self._wizardState = 2
1604 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1605 wx.CallAfter(self.resumeButton.Enable, True)
1606 elif self._wizardState == 3:
1607 self._wizardState = 4
1608 if profile.getMachineSetting('has_heated_bed') == 'True':
1609 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1611 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1612 wx.CallAfter(self.resumeButton.Enable, True)
1613 elif self._wizardState == 5:
1614 self._wizardState = 6
1615 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1616 wx.CallAfter(self.resumeButton.Enable, True)
1617 elif self._wizardState == 7:
1618 self._wizardState = 8
1619 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1620 wx.CallAfter(self.resumeButton.Enable, True)
1621 elif self._wizardState == 9:
1622 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1623 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1625 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1626 wx.CallAfter(self.resumeButton.Enable, True)
1627 self._wizardState = 10
1629 def mcStateChange(self, state):
1630 if self.comm is None:
1632 if self.comm.isOperational():
1633 if self._wizardState == 0:
1634 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1635 wx.CallAfter(self.upButton.Enable, True)
1636 wx.CallAfter(self.downButton.Enable, True)
1637 wx.CallAfter(self.upButton2.Enable, True)
1638 wx.CallAfter(self.downButton2.Enable, True)
1639 wx.CallAfter(self.resumeButton.Enable, True)
1640 self._wizardState = -1
1641 elif self._wizardState == 11 and not self.comm.isPrinting():
1642 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1643 self.comm.sendCommand('G92 E0')
1644 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1645 self.comm.sendCommand('M104 S0')
1646 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1647 wx.CallAfter(self.infoBox.SetReadyIndicator)
1648 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1649 wx.CallAfter(self.connectButton.Enable, True)
1650 self._wizardState = 12
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 headOffsetCalibrationPage(InfoPage):
1664 def __init__(self, parent):
1665 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1667 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1670 self.connectButton = self.AddButton(_('Connect to printer'))
1673 self.infoBox = self.AddInfoBox()
1674 self.textEntry = self.AddTextCtrl('')
1675 self.textEntry.Enable(False)
1676 self.resumeButton = self.AddButton(_('Resume'))
1677 self.resumeButton.Enable(False)
1679 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1680 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1682 def AllowBack(self):
1685 def OnConnect(self, e = None):
1686 if self.comm is not None:
1690 wx.CallAfter(self.OnConnect)
1692 self.connectButton.Enable(False)
1693 self.comm = machineCom.MachineCom(callbackObject=self)
1694 self.infoBox.SetBusy(_('Connecting to machine.'))
1695 self._wizardState = 0
1697 def OnResume(self, e):
1698 if self._wizardState == 2:
1699 self._wizardState = 3
1700 wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1702 w = profile.getMachineSettingFloat('machine_width')
1703 d = profile.getMachineSettingFloat('machine_depth')
1705 gcode = gcodeGenerator.gcodeGenerator()
1706 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1707 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1714 gcode.addMove(w/2, 5)
1715 gcode.addMove(z=0.2)
1717 gcode.addExtrude(w/2, d-5.0)
1719 gcode.addMove(5, d/2)
1721 gcode.addExtrude(w-5.0, d/2)
1722 gcode.addRetract(15)
1725 gcode.addMove(w/2, 5)
1727 gcode.addExtrude(w/2, d-5.0)
1729 gcode.addMove(5, d/2)
1731 gcode.addExtrude(w-5.0, d/2)
1732 gcode.addRetract(15)
1737 gcode.addCmd('M400')
1739 self.comm.printGCode(gcode.list())
1740 self.resumeButton.Enable(False)
1741 elif self._wizardState == 4:
1743 float(self.textEntry.GetValue())
1746 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1747 self._wizardState = 5
1748 self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1749 self.textEntry.SetValue('0.0')
1750 self.textEntry.Enable(True)
1751 elif self._wizardState == 5:
1753 float(self.textEntry.GetValue())
1756 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1757 self._wizardState = 6
1758 self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1759 self.textEntry.SetValue('')
1760 self.textEntry.Enable(False)
1761 self.resumeButton.Enable(False)
1763 x = profile.getMachineSettingFloat('extruder_offset_x1')
1764 y = profile.getMachineSettingFloat('extruder_offset_y1')
1765 gcode = gcodeGenerator.gcodeGenerator()
1766 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1767 gcode.setPrintSpeed(25)
1770 gcode.addMove(50, 40, 0.2)
1772 for n in xrange(0, 10):
1773 gcode.addExtrude(50 + n * 10, 150)
1774 gcode.addExtrude(50 + n * 10 + 5, 150)
1775 gcode.addExtrude(50 + n * 10 + 5, 40)
1776 gcode.addExtrude(50 + n * 10 + 10, 40)
1777 gcode.addMove(40, 50)
1778 for n in xrange(0, 10):
1779 gcode.addExtrude(150, 50 + n * 10)
1780 gcode.addExtrude(150, 50 + n * 10 + 5)
1781 gcode.addExtrude(40, 50 + n * 10 + 5)
1782 gcode.addExtrude(40, 50 + n * 10 + 10)
1783 gcode.addRetract(15)
1786 gcode.addMove(50 - x, 30 - y, 0.2)
1788 for n in xrange(0, 10):
1789 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1790 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1791 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1792 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1793 gcode.addMove(30 - x, 50 - y, 0.2)
1794 for n in xrange(0, 10):
1795 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1796 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1797 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1798 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1799 gcode.addRetract(15)
1801 gcode.addCmd('M400')
1802 gcode.addCmd('M104 T0 S0')
1803 gcode.addCmd('M104 T1 S0')
1804 self.comm.printGCode(gcode.list())
1805 elif self._wizardState == 7:
1807 n = int(self.textEntry.GetValue()) - 1
1810 x = profile.getMachineSettingFloat('extruder_offset_x1')
1812 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1813 self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1814 self.textEntry.SetValue('10')
1815 self._wizardState = 8
1816 elif self._wizardState == 8:
1818 n = int(self.textEntry.GetValue()) - 1
1821 y = profile.getMachineSettingFloat('extruder_offset_y1')
1823 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1824 self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1825 self.infoBox.SetReadyIndicator()
1826 self._wizardState = 8
1828 self.resumeButton.Enable(False)
1830 def mcLog(self, message):
1831 print 'Log:', message
1833 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1834 if self._wizardState == 1:
1835 if temp[0] >= 210 and temp[1] >= 210:
1836 self._wizardState = 2
1837 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1838 wx.CallAfter(self.resumeButton.Enable, True)
1839 wx.CallAfter(self.resumeButton.SetFocus)
1841 def mcStateChange(self, state):
1842 if self.comm is None:
1844 if self.comm.isOperational():
1845 if self._wizardState == 0:
1846 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1847 self.comm.sendCommand('M105')
1848 self.comm.sendCommand('M104 S220 T0')
1849 self.comm.sendCommand('M104 S220 T1')
1850 self.comm.sendCommand('G28')
1851 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1852 self._wizardState = 1
1853 if not self.comm.isPrinting():
1854 if self._wizardState == 3:
1855 self._wizardState = 4
1856 wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1857 wx.CallAfter(self.textEntry.SetValue, '0.0')
1858 wx.CallAfter(self.textEntry.Enable, True)
1859 wx.CallAfter(self.resumeButton.Enable, True)
1860 wx.CallAfter(self.resumeButton.SetFocus)
1861 elif self._wizardState == 6:
1862 self._wizardState = 7
1863 wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1864 wx.CallAfter(self.textEntry.SetValue, '10')
1865 wx.CallAfter(self.textEntry.Enable, True)
1866 wx.CallAfter(self.resumeButton.Enable, True)
1867 wx.CallAfter(self.resumeButton.SetFocus)
1869 elif self.comm.isError():
1870 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1872 def mcMessage(self, message):
1875 def mcProgress(self, lineNr):
1878 def mcZChange(self, newZ):
1881 class bedLevelWizard(wx.wizard.Wizard):
1883 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1885 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1886 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1888 self.mainPage = bedLevelWizardMain(self)
1889 self.headOffsetCalibration = None
1891 self.RunWizard(self.mainPage)
1894 def OnPageChanging(self, e):
1895 e.GetPage().StoreData()
1897 def OnPageChanged(self, e):
1898 if e.GetPage().AllowNext():
1899 self.FindWindowById(wx.ID_FORWARD).Enable()
1901 self.FindWindowById(wx.ID_FORWARD).Disable()
1902 if e.GetPage().AllowBack():
1903 self.FindWindowById(wx.ID_BACKWARD).Enable()
1905 self.FindWindowById(wx.ID_BACKWARD).Disable()
1907 class headOffsetWizard(wx.wizard.Wizard):
1909 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1911 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1912 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1914 self.mainPage = headOffsetCalibrationPage(self)
1916 self.RunWizard(self.mainPage)
1919 def OnPageChanging(self, e):
1920 e.GetPage().StoreData()
1922 def OnPageChanged(self, e):
1923 if e.GetPage().AllowNext():
1924 self.FindWindowById(wx.ID_FORWARD).Enable()
1926 self.FindWindowById(wx.ID_FORWARD).Disable()
1927 if e.GetPage().AllowBack():
1928 self.FindWindowById(wx.ID_BACKWARD).Enable()
1930 self.FindWindowById(wx.ID_BACKWARD).Disable()