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.BoxSizer(wx.VERTICAL)
128 self.SetSizer(self.sizer)
130 self.overlay = self.createOverlay(bitmap, overlay)
131 self.text = wx.StaticText(self, -1, label)
132 self.bmp = wx.StaticBitmap(self, -1, self.bitmap)
134 self.extra_text = wx.StaticText(self, -1, extra_label)
135 self.selected = False
137 self.sizer.Add(self.text, 0, flag=wx.ALL|wx.ALIGN_CENTER, border=5)
138 self.sizer.Add(self.bmp, 1, flag=wx.ALL|wx.ALIGN_CENTER|wx.EXPAND, border=5)
140 self.sizer.Add(self.extra_text, 0, flag=wx.ALL|wx.ALIGN_CENTER, border=5)
141 self.bmp.Bind(wx.EVT_LEFT_UP, self.OnLeftClick)
145 ImageButton.__groups__[self.group].remove(self)
146 if self == self.group:
147 for ib in ImageButton.__groups__[self.group]:
149 del ImageButton.__groups__[self.group]
150 if ImageButton.__last_group__ == self:
151 ImageButton.__last_group__ = None
153 def OnLeftClick(self, e):
159 def SetValue(self, value):
160 self.selected = bool(value)
161 self.bmp.SetBitmap(self.overlay if self.GetValue() else self.bitmap)
162 if self.selected and self.group:
163 for ib in ImageButton.__groups__[self.group]:
169 def createOverlay(self, bitmap, overlay):
170 result = bitmap.GetSubBitmap(wx.Rect(0, 0, *bitmap.Size))
171 (width, height) = bitmap.GetSize()
172 overlay_image = wx.ImageFromBitmap(overlay)
173 overlay_image = overlay_image.Scale(width, height, wx.IMAGE_QUALITY_HIGH)
174 overlay_scaled = wx.BitmapFromImage(overlay_image)
176 dc.SelectObject(result)
177 dc.DrawBitmap(overlay_scaled, 0, 0)
178 dc.SelectObject(wx.NullBitmap)
182 class InfoPage(wx.wizard.WizardPageSimple):
183 def __init__(self, parent, title):
184 wx.wizard.WizardPageSimple.__init__(self, parent)
186 parent.GetPageAreaSizer().Add(self)
187 sizer = wx.GridBagSizer(5, 5)
191 self.title = wx.StaticText(self, -1, title)
192 font = wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)
193 self.title.SetFont(font)
194 # HACK ALERT: For some reason, the StaticText keeps its same size as if
195 # the font was not modified, this causes the text to wrap and to
196 # get out of bounds of the widgets area and hide other widgets.
197 # The only way I found for the widget to get its right size was to calculate
198 # the new font's extent and set the min size on the widget
201 w,h = dc.GetTextExtent(title)
202 self.title.SetMinSize((w, h))
203 sizer.Add(self.title, pos=(0, 0), span=(1, 2), flag=wx.ALIGN_CENTRE | wx.ALL)
204 sizer.Add(wx.StaticLine(self, -1), pos=(1, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
205 sizer.AddGrowableCol(1)
209 def AddText(self, info):
210 text = wx.StaticText(self, -1, info)
211 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
215 def AddSeperator(self):
216 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
219 def AddHiddenSeperator(self):
222 def AddInfoBox(self):
223 infoBox = InfoBox(self)
224 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
228 def AddRadioButton(self, label, style=0):
229 radio = wx.RadioButton(self, -1, label, style=style)
230 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
234 def AddCheckbox(self, label, checked=False):
235 check = wx.CheckBox(self, -1)
236 text = wx.StaticText(self, -1, label)
237 check.SetValue(checked)
238 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
239 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 2), flag=wx.ALL)
243 def AddButton(self, label):
244 button = wx.Button(self, -1, label)
245 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
249 def AddDualButton(self, label1, label2):
250 button1 = wx.Button(self, -1, label1)
251 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
252 button2 = wx.Button(self, -1, label2)
253 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
255 return button1, button2
257 def AddTextCtrl(self, value):
258 ret = wx.TextCtrl(self, -1, value)
259 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
263 def AddLabelTextCtrl(self, info, value):
264 text = wx.StaticText(self, -1, info)
265 ret = wx.TextCtrl(self, -1, value)
266 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
267 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
271 def AddTextCtrlButton(self, value, buttonText):
272 text = wx.TextCtrl(self, -1, value)
273 button = wx.Button(self, -1, buttonText)
274 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
275 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
279 def AddBitmap(self, bitmap):
280 bitmap = wx.StaticBitmap(self, -1, bitmap)
281 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
286 panel = wx.Panel(self, -1)
287 sizer = wx.GridBagSizer(2, 2)
288 panel.SetSizer(sizer)
289 self.GetSizer().Add(panel, pos=(self.rowNr, 0), span=(1, 2), flag=wx.ALL | wx.EXPAND)
293 def AddCheckmark(self, label, bitmap):
294 check = wx.StaticBitmap(self, -1, bitmap)
295 text = wx.StaticText(self, -1, label)
296 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
297 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 1), flag=wx.ALL)
301 def AddCombo(self, label, options):
302 combo = wx.ComboBox(self, -1, options[0], choices=options, style=wx.CB_DROPDOWN|wx.CB_READONLY)
303 text = wx.StaticText(self, -1, label)
304 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER)
305 self.GetSizer().Add(combo, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
318 class PrintrbotPage(InfoPage):
319 def __init__(self, parent):
320 self._printer_info = [
321 # X, Y, Z, Nozzle Size, Filament Diameter, PrintTemperature, Print Speed, Travel Speed, Retract speed, Retract amount, use bed level sensor
322 ("Simple Metal", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, True),
323 ("Metal Plus", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
324 ("Simple Makers Kit", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, True),
325 (":" + _("Older models"),),
326 ("Original", 130, 130, 130, 0.5, 2.95, 208, 40, 70, 30, 1, False),
327 ("Simple Maker's Edition v1", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
328 ("Simple Maker's Edition v2 (2013 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
329 ("Simple Maker's Edition v3 (2014 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
330 ("Jr v1", 115, 120, 80, 0.4, 1.75, 208, 40, 70, 30, 1, False),
331 ("Jr v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
332 ("LC v1", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
333 ("LC v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
334 ("Plus v1", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
335 ("Plus v2", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
336 ("Plus v2.1", 185, 220, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
337 ("Plus v2.2 (Model 1404/140422/140501/140507)", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
338 ("Go v2 Large", 505, 306, 310, 0.4, 1.75, 208, 35, 70, 30, 1, True),
341 super(PrintrbotPage, self).__init__(parent, _("Printrbot Selection"))
342 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Printrbot_logo.png')))
343 self.AddText(_("Select which Printrbot machine you have:"))
345 for printer in self._printer_info:
346 if printer[0].startswith(":"):
348 self.AddText(printer[0][1:])
350 item = self.AddRadioButton(printer[0])
351 item.data = printer[1:]
352 self._items.append(item)
355 profile.putMachineSetting('machine_name', 'Printrbot ???')
356 for item in self._items:
359 profile.putMachineSetting('machine_name', 'Printrbot ' + item.GetLabel())
360 profile.putMachineSetting('machine_width', data[0])
361 profile.putMachineSetting('machine_depth', data[1])
362 profile.putMachineSetting('machine_height', data[2])
363 profile.putProfileSetting('nozzle_size', data[3])
364 profile.putProfileSetting('filament_diameter', data[4])
365 profile.putProfileSetting('print_temperature', data[5])
366 profile.putProfileSetting('print_speed', data[6])
367 profile.putProfileSetting('travel_speed', data[7])
368 profile.putProfileSetting('retraction_speed', data[8])
369 profile.putProfileSetting('retraction_amount', data[9])
370 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
371 profile.putMachineSetting('has_heated_bed', 'False')
372 profile.putMachineSetting('machine_center_is_zero', 'False')
373 profile.putMachineSetting('extruder_head_size_min_x', '0')
374 profile.putMachineSetting('extruder_head_size_min_y', '0')
375 profile.putMachineSetting('extruder_head_size_max_x', '0')
376 profile.putMachineSetting('extruder_head_size_max_y', '0')
377 profile.putMachineSetting('extruder_head_size_height', '0')
379 profile.setAlterationFile('start.gcode', """;Sliced at: {day} {date} {time}
380 ;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {fill_density}
381 ;Print time: {print_time}
382 ;Filament used: {filament_amount}m {filament_weight}g
383 ;Filament cost: {filament_cost}
384 ;M190 S{print_bed_temperature} ;Uncomment to add your own bed temperature line
385 ;M109 S{print_temperature} ;Uncomment to add your own temperature line
387 G90 ;absolute positioning
388 M82 ;set extruder to absolute mode
389 M107 ;start with the fan off
390 G28 X0 Y0 ;move X/Y to min endstops
391 G28 Z0 ;move Z to min endstops
392 G29 ;Run the auto bed leveling
393 G1 Z15.0 F{travel_speed} ;move the platform down 15mm
394 G92 E0 ;zero the extruded length
395 G1 F200 E3 ;extrude 3mm of feed stock
396 G92 E0 ;zero the extruded length again
398 ;Put printing message on LCD screen
402 class OtherMachineSelectPage(InfoPage):
403 def __init__(self, parent):
404 super(OtherMachineSelectPage, self).__init__(parent, _("Other machine information"))
405 self.AddText(_("The following pre-defined machine profiles are available"))
406 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."))
408 machines = resources.getDefaultMachineProfiles()
410 for filename in machines:
411 name = os.path.splitext(os.path.basename(filename))[0]
412 item = self.AddRadioButton(name)
413 item.filename = filename
414 item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
415 self.options.append(item)
417 item = self.AddRadioButton(_('Custom...'))
419 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
421 def OnProfileSelect(self, e):
422 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
424 def OnOtherSelect(self, e):
425 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
428 for option in self.options:
429 if option.GetValue():
430 profile.loadProfile(option.filename)
431 profile.loadMachineSettings(option.filename)
433 class OtherMachineInfoPage(InfoPage):
434 def __init__(self, parent):
435 super(OtherMachineInfoPage, self).__init__(parent, _("Cura Ready!"))
436 self.AddText(_("Cura is now ready to be used!"))
438 class CustomRepRapInfoPage(InfoPage):
439 def __init__(self, parent):
440 super(CustomRepRapInfoPage, self).__init__(parent, _("Custom RepRap information"))
441 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
442 self.AddText(_("Be sure to review the default profile before running it on your machine."))
443 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
445 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
447 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
448 self.machineWidth = self.AddLabelTextCtrl(_("Machine width X (mm)"), "80")
449 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth Y (mm)"), "80")
450 self.machineHeight = self.AddLabelTextCtrl(_("Machine height Z (mm)"), "55")
451 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
452 self.heatedBed = self.AddCheckbox(_("Heated bed"))
453 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
456 profile.putMachineSetting('machine_name', self.machineName.GetValue())
457 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
458 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
459 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
460 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
461 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
462 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
463 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
464 profile.putMachineSetting('extruder_head_size_min_x', '0')
465 profile.putMachineSetting('extruder_head_size_min_y', '0')
466 profile.putMachineSetting('extruder_head_size_max_x', '0')
467 profile.putMachineSetting('extruder_head_size_max_y', '0')
468 profile.putMachineSetting('extruder_head_size_height', '0')
469 profile.checkAndUpdateMachineName()
471 class MachineSelectPage(InfoPage):
472 def __init__(self, parent):
473 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
474 self.AddText(_("What kind of machine do you have:"))
476 self.LulzbotMiniRadio = self.AddRadioButton("LulzBot Mini", style=wx.RB_GROUP)
477 self.LulzbotMiniRadio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
478 self.LulzbotMiniRadio.SetValue(True)
479 self.LulzbotTaz5Radio = self.AddRadioButton("LulzBot TAZ 5")
480 self.LulzbotTaz5Radio.Bind(wx.EVT_RADIOBUTTON, self.OnTaz5Select)
481 self.LulzbotTaz4Radio = self.AddRadioButton("LulzBot TAZ 4")
482 self.LulzbotTaz4Radio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
483 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2")
484 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
485 self.Ultimaker2ExtRadio = self.AddRadioButton("Ultimaker2extended")
486 self.Ultimaker2ExtRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
487 self.Ultimaker2GoRadio = self.AddRadioButton("Ultimaker2go")
488 self.Ultimaker2GoRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
489 self.UltimakerRadio = self.AddRadioButton("Ultimaker Original")
490 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
491 self.UltimakerOPRadio = self.AddRadioButton("Ultimaker Original+")
492 self.UltimakerOPRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerOPSelect)
493 self.PrintrbotRadio = self.AddRadioButton("Printrbot")
494 self.PrintrbotRadio.Bind(wx.EVT_RADIOBUTTON, self.OnPrintrbotSelect)
495 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot, Witbox)"))
496 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
498 def OnUltimaker2Select(self, e):
499 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
501 def OnUltimakerSelect(self, e):
502 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
504 def OnUltimakerOPSelect(self, e):
505 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)
507 def OnPrintrbotSelect(self, e):
508 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().printrbotSelectType)
510 def OnLulzbotSelect(self, e):
511 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotToolheadPage)
513 def OnTaz5Select(self, e):
514 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().taz5NozzleSelectPage)
515 wx.wizard.WizardPageSimple.Chain(self.GetParent().taz5NozzleSelectPage, self.GetParent().lulzbotToolheadPage)
517 def OnOtherSelect(self, e):
518 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
527 profile.putProfileSetting('retraction_enable', 'True')
528 if self.Ultimaker2Radio.GetValue() or self.Ultimaker2GoRadio.GetValue() or self.Ultimaker2ExtRadio.GetValue():
529 if self.Ultimaker2Radio.GetValue():
530 profile.putMachineSetting('machine_width', '230')
531 profile.putMachineSetting('machine_depth', '225')
532 profile.putMachineSetting('machine_height', '205')
533 profile.putMachineSetting('machine_name', 'ultimaker2')
534 profile.putMachineSetting('machine_type', 'ultimaker2')
535 profile.putMachineSetting('has_heated_bed', 'True')
536 if self.Ultimaker2GoRadio.GetValue():
537 profile.putMachineSetting('machine_width', '120')
538 profile.putMachineSetting('machine_depth', '120')
539 profile.putMachineSetting('machine_height', '115')
540 profile.putMachineSetting('machine_name', 'ultimaker2go')
541 profile.putMachineSetting('machine_type', 'ultimaker2go')
542 profile.putMachineSetting('has_heated_bed', 'False')
543 if self.Ultimaker2ExtRadio.GetValue():
544 profile.putMachineSetting('machine_width', '230')
545 profile.putMachineSetting('machine_depth', '225')
546 profile.putMachineSetting('machine_height', '315')
547 profile.putMachineSetting('machine_name', 'ultimaker2extended')
548 profile.putMachineSetting('machine_type', 'ultimaker2extended')
549 profile.putMachineSetting('has_heated_bed', 'False')
550 profile.putMachineSetting('machine_center_is_zero', 'False')
551 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
552 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
553 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
554 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
555 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
556 profile.putMachineSetting('extruder_head_size_height', '48.0')
557 profile.putProfileSetting('nozzle_size', '0.4')
558 profile.putProfileSetting('fan_full_height', '5.0')
559 profile.putMachineSetting('extruder_offset_x1', '18.0')
560 profile.putMachineSetting('extruder_offset_y1', '0.0')
561 elif self.UltimakerRadio.GetValue():
562 profile.putMachineSetting('machine_width', '205')
563 profile.putMachineSetting('machine_depth', '205')
564 profile.putMachineSetting('machine_height', '200')
565 profile.putMachineSetting('machine_name', 'ultimaker original')
566 profile.putMachineSetting('machine_type', 'ultimaker')
567 profile.putMachineSetting('machine_center_is_zero', 'False')
568 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
569 profile.putProfileSetting('nozzle_size', '0.4')
570 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
571 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
572 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
573 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
574 profile.putMachineSetting('extruder_head_size_height', '55.0')
575 elif self.UltimakerOPRadio.GetValue():
576 profile.putMachineSetting('machine_width', '205')
577 profile.putMachineSetting('machine_depth', '205')
578 profile.putMachineSetting('machine_height', '200')
579 profile.putMachineSetting('machine_name', 'ultimaker original+')
580 profile.putMachineSetting('machine_type', 'ultimaker_plus')
581 profile.putMachineSetting('machine_center_is_zero', 'False')
582 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
583 profile.putProfileSetting('nozzle_size', '0.4')
584 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
585 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
586 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
587 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
588 profile.putMachineSetting('extruder_head_size_height', '55.0')
589 profile.putMachineSetting('has_heated_bed', 'True')
590 profile.putMachineSetting('extruder_amount', '1')
591 profile.putProfileSetting('retraction_enable', 'True')
592 elif self.LulzbotTaz4Radio.GetValue() or self.LulzbotTaz5Radio.GetValue() or self.LulzbotMiniRadio.GetValue():
593 if self.LulzbotTaz4Radio.GetValue():
594 profile.putMachineSetting('machine_width', '290')
595 profile.putMachineSetting('machine_depth', '275')
596 profile.putMachineSetting('machine_height', '250')
597 profile.putProfileSetting('nozzle_size', '0.35')
598 profile.putMachineSetting('machine_name', 'LulzBot TAZ 4')
599 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_4')
600 profile.putMachineSetting('serial_baud', '115200')
601 elif self.LulzbotTaz5Radio.GetValue():
602 profile.putMachineSetting('machine_width', '290')
603 profile.putMachineSetting('machine_depth', '275')
604 profile.putMachineSetting('machine_height', '250')
605 profile.putMachineSetting('serial_baud', '115200')
606 # Machine type and name are set in the nozzle select page
608 profile.putMachineSetting('machine_width', '155')
609 profile.putMachineSetting('machine_depth', '155')
610 profile.putMachineSetting('machine_height', '163')
611 profile.putProfileSetting('nozzle_size', '0.5')
612 profile.putMachineSetting('machine_name', 'LulzBot Mini')
613 profile.putMachineSetting('machine_type', 'lulzbot_mini')
614 profile.putMachineSetting('serial_baud', '115200')
615 profile.putMachineSetting('extruder_head_size_min_x', '40')
616 profile.putMachineSetting('extruder_head_size_max_x', '75')
617 profile.putMachineSetting('extruder_head_size_min_y', '25')
618 profile.putMachineSetting('extruder_head_size_max_y', '55')
619 profile.putMachineSetting('extruder_head_size_height', '17')
621 profile.putMachineSetting('machine_center_is_zero', 'False')
622 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
623 profile.putMachineSetting('has_heated_bed', 'True')
624 profile.putMachineSetting('extruder_head_size_min_x', '0.0')
625 profile.putMachineSetting('extruder_head_size_min_y', '0.0')
626 profile.putMachineSetting('extruder_head_size_max_x', '0.0')
627 profile.putMachineSetting('extruder_head_size_max_y', '0.0')
628 profile.putMachineSetting('extruder_head_size_height', '0.0')
629 profile.putPreference('startMode', 'Simple')
631 profile.putMachineSetting('machine_width', '80')
632 profile.putMachineSetting('machine_depth', '80')
633 profile.putMachineSetting('machine_height', '60')
634 profile.putMachineSetting('machine_name', 'reprap')
635 profile.putMachineSetting('machine_type', 'reprap')
636 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
637 profile.putPreference('startMode', 'Normal')
638 profile.putProfileSetting('nozzle_size', '0.5')
639 profile.checkAndUpdateMachineName()
640 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
642 class SelectParts(InfoPage):
643 def __init__(self, parent):
644 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
645 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."))
647 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
648 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
649 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
650 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
652 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."))
653 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
654 self.springExtruder.SetValue(True)
657 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
658 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
659 profile.putMachineSetting('has_heated_bed', 'True')
661 profile.putMachineSetting('has_heated_bed', 'False')
662 if self.dualExtrusion.GetValue():
663 profile.putMachineSetting('extruder_amount', '2')
664 profile.putMachineSetting('machine_depth', '195')
666 profile.putMachineSetting('extruder_amount', '1')
667 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
668 profile.putProfileSetting('retraction_enable', 'True')
670 profile.putProfileSetting('retraction_enable', 'False')
673 class UltimakerFirmwareUpgradePage(InfoPage):
674 def __init__(self, parent):
675 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
676 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."))
677 self.AddHiddenSeperator()
678 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
679 self.AddHiddenSeperator()
680 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."))
681 upgradeButton, skipUpgradeButton = self.AddDualButton(_('Upgrade to Marlin firmware'), _('Skip upgrade'))
682 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
683 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
684 self.AddHiddenSeperator()
685 if profile.getMachineSetting('machine_type') == 'ultimaker':
686 self.AddText(_("Do not upgrade to this firmware if:"))
687 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
688 self.AddText(_("* Build your own heated bed"))
689 self.AddText(_("* Have other changes in the firmware"))
690 # button = self.AddButton('Goto this page for a custom firmware')
691 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
696 def OnUpgradeClick(self, e):
697 if firmwareInstall.InstallFirmware():
698 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
700 def OnSkipClick(self, e):
701 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
702 self.GetParent().ShowPage(self.GetNext())
704 def OnUrlClick(self, e):
705 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
707 class UltimakerCheckupPage(InfoPage):
708 def __init__(self, parent):
709 super(UltimakerCheckupPage, self).__init__(parent, _("Ultimaker Checkup"))
711 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
712 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
713 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
714 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
715 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
716 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
717 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
718 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
719 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
720 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
723 _("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."))
724 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
725 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
726 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
728 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
729 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
730 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
732 self.infoBox = self.AddInfoBox()
733 self.machineState = self.AddText("")
734 self.temperatureLabel = self.AddText("")
735 self.errorLogButton = self.AddButton(_("Show error log"))
736 self.errorLogButton.Show(False)
738 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
740 self.xMinStop = False
741 self.xMaxStop = False
742 self.yMinStop = False
743 self.yMaxStop = False
744 self.zMinStop = False
745 self.zMaxStop = False
747 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
750 if self.comm is not None:
754 self.endstopBitmap.Show(False)
757 def OnSkipClick(self, e):
758 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
759 self.GetParent().ShowPage(self.GetNext())
761 def OnCheckClick(self, e=None):
762 self.errorLogButton.Show(False)
763 if self.comm is not None:
767 wx.CallAfter(self.OnCheckClick)
769 self.infoBox.SetBusy(_("Connecting to machine."))
770 self.commState.SetBitmap(self.unknownBitmap)
771 self.tempState.SetBitmap(self.unknownBitmap)
772 self.stopState.SetBitmap(self.unknownBitmap)
773 self.checkupState = 0
774 self.checkExtruderNr = 0
775 self.comm = machineCom.MachineCom(callbackObject=self)
777 def OnErrorLog(self, e):
778 printWindow.LogWindow('\n'.join(self.comm.getLog()))
780 def mcLog(self, message):
783 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
784 if not self.comm.isOperational():
786 if self.checkupState == 0:
787 self.tempCheckTimeout = 20
788 if temp[self.checkExtruderNr] > 70:
789 self.checkupState = 1
790 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
791 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
792 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
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 == 1:
800 if temp[self.checkExtruderNr] < 60:
801 self.startTemp = temp[self.checkExtruderNr]
802 self.checkupState = 2
803 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
804 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
805 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
806 elif self.checkupState == 2:
807 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
808 if temp[self.checkExtruderNr] > self.startTemp + 40:
809 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
810 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
811 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
812 self.checkExtruderNr = 0
813 self.checkupState = 3
814 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
815 wx.CallAfter(self.endstopBitmap.Show, True)
816 wx.CallAfter(self.Layout)
817 self.comm.sendCommand('M119')
818 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
820 self.checkupState = 0
821 self.checkExtruderNr += 1
823 self.tempCheckTimeout -= 1
824 if self.tempCheckTimeout < 1:
825 self.checkupState = -1
826 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
827 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
828 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
829 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
830 elif self.checkupState >= 3 and self.checkupState < 10:
831 self.comm.sendCommand('M119')
832 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
834 def mcStateChange(self, state):
835 if self.comm is None:
837 if self.comm.isOperational():
838 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
839 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
840 elif self.comm.isError():
841 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
842 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
843 wx.CallAfter(self.endstopBitmap.Show, False)
844 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
845 wx.CallAfter(self.errorLogButton.Show, True)
846 wx.CallAfter(self.Layout)
848 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
850 def mcMessage(self, message):
851 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
852 for data in message.split(' '):
854 tag, value = data.split(':', 1)
856 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
858 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
860 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
862 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
864 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
866 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
868 tag, value = map(str.strip, message.split(':', 1))
870 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
872 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
874 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
876 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
878 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
880 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
881 if 'z_max' in message:
882 self.comm.sendCommand('M119')
884 if self.checkupState == 3:
885 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
886 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
887 self.checkupState = 5
888 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
889 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
891 self.checkupState = 4
892 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
893 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
894 elif self.checkupState == 4:
895 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
896 self.checkupState = 5
897 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
898 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
899 elif self.checkupState == 5:
900 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
901 self.checkupState = 6
902 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
903 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
904 elif self.checkupState == 6:
905 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
906 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
907 self.checkupState = 8
908 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
909 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
911 self.checkupState = 7
912 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
913 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
914 elif self.checkupState == 7:
915 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
916 self.checkupState = 8
917 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
918 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
919 elif self.checkupState == 8:
920 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
921 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
922 self.checkupState = 10
924 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
925 wx.CallAfter(self.infoBox.SetReadyIndicator)
926 wx.CallAfter(self.endstopBitmap.Show, False)
927 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
928 wx.CallAfter(self.OnSkipClick, None)
930 self.checkupState = 9
931 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
932 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
933 elif self.checkupState == 9:
934 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
935 self.checkupState = 10
937 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
938 wx.CallAfter(self.infoBox.SetReadyIndicator)
939 wx.CallAfter(self.endstopBitmap.Show, False)
940 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
941 wx.CallAfter(self.OnSkipClick, None)
943 def mcProgress(self, lineNr):
946 def mcZChange(self, newZ):
950 class UltimakerCalibrationPage(InfoPage):
951 def __init__(self, parent):
952 super(UltimakerCalibrationPage, self).__init__(parent, _("Ultimaker Calibration"))
954 self.AddText("Your Ultimaker requires some calibration.")
955 self.AddText("This calibration is needed for a proper extrusion amount.")
957 self.AddText("The following values are needed:")
958 self.AddText("* Diameter of filament")
959 self.AddText("* Number of steps per mm of filament extrusion")
961 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
963 self.AddText("First we need the diameter of your filament:")
964 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
966 "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.")
967 self.AddText("Note: This value can be changed later at any time.")
970 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
973 class UltimakerCalibrateStepsPerEPage(InfoPage):
974 def __init__(self, parent):
975 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, _("Ultimaker Calibration"))
977 #if profile.getMachineSetting('steps_per_e') == '0':
978 # profile.putMachineSetting('steps_per_e', '865.888')
980 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
981 self.AddText(_("First remove any filament from your machine."))
982 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
983 self.AddText(_("We'll push the filament 100mm"))
984 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
985 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
986 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
987 self.AddText(_("This results in the following steps per E:"))
988 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
989 self.AddText(_("You can repeat these steps to get better calibration."))
992 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
993 self.heatButton = self.AddButton(_("Heatup for filament removal"))
995 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
996 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
997 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
999 def OnSaveLengthClick(self, e):
1000 currentEValue = float(self.stepsPerEInput.GetValue())
1001 realExtrudeLength = float(self.lengthInput.GetValue())
1002 newEValue = currentEValue * 100 / realExtrudeLength
1003 self.stepsPerEInput.SetValue(str(newEValue))
1004 self.lengthInput.SetValue("100")
1006 def OnExtrudeClick(self, e):
1007 t = threading.Thread(target=self.OnExtrudeRun)
1011 def OnExtrudeRun(self):
1012 self.heatButton.Enable(False)
1013 self.extrudeButton.Enable(False)
1014 currentEValue = float(self.stepsPerEInput.GetValue())
1015 self.comm = machineCom.MachineCom()
1016 if not self.comm.isOpen():
1018 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
1019 'Printer error', wx.OK | wx.ICON_INFORMATION)
1020 self.heatButton.Enable(True)
1021 self.extrudeButton.Enable(True)
1024 line = self.comm.readline()
1029 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
1032 self.sendGCommand('M302') #Disable cold extrusion protection
1033 self.sendGCommand("M92 E%f" % (currentEValue))
1034 self.sendGCommand("G92 E0")
1035 self.sendGCommand("G1 E100 F600")
1038 self.extrudeButton.Enable()
1039 self.heatButton.Enable()
1041 def OnHeatClick(self, e):
1042 t = threading.Thread(target=self.OnHeatRun)
1046 def OnHeatRun(self):
1047 self.heatButton.Enable(False)
1048 self.extrudeButton.Enable(False)
1049 self.comm = machineCom.MachineCom()
1050 if not self.comm.isOpen():
1052 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
1053 'Printer error', wx.OK | wx.ICON_INFORMATION)
1054 self.heatButton.Enable(True)
1055 self.extrudeButton.Enable(True)
1058 line = self.comm.readline()
1060 self.heatButton.Enable(True)
1061 self.extrudeButton.Enable(True)
1065 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
1068 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
1070 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
1071 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
1072 self.sendGCommand('M104 S0')
1075 self.heatButton.Enable(True)
1076 self.extrudeButton.Enable(True)
1078 def sendGCommand(self, cmd):
1079 self.comm.sendCommand(cmd) #Disable cold extrusion protection
1081 line = self.comm.readline()
1084 if line.startswith('ok'):
1087 def StoreData(self):
1088 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
1090 class Ultimaker2ReadyPage(InfoPage):
1091 def __init__(self, parent):
1092 super(Ultimaker2ReadyPage, self).__init__(parent, _("Ultimaker2"))
1093 self.AddText(_('Congratulations on your the purchase of your brand new Ultimaker2.'))
1094 self.AddText(_('Cura is now ready to be used with your Ultimaker2.'))
1097 class LulzbotReadyPage(InfoPage):
1098 def __init__(self, parent):
1099 super(LulzbotReadyPage, self).__init__(parent, _("LulzBot TAZ/Mini"))
1100 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Lulzbot_logo.png')))
1101 self.AddText(_('Cura is now ready to be used with your LulzBot 3D printer.'))
1103 self.AddText(_('For more information about using Cura with your LulzBot'))
1104 self.AddText(_('3D printer, please visit www.LulzBot.com/cura'))
1107 class LulzbotToolheadSelectPage(InfoPage):
1108 url='http://lulzbot.com/toolhead-identification'
1110 def __init__(self, parent):
1111 super(LulzbotToolheadSelectPage, self).__init__(parent, _("LulzBot Toolhead Selection"))
1113 self.mini_choices = [_('Standard'), _('Flexystruder')]
1114 self.taz_choices = [_('Standard v1'),
1115 _('Standard v2 0.35 mm nozzle'), _('Standard v2 0.5 mm nozzle'),
1116 _('Flexystruder v1'), _('Flexystruder v2'),
1117 _('Dually v1'), _('Dually v2'),
1118 _('FlexyDually v1'), _('FlexyDually v2')]
1119 self.description_map = {
1120 _('Standard'): _('This is the standard toolhead that comes with the Lulzbot Mini'),
1121 _('Flexystruder'): _('This is the Flexystruder for the Lulzbot Mini\nIt is used for printing Flexible materials'),
1122 _('Standard v1'): _('This is the standard toolhead that comes with the Lulzbot TAZ 1-2-3 and TAZ 4.\nIt uses the Budaschnozzle for the hotend'),
1123 _('Standard v2 0.35 mm nozzle'): _('This is the standard toolhead that comes with the Lulzbot TAZ 5.\nIt uses the Hexagon hotend and a 0.35 mm nozzle'),
1124 _('Standard v2 0.5 mm nozzle'): _('This is the standard toolhead that comes with the Lulzbot TAZ 5.\nIt uses the Hexagon hotend and a 0.5 mm nozzle'),
1125 _('Flexystruder v1'): _('It\'s the flexy!'),
1126 _('Flexystruder v2'): _('It\'s the flexy v2!'),
1127 _('Dually v1'): _('It\'s the dualy v1!'),
1128 _('Dually v2'): _('It\'s the dual v2!'),
1129 _('FlexyDually v1'): _('It\'s the flexy dually v1!'),
1130 _('FlexyDually v2'): _('It\'s the flexy dual v2!')
1133 _('Standard'): 'Lulzbot_Toolhead_Mini_Standard.jpg',
1134 _('Flexystruder'): 'Lulzbot_logo.png',
1135 _('Standard v1'): 'Lulzbot_logo.png',
1136 _('Standard v2 0.35 mm nozzle'): 'Lulzbot_Toolhead_TAZ_Single_v2.jpg',
1137 _('Standard v2 0.5 mm nozzle'): 'Lulzbot_Toolhead_TAZ_Single_v2.jpg',
1138 _('Flexystruder v1'): 'Lulzbot_Toolhead_TAZ_Flexystruder_v1.jpg',
1139 _('Flexystruder v2'): 'Lulzbot_logo.png',
1140 _('Dually v1'): 'Lulzbot_Toolhead_TAZ_Dually_v1.jpg',
1141 _('Dually v2'): 'Lulzbot_logo.png',
1142 _('FlexyDually v1'): 'Lulzbot_logo.png',
1143 _('FlexyDually v2'): 'Lulzbot_logo.png'
1145 self.AddBitmap(wx.Bitmap(resources.getPathForImage('LulzBot_logo.png')))
1146 printer_name = profile.getMachineSetting('machine_type')
1147 self.Bind(wx.wizard.EVT_WIZARD_PAGE_SHOWN, self.OnPageShown)
1149 self.AddText(_('Please select your currently installed Tool Head'))
1150 txt = self.AddText(_('It is important to select the correct Tool head for your printer.\n' +
1151 'Flashing the wrong firmware on your printer can cause damage to your printer and to your toolhead\n' +
1152 'If you are not sure which toolhead you have, please refer to this webpage for more information: '))
1153 txt.SetForegroundColour(wx.RED)
1154 button = self.AddButton(self.url)
1155 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1158 #self.combo = self.AddCombo(_('Currently installed Toolhead'), [''])
1159 #self.combo.SetEditable(False)
1160 #self.combo.Bind(wx.EVT_COMBOBOX, self.OnToolheadSelected)
1161 #self.description = self.AddText('\n\n')
1162 #self.description.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.BOLD))
1163 #self.image = self.AddBitmap(wx.Bitmap(resources.getPathForImage(self.image_map[self.mini_choices[0]])))
1164 self.panel = self.AddPanel()
1165 ib1 = ImageButton(self.panel, "Mini", wx.Bitmap(resources.getPathForImage('Lulzbot_Toolhead_TAZ_Flexystruder_v1.jpg')), "Some description", style=ImageButton.IB_GROUP)
1166 ib2 = ImageButton(self.panel, "TAZ 4 ", wx.Bitmap(resources.getPathForImage('Lulzbot_Toolhead_TAZ_Single_v2.jpg')), "Some description 2")
1167 ib3 = ImageButton(self.panel, "TAZ 5 ", wx.Bitmap(resources.getPathForImage('Lulzbot_Toolhead_TAZ_Flexystruder_v1.jpg')))
1168 ib4 = ImageButton(self.panel, "Others ", wx.Bitmap(resources.getPathForImage('Lulzbot_Toolhead_TAZ_Dually_v1.jpg')))
1169 self.panel.GetSizer().Add(ib1, pos=(0, 0), flag=wx.EXPAND)
1170 self.panel.GetSizer().Add(ib2, pos=(0, 1), flag=wx.EXPAND)
1171 self.panel.GetSizer().Add(ib3, pos=(1, 0), flag=wx.EXPAND)
1172 self.panel.GetSizer().Add(ib4, pos=(1, 1), flag=wx.EXPAND)
1175 def OnPageShown(self, e):
1176 printer_name = profile.getMachineSetting('machine_type')
1177 if printer_name == 'lulzbot_mini':
1178 choices = self.mini_choices
1181 choices = self.taz_choices
1182 if printer_name == 'lulzbot_TAZ_4':
1184 elif printer_name == 'lulzbot_TAZ_5':
1190 self.combo.AppendItems(choices)
1191 self.combo.SetValue(choices[default])
1192 self.OnToolheadSelected(e)
1194 def OnUrlClick(self, e):
1195 webbrowser.open(LulzbotToolheadSelectPage.url)
1197 def OnToolheadSelected(self, e):
1198 toolhead = self.combo.GetValue()
1199 if self.description_map.has_key(toolhead):
1200 self.image.SetBitmap(wx.Bitmap(resources.getPathForImage(self.image_map[toolhead])))
1201 self.description.SetLabel(self.description_map[toolhead])
1203 self.image.SetBitmap(wx.NullBitmap)
1204 self.description.SetLabel('\n\n')
1209 class Taz5NozzleSelectPage(InfoPage):
1210 url='http://lulzbot.com/printer-identification'
1212 def __init__(self, parent):
1213 super(Taz5NozzleSelectPage, self).__init__(parent, _("LulzBot TAZ5"))
1214 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Lulzbot_logo.png')))
1216 self.AddText(_(' '))
1217 self.AddText(_('Please select nozzle size:'))
1218 self.Nozzle35Radio = self.AddRadioButton("0.35 mm", style=wx.RB_GROUP)
1219 self.Nozzle35Radio.SetValue(True)
1220 self.Nozzle50Radio = self.AddRadioButton("0.5 mm")
1221 self.AddText(_(' '))
1224 self.AddText(_('If you are not sure which nozzle size you have'))
1225 self.AddText(_('please check this webpage: '))
1226 button = self.AddButton(Taz5NozzleSelectPage.url)
1227 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1229 def OnUrlClick(self, e):
1230 webbrowser.open(Taz5NozzleSelectPage.url)
1232 def StoreData(self):
1233 if self.Nozzle35Radio.GetValue():
1234 profile.putProfileSetting('nozzle_size', '0.35')
1235 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.35 nozzle)')
1236 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5')
1239 profile.putProfileSetting('nozzle_size', '0.5')
1240 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.5 nozzle)')
1241 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5_05nozzle')
1243 class ConfigWizard(wx.wizard.Wizard):
1244 def __init__(self, addNew = False):
1245 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
1247 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1249 profile.setActiveMachine(profile.getMachineCount())
1251 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1252 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1253 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1255 self.machineSelectPage = MachineSelectPage(self)
1256 self.ultimakerSelectParts = SelectParts(self)
1257 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
1258 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
1259 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
1260 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
1261 self.bedLevelPage = bedLevelWizardMain(self)
1262 self.headOffsetCalibration = headOffsetCalibrationPage(self)
1263 self.printrbotSelectType = PrintrbotPage(self)
1264 self.otherMachineSelectPage = OtherMachineSelectPage(self)
1265 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
1266 self.otherMachineInfoPage = OtherMachineInfoPage(self)
1268 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
1269 self.lulzbotReadyPage = LulzbotReadyPage(self)
1270 self.lulzbotToolheadPage = LulzbotToolheadSelectPage(self)
1271 self.taz5NozzleSelectPage = Taz5NozzleSelectPage(self)
1273 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
1274 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
1275 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
1276 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
1277 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
1278 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
1279 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
1280 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
1281 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.lulzbotToolheadPage)
1282 wx.wizard.WizardPageSimple.Chain(self.lulzbotToolheadPage, self.lulzbotReadyPage)
1284 self.RunWizard(self.machineSelectPage)
1287 def OnPageChanging(self, e):
1288 e.GetPage().StoreData()
1290 def OnPageChanged(self, e):
1291 if e.GetPage().AllowNext():
1292 self.FindWindowById(wx.ID_FORWARD).Enable()
1294 self.FindWindowById(wx.ID_FORWARD).Disable()
1295 if e.GetPage().AllowBack():
1296 self.FindWindowById(wx.ID_BACKWARD).Enable()
1298 self.FindWindowById(wx.ID_BACKWARD).Disable()
1300 def OnCancel(self, e):
1301 new_machine_index = int(profile.getPreferenceFloat('active_machine'))
1302 profile.setActiveMachine(self._old_machine_index)
1303 profile.removeMachine(new_machine_index)
1305 class bedLevelWizardMain(InfoPage):
1306 def __init__(self, parent):
1307 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1309 self.AddText(_('This wizard will help you in leveling your printer bed'))
1311 self.AddText(_('It will do the following steps'))
1312 self.AddText(_('* Move the printer head to each corner'))
1313 self.AddText(_(' and let you adjust the height of the bed to the nozzle'))
1314 self.AddText(_('* Print a line around the bed to check if it is level'))
1317 self.connectButton = self.AddButton(_('Connect to printer'))
1320 self.infoBox = self.AddInfoBox()
1321 self.resumeButton = self.AddButton(_('Resume'))
1322 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1323 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1324 self.resumeButton.Enable(False)
1326 self.upButton.Enable(False)
1327 self.downButton.Enable(False)
1328 self.upButton2.Enable(False)
1329 self.downButton2.Enable(False)
1331 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1332 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1333 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1334 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1335 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1336 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1338 def OnConnect(self, e = None):
1339 if self.comm is not None:
1343 wx.CallAfter(self.OnConnect)
1345 self.connectButton.Enable(False)
1346 self.comm = machineCom.MachineCom(callbackObject=self)
1347 self.infoBox.SetBusy(_('Connecting to machine.'))
1348 self._wizardState = 0
1350 def OnBedUp(self, e):
1351 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1352 self.comm.sendCommand('G92 Z10')
1353 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1354 self.comm.sendCommand('M400')
1356 def OnBedDown(self, e):
1357 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1358 self.comm.sendCommand('G92 Z10')
1359 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1360 self.comm.sendCommand('M400')
1362 def OnBedUp2(self, e):
1363 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1364 self.comm.sendCommand('G92 Z10')
1365 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1366 self.comm.sendCommand('M400')
1368 def OnBedDown2(self, e):
1369 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1370 self.comm.sendCommand('G92 Z10')
1371 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1372 self.comm.sendCommand('M400')
1374 def AllowNext(self):
1375 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1376 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1379 def OnResume(self, e):
1380 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1381 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1382 if self._wizardState == -1:
1383 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1384 wx.CallAfter(self.upButton.Enable, False)
1385 wx.CallAfter(self.downButton.Enable, False)
1386 wx.CallAfter(self.upButton2.Enable, False)
1387 wx.CallAfter(self.downButton2.Enable, False)
1388 self.comm.sendCommand('M105')
1389 self.comm.sendCommand('G28')
1390 self._wizardState = 1
1391 elif self._wizardState == 2:
1392 if profile.getMachineSetting('has_heated_bed') == 'True':
1393 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1394 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1395 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1396 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1397 self.comm.sendCommand('M400')
1398 self._wizardState = 3
1400 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1401 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1402 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1403 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1404 self.comm.sendCommand('M400')
1405 self._wizardState = 3
1406 elif self._wizardState == 4:
1407 if profile.getMachineSetting('has_heated_bed') == 'True':
1408 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1409 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1410 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1411 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1412 self.comm.sendCommand('M400')
1413 self._wizardState = 7
1415 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1416 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1417 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1418 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1419 self.comm.sendCommand('M400')
1420 self._wizardState = 5
1421 elif self._wizardState == 6:
1422 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1423 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1424 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1425 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1426 self.comm.sendCommand('M400')
1427 self._wizardState = 7
1428 elif self._wizardState == 8:
1429 wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1430 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1431 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1432 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1433 self._wizardState = 9
1434 elif self._wizardState == 10:
1435 self._wizardState = 11
1436 wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1437 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1438 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1439 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1440 w = profile.getMachineSettingFloat('machine_width') - 10
1441 d = profile.getMachineSettingFloat('machine_depth')
1442 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1443 filamentArea = math.pi * filamentRadius * filamentRadius
1444 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1448 'G1 Z2 F%d' % (feedZ),
1450 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1451 'G1 Z0.3 F%d' % (feedZ)]
1453 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1455 for i in xrange(0, 3):
1456 dist = 5.0 + 0.4 * float(i)
1457 eValue += (d - 2.0*dist) * ePerMM
1458 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1459 eValue += (w - 2.0*dist) * ePerMM
1460 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1461 eValue += (d - 2.0*dist) * ePerMM
1462 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1463 eValue += (w - 2.0*dist) * ePerMM
1464 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1466 gcodeList.append('M400')
1467 self.comm.printGCode(gcodeList)
1468 self.resumeButton.Enable(False)
1470 def mcLog(self, message):
1471 print 'Log:', message
1473 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1474 if self._wizardState == 1:
1475 self._wizardState = 2
1476 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1477 wx.CallAfter(self.resumeButton.Enable, True)
1478 elif self._wizardState == 3:
1479 self._wizardState = 4
1480 if profile.getMachineSetting('has_heated_bed') == 'True':
1481 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1483 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1484 wx.CallAfter(self.resumeButton.Enable, True)
1485 elif self._wizardState == 5:
1486 self._wizardState = 6
1487 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1488 wx.CallAfter(self.resumeButton.Enable, True)
1489 elif self._wizardState == 7:
1490 self._wizardState = 8
1491 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1492 wx.CallAfter(self.resumeButton.Enable, True)
1493 elif self._wizardState == 9:
1494 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1495 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1497 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1498 wx.CallAfter(self.resumeButton.Enable, True)
1499 self._wizardState = 10
1501 def mcStateChange(self, state):
1502 if self.comm is None:
1504 if self.comm.isOperational():
1505 if self._wizardState == 0:
1506 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1507 wx.CallAfter(self.upButton.Enable, True)
1508 wx.CallAfter(self.downButton.Enable, True)
1509 wx.CallAfter(self.upButton2.Enable, True)
1510 wx.CallAfter(self.downButton2.Enable, True)
1511 wx.CallAfter(self.resumeButton.Enable, True)
1512 self._wizardState = -1
1513 elif self._wizardState == 11 and not self.comm.isPrinting():
1514 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1515 self.comm.sendCommand('G92 E0')
1516 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1517 self.comm.sendCommand('M104 S0')
1518 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1519 wx.CallAfter(self.infoBox.SetReadyIndicator)
1520 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1521 wx.CallAfter(self.connectButton.Enable, True)
1522 self._wizardState = 12
1523 elif self.comm.isError():
1524 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1526 def mcMessage(self, message):
1529 def mcProgress(self, lineNr):
1532 def mcZChange(self, newZ):
1535 class headOffsetCalibrationPage(InfoPage):
1536 def __init__(self, parent):
1537 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1539 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1542 self.connectButton = self.AddButton(_('Connect to printer'))
1545 self.infoBox = self.AddInfoBox()
1546 self.textEntry = self.AddTextCtrl('')
1547 self.textEntry.Enable(False)
1548 self.resumeButton = self.AddButton(_('Resume'))
1549 self.resumeButton.Enable(False)
1551 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1552 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1554 def AllowBack(self):
1557 def OnConnect(self, e = None):
1558 if self.comm is not None:
1562 wx.CallAfter(self.OnConnect)
1564 self.connectButton.Enable(False)
1565 self.comm = machineCom.MachineCom(callbackObject=self)
1566 self.infoBox.SetBusy(_('Connecting to machine.'))
1567 self._wizardState = 0
1569 def OnResume(self, e):
1570 if self._wizardState == 2:
1571 self._wizardState = 3
1572 wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1574 w = profile.getMachineSettingFloat('machine_width')
1575 d = profile.getMachineSettingFloat('machine_depth')
1577 gcode = gcodeGenerator.gcodeGenerator()
1578 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1579 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1586 gcode.addMove(w/2, 5)
1587 gcode.addMove(z=0.2)
1589 gcode.addExtrude(w/2, d-5.0)
1591 gcode.addMove(5, d/2)
1593 gcode.addExtrude(w-5.0, d/2)
1594 gcode.addRetract(15)
1597 gcode.addMove(w/2, 5)
1599 gcode.addExtrude(w/2, d-5.0)
1601 gcode.addMove(5, d/2)
1603 gcode.addExtrude(w-5.0, d/2)
1604 gcode.addRetract(15)
1609 gcode.addCmd('M400')
1611 self.comm.printGCode(gcode.list())
1612 self.resumeButton.Enable(False)
1613 elif self._wizardState == 4:
1615 float(self.textEntry.GetValue())
1618 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1619 self._wizardState = 5
1620 self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1621 self.textEntry.SetValue('0.0')
1622 self.textEntry.Enable(True)
1623 elif self._wizardState == 5:
1625 float(self.textEntry.GetValue())
1628 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1629 self._wizardState = 6
1630 self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1631 self.textEntry.SetValue('')
1632 self.textEntry.Enable(False)
1633 self.resumeButton.Enable(False)
1635 x = profile.getMachineSettingFloat('extruder_offset_x1')
1636 y = profile.getMachineSettingFloat('extruder_offset_y1')
1637 gcode = gcodeGenerator.gcodeGenerator()
1638 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1639 gcode.setPrintSpeed(25)
1642 gcode.addMove(50, 40, 0.2)
1644 for n in xrange(0, 10):
1645 gcode.addExtrude(50 + n * 10, 150)
1646 gcode.addExtrude(50 + n * 10 + 5, 150)
1647 gcode.addExtrude(50 + n * 10 + 5, 40)
1648 gcode.addExtrude(50 + n * 10 + 10, 40)
1649 gcode.addMove(40, 50)
1650 for n in xrange(0, 10):
1651 gcode.addExtrude(150, 50 + n * 10)
1652 gcode.addExtrude(150, 50 + n * 10 + 5)
1653 gcode.addExtrude(40, 50 + n * 10 + 5)
1654 gcode.addExtrude(40, 50 + n * 10 + 10)
1655 gcode.addRetract(15)
1658 gcode.addMove(50 - x, 30 - y, 0.2)
1660 for n in xrange(0, 10):
1661 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1662 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1663 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1664 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1665 gcode.addMove(30 - x, 50 - y, 0.2)
1666 for n in xrange(0, 10):
1667 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1668 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1669 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1670 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1671 gcode.addRetract(15)
1673 gcode.addCmd('M400')
1674 gcode.addCmd('M104 T0 S0')
1675 gcode.addCmd('M104 T1 S0')
1676 self.comm.printGCode(gcode.list())
1677 elif self._wizardState == 7:
1679 n = int(self.textEntry.GetValue()) - 1
1682 x = profile.getMachineSettingFloat('extruder_offset_x1')
1684 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1685 self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1686 self.textEntry.SetValue('10')
1687 self._wizardState = 8
1688 elif self._wizardState == 8:
1690 n = int(self.textEntry.GetValue()) - 1
1693 y = profile.getMachineSettingFloat('extruder_offset_y1')
1695 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1696 self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1697 self.infoBox.SetReadyIndicator()
1698 self._wizardState = 8
1700 self.resumeButton.Enable(False)
1702 def mcLog(self, message):
1703 print 'Log:', message
1705 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1706 if self._wizardState == 1:
1707 if temp[0] >= 210 and temp[1] >= 210:
1708 self._wizardState = 2
1709 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1710 wx.CallAfter(self.resumeButton.Enable, True)
1711 wx.CallAfter(self.resumeButton.SetFocus)
1713 def mcStateChange(self, state):
1714 if self.comm is None:
1716 if self.comm.isOperational():
1717 if self._wizardState == 0:
1718 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1719 self.comm.sendCommand('M105')
1720 self.comm.sendCommand('M104 S220 T0')
1721 self.comm.sendCommand('M104 S220 T1')
1722 self.comm.sendCommand('G28')
1723 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1724 self._wizardState = 1
1725 if not self.comm.isPrinting():
1726 if self._wizardState == 3:
1727 self._wizardState = 4
1728 wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1729 wx.CallAfter(self.textEntry.SetValue, '0.0')
1730 wx.CallAfter(self.textEntry.Enable, True)
1731 wx.CallAfter(self.resumeButton.Enable, True)
1732 wx.CallAfter(self.resumeButton.SetFocus)
1733 elif self._wizardState == 6:
1734 self._wizardState = 7
1735 wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1736 wx.CallAfter(self.textEntry.SetValue, '10')
1737 wx.CallAfter(self.textEntry.Enable, True)
1738 wx.CallAfter(self.resumeButton.Enable, True)
1739 wx.CallAfter(self.resumeButton.SetFocus)
1741 elif self.comm.isError():
1742 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1744 def mcMessage(self, message):
1747 def mcProgress(self, lineNr):
1750 def mcZChange(self, newZ):
1753 class bedLevelWizard(wx.wizard.Wizard):
1755 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1757 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1758 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1760 self.mainPage = bedLevelWizardMain(self)
1761 self.headOffsetCalibration = None
1763 self.RunWizard(self.mainPage)
1766 def OnPageChanging(self, e):
1767 e.GetPage().StoreData()
1769 def OnPageChanged(self, e):
1770 if e.GetPage().AllowNext():
1771 self.FindWindowById(wx.ID_FORWARD).Enable()
1773 self.FindWindowById(wx.ID_FORWARD).Disable()
1774 if e.GetPage().AllowBack():
1775 self.FindWindowById(wx.ID_BACKWARD).Enable()
1777 self.FindWindowById(wx.ID_BACKWARD).Disable()
1779 class headOffsetWizard(wx.wizard.Wizard):
1781 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1783 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1784 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1786 self.mainPage = headOffsetCalibrationPage(self)
1788 self.RunWizard(self.mainPage)
1791 def OnPageChanging(self, e):
1792 e.GetPage().StoreData()
1794 def OnPageChanged(self, e):
1795 if e.GetPage().AllowNext():
1796 self.FindWindowById(wx.ID_FORWARD).Enable()
1798 self.FindWindowById(wx.ID_FORWARD).Disable()
1799 if e.GetPage().AllowBack():
1800 self.FindWindowById(wx.ID_BACKWARD).Enable()
1802 self.FindWindowById(wx.ID_BACKWARD).Disable()