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_type', 'lulzbot_TAZ_5')
512 profile.putMachineSetting('serial_baud', '115200')
514 profile.putMachineSetting('machine_width', '155')
515 profile.putMachineSetting('machine_depth', '155')
516 profile.putMachineSetting('machine_height', '163')
517 profile.putProfileSetting('nozzle_size', '0.5')
518 profile.putMachineSetting('machine_name', 'LulzBot Mini')
519 profile.putMachineSetting('machine_type', 'lulzbot_mini')
520 profile.putMachineSetting('serial_baud', '115200')
521 profile.putMachineSetting('machine_center_is_zero', 'False')
522 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
523 profile.putMachineSetting('has_heated_bed', 'True')
524 profile.putMachineSetting('extruder_head_size_min_x', '0.0')
525 profile.putMachineSetting('extruder_head_size_min_y', '0.0')
526 profile.putMachineSetting('extruder_head_size_max_x', '0.0')
527 profile.putMachineSetting('extruder_head_size_max_y', '0.0')
528 profile.putMachineSetting('extruder_head_size_height', '0.0')
529 profile.putPreference('startMode', 'Simple')
531 profile.putMachineSetting('machine_width', '80')
532 profile.putMachineSetting('machine_depth', '80')
533 profile.putMachineSetting('machine_height', '60')
534 profile.putMachineSetting('machine_name', 'reprap')
535 profile.putMachineSetting('machine_type', 'reprap')
536 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
537 profile.putPreference('startMode', 'Normal')
538 profile.putProfileSetting('nozzle_size', '0.5')
539 profile.checkAndUpdateMachineName()
540 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
542 class SelectParts(InfoPage):
543 def __init__(self, parent):
544 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
545 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."))
547 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
548 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
549 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
550 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
552 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."))
553 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
554 self.springExtruder.SetValue(True)
557 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
558 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
559 profile.putMachineSetting('has_heated_bed', 'True')
561 profile.putMachineSetting('has_heated_bed', 'False')
562 if self.dualExtrusion.GetValue():
563 profile.putMachineSetting('extruder_amount', '2')
564 profile.putMachineSetting('machine_depth', '195')
566 profile.putMachineSetting('extruder_amount', '1')
567 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
568 profile.putProfileSetting('retraction_enable', 'True')
570 profile.putProfileSetting('retraction_enable', 'False')
573 class UltimakerFirmwareUpgradePage(InfoPage):
574 def __init__(self, parent):
575 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
576 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."))
577 self.AddHiddenSeperator()
578 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
579 self.AddHiddenSeperator()
580 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."))
581 upgradeButton, skipUpgradeButton = self.AddDualButton(_('Upgrade to Marlin firmware'), _('Skip upgrade'))
582 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
583 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
584 self.AddHiddenSeperator()
585 if profile.getMachineSetting('machine_type') == 'ultimaker':
586 self.AddText(_("Do not upgrade to this firmware if:"))
587 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
588 self.AddText(_("* Build your own heated bed"))
589 self.AddText(_("* Have other changes in the firmware"))
590 # button = self.AddButton('Goto this page for a custom firmware')
591 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
596 def OnUpgradeClick(self, e):
597 if firmwareInstall.InstallFirmware():
598 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
600 def OnSkipClick(self, e):
601 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
602 self.GetParent().ShowPage(self.GetNext())
604 def OnUrlClick(self, e):
605 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
607 class UltimakerCheckupPage(InfoPage):
608 def __init__(self, parent):
609 super(UltimakerCheckupPage, self).__init__(parent, _("Ultimaker Checkup"))
611 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
612 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
613 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
614 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
615 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
616 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
617 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
618 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
619 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
620 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
623 _("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."))
624 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
625 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
626 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
628 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
629 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
630 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
632 self.infoBox = self.AddInfoBox()
633 self.machineState = self.AddText("")
634 self.temperatureLabel = self.AddText("")
635 self.errorLogButton = self.AddButton(_("Show error log"))
636 self.errorLogButton.Show(False)
638 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
640 self.xMinStop = False
641 self.xMaxStop = False
642 self.yMinStop = False
643 self.yMaxStop = False
644 self.zMinStop = False
645 self.zMaxStop = False
647 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
650 if self.comm is not None:
654 self.endstopBitmap.Show(False)
657 def OnSkipClick(self, e):
658 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
659 self.GetParent().ShowPage(self.GetNext())
661 def OnCheckClick(self, e=None):
662 self.errorLogButton.Show(False)
663 if self.comm is not None:
667 wx.CallAfter(self.OnCheckClick)
669 self.infoBox.SetBusy(_("Connecting to machine."))
670 self.commState.SetBitmap(self.unknownBitmap)
671 self.tempState.SetBitmap(self.unknownBitmap)
672 self.stopState.SetBitmap(self.unknownBitmap)
673 self.checkupState = 0
674 self.checkExtruderNr = 0
675 self.comm = machineCom.MachineCom(callbackObject=self)
677 def OnErrorLog(self, e):
678 printWindow.LogWindow('\n'.join(self.comm.getLog()))
680 def mcLog(self, message):
683 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
684 if not self.comm.isOperational():
686 if self.checkupState == 0:
687 self.tempCheckTimeout = 20
688 if temp[self.checkExtruderNr] > 70:
689 self.checkupState = 1
690 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
691 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
692 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
694 self.startTemp = temp[self.checkExtruderNr]
695 self.checkupState = 2
696 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
697 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
698 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
699 elif self.checkupState == 1:
700 if temp[self.checkExtruderNr] < 60:
701 self.startTemp = temp[self.checkExtruderNr]
702 self.checkupState = 2
703 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
704 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
705 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
706 elif self.checkupState == 2:
707 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
708 if temp[self.checkExtruderNr] > self.startTemp + 40:
709 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
710 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
711 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
712 self.checkExtruderNr = 0
713 self.checkupState = 3
714 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
715 wx.CallAfter(self.endstopBitmap.Show, True)
716 wx.CallAfter(self.Layout)
717 self.comm.sendCommand('M119')
718 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
720 self.checkupState = 0
721 self.checkExtruderNr += 1
723 self.tempCheckTimeout -= 1
724 if self.tempCheckTimeout < 1:
725 self.checkupState = -1
726 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
727 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
728 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
729 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
730 elif self.checkupState >= 3 and self.checkupState < 10:
731 self.comm.sendCommand('M119')
732 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
734 def mcStateChange(self, state):
735 if self.comm is None:
737 if self.comm.isOperational():
738 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
739 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
740 elif self.comm.isError():
741 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
742 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
743 wx.CallAfter(self.endstopBitmap.Show, False)
744 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
745 wx.CallAfter(self.errorLogButton.Show, True)
746 wx.CallAfter(self.Layout)
748 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
750 def mcMessage(self, message):
751 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
752 for data in message.split(' '):
754 tag, value = data.split(':', 1)
756 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
758 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
760 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
762 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
764 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
766 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
768 tag, value = map(str.strip, message.split(':', 1))
770 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
772 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
774 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
776 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
778 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
780 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
781 if 'z_max' in message:
782 self.comm.sendCommand('M119')
784 if self.checkupState == 3:
785 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
786 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
787 self.checkupState = 5
788 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
789 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
791 self.checkupState = 4
792 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
793 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
794 elif self.checkupState == 4:
795 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
796 self.checkupState = 5
797 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
798 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
799 elif self.checkupState == 5:
800 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
801 self.checkupState = 6
802 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
803 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
804 elif self.checkupState == 6:
805 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
806 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
807 self.checkupState = 8
808 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
809 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
811 self.checkupState = 7
812 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
813 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
814 elif self.checkupState == 7:
815 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
816 self.checkupState = 8
817 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
818 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
819 elif self.checkupState == 8:
820 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
821 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
822 self.checkupState = 10
824 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
825 wx.CallAfter(self.infoBox.SetReadyIndicator)
826 wx.CallAfter(self.endstopBitmap.Show, False)
827 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
828 wx.CallAfter(self.OnSkipClick, None)
830 self.checkupState = 9
831 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
832 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
833 elif self.checkupState == 9:
834 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
835 self.checkupState = 10
837 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
838 wx.CallAfter(self.infoBox.SetReadyIndicator)
839 wx.CallAfter(self.endstopBitmap.Show, False)
840 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
841 wx.CallAfter(self.OnSkipClick, None)
843 def mcProgress(self, lineNr):
846 def mcZChange(self, newZ):
850 class UltimakerCalibrationPage(InfoPage):
851 def __init__(self, parent):
852 super(UltimakerCalibrationPage, self).__init__(parent, _("Ultimaker Calibration"))
854 self.AddText("Your Ultimaker requires some calibration.")
855 self.AddText("This calibration is needed for a proper extrusion amount.")
857 self.AddText("The following values are needed:")
858 self.AddText("* Diameter of filament")
859 self.AddText("* Number of steps per mm of filament extrusion")
861 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
863 self.AddText("First we need the diameter of your filament:")
864 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
866 "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.")
867 self.AddText("Note: This value can be changed later at any time.")
870 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
873 class UltimakerCalibrateStepsPerEPage(InfoPage):
874 def __init__(self, parent):
875 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, _("Ultimaker Calibration"))
877 #if profile.getMachineSetting('steps_per_e') == '0':
878 # profile.putMachineSetting('steps_per_e', '865.888')
880 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
881 self.AddText(_("First remove any filament from your machine."))
882 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
883 self.AddText(_("We'll push the filament 100mm"))
884 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
885 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
886 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
887 self.AddText(_("This results in the following steps per E:"))
888 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
889 self.AddText(_("You can repeat these steps to get better calibration."))
892 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
893 self.heatButton = self.AddButton(_("Heatup for filament removal"))
895 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
896 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
897 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
899 def OnSaveLengthClick(self, e):
900 currentEValue = float(self.stepsPerEInput.GetValue())
901 realExtrudeLength = float(self.lengthInput.GetValue())
902 newEValue = currentEValue * 100 / realExtrudeLength
903 self.stepsPerEInput.SetValue(str(newEValue))
904 self.lengthInput.SetValue("100")
906 def OnExtrudeClick(self, e):
907 t = threading.Thread(target=self.OnExtrudeRun)
911 def OnExtrudeRun(self):
912 self.heatButton.Enable(False)
913 self.extrudeButton.Enable(False)
914 currentEValue = float(self.stepsPerEInput.GetValue())
915 self.comm = machineCom.MachineCom()
916 if not self.comm.isOpen():
918 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
919 'Printer error', wx.OK | wx.ICON_INFORMATION)
920 self.heatButton.Enable(True)
921 self.extrudeButton.Enable(True)
924 line = self.comm.readline()
929 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
932 self.sendGCommand('M302') #Disable cold extrusion protection
933 self.sendGCommand("M92 E%f" % (currentEValue))
934 self.sendGCommand("G92 E0")
935 self.sendGCommand("G1 E100 F600")
938 self.extrudeButton.Enable()
939 self.heatButton.Enable()
941 def OnHeatClick(self, e):
942 t = threading.Thread(target=self.OnHeatRun)
947 self.heatButton.Enable(False)
948 self.extrudeButton.Enable(False)
949 self.comm = machineCom.MachineCom()
950 if not self.comm.isOpen():
952 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
953 'Printer error', wx.OK | wx.ICON_INFORMATION)
954 self.heatButton.Enable(True)
955 self.extrudeButton.Enable(True)
958 line = self.comm.readline()
960 self.heatButton.Enable(True)
961 self.extrudeButton.Enable(True)
965 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
968 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
970 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
971 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
972 self.sendGCommand('M104 S0')
975 self.heatButton.Enable(True)
976 self.extrudeButton.Enable(True)
978 def sendGCommand(self, cmd):
979 self.comm.sendCommand(cmd) #Disable cold extrusion protection
981 line = self.comm.readline()
984 if line.startswith('ok'):
988 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
990 class Ultimaker2ReadyPage(InfoPage):
991 def __init__(self, parent):
992 super(Ultimaker2ReadyPage, self).__init__(parent, _("Ultimaker2"))
993 self.AddText(_('Congratulations on your the purchase of your brand new Ultimaker2.'))
994 self.AddText(_('Cura is now ready to be used with your Ultimaker2.'))
997 class LulzbotReadyPage(InfoPage):
998 def __init__(self, parent):
999 super(LulzbotReadyPage, self).__init__(parent, _("LulzBot TAZ/Mini"))
1000 self.AddText(_('Cura is now ready to be used with your LulzBot 3D printer.'))
1002 self.AddText(_('For more information about using Cura with your LulzBot'))
1003 self.AddText(_('3D printer, please visit www.LulzBot.com/cura'))
1006 class Taz5NozzleSelectPage(InfoPage):
1007 url='http://lulzbot.com/printer-identification'
1009 def __init__(self, parent):
1010 super(Taz5NozzleSelectPage, self).__init__(parent, _("LulzBot TAZ5"))
1011 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1013 self.AddText(_(' '))
1014 self.AddText(_('Please select nozzle size:'))
1015 self.Nozzle35Radio = self.AddRadioButton("0.35 mm", style=wx.RB_GROUP)
1016 self.Nozzle35Radio.Bind(wx.EVT_RADIOBUTTON, self.OnNozzleSelect)
1017 self.Nozzle50Radio = self.AddRadioButton("0.5 mm")
1018 self.Nozzle50Radio.Bind(wx.EVT_RADIOBUTTON, self.OnNozzleSelect)
1019 self.Nozzle50Radio.SetValue(True)
1020 self.AddText(_(' '))
1023 self.AddText(_('If you are not sure which nozzle size you have please check this webpage: '))
1024 button = self.AddButton(Taz5NozzleSelectPage.url)
1025 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1027 def OnUrlClick(self, e):
1028 webbrowser.open(Taz5NozzleSelectPage.url)
1030 def OnNozzleSelect(self, e):
1031 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
1033 def StoreData(self):
1034 if self.Nozzle35Radio.GetValue():
1035 profile.putProfileSetting('nozzle_size', '0.35')
1036 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.35 nozzle)')
1037 #TODO: Use existing profiles
1039 profile.putProfileSetting('nozzle_size', '0.5')
1040 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.5 nozzle)')
1041 #TODO: Use new profiles
1043 def OnPageChanging(self, e):
1044 e.GetPage().StoreData()
1046 class ConfigWizard(wx.wizard.Wizard):
1047 def __init__(self, addNew = False):
1048 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
1050 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1052 profile.setActiveMachine(profile.getMachineCount())
1054 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1055 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1056 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1058 self.machineSelectPage = MachineSelectPage(self)
1059 self.ultimakerSelectParts = SelectParts(self)
1060 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
1061 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
1062 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
1063 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
1064 self.bedLevelPage = bedLevelWizardMain(self)
1065 self.headOffsetCalibration = headOffsetCalibrationPage(self)
1066 self.printrbotSelectType = PrintrbotPage(self)
1067 self.otherMachineSelectPage = OtherMachineSelectPage(self)
1068 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
1069 self.otherMachineInfoPage = OtherMachineInfoPage(self)
1071 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
1072 self.lulzbotReadyPage = LulzbotReadyPage(self)
1073 self.taz5NozzleSelectPage = Taz5NozzleSelectPage(self)
1075 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
1076 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
1077 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
1078 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
1079 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
1080 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
1081 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
1082 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
1083 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.taz5NozzleSelectPage)
1084 wx.wizard.WizardPageSimple.Chain(self.taz5NozzleSelectPage, self.lulzbotReadyPage)
1086 self.FitToPage(self.machineSelectPage)
1087 self.GetPageAreaSizer().Add(self.machineSelectPage)
1089 self.RunWizard(self.machineSelectPage)
1092 def OnPageChanging(self, e):
1093 e.GetPage().StoreData()
1095 def OnPageChanged(self, e):
1096 if e.GetPage().AllowNext():
1097 self.FindWindowById(wx.ID_FORWARD).Enable()
1099 self.FindWindowById(wx.ID_FORWARD).Disable()
1100 if e.GetPage().AllowBack():
1101 self.FindWindowById(wx.ID_BACKWARD).Enable()
1103 self.FindWindowById(wx.ID_BACKWARD).Disable()
1105 def OnCancel(self, e):
1106 new_machine_index = int(profile.getPreferenceFloat('active_machine'))
1107 profile.setActiveMachine(self._old_machine_index)
1108 profile.removeMachine(new_machine_index)
1110 class bedLevelWizardMain(InfoPage):
1111 def __init__(self, parent):
1112 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1114 self.AddText(_('This wizard will help you in leveling your printer bed'))
1116 self.AddText(_('It will do the following steps'))
1117 self.AddText(_('* Move the printer head to each corner'))
1118 self.AddText(_(' and let you adjust the height of the bed to the nozzle'))
1119 self.AddText(_('* Print a line around the bed to check if it is level'))
1122 self.connectButton = self.AddButton(_('Connect to printer'))
1125 self.infoBox = self.AddInfoBox()
1126 self.resumeButton = self.AddButton(_('Resume'))
1127 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1128 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1129 self.resumeButton.Enable(False)
1131 self.upButton.Enable(False)
1132 self.downButton.Enable(False)
1133 self.upButton2.Enable(False)
1134 self.downButton2.Enable(False)
1136 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1137 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1138 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1139 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1140 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1141 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1143 def OnConnect(self, e = None):
1144 if self.comm is not None:
1148 wx.CallAfter(self.OnConnect)
1150 self.connectButton.Enable(False)
1151 self.comm = machineCom.MachineCom(callbackObject=self)
1152 self.infoBox.SetBusy(_('Connecting to machine.'))
1153 self._wizardState = 0
1155 def OnBedUp(self, e):
1156 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1157 self.comm.sendCommand('G92 Z10')
1158 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1159 self.comm.sendCommand('M400')
1161 def OnBedDown(self, e):
1162 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1163 self.comm.sendCommand('G92 Z10')
1164 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1165 self.comm.sendCommand('M400')
1167 def OnBedUp2(self, e):
1168 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1169 self.comm.sendCommand('G92 Z10')
1170 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1171 self.comm.sendCommand('M400')
1173 def OnBedDown2(self, e):
1174 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1175 self.comm.sendCommand('G92 Z10')
1176 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1177 self.comm.sendCommand('M400')
1179 def AllowNext(self):
1180 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1181 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1184 def OnResume(self, e):
1185 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1186 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1187 if self._wizardState == -1:
1188 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1189 wx.CallAfter(self.upButton.Enable, False)
1190 wx.CallAfter(self.downButton.Enable, False)
1191 wx.CallAfter(self.upButton2.Enable, False)
1192 wx.CallAfter(self.downButton2.Enable, False)
1193 self.comm.sendCommand('M105')
1194 self.comm.sendCommand('G28')
1195 self._wizardState = 1
1196 elif self._wizardState == 2:
1197 if profile.getMachineSetting('has_heated_bed') == 'True':
1198 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1199 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1200 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1201 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1202 self.comm.sendCommand('M400')
1203 self._wizardState = 3
1205 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1206 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1207 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1208 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1209 self.comm.sendCommand('M400')
1210 self._wizardState = 3
1211 elif self._wizardState == 4:
1212 if profile.getMachineSetting('has_heated_bed') == 'True':
1213 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1214 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1215 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1216 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1217 self.comm.sendCommand('M400')
1218 self._wizardState = 7
1220 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1221 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1222 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1223 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1224 self.comm.sendCommand('M400')
1225 self._wizardState = 5
1226 elif self._wizardState == 6:
1227 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1228 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1229 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1230 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1231 self.comm.sendCommand('M400')
1232 self._wizardState = 7
1233 elif self._wizardState == 8:
1234 wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1235 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1236 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1237 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1238 self._wizardState = 9
1239 elif self._wizardState == 10:
1240 self._wizardState = 11
1241 wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1242 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1243 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1244 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1245 w = profile.getMachineSettingFloat('machine_width') - 10
1246 d = profile.getMachineSettingFloat('machine_depth')
1247 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1248 filamentArea = math.pi * filamentRadius * filamentRadius
1249 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1253 'G1 Z2 F%d' % (feedZ),
1255 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1256 'G1 Z0.3 F%d' % (feedZ)]
1258 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1260 for i in xrange(0, 3):
1261 dist = 5.0 + 0.4 * float(i)
1262 eValue += (d - 2.0*dist) * ePerMM
1263 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1264 eValue += (w - 2.0*dist) * ePerMM
1265 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1266 eValue += (d - 2.0*dist) * ePerMM
1267 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1268 eValue += (w - 2.0*dist) * ePerMM
1269 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1271 gcodeList.append('M400')
1272 self.comm.printGCode(gcodeList)
1273 self.resumeButton.Enable(False)
1275 def mcLog(self, message):
1276 print 'Log:', message
1278 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1279 if self._wizardState == 1:
1280 self._wizardState = 2
1281 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1282 wx.CallAfter(self.resumeButton.Enable, True)
1283 elif self._wizardState == 3:
1284 self._wizardState = 4
1285 if profile.getMachineSetting('has_heated_bed') == 'True':
1286 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1288 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1289 wx.CallAfter(self.resumeButton.Enable, True)
1290 elif self._wizardState == 5:
1291 self._wizardState = 6
1292 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1293 wx.CallAfter(self.resumeButton.Enable, True)
1294 elif self._wizardState == 7:
1295 self._wizardState = 8
1296 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1297 wx.CallAfter(self.resumeButton.Enable, True)
1298 elif self._wizardState == 9:
1299 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1300 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1302 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1303 wx.CallAfter(self.resumeButton.Enable, True)
1304 self._wizardState = 10
1306 def mcStateChange(self, state):
1307 if self.comm is None:
1309 if self.comm.isOperational():
1310 if self._wizardState == 0:
1311 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1312 wx.CallAfter(self.upButton.Enable, True)
1313 wx.CallAfter(self.downButton.Enable, True)
1314 wx.CallAfter(self.upButton2.Enable, True)
1315 wx.CallAfter(self.downButton2.Enable, True)
1316 wx.CallAfter(self.resumeButton.Enable, True)
1317 self._wizardState = -1
1318 elif self._wizardState == 11 and not self.comm.isPrinting():
1319 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1320 self.comm.sendCommand('G92 E0')
1321 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1322 self.comm.sendCommand('M104 S0')
1323 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1324 wx.CallAfter(self.infoBox.SetReadyIndicator)
1325 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1326 wx.CallAfter(self.connectButton.Enable, True)
1327 self._wizardState = 12
1328 elif self.comm.isError():
1329 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1331 def mcMessage(self, message):
1334 def mcProgress(self, lineNr):
1337 def mcZChange(self, newZ):
1340 class headOffsetCalibrationPage(InfoPage):
1341 def __init__(self, parent):
1342 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1344 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1347 self.connectButton = self.AddButton(_('Connect to printer'))
1350 self.infoBox = self.AddInfoBox()
1351 self.textEntry = self.AddTextCtrl('')
1352 self.textEntry.Enable(False)
1353 self.resumeButton = self.AddButton(_('Resume'))
1354 self.resumeButton.Enable(False)
1356 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1357 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1359 def AllowBack(self):
1362 def OnConnect(self, e = None):
1363 if self.comm is not None:
1367 wx.CallAfter(self.OnConnect)
1369 self.connectButton.Enable(False)
1370 self.comm = machineCom.MachineCom(callbackObject=self)
1371 self.infoBox.SetBusy(_('Connecting to machine.'))
1372 self._wizardState = 0
1374 def OnResume(self, e):
1375 if self._wizardState == 2:
1376 self._wizardState = 3
1377 wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1379 w = profile.getMachineSettingFloat('machine_width')
1380 d = profile.getMachineSettingFloat('machine_depth')
1382 gcode = gcodeGenerator.gcodeGenerator()
1383 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1384 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1391 gcode.addMove(w/2, 5)
1392 gcode.addMove(z=0.2)
1394 gcode.addExtrude(w/2, d-5.0)
1396 gcode.addMove(5, d/2)
1398 gcode.addExtrude(w-5.0, d/2)
1399 gcode.addRetract(15)
1402 gcode.addMove(w/2, 5)
1404 gcode.addExtrude(w/2, d-5.0)
1406 gcode.addMove(5, d/2)
1408 gcode.addExtrude(w-5.0, d/2)
1409 gcode.addRetract(15)
1414 gcode.addCmd('M400')
1416 self.comm.printGCode(gcode.list())
1417 self.resumeButton.Enable(False)
1418 elif self._wizardState == 4:
1420 float(self.textEntry.GetValue())
1423 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1424 self._wizardState = 5
1425 self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1426 self.textEntry.SetValue('0.0')
1427 self.textEntry.Enable(True)
1428 elif self._wizardState == 5:
1430 float(self.textEntry.GetValue())
1433 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1434 self._wizardState = 6
1435 self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1436 self.textEntry.SetValue('')
1437 self.textEntry.Enable(False)
1438 self.resumeButton.Enable(False)
1440 x = profile.getMachineSettingFloat('extruder_offset_x1')
1441 y = profile.getMachineSettingFloat('extruder_offset_y1')
1442 gcode = gcodeGenerator.gcodeGenerator()
1443 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1444 gcode.setPrintSpeed(25)
1447 gcode.addMove(50, 40, 0.2)
1449 for n in xrange(0, 10):
1450 gcode.addExtrude(50 + n * 10, 150)
1451 gcode.addExtrude(50 + n * 10 + 5, 150)
1452 gcode.addExtrude(50 + n * 10 + 5, 40)
1453 gcode.addExtrude(50 + n * 10 + 10, 40)
1454 gcode.addMove(40, 50)
1455 for n in xrange(0, 10):
1456 gcode.addExtrude(150, 50 + n * 10)
1457 gcode.addExtrude(150, 50 + n * 10 + 5)
1458 gcode.addExtrude(40, 50 + n * 10 + 5)
1459 gcode.addExtrude(40, 50 + n * 10 + 10)
1460 gcode.addRetract(15)
1463 gcode.addMove(50 - x, 30 - y, 0.2)
1465 for n in xrange(0, 10):
1466 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1467 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1468 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1469 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1470 gcode.addMove(30 - x, 50 - y, 0.2)
1471 for n in xrange(0, 10):
1472 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1473 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1474 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1475 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1476 gcode.addRetract(15)
1478 gcode.addCmd('M400')
1479 gcode.addCmd('M104 T0 S0')
1480 gcode.addCmd('M104 T1 S0')
1481 self.comm.printGCode(gcode.list())
1482 elif self._wizardState == 7:
1484 n = int(self.textEntry.GetValue()) - 1
1487 x = profile.getMachineSettingFloat('extruder_offset_x1')
1489 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1490 self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1491 self.textEntry.SetValue('10')
1492 self._wizardState = 8
1493 elif self._wizardState == 8:
1495 n = int(self.textEntry.GetValue()) - 1
1498 y = profile.getMachineSettingFloat('extruder_offset_y1')
1500 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1501 self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1502 self.infoBox.SetReadyIndicator()
1503 self._wizardState = 8
1505 self.resumeButton.Enable(False)
1507 def mcLog(self, message):
1508 print 'Log:', message
1510 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1511 if self._wizardState == 1:
1512 if temp[0] >= 210 and temp[1] >= 210:
1513 self._wizardState = 2
1514 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1515 wx.CallAfter(self.resumeButton.Enable, True)
1516 wx.CallAfter(self.resumeButton.SetFocus)
1518 def mcStateChange(self, state):
1519 if self.comm is None:
1521 if self.comm.isOperational():
1522 if self._wizardState == 0:
1523 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1524 self.comm.sendCommand('M105')
1525 self.comm.sendCommand('M104 S220 T0')
1526 self.comm.sendCommand('M104 S220 T1')
1527 self.comm.sendCommand('G28')
1528 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1529 self._wizardState = 1
1530 if not self.comm.isPrinting():
1531 if self._wizardState == 3:
1532 self._wizardState = 4
1533 wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1534 wx.CallAfter(self.textEntry.SetValue, '0.0')
1535 wx.CallAfter(self.textEntry.Enable, True)
1536 wx.CallAfter(self.resumeButton.Enable, True)
1537 wx.CallAfter(self.resumeButton.SetFocus)
1538 elif self._wizardState == 6:
1539 self._wizardState = 7
1540 wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1541 wx.CallAfter(self.textEntry.SetValue, '10')
1542 wx.CallAfter(self.textEntry.Enable, True)
1543 wx.CallAfter(self.resumeButton.Enable, True)
1544 wx.CallAfter(self.resumeButton.SetFocus)
1546 elif self.comm.isError():
1547 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1549 def mcMessage(self, message):
1552 def mcProgress(self, lineNr):
1555 def mcZChange(self, newZ):
1558 class bedLevelWizard(wx.wizard.Wizard):
1560 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1562 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1563 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1565 self.mainPage = bedLevelWizardMain(self)
1566 self.headOffsetCalibration = None
1568 self.FitToPage(self.mainPage)
1569 self.GetPageAreaSizer().Add(self.mainPage)
1571 self.RunWizard(self.mainPage)
1574 def OnPageChanging(self, e):
1575 e.GetPage().StoreData()
1577 def OnPageChanged(self, e):
1578 if e.GetPage().AllowNext():
1579 self.FindWindowById(wx.ID_FORWARD).Enable()
1581 self.FindWindowById(wx.ID_FORWARD).Disable()
1582 if e.GetPage().AllowBack():
1583 self.FindWindowById(wx.ID_BACKWARD).Enable()
1585 self.FindWindowById(wx.ID_BACKWARD).Disable()
1587 class headOffsetWizard(wx.wizard.Wizard):
1589 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1591 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1592 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1594 self.mainPage = headOffsetCalibrationPage(self)
1596 self.FitToPage(self.mainPage)
1597 self.GetPageAreaSizer().Add(self.mainPage)
1599 self.RunWizard(self.mainPage)
1602 def OnPageChanging(self, e):
1603 e.GetPage().StoreData()
1605 def OnPageChanged(self, e):
1606 if e.GetPage().AllowNext():
1607 self.FindWindowById(wx.ID_FORWARD).Enable()
1609 self.FindWindowById(wx.ID_FORWARD).Disable()
1610 if e.GetPage().AllowBack():
1611 self.FindWindowById(wx.ID_BACKWARD).Enable()
1613 self.FindWindowById(wx.ID_BACKWARD).Disable()