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.putMachineSetting('machine_name', 'LulzBot TAZ 5')
512 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5')
513 profile.putMachineSetting('serial_baud', '115200')
515 profile.putMachineSetting('machine_width', '155')
516 profile.putMachineSetting('machine_depth', '155')
517 profile.putMachineSetting('machine_height', '163')
518 profile.putProfileSetting('nozzle_size', '0.5')
519 profile.putMachineSetting('machine_name', 'LulzBot Mini')
520 profile.putMachineSetting('machine_type', 'lulzbot_mini')
521 profile.putMachineSetting('serial_baud', '115200')
522 profile.putMachineSetting('machine_center_is_zero', 'False')
523 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
524 profile.putMachineSetting('has_heated_bed', 'True')
525 profile.putMachineSetting('extruder_head_size_min_x', '0.0')
526 profile.putMachineSetting('extruder_head_size_min_y', '0.0')
527 profile.putMachineSetting('extruder_head_size_max_x', '0.0')
528 profile.putMachineSetting('extruder_head_size_max_y', '0.0')
529 profile.putMachineSetting('extruder_head_size_height', '0.0')
530 profile.putPreference('startMode', 'Simple')
532 profile.putMachineSetting('machine_width', '80')
533 profile.putMachineSetting('machine_depth', '80')
534 profile.putMachineSetting('machine_height', '60')
535 profile.putMachineSetting('machine_name', 'reprap')
536 profile.putMachineSetting('machine_type', 'reprap')
537 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
538 profile.putPreference('startMode', 'Normal')
539 profile.putProfileSetting('nozzle_size', '0.5')
540 profile.checkAndUpdateMachineName()
541 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
543 class SelectParts(InfoPage):
544 def __init__(self, parent):
545 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
546 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."))
548 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
549 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
550 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
551 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
553 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."))
554 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
555 self.springExtruder.SetValue(True)
558 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
559 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
560 profile.putMachineSetting('has_heated_bed', 'True')
562 profile.putMachineSetting('has_heated_bed', 'False')
563 if self.dualExtrusion.GetValue():
564 profile.putMachineSetting('extruder_amount', '2')
565 profile.putMachineSetting('machine_depth', '195')
567 profile.putMachineSetting('extruder_amount', '1')
568 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
569 profile.putProfileSetting('retraction_enable', 'True')
571 profile.putProfileSetting('retraction_enable', 'False')
574 class UltimakerFirmwareUpgradePage(InfoPage):
575 def __init__(self, parent):
576 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
577 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."))
578 self.AddHiddenSeperator()
579 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
580 self.AddHiddenSeperator()
581 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."))
582 upgradeButton, skipUpgradeButton = self.AddDualButton(_('Upgrade to Marlin firmware'), _('Skip upgrade'))
583 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
584 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
585 self.AddHiddenSeperator()
586 if profile.getMachineSetting('machine_type') == 'ultimaker':
587 self.AddText(_("Do not upgrade to this firmware if:"))
588 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
589 self.AddText(_("* Build your own heated bed"))
590 self.AddText(_("* Have other changes in the firmware"))
591 # button = self.AddButton('Goto this page for a custom firmware')
592 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
597 def OnUpgradeClick(self, e):
598 if firmwareInstall.InstallFirmware():
599 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
601 def OnSkipClick(self, e):
602 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
603 self.GetParent().ShowPage(self.GetNext())
605 def OnUrlClick(self, e):
606 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
608 class UltimakerCheckupPage(InfoPage):
609 def __init__(self, parent):
610 super(UltimakerCheckupPage, self).__init__(parent, _("Ultimaker Checkup"))
612 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
613 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
614 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
615 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
616 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
617 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
618 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
619 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
620 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
621 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
624 _("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."))
625 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
626 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
627 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
629 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
630 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
631 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
633 self.infoBox = self.AddInfoBox()
634 self.machineState = self.AddText("")
635 self.temperatureLabel = self.AddText("")
636 self.errorLogButton = self.AddButton(_("Show error log"))
637 self.errorLogButton.Show(False)
639 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
641 self.xMinStop = False
642 self.xMaxStop = False
643 self.yMinStop = False
644 self.yMaxStop = False
645 self.zMinStop = False
646 self.zMaxStop = False
648 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
651 if self.comm is not None:
655 self.endstopBitmap.Show(False)
658 def OnSkipClick(self, e):
659 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
660 self.GetParent().ShowPage(self.GetNext())
662 def OnCheckClick(self, e=None):
663 self.errorLogButton.Show(False)
664 if self.comm is not None:
668 wx.CallAfter(self.OnCheckClick)
670 self.infoBox.SetBusy(_("Connecting to machine."))
671 self.commState.SetBitmap(self.unknownBitmap)
672 self.tempState.SetBitmap(self.unknownBitmap)
673 self.stopState.SetBitmap(self.unknownBitmap)
674 self.checkupState = 0
675 self.checkExtruderNr = 0
676 self.comm = machineCom.MachineCom(callbackObject=self)
678 def OnErrorLog(self, e):
679 printWindow.LogWindow('\n'.join(self.comm.getLog()))
681 def mcLog(self, message):
684 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
685 if not self.comm.isOperational():
687 if self.checkupState == 0:
688 self.tempCheckTimeout = 20
689 if temp[self.checkExtruderNr] > 70:
690 self.checkupState = 1
691 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
692 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
693 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
695 self.startTemp = temp[self.checkExtruderNr]
696 self.checkupState = 2
697 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
698 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
699 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
700 elif self.checkupState == 1:
701 if temp[self.checkExtruderNr] < 60:
702 self.startTemp = temp[self.checkExtruderNr]
703 self.checkupState = 2
704 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
705 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
706 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
707 elif self.checkupState == 2:
708 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
709 if temp[self.checkExtruderNr] > self.startTemp + 40:
710 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
711 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
712 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
713 self.checkExtruderNr = 0
714 self.checkupState = 3
715 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
716 wx.CallAfter(self.endstopBitmap.Show, True)
717 wx.CallAfter(self.Layout)
718 self.comm.sendCommand('M119')
719 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
721 self.checkupState = 0
722 self.checkExtruderNr += 1
724 self.tempCheckTimeout -= 1
725 if self.tempCheckTimeout < 1:
726 self.checkupState = -1
727 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
728 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
729 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
730 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
731 elif self.checkupState >= 3 and self.checkupState < 10:
732 self.comm.sendCommand('M119')
733 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
735 def mcStateChange(self, state):
736 if self.comm is None:
738 if self.comm.isOperational():
739 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
740 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
741 elif self.comm.isError():
742 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
743 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
744 wx.CallAfter(self.endstopBitmap.Show, False)
745 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
746 wx.CallAfter(self.errorLogButton.Show, True)
747 wx.CallAfter(self.Layout)
749 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
751 def mcMessage(self, message):
752 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
753 for data in message.split(' '):
755 tag, value = data.split(':', 1)
757 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
759 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
761 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
763 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
765 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
767 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
769 tag, value = map(str.strip, message.split(':', 1))
771 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
773 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
775 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
777 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
779 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
781 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
782 if 'z_max' in message:
783 self.comm.sendCommand('M119')
785 if self.checkupState == 3:
786 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
787 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
788 self.checkupState = 5
789 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
790 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
792 self.checkupState = 4
793 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
794 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
795 elif self.checkupState == 4:
796 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
797 self.checkupState = 5
798 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
799 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
800 elif self.checkupState == 5:
801 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
802 self.checkupState = 6
803 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
804 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
805 elif self.checkupState == 6:
806 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
807 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
808 self.checkupState = 8
809 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
810 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
812 self.checkupState = 7
813 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
814 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
815 elif self.checkupState == 7:
816 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
817 self.checkupState = 8
818 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
819 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
820 elif self.checkupState == 8:
821 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
822 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
823 self.checkupState = 10
825 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
826 wx.CallAfter(self.infoBox.SetReadyIndicator)
827 wx.CallAfter(self.endstopBitmap.Show, False)
828 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
829 wx.CallAfter(self.OnSkipClick, None)
831 self.checkupState = 9
832 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
833 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
834 elif self.checkupState == 9:
835 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
836 self.checkupState = 10
838 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
839 wx.CallAfter(self.infoBox.SetReadyIndicator)
840 wx.CallAfter(self.endstopBitmap.Show, False)
841 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
842 wx.CallAfter(self.OnSkipClick, None)
844 def mcProgress(self, lineNr):
847 def mcZChange(self, newZ):
851 class UltimakerCalibrationPage(InfoPage):
852 def __init__(self, parent):
853 super(UltimakerCalibrationPage, self).__init__(parent, _("Ultimaker Calibration"))
855 self.AddText("Your Ultimaker requires some calibration.")
856 self.AddText("This calibration is needed for a proper extrusion amount.")
858 self.AddText("The following values are needed:")
859 self.AddText("* Diameter of filament")
860 self.AddText("* Number of steps per mm of filament extrusion")
862 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
864 self.AddText("First we need the diameter of your filament:")
865 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
867 "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.")
868 self.AddText("Note: This value can be changed later at any time.")
871 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
874 class UltimakerCalibrateStepsPerEPage(InfoPage):
875 def __init__(self, parent):
876 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, _("Ultimaker Calibration"))
878 #if profile.getMachineSetting('steps_per_e') == '0':
879 # profile.putMachineSetting('steps_per_e', '865.888')
881 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
882 self.AddText(_("First remove any filament from your machine."))
883 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
884 self.AddText(_("We'll push the filament 100mm"))
885 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
886 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
887 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
888 self.AddText(_("This results in the following steps per E:"))
889 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
890 self.AddText(_("You can repeat these steps to get better calibration."))
893 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
894 self.heatButton = self.AddButton(_("Heatup for filament removal"))
896 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
897 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
898 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
900 def OnSaveLengthClick(self, e):
901 currentEValue = float(self.stepsPerEInput.GetValue())
902 realExtrudeLength = float(self.lengthInput.GetValue())
903 newEValue = currentEValue * 100 / realExtrudeLength
904 self.stepsPerEInput.SetValue(str(newEValue))
905 self.lengthInput.SetValue("100")
907 def OnExtrudeClick(self, e):
908 t = threading.Thread(target=self.OnExtrudeRun)
912 def OnExtrudeRun(self):
913 self.heatButton.Enable(False)
914 self.extrudeButton.Enable(False)
915 currentEValue = float(self.stepsPerEInput.GetValue())
916 self.comm = machineCom.MachineCom()
917 if not self.comm.isOpen():
919 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
920 'Printer error', wx.OK | wx.ICON_INFORMATION)
921 self.heatButton.Enable(True)
922 self.extrudeButton.Enable(True)
925 line = self.comm.readline()
930 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
933 self.sendGCommand('M302') #Disable cold extrusion protection
934 self.sendGCommand("M92 E%f" % (currentEValue))
935 self.sendGCommand("G92 E0")
936 self.sendGCommand("G1 E100 F600")
939 self.extrudeButton.Enable()
940 self.heatButton.Enable()
942 def OnHeatClick(self, e):
943 t = threading.Thread(target=self.OnHeatRun)
948 self.heatButton.Enable(False)
949 self.extrudeButton.Enable(False)
950 self.comm = machineCom.MachineCom()
951 if not self.comm.isOpen():
953 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
954 'Printer error', wx.OK | wx.ICON_INFORMATION)
955 self.heatButton.Enable(True)
956 self.extrudeButton.Enable(True)
959 line = self.comm.readline()
961 self.heatButton.Enable(True)
962 self.extrudeButton.Enable(True)
966 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
969 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
971 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
972 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
973 self.sendGCommand('M104 S0')
976 self.heatButton.Enable(True)
977 self.extrudeButton.Enable(True)
979 def sendGCommand(self, cmd):
980 self.comm.sendCommand(cmd) #Disable cold extrusion protection
982 line = self.comm.readline()
985 if line.startswith('ok'):
989 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
991 class Ultimaker2ReadyPage(InfoPage):
992 def __init__(self, parent):
993 super(Ultimaker2ReadyPage, self).__init__(parent, _("Ultimaker2"))
994 self.AddText(_('Congratulations on your the purchase of your brand new Ultimaker2.'))
995 self.AddText(_('Cura is now ready to be used with your Ultimaker2.'))
998 class LulzbotReadyPage(InfoPage):
999 def __init__(self, parent):
1000 super(LulzbotReadyPage, self).__init__(parent, _("LulzBot TAZ/Mini"))
1001 self.AddText(_('Cura is now ready to be used with your LulzBot 3D printer.'))
1003 self.AddText(_('For more information about using Cura with your LulzBot'))
1004 self.AddText(_('3D printer, please visit www.LulzBot.com/cura'))
1007 class Taz5NozzleSelectPage(InfoPage):
1008 def __init__(self, parent):
1009 super(Taz5NozzleSelectPage, self).__init__(parent, _("LulzBot TAZ5"))
1010 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1012 #self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1013 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1014 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1016 self.AddText(_('Please select nozzle size:'))
1017 self.Nozzle35Radio = self.AddRadioButton("0.35 mm", style=wx.RB_GROUP)
1018 self.Nozzle35Radio.Bind(wx.EVT_RADIOBUTTON, self.OnNozzleSelect)
1019 self.Nozzle50Radio = self.AddRadioButton("0.5 mm (after x date)")
1020 self.Nozzle50Radio.Bind(wx.EVT_RADIOBUTTON, self.OnNozzleSelect)
1021 #self.Nozzle50Radio.SetValue(True)
1024 def OnNozzleSelect(self, e):
1025 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
1027 def StoreData(self):
1028 if self.Nozzle35Radio.GetValue():
1029 profile.putProfileSetting('nozzle_size', '0.35') #TODO: does more magic need to happen here?
1031 profile.putProfileSetting('nozzle_size', '0.5')
1033 def OnPageChanging(self, e):
1034 e.GetPage().StoreData()
1036 # def OnPageChanged(self, e):
1037 # if e.GetPage().AllowNext():
1038 # self.FindWindowById(wx.ID_FORWARD).Enable()
1040 # self.FindWindowById(wx.ID_FORWARD).Disable()
1041 # if e.GetPage().AllowBack():
1042 # self.FindWindowById(wx.ID_BACKWARD).Enable()
1044 # self.FindWindowById(wx.ID_BACKWARD).Disable()
1046 def OnCancel(self, e): #TODO: this is not being triggered
1047 profile.setActiveMachine(self._old_machine_index)
1049 class ConfigWizard(wx.wizard.Wizard):
1050 def __init__(self, addNew = False):
1051 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
1053 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1055 profile.setActiveMachine(profile.getMachineCount())
1057 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1058 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1059 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1061 self.machineSelectPage = MachineSelectPage(self)
1062 self.ultimakerSelectParts = SelectParts(self)
1063 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
1064 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
1065 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
1066 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
1067 self.bedLevelPage = bedLevelWizardMain(self)
1068 self.headOffsetCalibration = headOffsetCalibrationPage(self)
1069 self.printrbotSelectType = PrintrbotPage(self)
1070 self.otherMachineSelectPage = OtherMachineSelectPage(self)
1071 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
1072 self.otherMachineInfoPage = OtherMachineInfoPage(self)
1074 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
1075 self.lulzbotReadyPage = LulzbotReadyPage(self)
1076 self.taz5NozzleSelectPage = Taz5NozzleSelectPage(self)
1078 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
1079 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
1080 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
1081 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
1082 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
1083 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
1084 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
1085 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
1087 self.FitToPage(self.machineSelectPage)
1088 self.GetPageAreaSizer().Add(self.machineSelectPage)
1090 self.RunWizard(self.machineSelectPage)
1093 def OnPageChanging(self, e):
1094 e.GetPage().StoreData()
1096 def OnPageChanged(self, e):
1097 if e.GetPage().AllowNext():
1098 self.FindWindowById(wx.ID_FORWARD).Enable()
1100 self.FindWindowById(wx.ID_FORWARD).Disable()
1101 if e.GetPage().AllowBack():
1102 self.FindWindowById(wx.ID_BACKWARD).Enable()
1104 self.FindWindowById(wx.ID_BACKWARD).Disable()
1106 def OnCancel(self, e):
1107 profile.setActiveMachine(self._old_machine_index)
1109 class bedLevelWizardMain(InfoPage):
1110 def __init__(self, parent):
1111 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1113 self.AddText(_('This wizard will help you in leveling your printer bed'))
1115 self.AddText(_('It will do the following steps'))
1116 self.AddText(_('* Move the printer head to each corner'))
1117 self.AddText(_(' and let you adjust the height of the bed to the nozzle'))
1118 self.AddText(_('* Print a line around the bed to check if it is level'))
1121 self.connectButton = self.AddButton(_('Connect to printer'))
1124 self.infoBox = self.AddInfoBox()
1125 self.resumeButton = self.AddButton(_('Resume'))
1126 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1127 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1128 self.resumeButton.Enable(False)
1130 self.upButton.Enable(False)
1131 self.downButton.Enable(False)
1132 self.upButton2.Enable(False)
1133 self.downButton2.Enable(False)
1135 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1136 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1137 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1138 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1139 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1140 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1142 def OnConnect(self, e = None):
1143 if self.comm is not None:
1147 wx.CallAfter(self.OnConnect)
1149 self.connectButton.Enable(False)
1150 self.comm = machineCom.MachineCom(callbackObject=self)
1151 self.infoBox.SetBusy(_('Connecting to machine.'))
1152 self._wizardState = 0
1154 def OnBedUp(self, e):
1155 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1156 self.comm.sendCommand('G92 Z10')
1157 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1158 self.comm.sendCommand('M400')
1160 def OnBedDown(self, e):
1161 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1162 self.comm.sendCommand('G92 Z10')
1163 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1164 self.comm.sendCommand('M400')
1166 def OnBedUp2(self, e):
1167 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1168 self.comm.sendCommand('G92 Z10')
1169 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1170 self.comm.sendCommand('M400')
1172 def OnBedDown2(self, e):
1173 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1174 self.comm.sendCommand('G92 Z10')
1175 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1176 self.comm.sendCommand('M400')
1178 def AllowNext(self):
1179 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1180 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1183 def OnResume(self, e):
1184 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1185 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1186 if self._wizardState == -1:
1187 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1188 wx.CallAfter(self.upButton.Enable, False)
1189 wx.CallAfter(self.downButton.Enable, False)
1190 wx.CallAfter(self.upButton2.Enable, False)
1191 wx.CallAfter(self.downButton2.Enable, False)
1192 self.comm.sendCommand('M105')
1193 self.comm.sendCommand('G28')
1194 self._wizardState = 1
1195 elif self._wizardState == 2:
1196 if profile.getMachineSetting('has_heated_bed') == 'True':
1197 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1198 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1199 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1200 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1201 self.comm.sendCommand('M400')
1202 self._wizardState = 3
1204 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1205 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1206 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1207 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1208 self.comm.sendCommand('M400')
1209 self._wizardState = 3
1210 elif self._wizardState == 4:
1211 if profile.getMachineSetting('has_heated_bed') == 'True':
1212 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1213 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1214 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1215 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1216 self.comm.sendCommand('M400')
1217 self._wizardState = 7
1219 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1220 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1221 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1222 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1223 self.comm.sendCommand('M400')
1224 self._wizardState = 5
1225 elif self._wizardState == 6:
1226 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1227 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1228 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1229 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1230 self.comm.sendCommand('M400')
1231 self._wizardState = 7
1232 elif self._wizardState == 8:
1233 wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1234 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1235 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1236 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1237 self._wizardState = 9
1238 elif self._wizardState == 10:
1239 self._wizardState = 11
1240 wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1241 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1242 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1243 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1244 w = profile.getMachineSettingFloat('machine_width') - 10
1245 d = profile.getMachineSettingFloat('machine_depth')
1246 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1247 filamentArea = math.pi * filamentRadius * filamentRadius
1248 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1252 'G1 Z2 F%d' % (feedZ),
1254 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1255 'G1 Z0.3 F%d' % (feedZ)]
1257 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1259 for i in xrange(0, 3):
1260 dist = 5.0 + 0.4 * float(i)
1261 eValue += (d - 2.0*dist) * ePerMM
1262 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1263 eValue += (w - 2.0*dist) * ePerMM
1264 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1265 eValue += (d - 2.0*dist) * ePerMM
1266 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1267 eValue += (w - 2.0*dist) * ePerMM
1268 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1270 gcodeList.append('M400')
1271 self.comm.printGCode(gcodeList)
1272 self.resumeButton.Enable(False)
1274 def mcLog(self, message):
1275 print 'Log:', message
1277 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1278 if self._wizardState == 1:
1279 self._wizardState = 2
1280 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1281 wx.CallAfter(self.resumeButton.Enable, True)
1282 elif self._wizardState == 3:
1283 self._wizardState = 4
1284 if profile.getMachineSetting('has_heated_bed') == 'True':
1285 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1287 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1288 wx.CallAfter(self.resumeButton.Enable, True)
1289 elif self._wizardState == 5:
1290 self._wizardState = 6
1291 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1292 wx.CallAfter(self.resumeButton.Enable, True)
1293 elif self._wizardState == 7:
1294 self._wizardState = 8
1295 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1296 wx.CallAfter(self.resumeButton.Enable, True)
1297 elif self._wizardState == 9:
1298 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1299 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1301 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1302 wx.CallAfter(self.resumeButton.Enable, True)
1303 self._wizardState = 10
1305 def mcStateChange(self, state):
1306 if self.comm is None:
1308 if self.comm.isOperational():
1309 if self._wizardState == 0:
1310 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1311 wx.CallAfter(self.upButton.Enable, True)
1312 wx.CallAfter(self.downButton.Enable, True)
1313 wx.CallAfter(self.upButton2.Enable, True)
1314 wx.CallAfter(self.downButton2.Enable, True)
1315 wx.CallAfter(self.resumeButton.Enable, True)
1316 self._wizardState = -1
1317 elif self._wizardState == 11 and not self.comm.isPrinting():
1318 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1319 self.comm.sendCommand('G92 E0')
1320 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1321 self.comm.sendCommand('M104 S0')
1322 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1323 wx.CallAfter(self.infoBox.SetReadyIndicator)
1324 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1325 wx.CallAfter(self.connectButton.Enable, True)
1326 self._wizardState = 12
1327 elif self.comm.isError():
1328 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1330 def mcMessage(self, message):
1333 def mcProgress(self, lineNr):
1336 def mcZChange(self, newZ):
1339 class headOffsetCalibrationPage(InfoPage):
1340 def __init__(self, parent):
1341 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1343 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1346 self.connectButton = self.AddButton(_('Connect to printer'))
1349 self.infoBox = self.AddInfoBox()
1350 self.textEntry = self.AddTextCtrl('')
1351 self.textEntry.Enable(False)
1352 self.resumeButton = self.AddButton(_('Resume'))
1353 self.resumeButton.Enable(False)
1355 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1356 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1358 def AllowBack(self):
1361 def OnConnect(self, e = None):
1362 if self.comm is not None:
1366 wx.CallAfter(self.OnConnect)
1368 self.connectButton.Enable(False)
1369 self.comm = machineCom.MachineCom(callbackObject=self)
1370 self.infoBox.SetBusy(_('Connecting to machine.'))
1371 self._wizardState = 0
1373 def OnResume(self, e):
1374 if self._wizardState == 2:
1375 self._wizardState = 3
1376 wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1378 w = profile.getMachineSettingFloat('machine_width')
1379 d = profile.getMachineSettingFloat('machine_depth')
1381 gcode = gcodeGenerator.gcodeGenerator()
1382 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1383 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1390 gcode.addMove(w/2, 5)
1391 gcode.addMove(z=0.2)
1393 gcode.addExtrude(w/2, d-5.0)
1395 gcode.addMove(5, d/2)
1397 gcode.addExtrude(w-5.0, d/2)
1398 gcode.addRetract(15)
1401 gcode.addMove(w/2, 5)
1403 gcode.addExtrude(w/2, d-5.0)
1405 gcode.addMove(5, d/2)
1407 gcode.addExtrude(w-5.0, d/2)
1408 gcode.addRetract(15)
1413 gcode.addCmd('M400')
1415 self.comm.printGCode(gcode.list())
1416 self.resumeButton.Enable(False)
1417 elif self._wizardState == 4:
1419 float(self.textEntry.GetValue())
1422 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1423 self._wizardState = 5
1424 self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1425 self.textEntry.SetValue('0.0')
1426 self.textEntry.Enable(True)
1427 elif self._wizardState == 5:
1429 float(self.textEntry.GetValue())
1432 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1433 self._wizardState = 6
1434 self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1435 self.textEntry.SetValue('')
1436 self.textEntry.Enable(False)
1437 self.resumeButton.Enable(False)
1439 x = profile.getMachineSettingFloat('extruder_offset_x1')
1440 y = profile.getMachineSettingFloat('extruder_offset_y1')
1441 gcode = gcodeGenerator.gcodeGenerator()
1442 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1443 gcode.setPrintSpeed(25)
1446 gcode.addMove(50, 40, 0.2)
1448 for n in xrange(0, 10):
1449 gcode.addExtrude(50 + n * 10, 150)
1450 gcode.addExtrude(50 + n * 10 + 5, 150)
1451 gcode.addExtrude(50 + n * 10 + 5, 40)
1452 gcode.addExtrude(50 + n * 10 + 10, 40)
1453 gcode.addMove(40, 50)
1454 for n in xrange(0, 10):
1455 gcode.addExtrude(150, 50 + n * 10)
1456 gcode.addExtrude(150, 50 + n * 10 + 5)
1457 gcode.addExtrude(40, 50 + n * 10 + 5)
1458 gcode.addExtrude(40, 50 + n * 10 + 10)
1459 gcode.addRetract(15)
1462 gcode.addMove(50 - x, 30 - y, 0.2)
1464 for n in xrange(0, 10):
1465 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1466 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1467 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1468 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1469 gcode.addMove(30 - x, 50 - y, 0.2)
1470 for n in xrange(0, 10):
1471 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1472 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1473 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1474 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1475 gcode.addRetract(15)
1477 gcode.addCmd('M400')
1478 gcode.addCmd('M104 T0 S0')
1479 gcode.addCmd('M104 T1 S0')
1480 self.comm.printGCode(gcode.list())
1481 elif self._wizardState == 7:
1483 n = int(self.textEntry.GetValue()) - 1
1486 x = profile.getMachineSettingFloat('extruder_offset_x1')
1488 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1489 self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1490 self.textEntry.SetValue('10')
1491 self._wizardState = 8
1492 elif self._wizardState == 8:
1494 n = int(self.textEntry.GetValue()) - 1
1497 y = profile.getMachineSettingFloat('extruder_offset_y1')
1499 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1500 self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1501 self.infoBox.SetReadyIndicator()
1502 self._wizardState = 8
1504 self.resumeButton.Enable(False)
1506 def mcLog(self, message):
1507 print 'Log:', message
1509 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1510 if self._wizardState == 1:
1511 if temp[0] >= 210 and temp[1] >= 210:
1512 self._wizardState = 2
1513 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1514 wx.CallAfter(self.resumeButton.Enable, True)
1515 wx.CallAfter(self.resumeButton.SetFocus)
1517 def mcStateChange(self, state):
1518 if self.comm is None:
1520 if self.comm.isOperational():
1521 if self._wizardState == 0:
1522 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1523 self.comm.sendCommand('M105')
1524 self.comm.sendCommand('M104 S220 T0')
1525 self.comm.sendCommand('M104 S220 T1')
1526 self.comm.sendCommand('G28')
1527 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1528 self._wizardState = 1
1529 if not self.comm.isPrinting():
1530 if self._wizardState == 3:
1531 self._wizardState = 4
1532 wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1533 wx.CallAfter(self.textEntry.SetValue, '0.0')
1534 wx.CallAfter(self.textEntry.Enable, True)
1535 wx.CallAfter(self.resumeButton.Enable, True)
1536 wx.CallAfter(self.resumeButton.SetFocus)
1537 elif self._wizardState == 6:
1538 self._wizardState = 7
1539 wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1540 wx.CallAfter(self.textEntry.SetValue, '10')
1541 wx.CallAfter(self.textEntry.Enable, True)
1542 wx.CallAfter(self.resumeButton.Enable, True)
1543 wx.CallAfter(self.resumeButton.SetFocus)
1545 elif self.comm.isError():
1546 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1548 def mcMessage(self, message):
1551 def mcProgress(self, lineNr):
1554 def mcZChange(self, newZ):
1557 class bedLevelWizard(wx.wizard.Wizard):
1559 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1561 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1562 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1564 self.mainPage = bedLevelWizardMain(self)
1565 self.headOffsetCalibration = None
1567 self.FitToPage(self.mainPage)
1568 self.GetPageAreaSizer().Add(self.mainPage)
1570 self.RunWizard(self.mainPage)
1573 def OnPageChanging(self, e):
1574 e.GetPage().StoreData()
1576 def OnPageChanged(self, e):
1577 if e.GetPage().AllowNext():
1578 self.FindWindowById(wx.ID_FORWARD).Enable()
1580 self.FindWindowById(wx.ID_FORWARD).Disable()
1581 if e.GetPage().AllowBack():
1582 self.FindWindowById(wx.ID_BACKWARD).Enable()
1584 self.FindWindowById(wx.ID_BACKWARD).Disable()
1586 class headOffsetWizard(wx.wizard.Wizard):
1588 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1590 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1591 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1593 self.mainPage = headOffsetCalibrationPage(self)
1595 self.FitToPage(self.mainPage)
1596 self.GetPageAreaSizer().Add(self.mainPage)
1598 self.RunWizard(self.mainPage)
1601 def OnPageChanging(self, e):
1602 e.GetPage().StoreData()
1604 def OnPageChanged(self, e):
1605 if e.GetPage().AllowNext():
1606 self.FindWindowById(wx.ID_FORWARD).Enable()
1608 self.FindWindowById(wx.ID_FORWARD).Disable()
1609 if e.GetPage().AllowBack():
1610 self.FindWindowById(wx.ID_BACKWARD).Enable()
1612 self.FindWindowById(wx.ID_BACKWARD).Disable()