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]:
168 def createOverlay(self, bitmap, overlay):
169 result = bitmap.GetSubBitmap(wx.Rect(0, 0, *bitmap.Size))
170 (width, height) = bitmap.GetSize()
171 overlay_image = wx.ImageFromBitmap(overlay)
172 overlay_image = overlay_image.Scale(width, height, wx.IMAGE_QUALITY_HIGH)
173 overlay_scaled = wx.BitmapFromImage(overlay_image)
175 dc.SelectObject(result)
176 dc.DrawBitmap(overlay_scaled, 0, 0)
177 dc.SelectObject(wx.NullBitmap)
181 class InfoPage(wx.wizard.WizardPageSimple):
182 def __init__(self, parent, title):
183 wx.wizard.WizardPageSimple.__init__(self, parent)
185 parent.GetPageAreaSizer().Add(self)
186 sizer = wx.GridBagSizer(5, 5)
190 self.title = wx.StaticText(self, -1, title)
191 font = wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)
192 self.title.SetFont(font)
193 # HACK ALERT: For some reason, the StaticText keeps its same size as if
194 # the font was not modified, this causes the text to wrap and to
195 # get out of bounds of the widgets area and hide other widgets.
196 # The only way I found for the widget to get its right size was to calculate
197 # the new font's extent and set the min size on the widget
200 w,h = dc.GetTextExtent(title)
201 self.title.SetMinSize((w, h))
202 sizer.Add(self.title, pos=(0, 0), span=(1, 2), flag=wx.ALIGN_CENTRE | wx.ALL)
203 sizer.Add(wx.StaticLine(self, -1), pos=(1, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
204 sizer.AddGrowableCol(1)
208 def AddText(self, info):
209 text = wx.StaticText(self, -1, info)
210 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
214 def AddSeperator(self):
215 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
218 def AddHiddenSeperator(self):
221 def AddInfoBox(self):
222 infoBox = InfoBox(self)
223 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
227 def AddRadioButton(self, label, style=0):
228 radio = wx.RadioButton(self, -1, label, style=style)
229 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
233 def AddCheckbox(self, label, checked=False):
234 check = wx.CheckBox(self, -1)
235 text = wx.StaticText(self, -1, label)
236 check.SetValue(checked)
237 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
238 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 2), flag=wx.ALL)
242 def AddButton(self, label):
243 button = wx.Button(self, -1, label)
244 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
248 def AddDualButton(self, label1, label2):
249 button1 = wx.Button(self, -1, label1)
250 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
251 button2 = wx.Button(self, -1, label2)
252 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
254 return button1, button2
256 def AddTextCtrl(self, value):
257 ret = wx.TextCtrl(self, -1, value)
258 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
262 def AddLabelTextCtrl(self, info, value):
263 text = wx.StaticText(self, -1, info)
264 ret = wx.TextCtrl(self, -1, value)
265 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
266 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
270 def AddTextCtrlButton(self, value, buttonText):
271 text = wx.TextCtrl(self, -1, value)
272 button = wx.Button(self, -1, buttonText)
273 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
274 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
278 def AddBitmap(self, bitmap):
279 bitmap = wx.StaticBitmap(self, -1, bitmap)
280 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
284 def AddCheckmark(self, label, bitmap):
285 check = wx.StaticBitmap(self, -1, bitmap)
286 text = wx.StaticText(self, -1, label)
287 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
288 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 1), flag=wx.ALL)
292 def AddCombo(self, label, options):
293 combo = wx.ComboBox(self, -1, options[0], choices=options, style=wx.CB_DROPDOWN|wx.CB_READONLY)
294 text = wx.StaticText(self, -1, label)
295 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER)
296 self.GetSizer().Add(combo, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
309 class PrintrbotPage(InfoPage):
310 def __init__(self, parent):
311 self._printer_info = [
312 # X, Y, Z, Nozzle Size, Filament Diameter, PrintTemperature, Print Speed, Travel Speed, Retract speed, Retract amount, use bed level sensor
313 ("Simple Metal", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, True),
314 ("Metal Plus", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
315 ("Simple Makers Kit", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, True),
316 (":" + _("Older models"),),
317 ("Original", 130, 130, 130, 0.5, 2.95, 208, 40, 70, 30, 1, False),
318 ("Simple Maker's Edition v1", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
319 ("Simple Maker's Edition v2 (2013 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
320 ("Simple Maker's Edition v3 (2014 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
321 ("Jr v1", 115, 120, 80, 0.4, 1.75, 208, 40, 70, 30, 1, False),
322 ("Jr v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
323 ("LC v1", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
324 ("LC v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
325 ("Plus v1", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
326 ("Plus v2", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
327 ("Plus v2.1", 185, 220, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
328 ("Plus v2.2 (Model 1404/140422/140501/140507)", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
329 ("Go v2 Large", 505, 306, 310, 0.4, 1.75, 208, 35, 70, 30, 1, True),
332 super(PrintrbotPage, self).__init__(parent, _("Printrbot Selection"))
333 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Printrbot_logo.png')))
334 self.AddText(_("Select which Printrbot machine you have:"))
336 for printer in self._printer_info:
337 if printer[0].startswith(":"):
339 self.AddText(printer[0][1:])
341 item = self.AddRadioButton(printer[0])
342 item.data = printer[1:]
343 self._items.append(item)
346 profile.putMachineSetting('machine_name', 'Printrbot ???')
347 for item in self._items:
350 profile.putMachineSetting('machine_name', 'Printrbot ' + item.GetLabel())
351 profile.putMachineSetting('machine_width', data[0])
352 profile.putMachineSetting('machine_depth', data[1])
353 profile.putMachineSetting('machine_height', data[2])
354 profile.putProfileSetting('nozzle_size', data[3])
355 profile.putProfileSetting('filament_diameter', data[4])
356 profile.putProfileSetting('print_temperature', data[5])
357 profile.putProfileSetting('print_speed', data[6])
358 profile.putProfileSetting('travel_speed', data[7])
359 profile.putProfileSetting('retraction_speed', data[8])
360 profile.putProfileSetting('retraction_amount', data[9])
361 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
362 profile.putMachineSetting('has_heated_bed', 'False')
363 profile.putMachineSetting('machine_center_is_zero', 'False')
364 profile.putMachineSetting('extruder_head_size_min_x', '0')
365 profile.putMachineSetting('extruder_head_size_min_y', '0')
366 profile.putMachineSetting('extruder_head_size_max_x', '0')
367 profile.putMachineSetting('extruder_head_size_max_y', '0')
368 profile.putMachineSetting('extruder_head_size_height', '0')
370 profile.setAlterationFile('start.gcode', """;Sliced at: {day} {date} {time}
371 ;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {fill_density}
372 ;Print time: {print_time}
373 ;Filament used: {filament_amount}m {filament_weight}g
374 ;Filament cost: {filament_cost}
375 ;M190 S{print_bed_temperature} ;Uncomment to add your own bed temperature line
376 ;M109 S{print_temperature} ;Uncomment to add your own temperature line
378 G90 ;absolute positioning
379 M82 ;set extruder to absolute mode
380 M107 ;start with the fan off
381 G28 X0 Y0 ;move X/Y to min endstops
382 G28 Z0 ;move Z to min endstops
383 G29 ;Run the auto bed leveling
384 G1 Z15.0 F{travel_speed} ;move the platform down 15mm
385 G92 E0 ;zero the extruded length
386 G1 F200 E3 ;extrude 3mm of feed stock
387 G92 E0 ;zero the extruded length again
389 ;Put printing message on LCD screen
393 class OtherMachineSelectPage(InfoPage):
394 def __init__(self, parent):
395 super(OtherMachineSelectPage, self).__init__(parent, _("Other machine information"))
396 self.AddText(_("The following pre-defined machine profiles are available"))
397 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."))
399 machines = resources.getDefaultMachineProfiles()
401 for filename in machines:
402 name = os.path.splitext(os.path.basename(filename))[0]
403 item = self.AddRadioButton(name)
404 item.filename = filename
405 item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
406 self.options.append(item)
408 item = self.AddRadioButton(_('Custom...'))
410 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
412 def OnProfileSelect(self, e):
413 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
415 def OnOtherSelect(self, e):
416 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
419 for option in self.options:
420 if option.GetValue():
421 profile.loadProfile(option.filename)
422 profile.loadMachineSettings(option.filename)
424 class OtherMachineInfoPage(InfoPage):
425 def __init__(self, parent):
426 super(OtherMachineInfoPage, self).__init__(parent, _("Cura Ready!"))
427 self.AddText(_("Cura is now ready to be used!"))
429 class CustomRepRapInfoPage(InfoPage):
430 def __init__(self, parent):
431 super(CustomRepRapInfoPage, self).__init__(parent, _("Custom RepRap information"))
432 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
433 self.AddText(_("Be sure to review the default profile before running it on your machine."))
434 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
436 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
438 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
439 self.machineWidth = self.AddLabelTextCtrl(_("Machine width X (mm)"), "80")
440 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth Y (mm)"), "80")
441 self.machineHeight = self.AddLabelTextCtrl(_("Machine height Z (mm)"), "55")
442 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
443 self.heatedBed = self.AddCheckbox(_("Heated bed"))
444 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
447 profile.putMachineSetting('machine_name', self.machineName.GetValue())
448 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
449 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
450 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
451 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
452 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
453 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
454 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
455 profile.putMachineSetting('extruder_head_size_min_x', '0')
456 profile.putMachineSetting('extruder_head_size_min_y', '0')
457 profile.putMachineSetting('extruder_head_size_max_x', '0')
458 profile.putMachineSetting('extruder_head_size_max_y', '0')
459 profile.putMachineSetting('extruder_head_size_height', '0')
460 profile.checkAndUpdateMachineName()
462 class MachineSelectPage(InfoPage):
463 def __init__(self, parent):
464 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
465 self.AddText(_("What kind of machine do you have:"))
467 self.LulzbotMiniRadio = self.AddRadioButton("LulzBot Mini", style=wx.RB_GROUP)
468 self.LulzbotMiniRadio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
469 self.LulzbotMiniRadio.SetValue(True)
470 self.LulzbotTaz5Radio = self.AddRadioButton("LulzBot TAZ 5")
471 self.LulzbotTaz5Radio.Bind(wx.EVT_RADIOBUTTON, self.OnTaz5Select)
472 self.LulzbotTaz4Radio = self.AddRadioButton("LulzBot TAZ 4")
473 self.LulzbotTaz4Radio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
474 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2")
475 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
476 self.Ultimaker2ExtRadio = self.AddRadioButton("Ultimaker2extended")
477 self.Ultimaker2ExtRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
478 self.Ultimaker2GoRadio = self.AddRadioButton("Ultimaker2go")
479 self.Ultimaker2GoRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
480 self.UltimakerRadio = self.AddRadioButton("Ultimaker Original")
481 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
482 self.UltimakerOPRadio = self.AddRadioButton("Ultimaker Original+")
483 self.UltimakerOPRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerOPSelect)
484 self.PrintrbotRadio = self.AddRadioButton("Printrbot")
485 self.PrintrbotRadio.Bind(wx.EVT_RADIOBUTTON, self.OnPrintrbotSelect)
486 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot, Witbox)"))
487 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
489 def OnUltimaker2Select(self, e):
490 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
492 def OnUltimakerSelect(self, e):
493 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
495 def OnUltimakerOPSelect(self, e):
496 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)
498 def OnPrintrbotSelect(self, e):
499 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().printrbotSelectType)
501 def OnLulzbotSelect(self, e):
502 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotToolheadPage)
504 def OnTaz5Select(self, e):
505 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().taz5NozzleSelectPage)
506 wx.wizard.WizardPageSimple.Chain(self.GetParent().taz5NozzleSelectPage, self.GetParent().lulzbotToolheadPage)
508 def OnOtherSelect(self, e):
509 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
518 profile.putProfileSetting('retraction_enable', 'True')
519 if self.Ultimaker2Radio.GetValue() or self.Ultimaker2GoRadio.GetValue() or self.Ultimaker2ExtRadio.GetValue():
520 if self.Ultimaker2Radio.GetValue():
521 profile.putMachineSetting('machine_width', '230')
522 profile.putMachineSetting('machine_depth', '225')
523 profile.putMachineSetting('machine_height', '205')
524 profile.putMachineSetting('machine_name', 'ultimaker2')
525 profile.putMachineSetting('machine_type', 'ultimaker2')
526 profile.putMachineSetting('has_heated_bed', 'True')
527 if self.Ultimaker2GoRadio.GetValue():
528 profile.putMachineSetting('machine_width', '120')
529 profile.putMachineSetting('machine_depth', '120')
530 profile.putMachineSetting('machine_height', '115')
531 profile.putMachineSetting('machine_name', 'ultimaker2go')
532 profile.putMachineSetting('machine_type', 'ultimaker2go')
533 profile.putMachineSetting('has_heated_bed', 'False')
534 if self.Ultimaker2ExtRadio.GetValue():
535 profile.putMachineSetting('machine_width', '230')
536 profile.putMachineSetting('machine_depth', '225')
537 profile.putMachineSetting('machine_height', '315')
538 profile.putMachineSetting('machine_name', 'ultimaker2extended')
539 profile.putMachineSetting('machine_type', 'ultimaker2extended')
540 profile.putMachineSetting('has_heated_bed', 'False')
541 profile.putMachineSetting('machine_center_is_zero', 'False')
542 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
543 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
544 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
545 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
546 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
547 profile.putMachineSetting('extruder_head_size_height', '48.0')
548 profile.putProfileSetting('nozzle_size', '0.4')
549 profile.putProfileSetting('fan_full_height', '5.0')
550 profile.putMachineSetting('extruder_offset_x1', '18.0')
551 profile.putMachineSetting('extruder_offset_y1', '0.0')
552 elif self.UltimakerRadio.GetValue():
553 profile.putMachineSetting('machine_width', '205')
554 profile.putMachineSetting('machine_depth', '205')
555 profile.putMachineSetting('machine_height', '200')
556 profile.putMachineSetting('machine_name', 'ultimaker original')
557 profile.putMachineSetting('machine_type', 'ultimaker')
558 profile.putMachineSetting('machine_center_is_zero', 'False')
559 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
560 profile.putProfileSetting('nozzle_size', '0.4')
561 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
562 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
563 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
564 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
565 profile.putMachineSetting('extruder_head_size_height', '55.0')
566 elif self.UltimakerOPRadio.GetValue():
567 profile.putMachineSetting('machine_width', '205')
568 profile.putMachineSetting('machine_depth', '205')
569 profile.putMachineSetting('machine_height', '200')
570 profile.putMachineSetting('machine_name', 'ultimaker original+')
571 profile.putMachineSetting('machine_type', 'ultimaker_plus')
572 profile.putMachineSetting('machine_center_is_zero', 'False')
573 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
574 profile.putProfileSetting('nozzle_size', '0.4')
575 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
576 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
577 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
578 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
579 profile.putMachineSetting('extruder_head_size_height', '55.0')
580 profile.putMachineSetting('has_heated_bed', 'True')
581 profile.putMachineSetting('extruder_amount', '1')
582 profile.putProfileSetting('retraction_enable', 'True')
583 elif self.LulzbotTaz4Radio.GetValue() or self.LulzbotTaz5Radio.GetValue() or self.LulzbotMiniRadio.GetValue():
584 if self.LulzbotTaz4Radio.GetValue():
585 profile.putMachineSetting('machine_width', '290')
586 profile.putMachineSetting('machine_depth', '275')
587 profile.putMachineSetting('machine_height', '250')
588 profile.putProfileSetting('nozzle_size', '0.35')
589 profile.putMachineSetting('machine_name', 'LulzBot TAZ 4')
590 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_4')
591 profile.putMachineSetting('serial_baud', '115200')
592 elif self.LulzbotTaz5Radio.GetValue():
593 profile.putMachineSetting('machine_width', '290')
594 profile.putMachineSetting('machine_depth', '275')
595 profile.putMachineSetting('machine_height', '250')
596 profile.putMachineSetting('serial_baud', '115200')
597 # Machine type and name are set in the nozzle select page
599 profile.putMachineSetting('machine_width', '155')
600 profile.putMachineSetting('machine_depth', '155')
601 profile.putMachineSetting('machine_height', '163')
602 profile.putProfileSetting('nozzle_size', '0.5')
603 profile.putMachineSetting('machine_name', 'LulzBot Mini')
604 profile.putMachineSetting('machine_type', 'lulzbot_mini')
605 profile.putMachineSetting('serial_baud', '115200')
606 profile.putMachineSetting('extruder_head_size_min_x', '40')
607 profile.putMachineSetting('extruder_head_size_max_x', '75')
608 profile.putMachineSetting('extruder_head_size_min_y', '25')
609 profile.putMachineSetting('extruder_head_size_max_y', '55')
610 profile.putMachineSetting('extruder_head_size_height', '17')
612 profile.putMachineSetting('machine_center_is_zero', 'False')
613 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
614 profile.putMachineSetting('has_heated_bed', 'True')
615 profile.putMachineSetting('extruder_head_size_min_x', '0.0')
616 profile.putMachineSetting('extruder_head_size_min_y', '0.0')
617 profile.putMachineSetting('extruder_head_size_max_x', '0.0')
618 profile.putMachineSetting('extruder_head_size_max_y', '0.0')
619 profile.putMachineSetting('extruder_head_size_height', '0.0')
620 profile.putPreference('startMode', 'Simple')
622 profile.putMachineSetting('machine_width', '80')
623 profile.putMachineSetting('machine_depth', '80')
624 profile.putMachineSetting('machine_height', '60')
625 profile.putMachineSetting('machine_name', 'reprap')
626 profile.putMachineSetting('machine_type', 'reprap')
627 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
628 profile.putPreference('startMode', 'Normal')
629 profile.putProfileSetting('nozzle_size', '0.5')
630 profile.checkAndUpdateMachineName()
631 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
633 class SelectParts(InfoPage):
634 def __init__(self, parent):
635 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
636 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."))
638 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
639 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
640 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
641 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
643 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."))
644 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
645 self.springExtruder.SetValue(True)
648 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
649 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
650 profile.putMachineSetting('has_heated_bed', 'True')
652 profile.putMachineSetting('has_heated_bed', 'False')
653 if self.dualExtrusion.GetValue():
654 profile.putMachineSetting('extruder_amount', '2')
655 profile.putMachineSetting('machine_depth', '195')
657 profile.putMachineSetting('extruder_amount', '1')
658 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
659 profile.putProfileSetting('retraction_enable', 'True')
661 profile.putProfileSetting('retraction_enable', 'False')
664 class UltimakerFirmwareUpgradePage(InfoPage):
665 def __init__(self, parent):
666 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
667 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."))
668 self.AddHiddenSeperator()
669 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
670 self.AddHiddenSeperator()
671 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."))
672 upgradeButton, skipUpgradeButton = self.AddDualButton(_('Upgrade to Marlin firmware'), _('Skip upgrade'))
673 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
674 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
675 self.AddHiddenSeperator()
676 if profile.getMachineSetting('machine_type') == 'ultimaker':
677 self.AddText(_("Do not upgrade to this firmware if:"))
678 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
679 self.AddText(_("* Build your own heated bed"))
680 self.AddText(_("* Have other changes in the firmware"))
681 # button = self.AddButton('Goto this page for a custom firmware')
682 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
687 def OnUpgradeClick(self, e):
688 if firmwareInstall.InstallFirmware():
689 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
691 def OnSkipClick(self, e):
692 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
693 self.GetParent().ShowPage(self.GetNext())
695 def OnUrlClick(self, e):
696 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
698 class UltimakerCheckupPage(InfoPage):
699 def __init__(self, parent):
700 super(UltimakerCheckupPage, self).__init__(parent, _("Ultimaker Checkup"))
702 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
703 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
704 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
705 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
706 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
707 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
708 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
709 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
710 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
711 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
714 _("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."))
715 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
716 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
717 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
719 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
720 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
721 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
723 self.infoBox = self.AddInfoBox()
724 self.machineState = self.AddText("")
725 self.temperatureLabel = self.AddText("")
726 self.errorLogButton = self.AddButton(_("Show error log"))
727 self.errorLogButton.Show(False)
729 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
731 self.xMinStop = False
732 self.xMaxStop = False
733 self.yMinStop = False
734 self.yMaxStop = False
735 self.zMinStop = False
736 self.zMaxStop = False
738 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
741 if self.comm is not None:
745 self.endstopBitmap.Show(False)
748 def OnSkipClick(self, e):
749 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
750 self.GetParent().ShowPage(self.GetNext())
752 def OnCheckClick(self, e=None):
753 self.errorLogButton.Show(False)
754 if self.comm is not None:
758 wx.CallAfter(self.OnCheckClick)
760 self.infoBox.SetBusy(_("Connecting to machine."))
761 self.commState.SetBitmap(self.unknownBitmap)
762 self.tempState.SetBitmap(self.unknownBitmap)
763 self.stopState.SetBitmap(self.unknownBitmap)
764 self.checkupState = 0
765 self.checkExtruderNr = 0
766 self.comm = machineCom.MachineCom(callbackObject=self)
768 def OnErrorLog(self, e):
769 printWindow.LogWindow('\n'.join(self.comm.getLog()))
771 def mcLog(self, message):
774 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
775 if not self.comm.isOperational():
777 if self.checkupState == 0:
778 self.tempCheckTimeout = 20
779 if temp[self.checkExtruderNr] > 70:
780 self.checkupState = 1
781 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
782 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
783 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
785 self.startTemp = temp[self.checkExtruderNr]
786 self.checkupState = 2
787 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
788 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
789 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
790 elif self.checkupState == 1:
791 if temp[self.checkExtruderNr] < 60:
792 self.startTemp = temp[self.checkExtruderNr]
793 self.checkupState = 2
794 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
795 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
796 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
797 elif self.checkupState == 2:
798 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
799 if temp[self.checkExtruderNr] > self.startTemp + 40:
800 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
801 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
802 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
803 self.checkExtruderNr = 0
804 self.checkupState = 3
805 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
806 wx.CallAfter(self.endstopBitmap.Show, True)
807 wx.CallAfter(self.Layout)
808 self.comm.sendCommand('M119')
809 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
811 self.checkupState = 0
812 self.checkExtruderNr += 1
814 self.tempCheckTimeout -= 1
815 if self.tempCheckTimeout < 1:
816 self.checkupState = -1
817 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
818 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
819 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
820 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
821 elif self.checkupState >= 3 and self.checkupState < 10:
822 self.comm.sendCommand('M119')
823 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
825 def mcStateChange(self, state):
826 if self.comm is None:
828 if self.comm.isOperational():
829 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
830 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
831 elif self.comm.isError():
832 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
833 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
834 wx.CallAfter(self.endstopBitmap.Show, False)
835 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
836 wx.CallAfter(self.errorLogButton.Show, True)
837 wx.CallAfter(self.Layout)
839 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
841 def mcMessage(self, message):
842 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
843 for data in message.split(' '):
845 tag, value = data.split(':', 1)
847 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
849 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
851 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
853 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
855 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
857 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
859 tag, value = map(str.strip, message.split(':', 1))
861 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
863 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
865 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
867 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
869 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
871 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
872 if 'z_max' in message:
873 self.comm.sendCommand('M119')
875 if self.checkupState == 3:
876 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
877 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
878 self.checkupState = 5
879 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
880 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
882 self.checkupState = 4
883 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
884 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
885 elif self.checkupState == 4:
886 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
887 self.checkupState = 5
888 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
889 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
890 elif self.checkupState == 5:
891 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
892 self.checkupState = 6
893 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
894 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
895 elif self.checkupState == 6:
896 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
897 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
898 self.checkupState = 8
899 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
900 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
902 self.checkupState = 7
903 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
904 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
905 elif self.checkupState == 7:
906 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
907 self.checkupState = 8
908 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
909 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
910 elif self.checkupState == 8:
911 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
912 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
913 self.checkupState = 10
915 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
916 wx.CallAfter(self.infoBox.SetReadyIndicator)
917 wx.CallAfter(self.endstopBitmap.Show, False)
918 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
919 wx.CallAfter(self.OnSkipClick, None)
921 self.checkupState = 9
922 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
923 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
924 elif self.checkupState == 9:
925 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
926 self.checkupState = 10
928 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
929 wx.CallAfter(self.infoBox.SetReadyIndicator)
930 wx.CallAfter(self.endstopBitmap.Show, False)
931 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
932 wx.CallAfter(self.OnSkipClick, None)
934 def mcProgress(self, lineNr):
937 def mcZChange(self, newZ):
941 class UltimakerCalibrationPage(InfoPage):
942 def __init__(self, parent):
943 super(UltimakerCalibrationPage, self).__init__(parent, _("Ultimaker Calibration"))
945 self.AddText("Your Ultimaker requires some calibration.")
946 self.AddText("This calibration is needed for a proper extrusion amount.")
948 self.AddText("The following values are needed:")
949 self.AddText("* Diameter of filament")
950 self.AddText("* Number of steps per mm of filament extrusion")
952 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
954 self.AddText("First we need the diameter of your filament:")
955 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
957 "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.")
958 self.AddText("Note: This value can be changed later at any time.")
961 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
964 class UltimakerCalibrateStepsPerEPage(InfoPage):
965 def __init__(self, parent):
966 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, _("Ultimaker Calibration"))
968 #if profile.getMachineSetting('steps_per_e') == '0':
969 # profile.putMachineSetting('steps_per_e', '865.888')
971 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
972 self.AddText(_("First remove any filament from your machine."))
973 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
974 self.AddText(_("We'll push the filament 100mm"))
975 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
976 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
977 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
978 self.AddText(_("This results in the following steps per E:"))
979 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
980 self.AddText(_("You can repeat these steps to get better calibration."))
983 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
984 self.heatButton = self.AddButton(_("Heatup for filament removal"))
986 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
987 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
988 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
990 def OnSaveLengthClick(self, e):
991 currentEValue = float(self.stepsPerEInput.GetValue())
992 realExtrudeLength = float(self.lengthInput.GetValue())
993 newEValue = currentEValue * 100 / realExtrudeLength
994 self.stepsPerEInput.SetValue(str(newEValue))
995 self.lengthInput.SetValue("100")
997 def OnExtrudeClick(self, e):
998 t = threading.Thread(target=self.OnExtrudeRun)
1002 def OnExtrudeRun(self):
1003 self.heatButton.Enable(False)
1004 self.extrudeButton.Enable(False)
1005 currentEValue = float(self.stepsPerEInput.GetValue())
1006 self.comm = machineCom.MachineCom()
1007 if not self.comm.isOpen():
1009 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
1010 'Printer error', wx.OK | wx.ICON_INFORMATION)
1011 self.heatButton.Enable(True)
1012 self.extrudeButton.Enable(True)
1015 line = self.comm.readline()
1020 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
1023 self.sendGCommand('M302') #Disable cold extrusion protection
1024 self.sendGCommand("M92 E%f" % (currentEValue))
1025 self.sendGCommand("G92 E0")
1026 self.sendGCommand("G1 E100 F600")
1029 self.extrudeButton.Enable()
1030 self.heatButton.Enable()
1032 def OnHeatClick(self, e):
1033 t = threading.Thread(target=self.OnHeatRun)
1037 def OnHeatRun(self):
1038 self.heatButton.Enable(False)
1039 self.extrudeButton.Enable(False)
1040 self.comm = machineCom.MachineCom()
1041 if not self.comm.isOpen():
1043 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
1044 'Printer error', wx.OK | wx.ICON_INFORMATION)
1045 self.heatButton.Enable(True)
1046 self.extrudeButton.Enable(True)
1049 line = self.comm.readline()
1051 self.heatButton.Enable(True)
1052 self.extrudeButton.Enable(True)
1056 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
1059 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
1061 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
1062 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
1063 self.sendGCommand('M104 S0')
1066 self.heatButton.Enable(True)
1067 self.extrudeButton.Enable(True)
1069 def sendGCommand(self, cmd):
1070 self.comm.sendCommand(cmd) #Disable cold extrusion protection
1072 line = self.comm.readline()
1075 if line.startswith('ok'):
1078 def StoreData(self):
1079 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
1081 class Ultimaker2ReadyPage(InfoPage):
1082 def __init__(self, parent):
1083 super(Ultimaker2ReadyPage, self).__init__(parent, _("Ultimaker2"))
1084 self.AddText(_('Congratulations on your the purchase of your brand new Ultimaker2.'))
1085 self.AddText(_('Cura is now ready to be used with your Ultimaker2.'))
1088 class LulzbotReadyPage(InfoPage):
1089 def __init__(self, parent):
1090 super(LulzbotReadyPage, self).__init__(parent, _("LulzBot TAZ/Mini"))
1091 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Lulzbot_logo.png')))
1092 self.AddText(_('Cura is now ready to be used with your LulzBot 3D printer.'))
1094 self.AddText(_('For more information about using Cura with your LulzBot'))
1095 self.AddText(_('3D printer, please visit www.LulzBot.com/cura'))
1098 class LulzbotToolheadSelectPage(InfoPage):
1099 url='http://lulzbot.com/toolhead-identification'
1101 def __init__(self, parent):
1102 super(LulzbotToolheadSelectPage, self).__init__(parent, _("LulzBot Toolhead Selection"))
1104 self.mini_choices = [_('Standard'), _('Flexystruder')]
1105 self.taz_choices = [_('Standard v1'),
1106 _('Standard v2 0.35 mm nozzle'), _('Standard v2 0.5 mm nozzle'),
1107 _('Flexystruder v1'), _('Flexystruder v2'),
1108 _('Dually v1'), _('Dually v2'),
1109 _('FlexyDually v1'), _('FlexyDually v2')]
1110 self.description_map = {
1111 _('Standard'): _('This is the standard toolhead that comes with the Lulzbot Mini'),
1112 _('Flexystruder'): _('This is the Flexystruder for the Lulzbot Mini\nIt is used for printing Flexible materials'),
1113 _('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'),
1114 _('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'),
1115 _('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'),
1116 _('Flexystruder v1'): _('It\'s the flexy!'),
1117 _('Flexystruder v2'): _('It\'s the flexy v2!'),
1118 _('Dually v1'): _('It\'s the dualy v1!'),
1119 _('Dually v2'): _('It\'s the dual v2!'),
1120 _('FlexyDually v1'): _('It\'s the flexy dually v1!'),
1121 _('FlexyDually v2'): _('It\'s the flexy dual v2!')
1124 _('Standard'): 'Lulzbot_Toolhead_Mini_Standard.jpg',
1125 _('Flexystruder'): 'Lulzbot_logo.png',
1126 _('Standard v1'): 'Lulzbot_logo.png',
1127 _('Standard v2 0.35 mm nozzle'): 'Lulzbot_Toolhead_TAZ_Single_v2.jpg',
1128 _('Standard v2 0.5 mm nozzle'): 'Lulzbot_Toolhead_TAZ_Single_v2.jpg',
1129 _('Flexystruder v1'): 'Lulzbot_Toolhead_TAZ_Flexystruder_v1.jpg',
1130 _('Flexystruder v2'): 'Lulzbot_logo.png',
1131 _('Dually v1'): 'Lulzbot_Toolhead_TAZ_Dually_v1.jpg',
1132 _('Dually v2'): 'Lulzbot_logo.png',
1133 _('FlexyDually v1'): 'Lulzbot_logo.png',
1134 _('FlexyDually v2'): 'Lulzbot_logo.png'
1136 self.AddBitmap(wx.Bitmap(resources.getPathForImage('LulzBot_logo.png')))
1137 printer_name = profile.getMachineSetting('machine_type')
1138 self.Bind(wx.wizard.EVT_WIZARD_PAGE_SHOWN, self.OnPageShown)
1140 self.AddText(_('Please select your currently installed Tool Head'))
1141 txt = self.AddText(_('It is important to select the correct Tool head for your printer.\n' +
1142 'Flashing the wrong firmware on your printer can cause damage to your printer and to your toolhead\n' +
1143 'If you are not sure which toolhead you have, please refer to this webpage for more information: '))
1144 txt.SetForegroundColour(wx.RED)
1145 button = self.AddButton(self.url)
1146 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1149 self.combo = self.AddCombo(_('Currently installed Toolhead'), [''])
1150 self.combo.SetEditable(False)
1151 self.combo.Bind(wx.EVT_COMBOBOX, self.OnToolheadSelected)
1152 self.description = self.AddText('\n\n')
1153 self.description.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.BOLD))
1154 self.image = self.AddBitmap(wx.Bitmap(resources.getPathForImage(self.image_map[self.mini_choices[0]])))
1156 def OnPageShown(self, e):
1157 printer_name = profile.getMachineSetting('machine_type')
1158 if printer_name == 'lulzbot_mini':
1159 choices = self.mini_choices
1162 choices = self.taz_choices
1163 if printer_name == 'lulzbot_TAZ_4':
1165 elif printer_name == 'lulzbot_TAZ_5':
1171 self.combo.AppendItems(choices)
1172 self.combo.SetValue(choices[default])
1173 self.OnToolheadSelected(e)
1175 def OnUrlClick(self, e):
1176 webbrowser.open(LulzbotToolheadSelectPage.url)
1178 def OnToolheadSelected(self, e):
1179 toolhead = self.combo.GetValue()
1180 if self.description_map.has_key(toolhead):
1181 self.image.SetBitmap(wx.Bitmap(resources.getPathForImage(self.image_map[toolhead])))
1182 self.description.SetLabel(self.description_map[toolhead])
1184 self.image.SetBitmap(wx.NullBitmap)
1185 self.description.SetLabel('\n\n')
1190 class Taz5NozzleSelectPage(InfoPage):
1191 url='http://lulzbot.com/printer-identification'
1193 def __init__(self, parent):
1194 super(Taz5NozzleSelectPage, self).__init__(parent, _("LulzBot TAZ5"))
1195 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Lulzbot_logo.png')))
1197 self.AddText(_(' '))
1198 self.AddText(_('Please select nozzle size:'))
1199 self.Nozzle35Radio = self.AddRadioButton("0.35 mm", style=wx.RB_GROUP)
1200 self.Nozzle35Radio.SetValue(True)
1201 self.Nozzle50Radio = self.AddRadioButton("0.5 mm")
1202 self.AddText(_(' '))
1205 self.AddText(_('If you are not sure which nozzle size you have'))
1206 self.AddText(_('please check this webpage: '))
1207 button = self.AddButton(Taz5NozzleSelectPage.url)
1208 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1210 def OnUrlClick(self, e):
1211 webbrowser.open(Taz5NozzleSelectPage.url)
1213 def StoreData(self):
1214 if self.Nozzle35Radio.GetValue():
1215 profile.putProfileSetting('nozzle_size', '0.35')
1216 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.35 nozzle)')
1217 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5')
1220 profile.putProfileSetting('nozzle_size', '0.5')
1221 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.5 nozzle)')
1222 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5_05nozzle')
1224 class ConfigWizard(wx.wizard.Wizard):
1225 def __init__(self, addNew = False):
1226 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
1228 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1230 profile.setActiveMachine(profile.getMachineCount())
1232 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1233 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1234 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1236 self.machineSelectPage = MachineSelectPage(self)
1237 self.ultimakerSelectParts = SelectParts(self)
1238 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
1239 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
1240 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
1241 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
1242 self.bedLevelPage = bedLevelWizardMain(self)
1243 self.headOffsetCalibration = headOffsetCalibrationPage(self)
1244 self.printrbotSelectType = PrintrbotPage(self)
1245 self.otherMachineSelectPage = OtherMachineSelectPage(self)
1246 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
1247 self.otherMachineInfoPage = OtherMachineInfoPage(self)
1249 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
1250 self.lulzbotReadyPage = LulzbotReadyPage(self)
1251 self.lulzbotToolheadPage = LulzbotToolheadSelectPage(self)
1252 self.taz5NozzleSelectPage = Taz5NozzleSelectPage(self)
1254 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
1255 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
1256 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
1257 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
1258 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
1259 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
1260 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
1261 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
1262 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.lulzbotToolheadPage)
1263 wx.wizard.WizardPageSimple.Chain(self.lulzbotToolheadPage, self.lulzbotReadyPage)
1265 self.RunWizard(self.machineSelectPage)
1268 def OnPageChanging(self, e):
1269 e.GetPage().StoreData()
1271 def OnPageChanged(self, e):
1272 if e.GetPage().AllowNext():
1273 self.FindWindowById(wx.ID_FORWARD).Enable()
1275 self.FindWindowById(wx.ID_FORWARD).Disable()
1276 if e.GetPage().AllowBack():
1277 self.FindWindowById(wx.ID_BACKWARD).Enable()
1279 self.FindWindowById(wx.ID_BACKWARD).Disable()
1281 def OnCancel(self, e):
1282 new_machine_index = int(profile.getPreferenceFloat('active_machine'))
1283 profile.setActiveMachine(self._old_machine_index)
1284 profile.removeMachine(new_machine_index)
1286 class bedLevelWizardMain(InfoPage):
1287 def __init__(self, parent):
1288 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1290 self.AddText(_('This wizard will help you in leveling your printer bed'))
1292 self.AddText(_('It will do the following steps'))
1293 self.AddText(_('* Move the printer head to each corner'))
1294 self.AddText(_(' and let you adjust the height of the bed to the nozzle'))
1295 self.AddText(_('* Print a line around the bed to check if it is level'))
1298 self.connectButton = self.AddButton(_('Connect to printer'))
1301 self.infoBox = self.AddInfoBox()
1302 self.resumeButton = self.AddButton(_('Resume'))
1303 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1304 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1305 self.resumeButton.Enable(False)
1307 self.upButton.Enable(False)
1308 self.downButton.Enable(False)
1309 self.upButton2.Enable(False)
1310 self.downButton2.Enable(False)
1312 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1313 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1314 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1315 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1316 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1317 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1319 def OnConnect(self, e = None):
1320 if self.comm is not None:
1324 wx.CallAfter(self.OnConnect)
1326 self.connectButton.Enable(False)
1327 self.comm = machineCom.MachineCom(callbackObject=self)
1328 self.infoBox.SetBusy(_('Connecting to machine.'))
1329 self._wizardState = 0
1331 def OnBedUp(self, e):
1332 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1333 self.comm.sendCommand('G92 Z10')
1334 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1335 self.comm.sendCommand('M400')
1337 def OnBedDown(self, e):
1338 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1339 self.comm.sendCommand('G92 Z10')
1340 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1341 self.comm.sendCommand('M400')
1343 def OnBedUp2(self, e):
1344 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1345 self.comm.sendCommand('G92 Z10')
1346 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1347 self.comm.sendCommand('M400')
1349 def OnBedDown2(self, e):
1350 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1351 self.comm.sendCommand('G92 Z10')
1352 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1353 self.comm.sendCommand('M400')
1355 def AllowNext(self):
1356 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1357 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1360 def OnResume(self, e):
1361 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1362 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1363 if self._wizardState == -1:
1364 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1365 wx.CallAfter(self.upButton.Enable, False)
1366 wx.CallAfter(self.downButton.Enable, False)
1367 wx.CallAfter(self.upButton2.Enable, False)
1368 wx.CallAfter(self.downButton2.Enable, False)
1369 self.comm.sendCommand('M105')
1370 self.comm.sendCommand('G28')
1371 self._wizardState = 1
1372 elif self._wizardState == 2:
1373 if profile.getMachineSetting('has_heated_bed') == 'True':
1374 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1375 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1376 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1377 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1378 self.comm.sendCommand('M400')
1379 self._wizardState = 3
1381 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1382 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1383 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1384 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1385 self.comm.sendCommand('M400')
1386 self._wizardState = 3
1387 elif self._wizardState == 4:
1388 if profile.getMachineSetting('has_heated_bed') == 'True':
1389 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1390 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1391 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1392 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1393 self.comm.sendCommand('M400')
1394 self._wizardState = 7
1396 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1397 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1398 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1399 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1400 self.comm.sendCommand('M400')
1401 self._wizardState = 5
1402 elif self._wizardState == 6:
1403 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1404 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1405 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1406 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1407 self.comm.sendCommand('M400')
1408 self._wizardState = 7
1409 elif self._wizardState == 8:
1410 wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1411 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1412 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1413 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1414 self._wizardState = 9
1415 elif self._wizardState == 10:
1416 self._wizardState = 11
1417 wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1418 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1419 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1420 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1421 w = profile.getMachineSettingFloat('machine_width') - 10
1422 d = profile.getMachineSettingFloat('machine_depth')
1423 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1424 filamentArea = math.pi * filamentRadius * filamentRadius
1425 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1429 'G1 Z2 F%d' % (feedZ),
1431 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1432 'G1 Z0.3 F%d' % (feedZ)]
1434 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1436 for i in xrange(0, 3):
1437 dist = 5.0 + 0.4 * float(i)
1438 eValue += (d - 2.0*dist) * ePerMM
1439 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1440 eValue += (w - 2.0*dist) * ePerMM
1441 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1442 eValue += (d - 2.0*dist) * ePerMM
1443 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1444 eValue += (w - 2.0*dist) * ePerMM
1445 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1447 gcodeList.append('M400')
1448 self.comm.printGCode(gcodeList)
1449 self.resumeButton.Enable(False)
1451 def mcLog(self, message):
1452 print 'Log:', message
1454 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1455 if self._wizardState == 1:
1456 self._wizardState = 2
1457 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1458 wx.CallAfter(self.resumeButton.Enable, True)
1459 elif self._wizardState == 3:
1460 self._wizardState = 4
1461 if profile.getMachineSetting('has_heated_bed') == 'True':
1462 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1464 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1465 wx.CallAfter(self.resumeButton.Enable, True)
1466 elif self._wizardState == 5:
1467 self._wizardState = 6
1468 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1469 wx.CallAfter(self.resumeButton.Enable, True)
1470 elif self._wizardState == 7:
1471 self._wizardState = 8
1472 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1473 wx.CallAfter(self.resumeButton.Enable, True)
1474 elif self._wizardState == 9:
1475 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1476 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1478 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1479 wx.CallAfter(self.resumeButton.Enable, True)
1480 self._wizardState = 10
1482 def mcStateChange(self, state):
1483 if self.comm is None:
1485 if self.comm.isOperational():
1486 if self._wizardState == 0:
1487 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1488 wx.CallAfter(self.upButton.Enable, True)
1489 wx.CallAfter(self.downButton.Enable, True)
1490 wx.CallAfter(self.upButton2.Enable, True)
1491 wx.CallAfter(self.downButton2.Enable, True)
1492 wx.CallAfter(self.resumeButton.Enable, True)
1493 self._wizardState = -1
1494 elif self._wizardState == 11 and not self.comm.isPrinting():
1495 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1496 self.comm.sendCommand('G92 E0')
1497 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1498 self.comm.sendCommand('M104 S0')
1499 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1500 wx.CallAfter(self.infoBox.SetReadyIndicator)
1501 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1502 wx.CallAfter(self.connectButton.Enable, True)
1503 self._wizardState = 12
1504 elif self.comm.isError():
1505 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1507 def mcMessage(self, message):
1510 def mcProgress(self, lineNr):
1513 def mcZChange(self, newZ):
1516 class headOffsetCalibrationPage(InfoPage):
1517 def __init__(self, parent):
1518 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1520 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1523 self.connectButton = self.AddButton(_('Connect to printer'))
1526 self.infoBox = self.AddInfoBox()
1527 self.textEntry = self.AddTextCtrl('')
1528 self.textEntry.Enable(False)
1529 self.resumeButton = self.AddButton(_('Resume'))
1530 self.resumeButton.Enable(False)
1532 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1533 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1535 def AllowBack(self):
1538 def OnConnect(self, e = None):
1539 if self.comm is not None:
1543 wx.CallAfter(self.OnConnect)
1545 self.connectButton.Enable(False)
1546 self.comm = machineCom.MachineCom(callbackObject=self)
1547 self.infoBox.SetBusy(_('Connecting to machine.'))
1548 self._wizardState = 0
1550 def OnResume(self, e):
1551 if self._wizardState == 2:
1552 self._wizardState = 3
1553 wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1555 w = profile.getMachineSettingFloat('machine_width')
1556 d = profile.getMachineSettingFloat('machine_depth')
1558 gcode = gcodeGenerator.gcodeGenerator()
1559 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1560 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1567 gcode.addMove(w/2, 5)
1568 gcode.addMove(z=0.2)
1570 gcode.addExtrude(w/2, d-5.0)
1572 gcode.addMove(5, d/2)
1574 gcode.addExtrude(w-5.0, d/2)
1575 gcode.addRetract(15)
1578 gcode.addMove(w/2, 5)
1580 gcode.addExtrude(w/2, d-5.0)
1582 gcode.addMove(5, d/2)
1584 gcode.addExtrude(w-5.0, d/2)
1585 gcode.addRetract(15)
1590 gcode.addCmd('M400')
1592 self.comm.printGCode(gcode.list())
1593 self.resumeButton.Enable(False)
1594 elif self._wizardState == 4:
1596 float(self.textEntry.GetValue())
1599 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1600 self._wizardState = 5
1601 self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1602 self.textEntry.SetValue('0.0')
1603 self.textEntry.Enable(True)
1604 elif self._wizardState == 5:
1606 float(self.textEntry.GetValue())
1609 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1610 self._wizardState = 6
1611 self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1612 self.textEntry.SetValue('')
1613 self.textEntry.Enable(False)
1614 self.resumeButton.Enable(False)
1616 x = profile.getMachineSettingFloat('extruder_offset_x1')
1617 y = profile.getMachineSettingFloat('extruder_offset_y1')
1618 gcode = gcodeGenerator.gcodeGenerator()
1619 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1620 gcode.setPrintSpeed(25)
1623 gcode.addMove(50, 40, 0.2)
1625 for n in xrange(0, 10):
1626 gcode.addExtrude(50 + n * 10, 150)
1627 gcode.addExtrude(50 + n * 10 + 5, 150)
1628 gcode.addExtrude(50 + n * 10 + 5, 40)
1629 gcode.addExtrude(50 + n * 10 + 10, 40)
1630 gcode.addMove(40, 50)
1631 for n in xrange(0, 10):
1632 gcode.addExtrude(150, 50 + n * 10)
1633 gcode.addExtrude(150, 50 + n * 10 + 5)
1634 gcode.addExtrude(40, 50 + n * 10 + 5)
1635 gcode.addExtrude(40, 50 + n * 10 + 10)
1636 gcode.addRetract(15)
1639 gcode.addMove(50 - x, 30 - y, 0.2)
1641 for n in xrange(0, 10):
1642 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1643 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1644 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1645 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1646 gcode.addMove(30 - x, 50 - y, 0.2)
1647 for n in xrange(0, 10):
1648 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1649 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1650 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1651 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1652 gcode.addRetract(15)
1654 gcode.addCmd('M400')
1655 gcode.addCmd('M104 T0 S0')
1656 gcode.addCmd('M104 T1 S0')
1657 self.comm.printGCode(gcode.list())
1658 elif self._wizardState == 7:
1660 n = int(self.textEntry.GetValue()) - 1
1663 x = profile.getMachineSettingFloat('extruder_offset_x1')
1665 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1666 self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1667 self.textEntry.SetValue('10')
1668 self._wizardState = 8
1669 elif self._wizardState == 8:
1671 n = int(self.textEntry.GetValue()) - 1
1674 y = profile.getMachineSettingFloat('extruder_offset_y1')
1676 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1677 self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1678 self.infoBox.SetReadyIndicator()
1679 self._wizardState = 8
1681 self.resumeButton.Enable(False)
1683 def mcLog(self, message):
1684 print 'Log:', message
1686 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1687 if self._wizardState == 1:
1688 if temp[0] >= 210 and temp[1] >= 210:
1689 self._wizardState = 2
1690 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1691 wx.CallAfter(self.resumeButton.Enable, True)
1692 wx.CallAfter(self.resumeButton.SetFocus)
1694 def mcStateChange(self, state):
1695 if self.comm is None:
1697 if self.comm.isOperational():
1698 if self._wizardState == 0:
1699 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1700 self.comm.sendCommand('M105')
1701 self.comm.sendCommand('M104 S220 T0')
1702 self.comm.sendCommand('M104 S220 T1')
1703 self.comm.sendCommand('G28')
1704 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1705 self._wizardState = 1
1706 if not self.comm.isPrinting():
1707 if self._wizardState == 3:
1708 self._wizardState = 4
1709 wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1710 wx.CallAfter(self.textEntry.SetValue, '0.0')
1711 wx.CallAfter(self.textEntry.Enable, True)
1712 wx.CallAfter(self.resumeButton.Enable, True)
1713 wx.CallAfter(self.resumeButton.SetFocus)
1714 elif self._wizardState == 6:
1715 self._wizardState = 7
1716 wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1717 wx.CallAfter(self.textEntry.SetValue, '10')
1718 wx.CallAfter(self.textEntry.Enable, True)
1719 wx.CallAfter(self.resumeButton.Enable, True)
1720 wx.CallAfter(self.resumeButton.SetFocus)
1722 elif self.comm.isError():
1723 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1725 def mcMessage(self, message):
1728 def mcProgress(self, lineNr):
1731 def mcZChange(self, newZ):
1734 class bedLevelWizard(wx.wizard.Wizard):
1736 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1738 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1739 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1741 self.mainPage = bedLevelWizardMain(self)
1742 self.headOffsetCalibration = None
1744 self.RunWizard(self.mainPage)
1747 def OnPageChanging(self, e):
1748 e.GetPage().StoreData()
1750 def OnPageChanged(self, e):
1751 if e.GetPage().AllowNext():
1752 self.FindWindowById(wx.ID_FORWARD).Enable()
1754 self.FindWindowById(wx.ID_FORWARD).Disable()
1755 if e.GetPage().AllowBack():
1756 self.FindWindowById(wx.ID_BACKWARD).Enable()
1758 self.FindWindowById(wx.ID_BACKWARD).Disable()
1760 class headOffsetWizard(wx.wizard.Wizard):
1762 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1764 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1765 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1767 self.mainPage = headOffsetCalibrationPage(self)
1769 self.RunWizard(self.mainPage)
1772 def OnPageChanging(self, e):
1773 e.GetPage().StoreData()
1775 def OnPageChanged(self, e):
1776 if e.GetPage().AllowNext():
1777 self.FindWindowById(wx.ID_FORWARD).Enable()
1779 self.FindWindowById(wx.ID_FORWARD).Disable()
1780 if e.GetPage().AllowBack():
1781 self.FindWindowById(wx.ID_BACKWARD).Enable()
1783 self.FindWindowById(wx.ID_BACKWARD).Disable()