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)
285 panel = wx.Panel(self, -1)
286 sizer = wx.GridBagSizer(2, 2)
287 panel.SetSizer(sizer)
288 self.GetSizer().Add(panel, pos=(self.rowNr, 0), span=(1, 2), flag=wx.ALL | wx.EXPAND)
292 def AddCheckmark(self, label, bitmap):
293 check = wx.StaticBitmap(self, -1, bitmap)
294 text = wx.StaticText(self, -1, label)
295 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
296 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 1), flag=wx.ALL)
300 def AddCombo(self, label, options):
301 combo = wx.ComboBox(self, -1, options[0], choices=options, style=wx.CB_DROPDOWN|wx.CB_READONLY)
302 text = wx.StaticText(self, -1, label)
303 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER)
304 self.GetSizer().Add(combo, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
317 class PrintrbotPage(InfoPage):
318 def __init__(self, parent):
319 self._printer_info = [
320 # X, Y, Z, Nozzle Size, Filament Diameter, PrintTemperature, Print Speed, Travel Speed, Retract speed, Retract amount, use bed level sensor
321 ("Simple Metal", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, True),
322 ("Metal Plus", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
323 ("Simple Makers Kit", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, True),
324 (":" + _("Older models"),),
325 ("Original", 130, 130, 130, 0.5, 2.95, 208, 40, 70, 30, 1, False),
326 ("Simple Maker's Edition v1", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
327 ("Simple Maker's Edition v2 (2013 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
328 ("Simple Maker's Edition v3 (2014 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
329 ("Jr v1", 115, 120, 80, 0.4, 1.75, 208, 40, 70, 30, 1, False),
330 ("Jr v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
331 ("LC v1", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
332 ("LC v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
333 ("Plus v1", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
334 ("Plus v2", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
335 ("Plus v2.1", 185, 220, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
336 ("Plus v2.2 (Model 1404/140422/140501/140507)", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
337 ("Go v2 Large", 505, 306, 310, 0.4, 1.75, 208, 35, 70, 30, 1, True),
340 super(PrintrbotPage, self).__init__(parent, _("Printrbot Selection"))
341 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Printrbot_logo.png')))
342 self.AddText(_("Select which Printrbot machine you have:"))
344 for printer in self._printer_info:
345 if printer[0].startswith(":"):
347 self.AddText(printer[0][1:])
349 item = self.AddRadioButton(printer[0])
350 item.data = printer[1:]
351 self._items.append(item)
354 profile.putMachineSetting('machine_name', 'Printrbot ???')
355 for item in self._items:
358 profile.putMachineSetting('machine_name', 'Printrbot ' + item.GetLabel())
359 profile.putMachineSetting('machine_width', data[0])
360 profile.putMachineSetting('machine_depth', data[1])
361 profile.putMachineSetting('machine_height', data[2])
362 profile.putProfileSetting('nozzle_size', data[3])
363 profile.putProfileSetting('filament_diameter', data[4])
364 profile.putProfileSetting('print_temperature', data[5])
365 profile.putProfileSetting('print_speed', data[6])
366 profile.putProfileSetting('travel_speed', data[7])
367 profile.putProfileSetting('retraction_speed', data[8])
368 profile.putProfileSetting('retraction_amount', data[9])
369 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
370 profile.putMachineSetting('has_heated_bed', 'False')
371 profile.putMachineSetting('machine_center_is_zero', 'False')
372 profile.putMachineSetting('extruder_head_size_min_x', '0')
373 profile.putMachineSetting('extruder_head_size_min_y', '0')
374 profile.putMachineSetting('extruder_head_size_max_x', '0')
375 profile.putMachineSetting('extruder_head_size_max_y', '0')
376 profile.putMachineSetting('extruder_head_size_height', '0')
378 profile.setAlterationFile('start.gcode', """;Sliced at: {day} {date} {time}
379 ;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {fill_density}
380 ;Print time: {print_time}
381 ;Filament used: {filament_amount}m {filament_weight}g
382 ;Filament cost: {filament_cost}
383 ;M190 S{print_bed_temperature} ;Uncomment to add your own bed temperature line
384 ;M109 S{print_temperature} ;Uncomment to add your own temperature line
386 G90 ;absolute positioning
387 M82 ;set extruder to absolute mode
388 M107 ;start with the fan off
389 G28 X0 Y0 ;move X/Y to min endstops
390 G28 Z0 ;move Z to min endstops
391 G29 ;Run the auto bed leveling
392 G1 Z15.0 F{travel_speed} ;move the platform down 15mm
393 G92 E0 ;zero the extruded length
394 G1 F200 E3 ;extrude 3mm of feed stock
395 G92 E0 ;zero the extruded length again
397 ;Put printing message on LCD screen
401 class OtherMachineSelectPage(InfoPage):
402 def __init__(self, parent):
403 super(OtherMachineSelectPage, self).__init__(parent, _("Other machine information"))
404 self.AddText(_("The following pre-defined machine profiles are available"))
405 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."))
407 machines = resources.getDefaultMachineProfiles()
409 for filename in machines:
410 name = os.path.splitext(os.path.basename(filename))[0]
411 item = self.AddRadioButton(name)
412 item.filename = filename
413 item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
414 self.options.append(item)
416 item = self.AddRadioButton(_('Custom...'))
418 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
420 def OnProfileSelect(self, e):
421 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
423 def OnOtherSelect(self, e):
424 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
427 for option in self.options:
428 if option.GetValue():
429 profile.loadProfile(option.filename)
430 profile.loadMachineSettings(option.filename)
432 class OtherMachineInfoPage(InfoPage):
433 def __init__(self, parent):
434 super(OtherMachineInfoPage, self).__init__(parent, _("Cura Ready!"))
435 self.AddText(_("Cura is now ready to be used!"))
437 class CustomRepRapInfoPage(InfoPage):
438 def __init__(self, parent):
439 super(CustomRepRapInfoPage, self).__init__(parent, _("Custom RepRap information"))
440 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
441 self.AddText(_("Be sure to review the default profile before running it on your machine."))
442 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
444 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
446 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
447 self.machineWidth = self.AddLabelTextCtrl(_("Machine width X (mm)"), "80")
448 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth Y (mm)"), "80")
449 self.machineHeight = self.AddLabelTextCtrl(_("Machine height Z (mm)"), "55")
450 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
451 self.heatedBed = self.AddCheckbox(_("Heated bed"))
452 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
455 profile.putMachineSetting('machine_name', self.machineName.GetValue())
456 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
457 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
458 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
459 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
460 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
461 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
462 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
463 profile.putMachineSetting('extruder_head_size_min_x', '0')
464 profile.putMachineSetting('extruder_head_size_min_y', '0')
465 profile.putMachineSetting('extruder_head_size_max_x', '0')
466 profile.putMachineSetting('extruder_head_size_max_y', '0')
467 profile.putMachineSetting('extruder_head_size_height', '0')
468 profile.checkAndUpdateMachineName()
470 class MachineSelectPage(InfoPage):
471 def __init__(self, parent):
472 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
473 self.AddText(_("What kind of machine do you have:"))
475 self.LulzbotMiniRadio = self.AddRadioButton("LulzBot Mini", style=wx.RB_GROUP)
476 self.LulzbotMiniRadio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
477 self.LulzbotMiniRadio.SetValue(True)
478 self.LulzbotTaz5Radio = self.AddRadioButton("LulzBot TAZ 5")
479 self.LulzbotTaz5Radio.Bind(wx.EVT_RADIOBUTTON, self.OnTaz5Select)
480 self.LulzbotTaz4Radio = self.AddRadioButton("LulzBot TAZ 4")
481 self.LulzbotTaz4Radio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
482 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2")
483 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
484 self.Ultimaker2ExtRadio = self.AddRadioButton("Ultimaker2extended")
485 self.Ultimaker2ExtRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
486 self.Ultimaker2GoRadio = self.AddRadioButton("Ultimaker2go")
487 self.Ultimaker2GoRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
488 self.UltimakerRadio = self.AddRadioButton("Ultimaker Original")
489 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
490 self.UltimakerOPRadio = self.AddRadioButton("Ultimaker Original+")
491 self.UltimakerOPRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerOPSelect)
492 self.PrintrbotRadio = self.AddRadioButton("Printrbot")
493 self.PrintrbotRadio.Bind(wx.EVT_RADIOBUTTON, self.OnPrintrbotSelect)
494 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot, Witbox)"))
495 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
497 def OnUltimaker2Select(self, e):
498 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
500 def OnUltimakerSelect(self, e):
501 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
503 def OnUltimakerOPSelect(self, e):
504 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)
506 def OnPrintrbotSelect(self, e):
507 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().printrbotSelectType)
509 def OnLulzbotSelect(self, e):
510 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotToolheadPage)
512 def OnTaz5Select(self, e):
513 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().taz5NozzleSelectPage)
514 wx.wizard.WizardPageSimple.Chain(self.GetParent().taz5NozzleSelectPage, self.GetParent().lulzbotToolheadPage)
516 def OnOtherSelect(self, e):
517 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
526 profile.putProfileSetting('retraction_enable', 'True')
527 if self.Ultimaker2Radio.GetValue() or self.Ultimaker2GoRadio.GetValue() or self.Ultimaker2ExtRadio.GetValue():
528 if self.Ultimaker2Radio.GetValue():
529 profile.putMachineSetting('machine_width', '230')
530 profile.putMachineSetting('machine_depth', '225')
531 profile.putMachineSetting('machine_height', '205')
532 profile.putMachineSetting('machine_name', 'ultimaker2')
533 profile.putMachineSetting('machine_type', 'ultimaker2')
534 profile.putMachineSetting('has_heated_bed', 'True')
535 if self.Ultimaker2GoRadio.GetValue():
536 profile.putMachineSetting('machine_width', '120')
537 profile.putMachineSetting('machine_depth', '120')
538 profile.putMachineSetting('machine_height', '115')
539 profile.putMachineSetting('machine_name', 'ultimaker2go')
540 profile.putMachineSetting('machine_type', 'ultimaker2go')
541 profile.putMachineSetting('has_heated_bed', 'False')
542 if self.Ultimaker2ExtRadio.GetValue():
543 profile.putMachineSetting('machine_width', '230')
544 profile.putMachineSetting('machine_depth', '225')
545 profile.putMachineSetting('machine_height', '315')
546 profile.putMachineSetting('machine_name', 'ultimaker2extended')
547 profile.putMachineSetting('machine_type', 'ultimaker2extended')
548 profile.putMachineSetting('has_heated_bed', 'False')
549 profile.putMachineSetting('machine_center_is_zero', 'False')
550 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
551 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
552 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
553 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
554 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
555 profile.putMachineSetting('extruder_head_size_height', '48.0')
556 profile.putProfileSetting('nozzle_size', '0.4')
557 profile.putProfileSetting('fan_full_height', '5.0')
558 profile.putMachineSetting('extruder_offset_x1', '18.0')
559 profile.putMachineSetting('extruder_offset_y1', '0.0')
560 elif self.UltimakerRadio.GetValue():
561 profile.putMachineSetting('machine_width', '205')
562 profile.putMachineSetting('machine_depth', '205')
563 profile.putMachineSetting('machine_height', '200')
564 profile.putMachineSetting('machine_name', 'ultimaker original')
565 profile.putMachineSetting('machine_type', 'ultimaker')
566 profile.putMachineSetting('machine_center_is_zero', 'False')
567 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
568 profile.putProfileSetting('nozzle_size', '0.4')
569 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
570 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
571 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
572 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
573 profile.putMachineSetting('extruder_head_size_height', '55.0')
574 elif self.UltimakerOPRadio.GetValue():
575 profile.putMachineSetting('machine_width', '205')
576 profile.putMachineSetting('machine_depth', '205')
577 profile.putMachineSetting('machine_height', '200')
578 profile.putMachineSetting('machine_name', 'ultimaker original+')
579 profile.putMachineSetting('machine_type', 'ultimaker_plus')
580 profile.putMachineSetting('machine_center_is_zero', 'False')
581 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
582 profile.putProfileSetting('nozzle_size', '0.4')
583 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
584 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
585 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
586 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
587 profile.putMachineSetting('extruder_head_size_height', '55.0')
588 profile.putMachineSetting('has_heated_bed', 'True')
589 profile.putMachineSetting('extruder_amount', '1')
590 profile.putProfileSetting('retraction_enable', 'True')
591 elif self.LulzbotTaz4Radio.GetValue() or self.LulzbotTaz5Radio.GetValue() or self.LulzbotMiniRadio.GetValue():
592 if self.LulzbotTaz4Radio.GetValue():
593 profile.putMachineSetting('machine_width', '290')
594 profile.putMachineSetting('machine_depth', '275')
595 profile.putMachineSetting('machine_height', '250')
596 profile.putProfileSetting('nozzle_size', '0.35')
597 profile.putMachineSetting('machine_name', 'LulzBot TAZ 4')
598 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_4')
599 profile.putMachineSetting('serial_baud', '115200')
600 elif self.LulzbotTaz5Radio.GetValue():
601 profile.putMachineSetting('machine_width', '290')
602 profile.putMachineSetting('machine_depth', '275')
603 profile.putMachineSetting('machine_height', '250')
604 profile.putMachineSetting('serial_baud', '115200')
605 # Machine type and name are set in the nozzle select page
607 profile.putMachineSetting('machine_width', '155')
608 profile.putMachineSetting('machine_depth', '155')
609 profile.putMachineSetting('machine_height', '163')
610 profile.putProfileSetting('nozzle_size', '0.5')
611 profile.putMachineSetting('machine_name', 'LulzBot Mini')
612 profile.putMachineSetting('machine_type', 'lulzbot_mini')
613 profile.putMachineSetting('serial_baud', '115200')
614 profile.putMachineSetting('extruder_head_size_min_x', '40')
615 profile.putMachineSetting('extruder_head_size_max_x', '75')
616 profile.putMachineSetting('extruder_head_size_min_y', '25')
617 profile.putMachineSetting('extruder_head_size_max_y', '55')
618 profile.putMachineSetting('extruder_head_size_height', '17')
620 profile.putMachineSetting('machine_center_is_zero', 'False')
621 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
622 profile.putMachineSetting('has_heated_bed', 'True')
623 profile.putMachineSetting('extruder_head_size_min_x', '0.0')
624 profile.putMachineSetting('extruder_head_size_min_y', '0.0')
625 profile.putMachineSetting('extruder_head_size_max_x', '0.0')
626 profile.putMachineSetting('extruder_head_size_max_y', '0.0')
627 profile.putMachineSetting('extruder_head_size_height', '0.0')
628 profile.putPreference('startMode', 'Simple')
630 profile.putMachineSetting('machine_width', '80')
631 profile.putMachineSetting('machine_depth', '80')
632 profile.putMachineSetting('machine_height', '60')
633 profile.putMachineSetting('machine_name', 'reprap')
634 profile.putMachineSetting('machine_type', 'reprap')
635 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
636 profile.putPreference('startMode', 'Normal')
637 profile.putProfileSetting('nozzle_size', '0.5')
638 profile.checkAndUpdateMachineName()
639 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
641 class SelectParts(InfoPage):
642 def __init__(self, parent):
643 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
644 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."))
646 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
647 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
648 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
649 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
651 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."))
652 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
653 self.springExtruder.SetValue(True)
656 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
657 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
658 profile.putMachineSetting('has_heated_bed', 'True')
660 profile.putMachineSetting('has_heated_bed', 'False')
661 if self.dualExtrusion.GetValue():
662 profile.putMachineSetting('extruder_amount', '2')
663 profile.putMachineSetting('machine_depth', '195')
665 profile.putMachineSetting('extruder_amount', '1')
666 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
667 profile.putProfileSetting('retraction_enable', 'True')
669 profile.putProfileSetting('retraction_enable', 'False')
672 class UltimakerFirmwareUpgradePage(InfoPage):
673 def __init__(self, parent):
674 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
675 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."))
676 self.AddHiddenSeperator()
677 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
678 self.AddHiddenSeperator()
679 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."))
680 upgradeButton, skipUpgradeButton = self.AddDualButton(_('Upgrade to Marlin firmware'), _('Skip upgrade'))
681 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
682 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
683 self.AddHiddenSeperator()
684 if profile.getMachineSetting('machine_type') == 'ultimaker':
685 self.AddText(_("Do not upgrade to this firmware if:"))
686 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
687 self.AddText(_("* Build your own heated bed"))
688 self.AddText(_("* Have other changes in the firmware"))
689 # button = self.AddButton('Goto this page for a custom firmware')
690 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
695 def OnUpgradeClick(self, e):
696 if firmwareInstall.InstallFirmware():
697 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
699 def OnSkipClick(self, e):
700 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
701 self.GetParent().ShowPage(self.GetNext())
703 def OnUrlClick(self, e):
704 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
706 class UltimakerCheckupPage(InfoPage):
707 def __init__(self, parent):
708 super(UltimakerCheckupPage, self).__init__(parent, _("Ultimaker Checkup"))
710 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
711 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
712 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
713 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
714 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
715 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
716 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
717 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
718 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
719 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
722 _("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."))
723 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
724 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
725 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
727 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
728 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
729 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
731 self.infoBox = self.AddInfoBox()
732 self.machineState = self.AddText("")
733 self.temperatureLabel = self.AddText("")
734 self.errorLogButton = self.AddButton(_("Show error log"))
735 self.errorLogButton.Show(False)
737 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
739 self.xMinStop = False
740 self.xMaxStop = False
741 self.yMinStop = False
742 self.yMaxStop = False
743 self.zMinStop = False
744 self.zMaxStop = False
746 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
749 if self.comm is not None:
753 self.endstopBitmap.Show(False)
756 def OnSkipClick(self, e):
757 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
758 self.GetParent().ShowPage(self.GetNext())
760 def OnCheckClick(self, e=None):
761 self.errorLogButton.Show(False)
762 if self.comm is not None:
766 wx.CallAfter(self.OnCheckClick)
768 self.infoBox.SetBusy(_("Connecting to machine."))
769 self.commState.SetBitmap(self.unknownBitmap)
770 self.tempState.SetBitmap(self.unknownBitmap)
771 self.stopState.SetBitmap(self.unknownBitmap)
772 self.checkupState = 0
773 self.checkExtruderNr = 0
774 self.comm = machineCom.MachineCom(callbackObject=self)
776 def OnErrorLog(self, e):
777 printWindow.LogWindow('\n'.join(self.comm.getLog()))
779 def mcLog(self, message):
782 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
783 if not self.comm.isOperational():
785 if self.checkupState == 0:
786 self.tempCheckTimeout = 20
787 if temp[self.checkExtruderNr] > 70:
788 self.checkupState = 1
789 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
790 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
791 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
793 self.startTemp = temp[self.checkExtruderNr]
794 self.checkupState = 2
795 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
796 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
797 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
798 elif self.checkupState == 1:
799 if temp[self.checkExtruderNr] < 60:
800 self.startTemp = temp[self.checkExtruderNr]
801 self.checkupState = 2
802 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
803 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
804 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
805 elif self.checkupState == 2:
806 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
807 if temp[self.checkExtruderNr] > self.startTemp + 40:
808 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
809 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
810 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
811 self.checkExtruderNr = 0
812 self.checkupState = 3
813 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
814 wx.CallAfter(self.endstopBitmap.Show, True)
815 wx.CallAfter(self.Layout)
816 self.comm.sendCommand('M119')
817 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
819 self.checkupState = 0
820 self.checkExtruderNr += 1
822 self.tempCheckTimeout -= 1
823 if self.tempCheckTimeout < 1:
824 self.checkupState = -1
825 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
826 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
827 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
828 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
829 elif self.checkupState >= 3 and self.checkupState < 10:
830 self.comm.sendCommand('M119')
831 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
833 def mcStateChange(self, state):
834 if self.comm is None:
836 if self.comm.isOperational():
837 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
838 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
839 elif self.comm.isError():
840 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
841 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
842 wx.CallAfter(self.endstopBitmap.Show, False)
843 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
844 wx.CallAfter(self.errorLogButton.Show, True)
845 wx.CallAfter(self.Layout)
847 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
849 def mcMessage(self, message):
850 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
851 for data in message.split(' '):
853 tag, value = data.split(':', 1)
855 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
857 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
859 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
861 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
863 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
865 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
867 tag, value = map(str.strip, message.split(':', 1))
869 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
871 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
873 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
875 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
877 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
879 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
880 if 'z_max' in message:
881 self.comm.sendCommand('M119')
883 if self.checkupState == 3:
884 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
885 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
886 self.checkupState = 5
887 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
888 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
890 self.checkupState = 4
891 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
892 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
893 elif self.checkupState == 4:
894 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
895 self.checkupState = 5
896 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
897 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
898 elif self.checkupState == 5:
899 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
900 self.checkupState = 6
901 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
902 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
903 elif self.checkupState == 6:
904 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
905 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
906 self.checkupState = 8
907 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
908 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
910 self.checkupState = 7
911 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
912 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
913 elif self.checkupState == 7:
914 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
915 self.checkupState = 8
916 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
917 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
918 elif self.checkupState == 8:
919 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
920 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
921 self.checkupState = 10
923 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
924 wx.CallAfter(self.infoBox.SetReadyIndicator)
925 wx.CallAfter(self.endstopBitmap.Show, False)
926 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
927 wx.CallAfter(self.OnSkipClick, None)
929 self.checkupState = 9
930 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
931 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
932 elif self.checkupState == 9:
933 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
934 self.checkupState = 10
936 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
937 wx.CallAfter(self.infoBox.SetReadyIndicator)
938 wx.CallAfter(self.endstopBitmap.Show, False)
939 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
940 wx.CallAfter(self.OnSkipClick, None)
942 def mcProgress(self, lineNr):
945 def mcZChange(self, newZ):
949 class UltimakerCalibrationPage(InfoPage):
950 def __init__(self, parent):
951 super(UltimakerCalibrationPage, self).__init__(parent, _("Ultimaker Calibration"))
953 self.AddText("Your Ultimaker requires some calibration.")
954 self.AddText("This calibration is needed for a proper extrusion amount.")
956 self.AddText("The following values are needed:")
957 self.AddText("* Diameter of filament")
958 self.AddText("* Number of steps per mm of filament extrusion")
960 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
962 self.AddText("First we need the diameter of your filament:")
963 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
965 "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.")
966 self.AddText("Note: This value can be changed later at any time.")
969 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
972 class UltimakerCalibrateStepsPerEPage(InfoPage):
973 def __init__(self, parent):
974 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, _("Ultimaker Calibration"))
976 #if profile.getMachineSetting('steps_per_e') == '0':
977 # profile.putMachineSetting('steps_per_e', '865.888')
979 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
980 self.AddText(_("First remove any filament from your machine."))
981 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
982 self.AddText(_("We'll push the filament 100mm"))
983 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
984 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
985 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
986 self.AddText(_("This results in the following steps per E:"))
987 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
988 self.AddText(_("You can repeat these steps to get better calibration."))
991 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
992 self.heatButton = self.AddButton(_("Heatup for filament removal"))
994 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
995 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
996 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
998 def OnSaveLengthClick(self, e):
999 currentEValue = float(self.stepsPerEInput.GetValue())
1000 realExtrudeLength = float(self.lengthInput.GetValue())
1001 newEValue = currentEValue * 100 / realExtrudeLength
1002 self.stepsPerEInput.SetValue(str(newEValue))
1003 self.lengthInput.SetValue("100")
1005 def OnExtrudeClick(self, e):
1006 t = threading.Thread(target=self.OnExtrudeRun)
1010 def OnExtrudeRun(self):
1011 self.heatButton.Enable(False)
1012 self.extrudeButton.Enable(False)
1013 currentEValue = float(self.stepsPerEInput.GetValue())
1014 self.comm = machineCom.MachineCom()
1015 if not self.comm.isOpen():
1017 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
1018 'Printer error', wx.OK | wx.ICON_INFORMATION)
1019 self.heatButton.Enable(True)
1020 self.extrudeButton.Enable(True)
1023 line = self.comm.readline()
1028 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
1031 self.sendGCommand('M302') #Disable cold extrusion protection
1032 self.sendGCommand("M92 E%f" % (currentEValue))
1033 self.sendGCommand("G92 E0")
1034 self.sendGCommand("G1 E100 F600")
1037 self.extrudeButton.Enable()
1038 self.heatButton.Enable()
1040 def OnHeatClick(self, e):
1041 t = threading.Thread(target=self.OnHeatRun)
1045 def OnHeatRun(self):
1046 self.heatButton.Enable(False)
1047 self.extrudeButton.Enable(False)
1048 self.comm = machineCom.MachineCom()
1049 if not self.comm.isOpen():
1051 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
1052 'Printer error', wx.OK | wx.ICON_INFORMATION)
1053 self.heatButton.Enable(True)
1054 self.extrudeButton.Enable(True)
1057 line = self.comm.readline()
1059 self.heatButton.Enable(True)
1060 self.extrudeButton.Enable(True)
1064 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
1067 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
1069 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
1070 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
1071 self.sendGCommand('M104 S0')
1074 self.heatButton.Enable(True)
1075 self.extrudeButton.Enable(True)
1077 def sendGCommand(self, cmd):
1078 self.comm.sendCommand(cmd) #Disable cold extrusion protection
1080 line = self.comm.readline()
1083 if line.startswith('ok'):
1086 def StoreData(self):
1087 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
1089 class Ultimaker2ReadyPage(InfoPage):
1090 def __init__(self, parent):
1091 super(Ultimaker2ReadyPage, self).__init__(parent, _("Ultimaker2"))
1092 self.AddText(_('Congratulations on your the purchase of your brand new Ultimaker2.'))
1093 self.AddText(_('Cura is now ready to be used with your Ultimaker2.'))
1096 class LulzbotReadyPage(InfoPage):
1097 def __init__(self, parent):
1098 super(LulzbotReadyPage, self).__init__(parent, _("LulzBot TAZ/Mini"))
1099 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Lulzbot_logo.png')))
1100 self.AddText(_('Cura is now ready to be used with your LulzBot 3D printer.'))
1102 self.AddText(_('For more information about using Cura with your LulzBot'))
1103 self.AddText(_('3D printer, please visit www.LulzBot.com/cura'))
1106 class LulzbotToolheadSelectPage(InfoPage):
1107 url='http://lulzbot.com/toolhead-identification'
1109 def __init__(self, parent):
1110 super(LulzbotToolheadSelectPage, self).__init__(parent, _("LulzBot Toolhead Selection"))
1112 self.mini_choices = [_('Standard'), _('Flexystruder')]
1113 self.taz_choices = [_('Standard v1'),
1114 _('Standard v2 0.35 mm nozzle'), _('Standard v2 0.5 mm nozzle'),
1115 _('Flexystruder v1'), _('Flexystruder v2'),
1116 _('Dually v1'), _('Dually v2'),
1117 _('FlexyDually v1'), _('FlexyDually v2')]
1118 self.description_map = {
1119 _('Standard'): _('This is the standard toolhead that comes with the Lulzbot Mini'),
1120 _('Flexystruder'): _('This is the Flexystruder for the Lulzbot Mini\nIt is used for printing Flexible materials'),
1121 _('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'),
1122 _('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'),
1123 _('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'),
1124 _('Flexystruder v1'): _('It\'s the flexy!'),
1125 _('Flexystruder v2'): _('It\'s the flexy v2!'),
1126 _('Dually v1'): _('It\'s the dualy v1!'),
1127 _('Dually v2'): _('It\'s the dual v2!'),
1128 _('FlexyDually v1'): _('It\'s the flexy dually v1!'),
1129 _('FlexyDually v2'): _('It\'s the flexy dual v2!')
1132 _('Standard'): 'Lulzbot_Toolhead_Mini_Standard.jpg',
1133 _('Flexystruder'): 'Lulzbot_logo.png',
1134 _('Standard v1'): 'Lulzbot_logo.png',
1135 _('Standard v2 0.35 mm nozzle'): 'Lulzbot_Toolhead_TAZ_Single_v2.jpg',
1136 _('Standard v2 0.5 mm nozzle'): 'Lulzbot_Toolhead_TAZ_Single_v2.jpg',
1137 _('Flexystruder v1'): 'Lulzbot_Toolhead_TAZ_Flexystruder_v1.jpg',
1138 _('Flexystruder v2'): 'Lulzbot_logo.png',
1139 _('Dually v1'): 'Lulzbot_Toolhead_TAZ_Dually_v1.jpg',
1140 _('Dually v2'): 'Lulzbot_logo.png',
1141 _('FlexyDually v1'): 'Lulzbot_logo.png',
1142 _('FlexyDually v2'): 'Lulzbot_logo.png'
1144 self.AddBitmap(wx.Bitmap(resources.getPathForImage('LulzBot_logo.png')))
1145 printer_name = profile.getMachineSetting('machine_type')
1146 self.Bind(wx.wizard.EVT_WIZARD_PAGE_SHOWN, self.OnPageShown)
1148 self.AddText(_('Please select your currently installed Tool Head'))
1149 txt = self.AddText(_('It is important to select the correct Tool head for your printer.\n' +
1150 'Flashing the wrong firmware on your printer can cause damage to your printer and to your toolhead\n' +
1151 'If you are not sure which toolhead you have, please refer to this webpage for more information: '))
1152 txt.SetForegroundColour(wx.RED)
1153 button = self.AddButton(self.url)
1154 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1157 self.combo = self.AddCombo(_('Currently installed Toolhead'), [''])
1158 self.combo.SetEditable(False)
1159 self.combo.Bind(wx.EVT_COMBOBOX, self.OnToolheadSelected)
1160 self.description = self.AddText('\n\n')
1161 self.description.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.BOLD))
1162 self.image = self.AddBitmap(wx.Bitmap(resources.getPathForImage(self.image_map[self.mini_choices[0]])))
1164 def OnPageShown(self, e):
1165 printer_name = profile.getMachineSetting('machine_type')
1166 if printer_name == 'lulzbot_mini':
1167 choices = self.mini_choices
1170 choices = self.taz_choices
1171 if printer_name == 'lulzbot_TAZ_4':
1173 elif printer_name == 'lulzbot_TAZ_5':
1179 self.combo.AppendItems(choices)
1180 self.combo.SetValue(choices[default])
1181 self.OnToolheadSelected(e)
1183 def OnUrlClick(self, e):
1184 webbrowser.open(LulzbotToolheadSelectPage.url)
1186 def OnToolheadSelected(self, e):
1187 toolhead = self.combo.GetValue()
1188 if self.description_map.has_key(toolhead):
1189 self.image.SetBitmap(wx.Bitmap(resources.getPathForImage(self.image_map[toolhead])))
1190 self.description.SetLabel(self.description_map[toolhead])
1192 self.image.SetBitmap(wx.NullBitmap)
1193 self.description.SetLabel('\n\n')
1198 class Taz5NozzleSelectPage(InfoPage):
1199 url='http://lulzbot.com/printer-identification'
1201 def __init__(self, parent):
1202 super(Taz5NozzleSelectPage, self).__init__(parent, _("LulzBot TAZ5"))
1203 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Lulzbot_logo.png')))
1205 self.AddText(_(' '))
1206 self.AddText(_('Please select nozzle size:'))
1207 self.Nozzle35Radio = self.AddRadioButton("0.35 mm", style=wx.RB_GROUP)
1208 self.Nozzle35Radio.SetValue(True)
1209 self.Nozzle50Radio = self.AddRadioButton("0.5 mm")
1210 self.AddText(_(' '))
1213 self.AddText(_('If you are not sure which nozzle size you have'))
1214 self.AddText(_('please check this webpage: '))
1215 button = self.AddButton(Taz5NozzleSelectPage.url)
1216 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1218 def OnUrlClick(self, e):
1219 webbrowser.open(Taz5NozzleSelectPage.url)
1221 def StoreData(self):
1222 if self.Nozzle35Radio.GetValue():
1223 profile.putProfileSetting('nozzle_size', '0.35')
1224 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.35 nozzle)')
1225 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5')
1228 profile.putProfileSetting('nozzle_size', '0.5')
1229 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.5 nozzle)')
1230 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5_05nozzle')
1232 class ConfigWizard(wx.wizard.Wizard):
1233 def __init__(self, addNew = False):
1234 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
1236 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1238 profile.setActiveMachine(profile.getMachineCount())
1240 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1241 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1242 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1244 self.machineSelectPage = MachineSelectPage(self)
1245 self.ultimakerSelectParts = SelectParts(self)
1246 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
1247 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
1248 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
1249 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
1250 self.bedLevelPage = bedLevelWizardMain(self)
1251 self.headOffsetCalibration = headOffsetCalibrationPage(self)
1252 self.printrbotSelectType = PrintrbotPage(self)
1253 self.otherMachineSelectPage = OtherMachineSelectPage(self)
1254 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
1255 self.otherMachineInfoPage = OtherMachineInfoPage(self)
1257 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
1258 self.lulzbotReadyPage = LulzbotReadyPage(self)
1259 self.lulzbotToolheadPage = LulzbotToolheadSelectPage(self)
1260 self.taz5NozzleSelectPage = Taz5NozzleSelectPage(self)
1262 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
1263 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
1264 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
1265 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
1266 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
1267 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
1268 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
1269 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
1270 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.lulzbotToolheadPage)
1271 wx.wizard.WizardPageSimple.Chain(self.lulzbotToolheadPage, self.lulzbotReadyPage)
1273 self.RunWizard(self.machineSelectPage)
1276 def OnPageChanging(self, e):
1277 e.GetPage().StoreData()
1279 def OnPageChanged(self, e):
1280 if e.GetPage().AllowNext():
1281 self.FindWindowById(wx.ID_FORWARD).Enable()
1283 self.FindWindowById(wx.ID_FORWARD).Disable()
1284 if e.GetPage().AllowBack():
1285 self.FindWindowById(wx.ID_BACKWARD).Enable()
1287 self.FindWindowById(wx.ID_BACKWARD).Disable()
1289 def OnCancel(self, e):
1290 new_machine_index = int(profile.getPreferenceFloat('active_machine'))
1291 profile.setActiveMachine(self._old_machine_index)
1292 profile.removeMachine(new_machine_index)
1294 class bedLevelWizardMain(InfoPage):
1295 def __init__(self, parent):
1296 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1298 self.AddText(_('This wizard will help you in leveling your printer bed'))
1300 self.AddText(_('It will do the following steps'))
1301 self.AddText(_('* Move the printer head to each corner'))
1302 self.AddText(_(' and let you adjust the height of the bed to the nozzle'))
1303 self.AddText(_('* Print a line around the bed to check if it is level'))
1306 self.connectButton = self.AddButton(_('Connect to printer'))
1309 self.infoBox = self.AddInfoBox()
1310 self.resumeButton = self.AddButton(_('Resume'))
1311 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1312 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1313 self.resumeButton.Enable(False)
1315 self.upButton.Enable(False)
1316 self.downButton.Enable(False)
1317 self.upButton2.Enable(False)
1318 self.downButton2.Enable(False)
1320 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1321 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1322 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1323 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1324 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1325 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1327 def OnConnect(self, e = None):
1328 if self.comm is not None:
1332 wx.CallAfter(self.OnConnect)
1334 self.connectButton.Enable(False)
1335 self.comm = machineCom.MachineCom(callbackObject=self)
1336 self.infoBox.SetBusy(_('Connecting to machine.'))
1337 self._wizardState = 0
1339 def OnBedUp(self, e):
1340 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1341 self.comm.sendCommand('G92 Z10')
1342 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1343 self.comm.sendCommand('M400')
1345 def OnBedDown(self, e):
1346 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1347 self.comm.sendCommand('G92 Z10')
1348 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1349 self.comm.sendCommand('M400')
1351 def OnBedUp2(self, e):
1352 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1353 self.comm.sendCommand('G92 Z10')
1354 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1355 self.comm.sendCommand('M400')
1357 def OnBedDown2(self, e):
1358 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1359 self.comm.sendCommand('G92 Z10')
1360 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1361 self.comm.sendCommand('M400')
1363 def AllowNext(self):
1364 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1365 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1368 def OnResume(self, e):
1369 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1370 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1371 if self._wizardState == -1:
1372 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1373 wx.CallAfter(self.upButton.Enable, False)
1374 wx.CallAfter(self.downButton.Enable, False)
1375 wx.CallAfter(self.upButton2.Enable, False)
1376 wx.CallAfter(self.downButton2.Enable, False)
1377 self.comm.sendCommand('M105')
1378 self.comm.sendCommand('G28')
1379 self._wizardState = 1
1380 elif self._wizardState == 2:
1381 if profile.getMachineSetting('has_heated_bed') == 'True':
1382 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1383 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1384 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1385 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1386 self.comm.sendCommand('M400')
1387 self._wizardState = 3
1389 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1390 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1391 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1392 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1393 self.comm.sendCommand('M400')
1394 self._wizardState = 3
1395 elif self._wizardState == 4:
1396 if profile.getMachineSetting('has_heated_bed') == 'True':
1397 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1398 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1399 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1400 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1401 self.comm.sendCommand('M400')
1402 self._wizardState = 7
1404 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1405 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1406 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1407 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1408 self.comm.sendCommand('M400')
1409 self._wizardState = 5
1410 elif self._wizardState == 6:
1411 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1412 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1413 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1414 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1415 self.comm.sendCommand('M400')
1416 self._wizardState = 7
1417 elif self._wizardState == 8:
1418 wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1419 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1420 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1421 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1422 self._wizardState = 9
1423 elif self._wizardState == 10:
1424 self._wizardState = 11
1425 wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1426 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1427 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1428 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1429 w = profile.getMachineSettingFloat('machine_width') - 10
1430 d = profile.getMachineSettingFloat('machine_depth')
1431 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1432 filamentArea = math.pi * filamentRadius * filamentRadius
1433 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1437 'G1 Z2 F%d' % (feedZ),
1439 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1440 'G1 Z0.3 F%d' % (feedZ)]
1442 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1444 for i in xrange(0, 3):
1445 dist = 5.0 + 0.4 * float(i)
1446 eValue += (d - 2.0*dist) * ePerMM
1447 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1448 eValue += (w - 2.0*dist) * ePerMM
1449 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1450 eValue += (d - 2.0*dist) * ePerMM
1451 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1452 eValue += (w - 2.0*dist) * ePerMM
1453 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1455 gcodeList.append('M400')
1456 self.comm.printGCode(gcodeList)
1457 self.resumeButton.Enable(False)
1459 def mcLog(self, message):
1460 print 'Log:', message
1462 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1463 if self._wizardState == 1:
1464 self._wizardState = 2
1465 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1466 wx.CallAfter(self.resumeButton.Enable, True)
1467 elif self._wizardState == 3:
1468 self._wizardState = 4
1469 if profile.getMachineSetting('has_heated_bed') == 'True':
1470 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1472 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1473 wx.CallAfter(self.resumeButton.Enable, True)
1474 elif self._wizardState == 5:
1475 self._wizardState = 6
1476 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1477 wx.CallAfter(self.resumeButton.Enable, True)
1478 elif self._wizardState == 7:
1479 self._wizardState = 8
1480 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1481 wx.CallAfter(self.resumeButton.Enable, True)
1482 elif self._wizardState == 9:
1483 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1484 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1486 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1487 wx.CallAfter(self.resumeButton.Enable, True)
1488 self._wizardState = 10
1490 def mcStateChange(self, state):
1491 if self.comm is None:
1493 if self.comm.isOperational():
1494 if self._wizardState == 0:
1495 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1496 wx.CallAfter(self.upButton.Enable, True)
1497 wx.CallAfter(self.downButton.Enable, True)
1498 wx.CallAfter(self.upButton2.Enable, True)
1499 wx.CallAfter(self.downButton2.Enable, True)
1500 wx.CallAfter(self.resumeButton.Enable, True)
1501 self._wizardState = -1
1502 elif self._wizardState == 11 and not self.comm.isPrinting():
1503 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1504 self.comm.sendCommand('G92 E0')
1505 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1506 self.comm.sendCommand('M104 S0')
1507 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1508 wx.CallAfter(self.infoBox.SetReadyIndicator)
1509 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1510 wx.CallAfter(self.connectButton.Enable, True)
1511 self._wizardState = 12
1512 elif self.comm.isError():
1513 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1515 def mcMessage(self, message):
1518 def mcProgress(self, lineNr):
1521 def mcZChange(self, newZ):
1524 class headOffsetCalibrationPage(InfoPage):
1525 def __init__(self, parent):
1526 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1528 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1531 self.connectButton = self.AddButton(_('Connect to printer'))
1534 self.infoBox = self.AddInfoBox()
1535 self.textEntry = self.AddTextCtrl('')
1536 self.textEntry.Enable(False)
1537 self.resumeButton = self.AddButton(_('Resume'))
1538 self.resumeButton.Enable(False)
1540 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1541 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1543 def AllowBack(self):
1546 def OnConnect(self, e = None):
1547 if self.comm is not None:
1551 wx.CallAfter(self.OnConnect)
1553 self.connectButton.Enable(False)
1554 self.comm = machineCom.MachineCom(callbackObject=self)
1555 self.infoBox.SetBusy(_('Connecting to machine.'))
1556 self._wizardState = 0
1558 def OnResume(self, e):
1559 if self._wizardState == 2:
1560 self._wizardState = 3
1561 wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1563 w = profile.getMachineSettingFloat('machine_width')
1564 d = profile.getMachineSettingFloat('machine_depth')
1566 gcode = gcodeGenerator.gcodeGenerator()
1567 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1568 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1575 gcode.addMove(w/2, 5)
1576 gcode.addMove(z=0.2)
1578 gcode.addExtrude(w/2, d-5.0)
1580 gcode.addMove(5, d/2)
1582 gcode.addExtrude(w-5.0, d/2)
1583 gcode.addRetract(15)
1586 gcode.addMove(w/2, 5)
1588 gcode.addExtrude(w/2, d-5.0)
1590 gcode.addMove(5, d/2)
1592 gcode.addExtrude(w-5.0, d/2)
1593 gcode.addRetract(15)
1598 gcode.addCmd('M400')
1600 self.comm.printGCode(gcode.list())
1601 self.resumeButton.Enable(False)
1602 elif self._wizardState == 4:
1604 float(self.textEntry.GetValue())
1607 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1608 self._wizardState = 5
1609 self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1610 self.textEntry.SetValue('0.0')
1611 self.textEntry.Enable(True)
1612 elif self._wizardState == 5:
1614 float(self.textEntry.GetValue())
1617 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1618 self._wizardState = 6
1619 self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1620 self.textEntry.SetValue('')
1621 self.textEntry.Enable(False)
1622 self.resumeButton.Enable(False)
1624 x = profile.getMachineSettingFloat('extruder_offset_x1')
1625 y = profile.getMachineSettingFloat('extruder_offset_y1')
1626 gcode = gcodeGenerator.gcodeGenerator()
1627 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1628 gcode.setPrintSpeed(25)
1631 gcode.addMove(50, 40, 0.2)
1633 for n in xrange(0, 10):
1634 gcode.addExtrude(50 + n * 10, 150)
1635 gcode.addExtrude(50 + n * 10 + 5, 150)
1636 gcode.addExtrude(50 + n * 10 + 5, 40)
1637 gcode.addExtrude(50 + n * 10 + 10, 40)
1638 gcode.addMove(40, 50)
1639 for n in xrange(0, 10):
1640 gcode.addExtrude(150, 50 + n * 10)
1641 gcode.addExtrude(150, 50 + n * 10 + 5)
1642 gcode.addExtrude(40, 50 + n * 10 + 5)
1643 gcode.addExtrude(40, 50 + n * 10 + 10)
1644 gcode.addRetract(15)
1647 gcode.addMove(50 - x, 30 - y, 0.2)
1649 for n in xrange(0, 10):
1650 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1651 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1652 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1653 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1654 gcode.addMove(30 - x, 50 - y, 0.2)
1655 for n in xrange(0, 10):
1656 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1657 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1658 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1659 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1660 gcode.addRetract(15)
1662 gcode.addCmd('M400')
1663 gcode.addCmd('M104 T0 S0')
1664 gcode.addCmd('M104 T1 S0')
1665 self.comm.printGCode(gcode.list())
1666 elif self._wizardState == 7:
1668 n = int(self.textEntry.GetValue()) - 1
1671 x = profile.getMachineSettingFloat('extruder_offset_x1')
1673 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1674 self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1675 self.textEntry.SetValue('10')
1676 self._wizardState = 8
1677 elif self._wizardState == 8:
1679 n = int(self.textEntry.GetValue()) - 1
1682 y = profile.getMachineSettingFloat('extruder_offset_y1')
1684 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1685 self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1686 self.infoBox.SetReadyIndicator()
1687 self._wizardState = 8
1689 self.resumeButton.Enable(False)
1691 def mcLog(self, message):
1692 print 'Log:', message
1694 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1695 if self._wizardState == 1:
1696 if temp[0] >= 210 and temp[1] >= 210:
1697 self._wizardState = 2
1698 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1699 wx.CallAfter(self.resumeButton.Enable, True)
1700 wx.CallAfter(self.resumeButton.SetFocus)
1702 def mcStateChange(self, state):
1703 if self.comm is None:
1705 if self.comm.isOperational():
1706 if self._wizardState == 0:
1707 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1708 self.comm.sendCommand('M105')
1709 self.comm.sendCommand('M104 S220 T0')
1710 self.comm.sendCommand('M104 S220 T1')
1711 self.comm.sendCommand('G28')
1712 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1713 self._wizardState = 1
1714 if not self.comm.isPrinting():
1715 if self._wizardState == 3:
1716 self._wizardState = 4
1717 wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1718 wx.CallAfter(self.textEntry.SetValue, '0.0')
1719 wx.CallAfter(self.textEntry.Enable, True)
1720 wx.CallAfter(self.resumeButton.Enable, True)
1721 wx.CallAfter(self.resumeButton.SetFocus)
1722 elif self._wizardState == 6:
1723 self._wizardState = 7
1724 wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1725 wx.CallAfter(self.textEntry.SetValue, '10')
1726 wx.CallAfter(self.textEntry.Enable, True)
1727 wx.CallAfter(self.resumeButton.Enable, True)
1728 wx.CallAfter(self.resumeButton.SetFocus)
1730 elif self.comm.isError():
1731 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1733 def mcMessage(self, message):
1736 def mcProgress(self, lineNr):
1739 def mcZChange(self, newZ):
1742 class bedLevelWizard(wx.wizard.Wizard):
1744 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1746 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1747 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1749 self.mainPage = bedLevelWizardMain(self)
1750 self.headOffsetCalibration = None
1752 self.RunWizard(self.mainPage)
1755 def OnPageChanging(self, e):
1756 e.GetPage().StoreData()
1758 def OnPageChanged(self, e):
1759 if e.GetPage().AllowNext():
1760 self.FindWindowById(wx.ID_FORWARD).Enable()
1762 self.FindWindowById(wx.ID_FORWARD).Disable()
1763 if e.GetPage().AllowBack():
1764 self.FindWindowById(wx.ID_BACKWARD).Enable()
1766 self.FindWindowById(wx.ID_BACKWARD).Disable()
1768 class headOffsetWizard(wx.wizard.Wizard):
1770 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1772 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1773 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1775 self.mainPage = headOffsetCalibrationPage(self)
1777 self.RunWizard(self.mainPage)
1780 def OnPageChanging(self, e):
1781 e.GetPage().StoreData()
1783 def OnPageChanged(self, e):
1784 if e.GetPage().AllowNext():
1785 self.FindWindowById(wx.ID_FORWARD).Enable()
1787 self.FindWindowById(wx.ID_FORWARD).Disable()
1788 if e.GetPage().AllowBack():
1789 self.FindWindowById(wx.ID_BACKWARD).Enable()
1791 self.FindWindowById(wx.ID_BACKWARD).Disable()