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, _("Non-LulzBot 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 profile.putMachineSetting('machine_width', '290')
1137 profile.putMachineSetting('machine_depth', '275')
1138 profile.putMachineSetting('machine_height', '250')
1139 profile.putProfileSetting('nozzle_size', '0.35')
1140 profile.putMachineSetting('machine_name', 'LulzBot TAZ 4')
1141 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_4')
1142 profile.putMachineSetting('serial_baud', '115200')
1143 elif self.LulzbotTaz5.GetValue():
1144 profile.putProfileSetting('nozzle_size', '0.35')
1145 profile.putMachineSetting('machine_name', 'LulzBot TAZ 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 profile.putMachineSetting('machine_width', '155')
1153 profile.putMachineSetting('machine_depth', '155')
1154 profile.putMachineSetting('machine_height', '163')
1155 profile.putProfileSetting('nozzle_size', '0.5')
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.putMachineSetting('machine_name', 'LulzBot Mini')
1221 profile.putMachineSetting('machine_type', 'lulzbot_mini')
1223 profile.putMachineSetting('machine_name', 'LulzBot Mini (Flexy)')
1224 profile.putMachineSetting('machine_type', 'lulzbot_mini_flexy')
1227 class LulzbotTazToolheadSelectPage(LulzbotToolheadSelectPage):
1228 def __init__(self, parent):
1229 super(LulzbotTazToolheadSelectPage, self).__init__(parent, _("LulzBot TAZ Toolhead Selection"))
1231 self.panel = self.AddPanel()
1232 image_size=(LulzbotMachineSelectPage.IMAGE_WIDTH, LulzbotMachineSelectPage.IMAGE_HEIGHT)
1233 self.standard = self.AddImageButton(self.panel, 0, 0, _('Single Extruder v1'),
1234 'Lulzbot_Toolhead_TAZ_Single_v1.jpg', image_size,
1235 style=ImageButton.IB_GROUP)
1236 self.flexy = self.AddImageButton(self.panel, 0, 1, _('Flexystruder v1'),
1237 'Lulzbot_Toolhead_TAZ_Flexystruder_v1.jpg', image_size)
1238 self.dually = self.AddImageButton(self.panel, 1, 0, _('Dual Extruder v1'),
1239 'Lulzbot_Toolhead_TAZ_Dually_v1.jpg', image_size)
1240 self.flexydually = self.AddImageButton(self.panel, 1, 1, _('FlexyDually v1'),
1241 'Lulzbot_Toolhead_TAZ_FlexyDually_v1.jpg', image_size)
1243 self.standard.SetValue(True)
1245 def SetVersion(self, version):
1246 image_size=(LulzbotMachineSelectPage.IMAGE_WIDTH, LulzbotMachineSelectPage.IMAGE_HEIGHT)
1247 self.standard.SetBitmap(self.GetBitmap('Lulzbot_Toolhead_TAZ_Single_v%d.jpg' % version, image_size))
1248 self.standard.SetLabel(_('Single Extruder v%d' % version))
1249 self.flexy.SetBitmap(self.GetBitmap('Lulzbot_Toolhead_TAZ_Flexystruder_v%d.jpg' % version, image_size))
1250 self.flexy.SetLabel(_('Flexystruder v%d' % version))
1251 self.dually.SetBitmap(self.GetBitmap('Lulzbot_Toolhead_TAZ_Dually_v%d.jpg' % version, image_size))
1252 self.dually.SetLabel(_('Dual Extruder v%d' % version))
1253 self.flexydually.SetBitmap(self.GetBitmap('Lulzbot_Toolhead_TAZ_FlexyDually_v%d.jpg' % version, image_size))
1254 self.flexydually.SetLabel(_('FlexyDually v%d' % version))
1256 self.standard.OnSelected(None)
1257 self.flexy.OnSelected(None)
1258 self.dually.OnSelected(None)
1259 self.flexydually.OnSelected(None)
1260 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
1262 self.standard.OnSelected(self.OnStandardV2)
1263 self.flexy.OnSelected(self.OnNonStandard)
1264 self.dually.OnSelected(self.OnNonStandard)
1265 self.flexydually.OnSelected(self.OnNonStandard)
1266 if self.standard.GetValue():
1267 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotTaz5NozzleSelectPage)
1269 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
1271 def OnStandardV2(self):
1272 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotTaz5NozzleSelectPage)
1274 def OnNonStandard(self):
1275 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
1278 def StoreData(self):
1282 class LulzbotHotendSelectPage(LulzbotToolheadSelectPage):
1283 def __init__(self, parent):
1284 super(LulzbotHotendSelectPage, self).__init__(parent, _("LulzBot Toolhead Hotend Selection"))
1286 self.panel = self.AddPanel()
1287 image_size=(LulzbotMachineSelectPage.IMAGE_WIDTH, LulzbotMachineSelectPage.IMAGE_HEIGHT)
1288 self.v1 = self.AddImageButton(self.panel, 0, 0, _('v1 (Budaschnozzle Hotends)'),
1289 'Lulzbot_Toolhead_v1.jpg', image_size,
1290 style=ImageButton.IB_GROUP)
1291 self.v2 = self.AddImageButton(self.panel, 0, 1, _('v2 (Hexagon Hotends)'),
1292 'Lulzbot_Toolhead_v2.jpg', image_size)
1293 self.v1.SetValue(True)
1295 def StoreData(self):
1296 self.GetParent().lulzbotTazToolheadPage.SetVersion(1 if self.v1.GetValue() else 2)
1299 class LulzbotTaz5NozzleSelectPage(LulzbotToolheadSelectPage):
1300 url2='http://lulzbot.com/printer-identification'
1302 def __init__(self, parent):
1303 super(LulzbotTaz5NozzleSelectPage, self).__init__(parent, _("LulzBot TAZ Standard V2 Nozzle Selection"))
1305 self.AddText(_('Please select your Hexagon hotend\'s nozzle size:'))
1306 self.Nozzle35Radio = self.AddRadioButton("0.35 mm", style=wx.RB_GROUP)
1307 self.Nozzle35Radio.SetValue(True)
1308 self.Nozzle50Radio = self.AddRadioButton("0.5 mm")
1309 self.AddText(_(' '))
1312 self.AddText(_('If you are not sure which nozzle size you have'))
1313 self.AddText(_('please check this webpage: '))
1314 button = self.AddButton(LulzbotTaz5NozzleSelectPage.url2)
1315 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1317 def OnUrlClick(self, e):
1318 webbrowser.open(LulzbotTaz5NozzleSelectPage.url2)
1320 def StoreData(self):
1321 if self.Nozzle35Radio.GetValue():
1322 profile.putProfileSetting('nozzle_size', '0.35')
1323 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.35 nozzle)')
1324 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5_035nozzle')
1327 profile.putProfileSetting('nozzle_size', '0.5')
1328 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.5 nozzle)')
1329 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5_05nozzle')
1331 class ConfigWizard(wx.wizard.Wizard):
1332 def __init__(self, addNew = False):
1333 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
1335 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1337 profile.setActiveMachine(profile.getMachineCount())
1339 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1340 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1341 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1343 self.machineSelectPage = MachineSelectPage(self)
1344 self.ultimakerSelectParts = SelectParts(self)
1345 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
1346 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
1347 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
1348 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
1349 self.bedLevelPage = bedLevelWizardMain(self)
1350 self.headOffsetCalibration = headOffsetCalibrationPage(self)
1351 self.printrbotSelectType = PrintrbotPage(self)
1352 self.otherMachineSelectPage = OtherMachineSelectPage(self)
1353 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
1354 self.otherMachineInfoPage = OtherMachineInfoPage(self)
1356 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
1357 self.lulzbotReadyPage = LulzbotReadyPage(self)
1358 self.lulzbotMiniToolheadPage = LulzbotMiniToolheadSelectPage(self)
1359 self.lulzbotTazToolheadPage = LulzbotTazToolheadSelectPage(self)
1360 self.lulzbotTazHotendPage = LulzbotHotendSelectPage(self)
1361 self.lulzbotTaz5NozzleSelectPage = LulzbotTaz5NozzleSelectPage(self)
1362 self.lulzbotMachineSelectPage = LulzbotMachineSelectPage(self)
1364 wx.wizard.WizardPageSimple.Chain(self.lulzbotMachineSelectPage, self.lulzbotMiniToolheadPage)
1365 wx.wizard.WizardPageSimple.Chain(self.lulzbotMiniToolheadPage, self.lulzbotReadyPage)
1366 wx.wizard.WizardPageSimple.Chain(self.lulzbotTazHotendPage, self.lulzbotTazToolheadPage)
1367 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
1368 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
1369 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
1370 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
1371 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
1372 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
1374 self.RunWizard(self.lulzbotMachineSelectPage)
1377 def OnPageChanging(self, e):
1378 e.GetPage().StoreData()
1380 def OnPageChanged(self, e):
1381 if e.GetPage().AllowNext():
1382 self.FindWindowById(wx.ID_FORWARD).Enable()
1384 self.FindWindowById(wx.ID_FORWARD).Disable()
1385 if e.GetPage().AllowBack():
1386 self.FindWindowById(wx.ID_BACKWARD).Enable()
1388 self.FindWindowById(wx.ID_BACKWARD).Disable()
1390 def OnCancel(self, e):
1391 new_machine_index = int(profile.getPreferenceFloat('active_machine'))
1392 profile.setActiveMachine(self._old_machine_index)
1393 profile.removeMachine(new_machine_index)
1395 class bedLevelWizardMain(InfoPage):
1396 def __init__(self, parent):
1397 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1399 self.AddText(_('This wizard will help you in leveling your printer bed'))
1401 self.AddText(_('It will do the following steps'))
1402 self.AddText(_('* Move the printer head to each corner'))
1403 self.AddText(_(' and let you adjust the height of the bed to the nozzle'))
1404 self.AddText(_('* Print a line around the bed to check if it is level'))
1407 self.connectButton = self.AddButton(_('Connect to printer'))
1410 self.infoBox = self.AddInfoBox()
1411 self.resumeButton = self.AddButton(_('Resume'))
1412 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1413 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1414 self.resumeButton.Enable(False)
1416 self.upButton.Enable(False)
1417 self.downButton.Enable(False)
1418 self.upButton2.Enable(False)
1419 self.downButton2.Enable(False)
1421 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1422 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1423 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1424 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1425 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1426 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1428 def OnConnect(self, e = None):
1429 if self.comm is not None:
1433 wx.CallAfter(self.OnConnect)
1435 self.connectButton.Enable(False)
1436 self.comm = machineCom.MachineCom(callbackObject=self)
1437 self.infoBox.SetBusy(_('Connecting to machine.'))
1438 self._wizardState = 0
1440 def OnBedUp(self, e):
1441 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1442 self.comm.sendCommand('G92 Z10')
1443 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1444 self.comm.sendCommand('M400')
1446 def OnBedDown(self, e):
1447 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1448 self.comm.sendCommand('G92 Z10')
1449 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1450 self.comm.sendCommand('M400')
1452 def OnBedUp2(self, e):
1453 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1454 self.comm.sendCommand('G92 Z10')
1455 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1456 self.comm.sendCommand('M400')
1458 def OnBedDown2(self, e):
1459 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1460 self.comm.sendCommand('G92 Z10')
1461 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1462 self.comm.sendCommand('M400')
1464 def AllowNext(self):
1465 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1466 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1469 def OnResume(self, e):
1470 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1471 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1472 if self._wizardState == -1:
1473 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1474 wx.CallAfter(self.upButton.Enable, False)
1475 wx.CallAfter(self.downButton.Enable, False)
1476 wx.CallAfter(self.upButton2.Enable, False)
1477 wx.CallAfter(self.downButton2.Enable, False)
1478 self.comm.sendCommand('M105')
1479 self.comm.sendCommand('G28')
1480 self._wizardState = 1
1481 elif self._wizardState == 2:
1482 if profile.getMachineSetting('has_heated_bed') == 'True':
1483 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1484 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1485 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1486 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1487 self.comm.sendCommand('M400')
1488 self._wizardState = 3
1490 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1491 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1492 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1493 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1494 self.comm.sendCommand('M400')
1495 self._wizardState = 3
1496 elif self._wizardState == 4:
1497 if profile.getMachineSetting('has_heated_bed') == 'True':
1498 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1499 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1500 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1501 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1502 self.comm.sendCommand('M400')
1503 self._wizardState = 7
1505 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1506 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1507 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1508 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1509 self.comm.sendCommand('M400')
1510 self._wizardState = 5
1511 elif self._wizardState == 6:
1512 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1513 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1514 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1515 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1516 self.comm.sendCommand('M400')
1517 self._wizardState = 7
1518 elif self._wizardState == 8:
1519 wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1520 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1521 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1522 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1523 self._wizardState = 9
1524 elif self._wizardState == 10:
1525 self._wizardState = 11
1526 wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1527 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1528 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1529 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1530 w = profile.getMachineSettingFloat('machine_width') - 10
1531 d = profile.getMachineSettingFloat('machine_depth')
1532 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1533 filamentArea = math.pi * filamentRadius * filamentRadius
1534 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1538 'G1 Z2 F%d' % (feedZ),
1540 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1541 'G1 Z0.3 F%d' % (feedZ)]
1543 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1545 for i in xrange(0, 3):
1546 dist = 5.0 + 0.4 * float(i)
1547 eValue += (d - 2.0*dist) * ePerMM
1548 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1549 eValue += (w - 2.0*dist) * ePerMM
1550 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1551 eValue += (d - 2.0*dist) * ePerMM
1552 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1553 eValue += (w - 2.0*dist) * ePerMM
1554 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1556 gcodeList.append('M400')
1557 self.comm.printGCode(gcodeList)
1558 self.resumeButton.Enable(False)
1560 def mcLog(self, message):
1561 print 'Log:', message
1563 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1564 if self._wizardState == 1:
1565 self._wizardState = 2
1566 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1567 wx.CallAfter(self.resumeButton.Enable, True)
1568 elif self._wizardState == 3:
1569 self._wizardState = 4
1570 if profile.getMachineSetting('has_heated_bed') == 'True':
1571 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1573 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1574 wx.CallAfter(self.resumeButton.Enable, True)
1575 elif self._wizardState == 5:
1576 self._wizardState = 6
1577 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1578 wx.CallAfter(self.resumeButton.Enable, True)
1579 elif self._wizardState == 7:
1580 self._wizardState = 8
1581 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1582 wx.CallAfter(self.resumeButton.Enable, True)
1583 elif self._wizardState == 9:
1584 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1585 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1587 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1588 wx.CallAfter(self.resumeButton.Enable, True)
1589 self._wizardState = 10
1591 def mcStateChange(self, state):
1592 if self.comm is None:
1594 if self.comm.isOperational():
1595 if self._wizardState == 0:
1596 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1597 wx.CallAfter(self.upButton.Enable, True)
1598 wx.CallAfter(self.downButton.Enable, True)
1599 wx.CallAfter(self.upButton2.Enable, True)
1600 wx.CallAfter(self.downButton2.Enable, True)
1601 wx.CallAfter(self.resumeButton.Enable, True)
1602 self._wizardState = -1
1603 elif self._wizardState == 11 and not self.comm.isPrinting():
1604 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1605 self.comm.sendCommand('G92 E0')
1606 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1607 self.comm.sendCommand('M104 S0')
1608 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1609 wx.CallAfter(self.infoBox.SetReadyIndicator)
1610 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1611 wx.CallAfter(self.connectButton.Enable, True)
1612 self._wizardState = 12
1613 elif self.comm.isError():
1614 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1616 def mcMessage(self, message):
1619 def mcProgress(self, lineNr):
1622 def mcZChange(self, newZ):
1625 class headOffsetCalibrationPage(InfoPage):
1626 def __init__(self, parent):
1627 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1629 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1632 self.connectButton = self.AddButton(_('Connect to printer'))
1635 self.infoBox = self.AddInfoBox()
1636 self.textEntry = self.AddTextCtrl('')
1637 self.textEntry.Enable(False)
1638 self.resumeButton = self.AddButton(_('Resume'))
1639 self.resumeButton.Enable(False)
1641 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1642 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1644 def AllowBack(self):
1647 def OnConnect(self, e = None):
1648 if self.comm is not None:
1652 wx.CallAfter(self.OnConnect)
1654 self.connectButton.Enable(False)
1655 self.comm = machineCom.MachineCom(callbackObject=self)
1656 self.infoBox.SetBusy(_('Connecting to machine.'))
1657 self._wizardState = 0
1659 def OnResume(self, e):
1660 if self._wizardState == 2:
1661 self._wizardState = 3
1662 wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1664 w = profile.getMachineSettingFloat('machine_width')
1665 d = profile.getMachineSettingFloat('machine_depth')
1667 gcode = gcodeGenerator.gcodeGenerator()
1668 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1669 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1676 gcode.addMove(w/2, 5)
1677 gcode.addMove(z=0.2)
1679 gcode.addExtrude(w/2, d-5.0)
1681 gcode.addMove(5, d/2)
1683 gcode.addExtrude(w-5.0, d/2)
1684 gcode.addRetract(15)
1687 gcode.addMove(w/2, 5)
1689 gcode.addExtrude(w/2, d-5.0)
1691 gcode.addMove(5, d/2)
1693 gcode.addExtrude(w-5.0, d/2)
1694 gcode.addRetract(15)
1699 gcode.addCmd('M400')
1701 self.comm.printGCode(gcode.list())
1702 self.resumeButton.Enable(False)
1703 elif self._wizardState == 4:
1705 float(self.textEntry.GetValue())
1708 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1709 self._wizardState = 5
1710 self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1711 self.textEntry.SetValue('0.0')
1712 self.textEntry.Enable(True)
1713 elif self._wizardState == 5:
1715 float(self.textEntry.GetValue())
1718 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1719 self._wizardState = 6
1720 self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1721 self.textEntry.SetValue('')
1722 self.textEntry.Enable(False)
1723 self.resumeButton.Enable(False)
1725 x = profile.getMachineSettingFloat('extruder_offset_x1')
1726 y = profile.getMachineSettingFloat('extruder_offset_y1')
1727 gcode = gcodeGenerator.gcodeGenerator()
1728 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1729 gcode.setPrintSpeed(25)
1732 gcode.addMove(50, 40, 0.2)
1734 for n in xrange(0, 10):
1735 gcode.addExtrude(50 + n * 10, 150)
1736 gcode.addExtrude(50 + n * 10 + 5, 150)
1737 gcode.addExtrude(50 + n * 10 + 5, 40)
1738 gcode.addExtrude(50 + n * 10 + 10, 40)
1739 gcode.addMove(40, 50)
1740 for n in xrange(0, 10):
1741 gcode.addExtrude(150, 50 + n * 10)
1742 gcode.addExtrude(150, 50 + n * 10 + 5)
1743 gcode.addExtrude(40, 50 + n * 10 + 5)
1744 gcode.addExtrude(40, 50 + n * 10 + 10)
1745 gcode.addRetract(15)
1748 gcode.addMove(50 - x, 30 - y, 0.2)
1750 for n in xrange(0, 10):
1751 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1752 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1753 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1754 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1755 gcode.addMove(30 - x, 50 - y, 0.2)
1756 for n in xrange(0, 10):
1757 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1758 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1759 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1760 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1761 gcode.addRetract(15)
1763 gcode.addCmd('M400')
1764 gcode.addCmd('M104 T0 S0')
1765 gcode.addCmd('M104 T1 S0')
1766 self.comm.printGCode(gcode.list())
1767 elif self._wizardState == 7:
1769 n = int(self.textEntry.GetValue()) - 1
1772 x = profile.getMachineSettingFloat('extruder_offset_x1')
1774 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1775 self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1776 self.textEntry.SetValue('10')
1777 self._wizardState = 8
1778 elif self._wizardState == 8:
1780 n = int(self.textEntry.GetValue()) - 1
1783 y = profile.getMachineSettingFloat('extruder_offset_y1')
1785 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1786 self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1787 self.infoBox.SetReadyIndicator()
1788 self._wizardState = 8
1790 self.resumeButton.Enable(False)
1792 def mcLog(self, message):
1793 print 'Log:', message
1795 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1796 if self._wizardState == 1:
1797 if temp[0] >= 210 and temp[1] >= 210:
1798 self._wizardState = 2
1799 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1800 wx.CallAfter(self.resumeButton.Enable, True)
1801 wx.CallAfter(self.resumeButton.SetFocus)
1803 def mcStateChange(self, state):
1804 if self.comm is None:
1806 if self.comm.isOperational():
1807 if self._wizardState == 0:
1808 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1809 self.comm.sendCommand('M105')
1810 self.comm.sendCommand('M104 S220 T0')
1811 self.comm.sendCommand('M104 S220 T1')
1812 self.comm.sendCommand('G28')
1813 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1814 self._wizardState = 1
1815 if not self.comm.isPrinting():
1816 if self._wizardState == 3:
1817 self._wizardState = 4
1818 wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1819 wx.CallAfter(self.textEntry.SetValue, '0.0')
1820 wx.CallAfter(self.textEntry.Enable, True)
1821 wx.CallAfter(self.resumeButton.Enable, True)
1822 wx.CallAfter(self.resumeButton.SetFocus)
1823 elif self._wizardState == 6:
1824 self._wizardState = 7
1825 wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1826 wx.CallAfter(self.textEntry.SetValue, '10')
1827 wx.CallAfter(self.textEntry.Enable, True)
1828 wx.CallAfter(self.resumeButton.Enable, True)
1829 wx.CallAfter(self.resumeButton.SetFocus)
1831 elif self.comm.isError():
1832 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1834 def mcMessage(self, message):
1837 def mcProgress(self, lineNr):
1840 def mcZChange(self, newZ):
1843 class bedLevelWizard(wx.wizard.Wizard):
1845 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1847 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1848 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1850 self.mainPage = bedLevelWizardMain(self)
1851 self.headOffsetCalibration = None
1853 self.RunWizard(self.mainPage)
1856 def OnPageChanging(self, e):
1857 e.GetPage().StoreData()
1859 def OnPageChanged(self, e):
1860 if e.GetPage().AllowNext():
1861 self.FindWindowById(wx.ID_FORWARD).Enable()
1863 self.FindWindowById(wx.ID_FORWARD).Disable()
1864 if e.GetPage().AllowBack():
1865 self.FindWindowById(wx.ID_BACKWARD).Enable()
1867 self.FindWindowById(wx.ID_BACKWARD).Disable()
1869 class headOffsetWizard(wx.wizard.Wizard):
1871 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1873 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1874 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1876 self.mainPage = headOffsetCalibrationPage(self)
1878 self.RunWizard(self.mainPage)
1881 def OnPageChanging(self, e):
1882 e.GetPage().StoreData()
1884 def OnPageChanged(self, e):
1885 if e.GetPage().AllowNext():
1886 self.FindWindowById(wx.ID_FORWARD).Enable()
1888 self.FindWindowById(wx.ID_FORWARD).Disable()
1889 if e.GetPage().AllowBack():
1890 self.FindWindowById(wx.ID_BACKWARD).Enable()
1892 self.FindWindowById(wx.ID_BACKWARD).Disable()