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)
110 class InfoPage(wx.wizard.WizardPageSimple):
111 def __init__(self, parent, title):
112 wx.wizard.WizardPageSimple.__init__(self, parent)
114 sizer = wx.GridBagSizer(5, 5)
118 title = wx.StaticText(self, -1, title)
119 title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
120 sizer.Add(title, pos=(0, 0), span=(1, 2), flag=wx.ALIGN_CENTRE | wx.ALL)
121 sizer.Add(wx.StaticLine(self, -1), pos=(1, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
122 sizer.AddGrowableCol(1)
126 def AddText(self, info):
127 text = wx.StaticText(self, -1, info)
128 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
132 def AddSeperator(self):
133 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
136 def AddHiddenSeperator(self):
139 def AddInfoBox(self):
140 infoBox = InfoBox(self)
141 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
145 def AddRadioButton(self, label, style=0):
146 radio = wx.RadioButton(self, -1, label, style=style)
147 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1, 2), flag=wx.EXPAND | wx.ALL)
151 def AddCheckbox(self, label, checked=False):
152 check = wx.CheckBox(self, -1)
153 text = wx.StaticText(self, -1, label)
154 check.SetValue(checked)
155 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
156 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 2), flag=wx.ALL)
160 def AddButton(self, label):
161 button = wx.Button(self, -1, label)
162 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
166 def AddDualButton(self, label1, label2):
167 button1 = wx.Button(self, -1, label1)
168 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
169 button2 = wx.Button(self, -1, label2)
170 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
172 return button1, button2
174 def AddTextCtrl(self, value):
175 ret = wx.TextCtrl(self, -1, value)
176 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT)
180 def AddLabelTextCtrl(self, info, value):
181 text = wx.StaticText(self, -1, info)
182 ret = wx.TextCtrl(self, -1, value)
183 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
184 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
188 def AddTextCtrlButton(self, value, buttonText):
189 text = wx.TextCtrl(self, -1, value)
190 button = wx.Button(self, -1, buttonText)
191 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT)
192 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT)
196 def AddBitmap(self, bitmap):
197 bitmap = wx.StaticBitmap(self, -1, bitmap)
198 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1, 2), flag=wx.LEFT | wx.RIGHT)
202 def AddCheckmark(self, label, bitmap):
203 check = wx.StaticBitmap(self, -1, bitmap)
204 text = wx.StaticText(self, -1, label)
205 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
206 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1, 1), flag=wx.ALL)
210 def AddCombo(self, label, options):
211 combo = wx.ComboBox(self, -1, options[0], choices=options, style=wx.CB_DROPDOWN|wx.CB_READONLY)
212 text = wx.StaticText(self, -1, label)
213 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
214 self.GetSizer().Add(combo, pos=(self.rowNr, 1), span=(1, 1), flag=wx.LEFT | wx.RIGHT)
227 class PrintrbotPage(InfoPage):
228 def __init__(self, parent):
229 self._printer_info = [
230 # X, Y, Z, Nozzle Size, Filament Diameter, PrintTemperature, Print Speed, Travel Speed, Retract speed, Retract amount, use bed level sensor
231 ("Simple Metal", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, True),
232 ("Metal Plus", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
233 ("Simple Makers Kit", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, True),
234 (":" + _("Older models"),),
235 ("Original", 130, 130, 130, 0.5, 2.95, 208, 40, 70, 30, 1, False),
236 ("Simple Maker's Edition v1", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
237 ("Simple Maker's Edition v2 (2013 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
238 ("Simple Maker's Edition v3 (2014 Printrbot Simple)", 100, 100, 100, 0.4, 1.75, 208, 40, 70, 30, 1, False),
239 ("Jr v1", 115, 120, 80, 0.4, 1.75, 208, 40, 70, 30, 1, False),
240 ("Jr v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
241 ("LC v1", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
242 ("LC v2", 150, 150, 150, 0.4, 1.75, 208, 40, 70, 30, 1, False),
243 ("Plus v1", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
244 ("Plus v2", 200, 200, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
245 ("Plus v2.1", 185, 220, 200, 0.4, 1.75, 208, 40, 70, 30, 1, False),
246 ("Plus v2.2 (Model 1404/140422/140501/140507)", 250, 250, 250, 0.4, 1.75, 208, 40, 70, 30, 1, True),
247 ("Go v2 Large", 505, 306, 310, 0.4, 1.75, 208, 35, 70, 30, 1, True),
250 super(PrintrbotPage, self).__init__(parent, _("Printrbot Selection"))
251 self.AddBitmap(wx.Bitmap(resources.getPathForImage('Printrbot_logo.png')))
252 self.AddText(_("Select which Printrbot machine you have:"))
254 for printer in self._printer_info:
255 if printer[0].startswith(":"):
257 self.AddText(printer[0][1:])
259 item = self.AddRadioButton(printer[0])
260 item.data = printer[1:]
261 self._items.append(item)
264 profile.putMachineSetting('machine_name', 'Printrbot ???')
265 for item in self._items:
268 profile.putMachineSetting('machine_name', 'Printrbot ' + item.GetLabel())
269 profile.putMachineSetting('machine_width', data[0])
270 profile.putMachineSetting('machine_depth', data[1])
271 profile.putMachineSetting('machine_height', data[2])
272 profile.putProfileSetting('nozzle_size', data[3])
273 profile.putProfileSetting('filament_diameter', data[4])
274 profile.putProfileSetting('print_temperature', data[5])
275 profile.putProfileSetting('print_speed', data[6])
276 profile.putProfileSetting('travel_speed', data[7])
277 profile.putProfileSetting('retraction_speed', data[8])
278 profile.putProfileSetting('retraction_amount', data[9])
279 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
280 profile.putMachineSetting('has_heated_bed', 'False')
281 profile.putMachineSetting('machine_center_is_zero', 'False')
282 profile.putMachineSetting('extruder_head_size_min_x', '0')
283 profile.putMachineSetting('extruder_head_size_min_y', '0')
284 profile.putMachineSetting('extruder_head_size_max_x', '0')
285 profile.putMachineSetting('extruder_head_size_max_y', '0')
286 profile.putMachineSetting('extruder_head_size_height', '0')
288 profile.setAlterationFile('start.gcode', """;Sliced at: {day} {date} {time}
289 ;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {fill_density}
290 ;Print time: {print_time}
291 ;Filament used: {filament_amount}m {filament_weight}g
292 ;Filament cost: {filament_cost}
293 ;M190 S{print_bed_temperature} ;Uncomment to add your own bed temperature line
294 ;M109 S{print_temperature} ;Uncomment to add your own temperature line
296 G90 ;absolute positioning
297 M82 ;set extruder to absolute mode
298 M107 ;start with the fan off
299 G28 X0 Y0 ;move X/Y to min endstops
300 G28 Z0 ;move Z to min endstops
301 G29 ;Run the auto bed leveling
302 G1 Z15.0 F{travel_speed} ;move the platform down 15mm
303 G92 E0 ;zero the extruded length
304 G1 F200 E3 ;extrude 3mm of feed stock
305 G92 E0 ;zero the extruded length again
307 ;Put printing message on LCD screen
311 class OtherMachineSelectPage(InfoPage):
312 def __init__(self, parent):
313 super(OtherMachineSelectPage, self).__init__(parent, _("Other machine information"))
314 self.AddText(_("The following pre-defined machine profiles are available"))
315 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."))
317 machines = resources.getDefaultMachineProfiles()
319 for filename in machines:
320 name = os.path.splitext(os.path.basename(filename))[0]
321 item = self.AddRadioButton(name)
322 item.filename = filename
323 item.Bind(wx.EVT_RADIOBUTTON, self.OnProfileSelect)
324 self.options.append(item)
326 item = self.AddRadioButton(_('Custom...'))
328 item.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
330 def OnProfileSelect(self, e):
331 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineInfoPage)
333 def OnOtherSelect(self, e):
334 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().customRepRapInfoPage)
337 for option in self.options:
338 if option.GetValue():
339 profile.loadProfile(option.filename)
340 profile.loadMachineSettings(option.filename)
342 class OtherMachineInfoPage(InfoPage):
343 def __init__(self, parent):
344 super(OtherMachineInfoPage, self).__init__(parent, _("Cura Ready!"))
345 self.AddText(_("Cura is now ready to be used!"))
347 class CustomRepRapInfoPage(InfoPage):
348 def __init__(self, parent):
349 super(CustomRepRapInfoPage, self).__init__(parent, _("Custom RepRap information"))
350 self.AddText(_("RepRap machines can be vastly different, so here you can set your own settings."))
351 self.AddText(_("Be sure to review the default profile before running it on your machine."))
352 self.AddText(_("If you like a default profile for your machine added,\nthen make an issue on github."))
354 self.AddText(_("You will have to manually install Marlin or Sprinter firmware."))
356 self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
357 self.machineWidth = self.AddLabelTextCtrl(_("Machine width X (mm)"), "80")
358 self.machineDepth = self.AddLabelTextCtrl(_("Machine depth Y (mm)"), "80")
359 self.machineHeight = self.AddLabelTextCtrl(_("Machine height Z (mm)"), "55")
360 self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
361 self.heatedBed = self.AddCheckbox(_("Heated bed"))
362 self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
365 profile.putMachineSetting('machine_name', self.machineName.GetValue())
366 profile.putMachineSetting('machine_width', self.machineWidth.GetValue())
367 profile.putMachineSetting('machine_depth', self.machineDepth.GetValue())
368 profile.putMachineSetting('machine_height', self.machineHeight.GetValue())
369 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
370 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
371 profile.putMachineSetting('has_heated_bed', str(self.heatedBed.GetValue()))
372 profile.putMachineSetting('machine_center_is_zero', str(self.HomeAtCenter.GetValue()))
373 profile.putMachineSetting('extruder_head_size_min_x', '0')
374 profile.putMachineSetting('extruder_head_size_min_y', '0')
375 profile.putMachineSetting('extruder_head_size_max_x', '0')
376 profile.putMachineSetting('extruder_head_size_max_y', '0')
377 profile.putMachineSetting('extruder_head_size_height', '0')
378 profile.checkAndUpdateMachineName()
380 class MachineSelectPage(InfoPage):
381 def __init__(self, parent):
382 super(MachineSelectPage, self).__init__(parent, _("Select your machine"))
383 self.AddText(_("What kind of machine do you have:"))
385 self.LulzbotMiniRadio = self.AddRadioButton("LulzBot Mini", style=wx.RB_GROUP)
386 self.LulzbotMiniRadio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
387 self.LulzbotMiniRadio.SetValue(True)
388 self.LulzbotTaz5Radio = self.AddRadioButton("LulzBot TAZ 5")
389 self.LulzbotTaz5Radio.Bind(wx.EVT_RADIOBUTTON, self.OnTaz5Select)
390 self.LulzbotTaz4Radio = self.AddRadioButton("LulzBot TAZ 4")
391 self.LulzbotTaz4Radio.Bind(wx.EVT_RADIOBUTTON, self.OnLulzbotSelect)
392 self.Ultimaker2Radio = self.AddRadioButton("Ultimaker2")
393 self.Ultimaker2Radio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
394 self.Ultimaker2ExtRadio = self.AddRadioButton("Ultimaker2extended")
395 self.Ultimaker2ExtRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
396 self.Ultimaker2GoRadio = self.AddRadioButton("Ultimaker2go")
397 self.Ultimaker2GoRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimaker2Select)
398 self.UltimakerRadio = self.AddRadioButton("Ultimaker Original")
399 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
400 self.UltimakerOPRadio = self.AddRadioButton("Ultimaker Original+")
401 self.UltimakerOPRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerOPSelect)
402 self.PrintrbotRadio = self.AddRadioButton("Printrbot")
403 self.PrintrbotRadio.Bind(wx.EVT_RADIOBUTTON, self.OnPrintrbotSelect)
404 self.OtherRadio = self.AddRadioButton(_("Other (Ex: RepRap, MakerBot, Witbox)"))
405 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
407 def OnUltimaker2Select(self, e):
408 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimaker2ReadyPage)
410 def OnUltimakerSelect(self, e):
411 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerSelectParts)
413 def OnUltimakerOPSelect(self, e):
414 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)
416 def OnPrintrbotSelect(self, e):
417 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().printrbotSelectType)
419 def OnLulzbotSelect(self, e):
420 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
422 def OnTaz5Select(self, e):
423 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().taz5NozzleSelectPage)
425 def OnOtherSelect(self, e):
426 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
429 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
433 profile.putProfileSetting('retraction_enable', 'True')
434 if self.Ultimaker2Radio.GetValue() or self.Ultimaker2GoRadio.GetValue() or self.Ultimaker2ExtRadio.GetValue():
435 if self.Ultimaker2Radio.GetValue():
436 profile.putMachineSetting('machine_width', '230')
437 profile.putMachineSetting('machine_depth', '225')
438 profile.putMachineSetting('machine_height', '205')
439 profile.putMachineSetting('machine_name', 'ultimaker2')
440 profile.putMachineSetting('machine_type', 'ultimaker2')
441 profile.putMachineSetting('has_heated_bed', 'True')
442 if self.Ultimaker2GoRadio.GetValue():
443 profile.putMachineSetting('machine_width', '120')
444 profile.putMachineSetting('machine_depth', '120')
445 profile.putMachineSetting('machine_height', '115')
446 profile.putMachineSetting('machine_name', 'ultimaker2go')
447 profile.putMachineSetting('machine_type', 'ultimaker2go')
448 profile.putMachineSetting('has_heated_bed', 'False')
449 if self.Ultimaker2ExtRadio.GetValue():
450 profile.putMachineSetting('machine_width', '230')
451 profile.putMachineSetting('machine_depth', '225')
452 profile.putMachineSetting('machine_height', '315')
453 profile.putMachineSetting('machine_name', 'ultimaker2extended')
454 profile.putMachineSetting('machine_type', 'ultimaker2extended')
455 profile.putMachineSetting('has_heated_bed', 'False')
456 profile.putMachineSetting('machine_center_is_zero', 'False')
457 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
458 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
459 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
460 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
461 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
462 profile.putMachineSetting('extruder_head_size_height', '48.0')
463 profile.putProfileSetting('nozzle_size', '0.4')
464 profile.putProfileSetting('fan_full_height', '5.0')
465 profile.putMachineSetting('extruder_offset_x1', '18.0')
466 profile.putMachineSetting('extruder_offset_y1', '0.0')
467 elif self.UltimakerRadio.GetValue():
468 profile.putMachineSetting('machine_width', '205')
469 profile.putMachineSetting('machine_depth', '205')
470 profile.putMachineSetting('machine_height', '200')
471 profile.putMachineSetting('machine_name', 'ultimaker original')
472 profile.putMachineSetting('machine_type', 'ultimaker')
473 profile.putMachineSetting('machine_center_is_zero', 'False')
474 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
475 profile.putProfileSetting('nozzle_size', '0.4')
476 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
477 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
478 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
479 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
480 profile.putMachineSetting('extruder_head_size_height', '55.0')
481 elif self.UltimakerOPRadio.GetValue():
482 profile.putMachineSetting('machine_width', '205')
483 profile.putMachineSetting('machine_depth', '205')
484 profile.putMachineSetting('machine_height', '200')
485 profile.putMachineSetting('machine_name', 'ultimaker original+')
486 profile.putMachineSetting('machine_type', 'ultimaker_plus')
487 profile.putMachineSetting('machine_center_is_zero', 'False')
488 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
489 profile.putProfileSetting('nozzle_size', '0.4')
490 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
491 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
492 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
493 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
494 profile.putMachineSetting('extruder_head_size_height', '55.0')
495 profile.putMachineSetting('has_heated_bed', 'True')
496 profile.putMachineSetting('extruder_amount', '1')
497 profile.putProfileSetting('retraction_enable', 'True')
498 elif self.LulzbotTaz4Radio.GetValue() or self.LulzbotTaz5Radio.GetValue() or self.LulzbotMiniRadio.GetValue():
499 if self.LulzbotTaz4Radio.GetValue():
500 profile.putMachineSetting('machine_width', '298')
501 profile.putMachineSetting('machine_depth', '275')
502 profile.putMachineSetting('machine_height', '250')
503 profile.putProfileSetting('nozzle_size', '0.35')
504 profile.putMachineSetting('machine_name', 'LulzBot TAZ 4')
505 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_4')
506 profile.putMachineSetting('serial_baud', '115200')
507 elif self.LulzbotTaz5Radio.GetValue():
508 profile.putMachineSetting('machine_width', '298')
509 profile.putMachineSetting('machine_depth', '275')
510 profile.putMachineSetting('machine_height', '250')
511 profile.putProfileSetting('nozzle_size', '0.35')
512 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5')
513 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5')
514 profile.putMachineSetting('serial_baud', '115200')
516 profile.putMachineSetting('machine_width', '155')
517 profile.putMachineSetting('machine_depth', '155')
518 profile.putMachineSetting('machine_height', '163')
519 profile.putProfileSetting('nozzle_size', '0.5')
520 profile.putMachineSetting('machine_name', 'LulzBot Mini')
521 profile.putMachineSetting('machine_type', 'lulzbot_mini')
522 profile.putMachineSetting('serial_baud', '115200')
523 profile.putMachineSetting('machine_center_is_zero', 'False')
524 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
525 profile.putMachineSetting('has_heated_bed', 'True')
526 profile.putMachineSetting('extruder_head_size_min_x', '0.0')
527 profile.putMachineSetting('extruder_head_size_min_y', '0.0')
528 profile.putMachineSetting('extruder_head_size_max_x', '0.0')
529 profile.putMachineSetting('extruder_head_size_max_y', '0.0')
530 profile.putMachineSetting('extruder_head_size_height', '0.0')
531 profile.putPreference('startMode', 'Simple')
533 profile.putMachineSetting('machine_width', '80')
534 profile.putMachineSetting('machine_depth', '80')
535 profile.putMachineSetting('machine_height', '60')
536 profile.putMachineSetting('machine_name', 'reprap')
537 profile.putMachineSetting('machine_type', 'reprap')
538 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
539 profile.putPreference('startMode', 'Normal')
540 profile.putProfileSetting('nozzle_size', '0.5')
541 profile.checkAndUpdateMachineName()
542 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
544 class SelectParts(InfoPage):
545 def __init__(self, parent):
546 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
547 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."))
549 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
550 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
551 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
552 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
554 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."))
555 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
556 self.springExtruder.SetValue(True)
559 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
560 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
561 profile.putMachineSetting('has_heated_bed', 'True')
563 profile.putMachineSetting('has_heated_bed', 'False')
564 if self.dualExtrusion.GetValue():
565 profile.putMachineSetting('extruder_amount', '2')
566 profile.putMachineSetting('machine_depth', '195')
568 profile.putMachineSetting('extruder_amount', '1')
569 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
570 profile.putProfileSetting('retraction_enable', 'True')
572 profile.putProfileSetting('retraction_enable', 'False')
575 class UltimakerFirmwareUpgradePage(InfoPage):
576 def __init__(self, parent):
577 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
578 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."))
579 self.AddHiddenSeperator()
580 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
581 self.AddHiddenSeperator()
582 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."))
583 upgradeButton, skipUpgradeButton = self.AddDualButton(_('Upgrade to Marlin firmware'), _('Skip upgrade'))
584 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
585 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
586 self.AddHiddenSeperator()
587 if profile.getMachineSetting('machine_type') == 'ultimaker':
588 self.AddText(_("Do not upgrade to this firmware if:"))
589 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
590 self.AddText(_("* Build your own heated bed"))
591 self.AddText(_("* Have other changes in the firmware"))
592 # button = self.AddButton('Goto this page for a custom firmware')
593 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
598 def OnUpgradeClick(self, e):
599 if firmwareInstall.InstallFirmware():
600 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
602 def OnSkipClick(self, e):
603 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
604 self.GetParent().ShowPage(self.GetNext())
606 def OnUrlClick(self, e):
607 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
609 class UltimakerCheckupPage(InfoPage):
610 def __init__(self, parent):
611 super(UltimakerCheckupPage, self).__init__(parent, _("Ultimaker Checkup"))
613 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
614 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
615 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
616 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
617 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
618 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
619 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
620 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
621 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
622 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
625 _("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."))
626 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
627 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
628 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
630 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
631 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
632 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
634 self.infoBox = self.AddInfoBox()
635 self.machineState = self.AddText("")
636 self.temperatureLabel = self.AddText("")
637 self.errorLogButton = self.AddButton(_("Show error log"))
638 self.errorLogButton.Show(False)
640 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
642 self.xMinStop = False
643 self.xMaxStop = False
644 self.yMinStop = False
645 self.yMaxStop = False
646 self.zMinStop = False
647 self.zMaxStop = False
649 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
652 if self.comm is not None:
656 self.endstopBitmap.Show(False)
659 def OnSkipClick(self, e):
660 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
661 self.GetParent().ShowPage(self.GetNext())
663 def OnCheckClick(self, e=None):
664 self.errorLogButton.Show(False)
665 if self.comm is not None:
669 wx.CallAfter(self.OnCheckClick)
671 self.infoBox.SetBusy(_("Connecting to machine."))
672 self.commState.SetBitmap(self.unknownBitmap)
673 self.tempState.SetBitmap(self.unknownBitmap)
674 self.stopState.SetBitmap(self.unknownBitmap)
675 self.checkupState = 0
676 self.checkExtruderNr = 0
677 self.comm = machineCom.MachineCom(callbackObject=self)
679 def OnErrorLog(self, e):
680 printWindow.LogWindow('\n'.join(self.comm.getLog()))
682 def mcLog(self, message):
685 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
686 if not self.comm.isOperational():
688 if self.checkupState == 0:
689 self.tempCheckTimeout = 20
690 if temp[self.checkExtruderNr] > 70:
691 self.checkupState = 1
692 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
693 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
694 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
696 self.startTemp = temp[self.checkExtruderNr]
697 self.checkupState = 2
698 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
699 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
700 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
701 elif self.checkupState == 1:
702 if temp[self.checkExtruderNr] < 60:
703 self.startTemp = temp[self.checkExtruderNr]
704 self.checkupState = 2
705 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
706 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
707 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
708 elif self.checkupState == 2:
709 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
710 if temp[self.checkExtruderNr] > self.startTemp + 40:
711 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
712 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
713 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
714 self.checkExtruderNr = 0
715 self.checkupState = 3
716 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
717 wx.CallAfter(self.endstopBitmap.Show, True)
718 wx.CallAfter(self.Layout)
719 self.comm.sendCommand('M119')
720 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
722 self.checkupState = 0
723 self.checkExtruderNr += 1
725 self.tempCheckTimeout -= 1
726 if self.tempCheckTimeout < 1:
727 self.checkupState = -1
728 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
729 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
730 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
731 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
732 elif self.checkupState >= 3 and self.checkupState < 10:
733 self.comm.sendCommand('M119')
734 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
736 def mcStateChange(self, state):
737 if self.comm is None:
739 if self.comm.isOperational():
740 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
741 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
742 elif self.comm.isError():
743 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
744 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
745 wx.CallAfter(self.endstopBitmap.Show, False)
746 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
747 wx.CallAfter(self.errorLogButton.Show, True)
748 wx.CallAfter(self.Layout)
750 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
752 def mcMessage(self, message):
753 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
754 for data in message.split(' '):
756 tag, value = data.split(':', 1)
758 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
760 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
762 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
764 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
766 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
768 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
770 tag, value = map(str.strip, message.split(':', 1))
772 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
774 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
776 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
778 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
780 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
782 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
783 if 'z_max' in message:
784 self.comm.sendCommand('M119')
786 if self.checkupState == 3:
787 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
788 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
789 self.checkupState = 5
790 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
791 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
793 self.checkupState = 4
794 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
795 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
796 elif self.checkupState == 4:
797 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
798 self.checkupState = 5
799 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
800 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
801 elif self.checkupState == 5:
802 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
803 self.checkupState = 6
804 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
805 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
806 elif self.checkupState == 6:
807 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
808 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
809 self.checkupState = 8
810 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
811 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
813 self.checkupState = 7
814 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
815 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
816 elif self.checkupState == 7:
817 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
818 self.checkupState = 8
819 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
820 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
821 elif self.checkupState == 8:
822 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
823 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
824 self.checkupState = 10
826 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
827 wx.CallAfter(self.infoBox.SetReadyIndicator)
828 wx.CallAfter(self.endstopBitmap.Show, False)
829 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
830 wx.CallAfter(self.OnSkipClick, None)
832 self.checkupState = 9
833 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
834 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
835 elif self.checkupState == 9:
836 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
837 self.checkupState = 10
839 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
840 wx.CallAfter(self.infoBox.SetReadyIndicator)
841 wx.CallAfter(self.endstopBitmap.Show, False)
842 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
843 wx.CallAfter(self.OnSkipClick, None)
845 def mcProgress(self, lineNr):
848 def mcZChange(self, newZ):
852 class UltimakerCalibrationPage(InfoPage):
853 def __init__(self, parent):
854 super(UltimakerCalibrationPage, self).__init__(parent, _("Ultimaker Calibration"))
856 self.AddText("Your Ultimaker requires some calibration.")
857 self.AddText("This calibration is needed for a proper extrusion amount.")
859 self.AddText("The following values are needed:")
860 self.AddText("* Diameter of filament")
861 self.AddText("* Number of steps per mm of filament extrusion")
863 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
865 self.AddText("First we need the diameter of your filament:")
866 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
868 "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.")
869 self.AddText("Note: This value can be changed later at any time.")
872 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
875 class UltimakerCalibrateStepsPerEPage(InfoPage):
876 def __init__(self, parent):
877 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, _("Ultimaker Calibration"))
879 #if profile.getMachineSetting('steps_per_e') == '0':
880 # profile.putMachineSetting('steps_per_e', '865.888')
882 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
883 self.AddText(_("First remove any filament from your machine."))
884 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
885 self.AddText(_("We'll push the filament 100mm"))
886 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
887 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
888 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
889 self.AddText(_("This results in the following steps per E:"))
890 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
891 self.AddText(_("You can repeat these steps to get better calibration."))
894 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
895 self.heatButton = self.AddButton(_("Heatup for filament removal"))
897 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
898 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
899 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
901 def OnSaveLengthClick(self, e):
902 currentEValue = float(self.stepsPerEInput.GetValue())
903 realExtrudeLength = float(self.lengthInput.GetValue())
904 newEValue = currentEValue * 100 / realExtrudeLength
905 self.stepsPerEInput.SetValue(str(newEValue))
906 self.lengthInput.SetValue("100")
908 def OnExtrudeClick(self, e):
909 t = threading.Thread(target=self.OnExtrudeRun)
913 def OnExtrudeRun(self):
914 self.heatButton.Enable(False)
915 self.extrudeButton.Enable(False)
916 currentEValue = float(self.stepsPerEInput.GetValue())
917 self.comm = machineCom.MachineCom()
918 if not self.comm.isOpen():
920 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
921 'Printer error', wx.OK | wx.ICON_INFORMATION)
922 self.heatButton.Enable(True)
923 self.extrudeButton.Enable(True)
926 line = self.comm.readline()
931 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
934 self.sendGCommand('M302') #Disable cold extrusion protection
935 self.sendGCommand("M92 E%f" % (currentEValue))
936 self.sendGCommand("G92 E0")
937 self.sendGCommand("G1 E100 F600")
940 self.extrudeButton.Enable()
941 self.heatButton.Enable()
943 def OnHeatClick(self, e):
944 t = threading.Thread(target=self.OnHeatRun)
949 self.heatButton.Enable(False)
950 self.extrudeButton.Enable(False)
951 self.comm = machineCom.MachineCom()
952 if not self.comm.isOpen():
954 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
955 'Printer error', wx.OK | wx.ICON_INFORMATION)
956 self.heatButton.Enable(True)
957 self.extrudeButton.Enable(True)
960 line = self.comm.readline()
962 self.heatButton.Enable(True)
963 self.extrudeButton.Enable(True)
967 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
970 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
972 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
973 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
974 self.sendGCommand('M104 S0')
977 self.heatButton.Enable(True)
978 self.extrudeButton.Enable(True)
980 def sendGCommand(self, cmd):
981 self.comm.sendCommand(cmd) #Disable cold extrusion protection
983 line = self.comm.readline()
986 if line.startswith('ok'):
990 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
992 class Ultimaker2ReadyPage(InfoPage):
993 def __init__(self, parent):
994 super(Ultimaker2ReadyPage, self).__init__(parent, _("Ultimaker2"))
995 self.AddText(_('Congratulations on your the purchase of your brand new Ultimaker2.'))
996 self.AddText(_('Cura is now ready to be used with your Ultimaker2.'))
999 class LulzbotReadyPage(InfoPage):
1000 def __init__(self, parent):
1001 super(LulzbotReadyPage, self).__init__(parent, _("LulzBot TAZ4/Mini"))
1002 self.AddText(_('Cura is now ready to be used with your LulzBot 3D printer.'))
1004 self.AddText(_('For more information about using Cura with your LulzBot'))
1005 self.AddText(_('3D printer, please visit www.LulzBot.com/cura'))
1008 class Taz5NozzleSelectPage(InfoPage):
1009 def __init__(self, parent):
1010 super(Taz5NozzleSelectPage, self).__init__(parent, _("LulzBot TAZ5"))
1011 self.AddText(_('Please select nozzle size:'))
1014 class ConfigWizard(wx.wizard.Wizard):
1015 def __init__(self, addNew = False):
1016 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
1018 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1020 profile.setActiveMachine(profile.getMachineCount())
1022 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1023 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1024 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1026 self.machineSelectPage = MachineSelectPage(self)
1027 self.ultimakerSelectParts = SelectParts(self)
1028 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
1029 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
1030 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
1031 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
1032 self.bedLevelPage = bedLevelWizardMain(self)
1033 self.headOffsetCalibration = headOffsetCalibrationPage(self)
1034 self.printrbotSelectType = PrintrbotPage(self)
1035 self.otherMachineSelectPage = OtherMachineSelectPage(self)
1036 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
1037 self.otherMachineInfoPage = OtherMachineInfoPage(self)
1039 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
1040 self.lulzbotReadyPage = LulzbotReadyPage(self)
1041 self.taz5NozzleSelectPage = Taz5NozzleSelectPage(self)
1043 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
1044 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
1045 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
1046 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
1047 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
1048 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
1049 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
1050 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
1052 self.FitToPage(self.machineSelectPage)
1053 self.GetPageAreaSizer().Add(self.machineSelectPage)
1055 self.RunWizard(self.machineSelectPage)
1058 def OnPageChanging(self, e):
1059 e.GetPage().StoreData()
1061 def OnPageChanged(self, e):
1062 if e.GetPage().AllowNext():
1063 self.FindWindowById(wx.ID_FORWARD).Enable()
1065 self.FindWindowById(wx.ID_FORWARD).Disable()
1066 if e.GetPage().AllowBack():
1067 self.FindWindowById(wx.ID_BACKWARD).Enable()
1069 self.FindWindowById(wx.ID_BACKWARD).Disable()
1071 def OnCancel(self, e):
1072 profile.setActiveMachine(self._old_machine_index)
1074 class bedLevelWizardMain(InfoPage):
1075 def __init__(self, parent):
1076 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1078 self.AddText(_('This wizard will help you in leveling your printer bed'))
1080 self.AddText(_('It will do the following steps'))
1081 self.AddText(_('* Move the printer head to each corner'))
1082 self.AddText(_(' and let you adjust the height of the bed to the nozzle'))
1083 self.AddText(_('* Print a line around the bed to check if it is level'))
1086 self.connectButton = self.AddButton(_('Connect to printer'))
1089 self.infoBox = self.AddInfoBox()
1090 self.resumeButton = self.AddButton(_('Resume'))
1091 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1092 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1093 self.resumeButton.Enable(False)
1095 self.upButton.Enable(False)
1096 self.downButton.Enable(False)
1097 self.upButton2.Enable(False)
1098 self.downButton2.Enable(False)
1100 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1101 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1102 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1103 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1104 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1105 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1107 def OnConnect(self, e = None):
1108 if self.comm is not None:
1112 wx.CallAfter(self.OnConnect)
1114 self.connectButton.Enable(False)
1115 self.comm = machineCom.MachineCom(callbackObject=self)
1116 self.infoBox.SetBusy(_('Connecting to machine.'))
1117 self._wizardState = 0
1119 def OnBedUp(self, e):
1120 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1121 self.comm.sendCommand('G92 Z10')
1122 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1123 self.comm.sendCommand('M400')
1125 def OnBedDown(self, e):
1126 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1127 self.comm.sendCommand('G92 Z10')
1128 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1129 self.comm.sendCommand('M400')
1131 def OnBedUp2(self, e):
1132 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1133 self.comm.sendCommand('G92 Z10')
1134 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1135 self.comm.sendCommand('M400')
1137 def OnBedDown2(self, e):
1138 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1139 self.comm.sendCommand('G92 Z10')
1140 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1141 self.comm.sendCommand('M400')
1143 def AllowNext(self):
1144 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1145 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1148 def OnResume(self, e):
1149 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1150 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1151 if self._wizardState == -1:
1152 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1153 wx.CallAfter(self.upButton.Enable, False)
1154 wx.CallAfter(self.downButton.Enable, False)
1155 wx.CallAfter(self.upButton2.Enable, False)
1156 wx.CallAfter(self.downButton2.Enable, False)
1157 self.comm.sendCommand('M105')
1158 self.comm.sendCommand('G28')
1159 self._wizardState = 1
1160 elif self._wizardState == 2:
1161 if profile.getMachineSetting('has_heated_bed') == 'True':
1162 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1163 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1164 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1165 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1166 self.comm.sendCommand('M400')
1167 self._wizardState = 3
1169 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1170 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1171 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1172 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1173 self.comm.sendCommand('M400')
1174 self._wizardState = 3
1175 elif self._wizardState == 4:
1176 if profile.getMachineSetting('has_heated_bed') == 'True':
1177 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1178 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1179 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1180 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1181 self.comm.sendCommand('M400')
1182 self._wizardState = 7
1184 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1185 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1186 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1187 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1188 self.comm.sendCommand('M400')
1189 self._wizardState = 5
1190 elif self._wizardState == 6:
1191 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1192 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1193 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1194 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1195 self.comm.sendCommand('M400')
1196 self._wizardState = 7
1197 elif self._wizardState == 8:
1198 wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1199 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1200 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1201 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1202 self._wizardState = 9
1203 elif self._wizardState == 10:
1204 self._wizardState = 11
1205 wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1206 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1207 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1208 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1209 w = profile.getMachineSettingFloat('machine_width') - 10
1210 d = profile.getMachineSettingFloat('machine_depth')
1211 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1212 filamentArea = math.pi * filamentRadius * filamentRadius
1213 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1217 'G1 Z2 F%d' % (feedZ),
1219 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1220 'G1 Z0.3 F%d' % (feedZ)]
1222 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1224 for i in xrange(0, 3):
1225 dist = 5.0 + 0.4 * float(i)
1226 eValue += (d - 2.0*dist) * ePerMM
1227 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1228 eValue += (w - 2.0*dist) * ePerMM
1229 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1230 eValue += (d - 2.0*dist) * ePerMM
1231 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1232 eValue += (w - 2.0*dist) * ePerMM
1233 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1235 gcodeList.append('M400')
1236 self.comm.printGCode(gcodeList)
1237 self.resumeButton.Enable(False)
1239 def mcLog(self, message):
1240 print 'Log:', message
1242 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1243 if self._wizardState == 1:
1244 self._wizardState = 2
1245 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1246 wx.CallAfter(self.resumeButton.Enable, True)
1247 elif self._wizardState == 3:
1248 self._wizardState = 4
1249 if profile.getMachineSetting('has_heated_bed') == 'True':
1250 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1252 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1253 wx.CallAfter(self.resumeButton.Enable, True)
1254 elif self._wizardState == 5:
1255 self._wizardState = 6
1256 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1257 wx.CallAfter(self.resumeButton.Enable, True)
1258 elif self._wizardState == 7:
1259 self._wizardState = 8
1260 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1261 wx.CallAfter(self.resumeButton.Enable, True)
1262 elif self._wizardState == 9:
1263 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1264 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1266 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1267 wx.CallAfter(self.resumeButton.Enable, True)
1268 self._wizardState = 10
1270 def mcStateChange(self, state):
1271 if self.comm is None:
1273 if self.comm.isOperational():
1274 if self._wizardState == 0:
1275 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1276 wx.CallAfter(self.upButton.Enable, True)
1277 wx.CallAfter(self.downButton.Enable, True)
1278 wx.CallAfter(self.upButton2.Enable, True)
1279 wx.CallAfter(self.downButton2.Enable, True)
1280 wx.CallAfter(self.resumeButton.Enable, True)
1281 self._wizardState = -1
1282 elif self._wizardState == 11 and not self.comm.isPrinting():
1283 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1284 self.comm.sendCommand('G92 E0')
1285 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1286 self.comm.sendCommand('M104 S0')
1287 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1288 wx.CallAfter(self.infoBox.SetReadyIndicator)
1289 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1290 wx.CallAfter(self.connectButton.Enable, True)
1291 self._wizardState = 12
1292 elif self.comm.isError():
1293 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1295 def mcMessage(self, message):
1298 def mcProgress(self, lineNr):
1301 def mcZChange(self, newZ):
1304 class headOffsetCalibrationPage(InfoPage):
1305 def __init__(self, parent):
1306 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1308 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1311 self.connectButton = self.AddButton(_('Connect to printer'))
1314 self.infoBox = self.AddInfoBox()
1315 self.textEntry = self.AddTextCtrl('')
1316 self.textEntry.Enable(False)
1317 self.resumeButton = self.AddButton(_('Resume'))
1318 self.resumeButton.Enable(False)
1320 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1321 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1323 def AllowBack(self):
1326 def OnConnect(self, e = None):
1327 if self.comm is not None:
1331 wx.CallAfter(self.OnConnect)
1333 self.connectButton.Enable(False)
1334 self.comm = machineCom.MachineCom(callbackObject=self)
1335 self.infoBox.SetBusy(_('Connecting to machine.'))
1336 self._wizardState = 0
1338 def OnResume(self, e):
1339 if self._wizardState == 2:
1340 self._wizardState = 3
1341 wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1343 w = profile.getMachineSettingFloat('machine_width')
1344 d = profile.getMachineSettingFloat('machine_depth')
1346 gcode = gcodeGenerator.gcodeGenerator()
1347 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1348 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1355 gcode.addMove(w/2, 5)
1356 gcode.addMove(z=0.2)
1358 gcode.addExtrude(w/2, d-5.0)
1360 gcode.addMove(5, d/2)
1362 gcode.addExtrude(w-5.0, d/2)
1363 gcode.addRetract(15)
1366 gcode.addMove(w/2, 5)
1368 gcode.addExtrude(w/2, d-5.0)
1370 gcode.addMove(5, d/2)
1372 gcode.addExtrude(w-5.0, d/2)
1373 gcode.addRetract(15)
1378 gcode.addCmd('M400')
1380 self.comm.printGCode(gcode.list())
1381 self.resumeButton.Enable(False)
1382 elif self._wizardState == 4:
1384 float(self.textEntry.GetValue())
1387 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1388 self._wizardState = 5
1389 self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1390 self.textEntry.SetValue('0.0')
1391 self.textEntry.Enable(True)
1392 elif self._wizardState == 5:
1394 float(self.textEntry.GetValue())
1397 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1398 self._wizardState = 6
1399 self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1400 self.textEntry.SetValue('')
1401 self.textEntry.Enable(False)
1402 self.resumeButton.Enable(False)
1404 x = profile.getMachineSettingFloat('extruder_offset_x1')
1405 y = profile.getMachineSettingFloat('extruder_offset_y1')
1406 gcode = gcodeGenerator.gcodeGenerator()
1407 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1408 gcode.setPrintSpeed(25)
1411 gcode.addMove(50, 40, 0.2)
1413 for n in xrange(0, 10):
1414 gcode.addExtrude(50 + n * 10, 150)
1415 gcode.addExtrude(50 + n * 10 + 5, 150)
1416 gcode.addExtrude(50 + n * 10 + 5, 40)
1417 gcode.addExtrude(50 + n * 10 + 10, 40)
1418 gcode.addMove(40, 50)
1419 for n in xrange(0, 10):
1420 gcode.addExtrude(150, 50 + n * 10)
1421 gcode.addExtrude(150, 50 + n * 10 + 5)
1422 gcode.addExtrude(40, 50 + n * 10 + 5)
1423 gcode.addExtrude(40, 50 + n * 10 + 10)
1424 gcode.addRetract(15)
1427 gcode.addMove(50 - x, 30 - y, 0.2)
1429 for n in xrange(0, 10):
1430 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1431 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1432 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1433 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1434 gcode.addMove(30 - x, 50 - y, 0.2)
1435 for n in xrange(0, 10):
1436 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1437 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1438 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1439 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1440 gcode.addRetract(15)
1442 gcode.addCmd('M400')
1443 gcode.addCmd('M104 T0 S0')
1444 gcode.addCmd('M104 T1 S0')
1445 self.comm.printGCode(gcode.list())
1446 elif self._wizardState == 7:
1448 n = int(self.textEntry.GetValue()) - 1
1451 x = profile.getMachineSettingFloat('extruder_offset_x1')
1453 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1454 self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1455 self.textEntry.SetValue('10')
1456 self._wizardState = 8
1457 elif self._wizardState == 8:
1459 n = int(self.textEntry.GetValue()) - 1
1462 y = profile.getMachineSettingFloat('extruder_offset_y1')
1464 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1465 self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1466 self.infoBox.SetReadyIndicator()
1467 self._wizardState = 8
1469 self.resumeButton.Enable(False)
1471 def mcLog(self, message):
1472 print 'Log:', message
1474 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1475 if self._wizardState == 1:
1476 if temp[0] >= 210 and temp[1] >= 210:
1477 self._wizardState = 2
1478 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1479 wx.CallAfter(self.resumeButton.Enable, True)
1480 wx.CallAfter(self.resumeButton.SetFocus)
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.SetInfo, _('Homing printer and heating up both extruders.'))
1488 self.comm.sendCommand('M105')
1489 self.comm.sendCommand('M104 S220 T0')
1490 self.comm.sendCommand('M104 S220 T1')
1491 self.comm.sendCommand('G28')
1492 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1493 self._wizardState = 1
1494 if not self.comm.isPrinting():
1495 if self._wizardState == 3:
1496 self._wizardState = 4
1497 wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1498 wx.CallAfter(self.textEntry.SetValue, '0.0')
1499 wx.CallAfter(self.textEntry.Enable, True)
1500 wx.CallAfter(self.resumeButton.Enable, True)
1501 wx.CallAfter(self.resumeButton.SetFocus)
1502 elif self._wizardState == 6:
1503 self._wizardState = 7
1504 wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1505 wx.CallAfter(self.textEntry.SetValue, '10')
1506 wx.CallAfter(self.textEntry.Enable, True)
1507 wx.CallAfter(self.resumeButton.Enable, True)
1508 wx.CallAfter(self.resumeButton.SetFocus)
1510 elif self.comm.isError():
1511 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1513 def mcMessage(self, message):
1516 def mcProgress(self, lineNr):
1519 def mcZChange(self, newZ):
1522 class bedLevelWizard(wx.wizard.Wizard):
1524 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1526 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1527 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1529 self.mainPage = bedLevelWizardMain(self)
1530 self.headOffsetCalibration = None
1532 self.FitToPage(self.mainPage)
1533 self.GetPageAreaSizer().Add(self.mainPage)
1535 self.RunWizard(self.mainPage)
1538 def OnPageChanging(self, e):
1539 e.GetPage().StoreData()
1541 def OnPageChanged(self, e):
1542 if e.GetPage().AllowNext():
1543 self.FindWindowById(wx.ID_FORWARD).Enable()
1545 self.FindWindowById(wx.ID_FORWARD).Disable()
1546 if e.GetPage().AllowBack():
1547 self.FindWindowById(wx.ID_BACKWARD).Enable()
1549 self.FindWindowById(wx.ID_BACKWARD).Disable()
1551 class headOffsetWizard(wx.wizard.Wizard):
1553 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1555 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1556 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1558 self.mainPage = headOffsetCalibrationPage(self)
1560 self.FitToPage(self.mainPage)
1561 self.GetPageAreaSizer().Add(self.mainPage)
1563 self.RunWizard(self.mainPage)
1566 def OnPageChanging(self, e):
1567 e.GetPage().StoreData()
1569 def OnPageChanged(self, e):
1570 if e.GetPage().AllowNext():
1571 self.FindWindowById(wx.ID_FORWARD).Enable()
1573 self.FindWindowById(wx.ID_FORWARD).Disable()
1574 if e.GetPage().AllowBack():
1575 self.FindWindowById(wx.ID_BACKWARD).Enable()
1577 self.FindWindowById(wx.ID_BACKWARD).Disable()