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.single = 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.single.SetValue(True)
1245 def SetVersion(self, version):
1246 image_size=(LulzbotMachineSelectPage.IMAGE_WIDTH, LulzbotMachineSelectPage.IMAGE_HEIGHT)
1247 self.single.SetBitmap(self.GetBitmap('Lulzbot_Toolhead_TAZ_Single_v%d.jpg' % version, image_size))
1248 self.single.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))
1255 self.version = version
1257 self.single.OnSelected(None)
1258 self.flexy.OnSelected(None)
1259 self.dually.OnSelected(None)
1260 self.flexydually.OnSelected(None)
1261 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
1263 self.single.OnSelected(self.OnSingleV2)
1264 self.flexy.OnSelected(self.OnNonSingle)
1265 self.dually.OnSelected(self.OnNonSingle)
1266 self.flexydually.OnSelected(self.OnNonSingle)
1267 if self.single.GetValue():
1268 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotTaz5NozzleSelectPage)
1269 wx.wizard.WizardPageSimple.Chain(self.GetParent().lulzbotTaz5NozzleSelectPage, self.GetParent().lulzbotReadyPage)
1271 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
1273 def OnSingleV2(self):
1274 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotTaz5NozzleSelectPage)
1275 wx.wizard.WizardPageSimple.Chain(self.GetParent().lulzbotTaz5NozzleSelectPage, self.GetParent().lulzbotReadyPage)
1277 def OnNonSingle(self):
1278 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
1280 def StoreData(self):
1284 class LulzbotHotendSelectPage(LulzbotToolheadSelectPage):
1285 def __init__(self, parent):
1286 super(LulzbotHotendSelectPage, self).__init__(parent, _("LulzBot Toolhead Hotend Selection"))
1288 self.panel = self.AddPanel()
1289 image_size=(LulzbotMachineSelectPage.IMAGE_WIDTH, LulzbotMachineSelectPage.IMAGE_HEIGHT)
1290 self.v1 = self.AddImageButton(self.panel, 0, 0, _('v1 (Budaschnozzle Hotends)'),
1291 'Lulzbot_Toolhead_v1.jpg', image_size,
1292 style=ImageButton.IB_GROUP)
1293 self.v2 = self.AddImageButton(self.panel, 0, 1, _('v2 (Hexagon Hotends)'),
1294 'Lulzbot_Toolhead_v2.jpg', image_size)
1295 self.v1.SetValue(True)
1297 def StoreData(self):
1298 self.GetParent().lulzbotTazToolheadPage.SetVersion(1 if self.v1.GetValue() else 2)
1301 class LulzbotTaz5NozzleSelectPage(LulzbotToolheadSelectPage):
1302 url2='http://lulzbot.com/printer-identification'
1304 def __init__(self, parent):
1305 super(LulzbotTaz5NozzleSelectPage, self).__init__(parent, _("LulzBot TAZ Single V2 Nozzle Selection"))
1307 self.AddText(_('Please select your Hexagon hotend\'s nozzle size:'))
1308 self.Nozzle35Radio = self.AddRadioButton("0.35 mm", style=wx.RB_GROUP)
1309 self.Nozzle35Radio.SetValue(True)
1310 self.Nozzle50Radio = self.AddRadioButton("0.5 mm")
1311 self.AddText(_(' '))
1314 self.AddText(_('If you are not sure which nozzle size you have'))
1315 self.AddText(_('please check this webpage: '))
1316 button = self.AddButton(LulzbotTaz5NozzleSelectPage.url2)
1317 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1319 def OnUrlClick(self, e):
1320 webbrowser.open(LulzbotTaz5NozzleSelectPage.url2)
1322 def StoreData(self):
1323 if self.Nozzle35Radio.GetValue():
1324 profile.putProfileSetting('nozzle_size', '0.35')
1325 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.35 nozzle)')
1326 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5_035nozzle')
1329 profile.putProfileSetting('nozzle_size', '0.5')
1330 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.5 nozzle)')
1331 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5_05nozzle')
1333 class ConfigWizard(wx.wizard.Wizard):
1334 def __init__(self, addNew = False):
1335 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
1337 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1339 profile.setActiveMachine(profile.getMachineCount())
1341 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1342 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1343 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1345 self.machineSelectPage = MachineSelectPage(self)
1346 self.ultimakerSelectParts = SelectParts(self)
1347 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
1348 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
1349 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
1350 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
1351 self.bedLevelPage = bedLevelWizardMain(self)
1352 self.headOffsetCalibration = headOffsetCalibrationPage(self)
1353 self.printrbotSelectType = PrintrbotPage(self)
1354 self.otherMachineSelectPage = OtherMachineSelectPage(self)
1355 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
1356 self.otherMachineInfoPage = OtherMachineInfoPage(self)
1358 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
1359 self.lulzbotReadyPage = LulzbotReadyPage(self)
1360 self.lulzbotMiniToolheadPage = LulzbotMiniToolheadSelectPage(self)
1361 self.lulzbotTazToolheadPage = LulzbotTazToolheadSelectPage(self)
1362 self.lulzbotTazHotendPage = LulzbotHotendSelectPage(self)
1363 self.lulzbotTaz5NozzleSelectPage = LulzbotTaz5NozzleSelectPage(self)
1364 self.lulzbotMachineSelectPage = LulzbotMachineSelectPage(self)
1366 wx.wizard.WizardPageSimple.Chain(self.lulzbotMachineSelectPage, self.lulzbotMiniToolheadPage)
1367 wx.wizard.WizardPageSimple.Chain(self.lulzbotMiniToolheadPage, self.lulzbotReadyPage)
1368 wx.wizard.WizardPageSimple.Chain(self.lulzbotTazHotendPage, self.lulzbotTazToolheadPage)
1369 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
1370 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
1371 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
1372 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
1373 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
1374 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
1376 self.RunWizard(self.lulzbotMachineSelectPage)
1379 def OnPageChanging(self, e):
1380 e.GetPage().StoreData()
1382 def OnPageChanged(self, e):
1383 if e.GetPage().AllowNext():
1384 self.FindWindowById(wx.ID_FORWARD).Enable()
1386 self.FindWindowById(wx.ID_FORWARD).Disable()
1387 if e.GetPage().AllowBack():
1388 self.FindWindowById(wx.ID_BACKWARD).Enable()
1390 self.FindWindowById(wx.ID_BACKWARD).Disable()
1392 def OnCancel(self, e):
1393 new_machine_index = int(profile.getPreferenceFloat('active_machine'))
1394 profile.setActiveMachine(self._old_machine_index)
1395 profile.removeMachine(new_machine_index)
1397 class bedLevelWizardMain(InfoPage):
1398 def __init__(self, parent):
1399 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1401 self.AddText(_('This wizard will help you in leveling your printer bed'))
1403 self.AddText(_('It will do the following steps'))
1404 self.AddText(_('* Move the printer head to each corner'))
1405 self.AddText(_(' and let you adjust the height of the bed to the nozzle'))
1406 self.AddText(_('* Print a line around the bed to check if it is level'))
1409 self.connectButton = self.AddButton(_('Connect to printer'))
1412 self.infoBox = self.AddInfoBox()
1413 self.resumeButton = self.AddButton(_('Resume'))
1414 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1415 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1416 self.resumeButton.Enable(False)
1418 self.upButton.Enable(False)
1419 self.downButton.Enable(False)
1420 self.upButton2.Enable(False)
1421 self.downButton2.Enable(False)
1423 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1424 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1425 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1426 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1427 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1428 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1430 def OnConnect(self, e = None):
1431 if self.comm is not None:
1435 wx.CallAfter(self.OnConnect)
1437 self.connectButton.Enable(False)
1438 self.comm = machineCom.MachineCom(callbackObject=self)
1439 self.infoBox.SetBusy(_('Connecting to machine.'))
1440 self._wizardState = 0
1442 def OnBedUp(self, e):
1443 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1444 self.comm.sendCommand('G92 Z10')
1445 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1446 self.comm.sendCommand('M400')
1448 def OnBedDown(self, e):
1449 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1450 self.comm.sendCommand('G92 Z10')
1451 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1452 self.comm.sendCommand('M400')
1454 def OnBedUp2(self, e):
1455 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1456 self.comm.sendCommand('G92 Z10')
1457 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1458 self.comm.sendCommand('M400')
1460 def OnBedDown2(self, e):
1461 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1462 self.comm.sendCommand('G92 Z10')
1463 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1464 self.comm.sendCommand('M400')
1466 def AllowNext(self):
1467 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1468 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1471 def OnResume(self, e):
1472 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1473 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1474 if self._wizardState == -1:
1475 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1476 wx.CallAfter(self.upButton.Enable, False)
1477 wx.CallAfter(self.downButton.Enable, False)
1478 wx.CallAfter(self.upButton2.Enable, False)
1479 wx.CallAfter(self.downButton2.Enable, False)
1480 self.comm.sendCommand('M105')
1481 self.comm.sendCommand('G28')
1482 self._wizardState = 1
1483 elif self._wizardState == 2:
1484 if profile.getMachineSetting('has_heated_bed') == 'True':
1485 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1486 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1487 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1488 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1489 self.comm.sendCommand('M400')
1490 self._wizardState = 3
1492 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1493 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1494 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1495 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1496 self.comm.sendCommand('M400')
1497 self._wizardState = 3
1498 elif self._wizardState == 4:
1499 if profile.getMachineSetting('has_heated_bed') == 'True':
1500 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1501 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1502 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1503 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1504 self.comm.sendCommand('M400')
1505 self._wizardState = 7
1507 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1508 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1509 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1510 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1511 self.comm.sendCommand('M400')
1512 self._wizardState = 5
1513 elif self._wizardState == 6:
1514 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1515 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1516 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1517 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1518 self.comm.sendCommand('M400')
1519 self._wizardState = 7
1520 elif self._wizardState == 8:
1521 wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1522 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1523 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1524 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1525 self._wizardState = 9
1526 elif self._wizardState == 10:
1527 self._wizardState = 11
1528 wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1529 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1530 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1531 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1532 w = profile.getMachineSettingFloat('machine_width') - 10
1533 d = profile.getMachineSettingFloat('machine_depth')
1534 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1535 filamentArea = math.pi * filamentRadius * filamentRadius
1536 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1540 'G1 Z2 F%d' % (feedZ),
1542 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1543 'G1 Z0.3 F%d' % (feedZ)]
1545 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1547 for i in xrange(0, 3):
1548 dist = 5.0 + 0.4 * float(i)
1549 eValue += (d - 2.0*dist) * ePerMM
1550 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1551 eValue += (w - 2.0*dist) * ePerMM
1552 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1553 eValue += (d - 2.0*dist) * ePerMM
1554 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1555 eValue += (w - 2.0*dist) * ePerMM
1556 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1558 gcodeList.append('M400')
1559 self.comm.printGCode(gcodeList)
1560 self.resumeButton.Enable(False)
1562 def mcLog(self, message):
1563 print 'Log:', message
1565 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1566 if self._wizardState == 1:
1567 self._wizardState = 2
1568 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1569 wx.CallAfter(self.resumeButton.Enable, True)
1570 elif self._wizardState == 3:
1571 self._wizardState = 4
1572 if profile.getMachineSetting('has_heated_bed') == 'True':
1573 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1575 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1576 wx.CallAfter(self.resumeButton.Enable, True)
1577 elif self._wizardState == 5:
1578 self._wizardState = 6
1579 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1580 wx.CallAfter(self.resumeButton.Enable, True)
1581 elif self._wizardState == 7:
1582 self._wizardState = 8
1583 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1584 wx.CallAfter(self.resumeButton.Enable, True)
1585 elif self._wizardState == 9:
1586 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1587 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1589 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1590 wx.CallAfter(self.resumeButton.Enable, True)
1591 self._wizardState = 10
1593 def mcStateChange(self, state):
1594 if self.comm is None:
1596 if self.comm.isOperational():
1597 if self._wizardState == 0:
1598 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1599 wx.CallAfter(self.upButton.Enable, True)
1600 wx.CallAfter(self.downButton.Enable, True)
1601 wx.CallAfter(self.upButton2.Enable, True)
1602 wx.CallAfter(self.downButton2.Enable, True)
1603 wx.CallAfter(self.resumeButton.Enable, True)
1604 self._wizardState = -1
1605 elif self._wizardState == 11 and not self.comm.isPrinting():
1606 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1607 self.comm.sendCommand('G92 E0')
1608 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1609 self.comm.sendCommand('M104 S0')
1610 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1611 wx.CallAfter(self.infoBox.SetReadyIndicator)
1612 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1613 wx.CallAfter(self.connectButton.Enable, True)
1614 self._wizardState = 12
1615 elif self.comm.isError():
1616 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1618 def mcMessage(self, message):
1621 def mcProgress(self, lineNr):
1624 def mcZChange(self, newZ):
1627 class headOffsetCalibrationPage(InfoPage):
1628 def __init__(self, parent):
1629 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1631 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1634 self.connectButton = self.AddButton(_('Connect to printer'))
1637 self.infoBox = self.AddInfoBox()
1638 self.textEntry = self.AddTextCtrl('')
1639 self.textEntry.Enable(False)
1640 self.resumeButton = self.AddButton(_('Resume'))
1641 self.resumeButton.Enable(False)
1643 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1644 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1646 def AllowBack(self):
1649 def OnConnect(self, e = None):
1650 if self.comm is not None:
1654 wx.CallAfter(self.OnConnect)
1656 self.connectButton.Enable(False)
1657 self.comm = machineCom.MachineCom(callbackObject=self)
1658 self.infoBox.SetBusy(_('Connecting to machine.'))
1659 self._wizardState = 0
1661 def OnResume(self, e):
1662 if self._wizardState == 2:
1663 self._wizardState = 3
1664 wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1666 w = profile.getMachineSettingFloat('machine_width')
1667 d = profile.getMachineSettingFloat('machine_depth')
1669 gcode = gcodeGenerator.gcodeGenerator()
1670 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1671 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1678 gcode.addMove(w/2, 5)
1679 gcode.addMove(z=0.2)
1681 gcode.addExtrude(w/2, d-5.0)
1683 gcode.addMove(5, d/2)
1685 gcode.addExtrude(w-5.0, d/2)
1686 gcode.addRetract(15)
1689 gcode.addMove(w/2, 5)
1691 gcode.addExtrude(w/2, d-5.0)
1693 gcode.addMove(5, d/2)
1695 gcode.addExtrude(w-5.0, d/2)
1696 gcode.addRetract(15)
1701 gcode.addCmd('M400')
1703 self.comm.printGCode(gcode.list())
1704 self.resumeButton.Enable(False)
1705 elif self._wizardState == 4:
1707 float(self.textEntry.GetValue())
1710 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1711 self._wizardState = 5
1712 self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1713 self.textEntry.SetValue('0.0')
1714 self.textEntry.Enable(True)
1715 elif self._wizardState == 5:
1717 float(self.textEntry.GetValue())
1720 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1721 self._wizardState = 6
1722 self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1723 self.textEntry.SetValue('')
1724 self.textEntry.Enable(False)
1725 self.resumeButton.Enable(False)
1727 x = profile.getMachineSettingFloat('extruder_offset_x1')
1728 y = profile.getMachineSettingFloat('extruder_offset_y1')
1729 gcode = gcodeGenerator.gcodeGenerator()
1730 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1731 gcode.setPrintSpeed(25)
1734 gcode.addMove(50, 40, 0.2)
1736 for n in xrange(0, 10):
1737 gcode.addExtrude(50 + n * 10, 150)
1738 gcode.addExtrude(50 + n * 10 + 5, 150)
1739 gcode.addExtrude(50 + n * 10 + 5, 40)
1740 gcode.addExtrude(50 + n * 10 + 10, 40)
1741 gcode.addMove(40, 50)
1742 for n in xrange(0, 10):
1743 gcode.addExtrude(150, 50 + n * 10)
1744 gcode.addExtrude(150, 50 + n * 10 + 5)
1745 gcode.addExtrude(40, 50 + n * 10 + 5)
1746 gcode.addExtrude(40, 50 + n * 10 + 10)
1747 gcode.addRetract(15)
1750 gcode.addMove(50 - x, 30 - y, 0.2)
1752 for n in xrange(0, 10):
1753 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1754 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1755 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1756 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1757 gcode.addMove(30 - x, 50 - y, 0.2)
1758 for n in xrange(0, 10):
1759 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1760 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1761 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1762 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1763 gcode.addRetract(15)
1765 gcode.addCmd('M400')
1766 gcode.addCmd('M104 T0 S0')
1767 gcode.addCmd('M104 T1 S0')
1768 self.comm.printGCode(gcode.list())
1769 elif self._wizardState == 7:
1771 n = int(self.textEntry.GetValue()) - 1
1774 x = profile.getMachineSettingFloat('extruder_offset_x1')
1776 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1777 self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1778 self.textEntry.SetValue('10')
1779 self._wizardState = 8
1780 elif self._wizardState == 8:
1782 n = int(self.textEntry.GetValue()) - 1
1785 y = profile.getMachineSettingFloat('extruder_offset_y1')
1787 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1788 self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1789 self.infoBox.SetReadyIndicator()
1790 self._wizardState = 8
1792 self.resumeButton.Enable(False)
1794 def mcLog(self, message):
1795 print 'Log:', message
1797 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1798 if self._wizardState == 1:
1799 if temp[0] >= 210 and temp[1] >= 210:
1800 self._wizardState = 2
1801 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1802 wx.CallAfter(self.resumeButton.Enable, True)
1803 wx.CallAfter(self.resumeButton.SetFocus)
1805 def mcStateChange(self, state):
1806 if self.comm is None:
1808 if self.comm.isOperational():
1809 if self._wizardState == 0:
1810 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1811 self.comm.sendCommand('M105')
1812 self.comm.sendCommand('M104 S220 T0')
1813 self.comm.sendCommand('M104 S220 T1')
1814 self.comm.sendCommand('G28')
1815 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1816 self._wizardState = 1
1817 if not self.comm.isPrinting():
1818 if self._wizardState == 3:
1819 self._wizardState = 4
1820 wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1821 wx.CallAfter(self.textEntry.SetValue, '0.0')
1822 wx.CallAfter(self.textEntry.Enable, True)
1823 wx.CallAfter(self.resumeButton.Enable, True)
1824 wx.CallAfter(self.resumeButton.SetFocus)
1825 elif self._wizardState == 6:
1826 self._wizardState = 7
1827 wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1828 wx.CallAfter(self.textEntry.SetValue, '10')
1829 wx.CallAfter(self.textEntry.Enable, True)
1830 wx.CallAfter(self.resumeButton.Enable, True)
1831 wx.CallAfter(self.resumeButton.SetFocus)
1833 elif self.comm.isError():
1834 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1836 def mcMessage(self, message):
1839 def mcProgress(self, lineNr):
1842 def mcZChange(self, newZ):
1845 class bedLevelWizard(wx.wizard.Wizard):
1847 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1849 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1850 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1852 self.mainPage = bedLevelWizardMain(self)
1853 self.headOffsetCalibration = None
1855 self.RunWizard(self.mainPage)
1858 def OnPageChanging(self, e):
1859 e.GetPage().StoreData()
1861 def OnPageChanged(self, e):
1862 if e.GetPage().AllowNext():
1863 self.FindWindowById(wx.ID_FORWARD).Enable()
1865 self.FindWindowById(wx.ID_FORWARD).Disable()
1866 if e.GetPage().AllowBack():
1867 self.FindWindowById(wx.ID_BACKWARD).Enable()
1869 self.FindWindowById(wx.ID_BACKWARD).Disable()
1871 class headOffsetWizard(wx.wizard.Wizard):
1873 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1875 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1876 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1878 self.mainPage = headOffsetCalibrationPage(self)
1880 self.RunWizard(self.mainPage)
1883 def OnPageChanging(self, e):
1884 e.GetPage().StoreData()
1886 def OnPageChanged(self, e):
1887 if e.GetPage().AllowNext():
1888 self.FindWindowById(wx.ID_FORWARD).Enable()
1890 self.FindWindowById(wx.ID_FORWARD).Disable()
1891 if e.GetPage().AllowBack():
1892 self.FindWindowById(wx.ID_BACKWARD).Enable()
1894 self.FindWindowById(wx.ID_BACKWARD).Disable()