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)
424 wx.wizard.WizardPageSimple.Chain(self.GetParent().taz5NozzleSelectPage, self.GetParent().lulzbotReadyPage)
426 def OnOtherSelect(self, e):
427 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().otherMachineSelectPage)
436 profile.putProfileSetting('retraction_enable', 'True')
437 if self.Ultimaker2Radio.GetValue() or self.Ultimaker2GoRadio.GetValue() or self.Ultimaker2ExtRadio.GetValue():
438 if self.Ultimaker2Radio.GetValue():
439 profile.putMachineSetting('machine_width', '230')
440 profile.putMachineSetting('machine_depth', '225')
441 profile.putMachineSetting('machine_height', '205')
442 profile.putMachineSetting('machine_name', 'ultimaker2')
443 profile.putMachineSetting('machine_type', 'ultimaker2')
444 profile.putMachineSetting('has_heated_bed', 'True')
445 if self.Ultimaker2GoRadio.GetValue():
446 profile.putMachineSetting('machine_width', '120')
447 profile.putMachineSetting('machine_depth', '120')
448 profile.putMachineSetting('machine_height', '115')
449 profile.putMachineSetting('machine_name', 'ultimaker2go')
450 profile.putMachineSetting('machine_type', 'ultimaker2go')
451 profile.putMachineSetting('has_heated_bed', 'False')
452 if self.Ultimaker2ExtRadio.GetValue():
453 profile.putMachineSetting('machine_width', '230')
454 profile.putMachineSetting('machine_depth', '225')
455 profile.putMachineSetting('machine_height', '315')
456 profile.putMachineSetting('machine_name', 'ultimaker2extended')
457 profile.putMachineSetting('machine_type', 'ultimaker2extended')
458 profile.putMachineSetting('has_heated_bed', 'False')
459 profile.putMachineSetting('machine_center_is_zero', 'False')
460 profile.putMachineSetting('gcode_flavor', 'UltiGCode')
461 profile.putMachineSetting('extruder_head_size_min_x', '40.0')
462 profile.putMachineSetting('extruder_head_size_min_y', '10.0')
463 profile.putMachineSetting('extruder_head_size_max_x', '60.0')
464 profile.putMachineSetting('extruder_head_size_max_y', '30.0')
465 profile.putMachineSetting('extruder_head_size_height', '48.0')
466 profile.putProfileSetting('nozzle_size', '0.4')
467 profile.putProfileSetting('fan_full_height', '5.0')
468 profile.putMachineSetting('extruder_offset_x1', '18.0')
469 profile.putMachineSetting('extruder_offset_y1', '0.0')
470 elif self.UltimakerRadio.GetValue():
471 profile.putMachineSetting('machine_width', '205')
472 profile.putMachineSetting('machine_depth', '205')
473 profile.putMachineSetting('machine_height', '200')
474 profile.putMachineSetting('machine_name', 'ultimaker original')
475 profile.putMachineSetting('machine_type', 'ultimaker')
476 profile.putMachineSetting('machine_center_is_zero', 'False')
477 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
478 profile.putProfileSetting('nozzle_size', '0.4')
479 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
480 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
481 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
482 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
483 profile.putMachineSetting('extruder_head_size_height', '55.0')
484 elif self.UltimakerOPRadio.GetValue():
485 profile.putMachineSetting('machine_width', '205')
486 profile.putMachineSetting('machine_depth', '205')
487 profile.putMachineSetting('machine_height', '200')
488 profile.putMachineSetting('machine_name', 'ultimaker original+')
489 profile.putMachineSetting('machine_type', 'ultimaker_plus')
490 profile.putMachineSetting('machine_center_is_zero', 'False')
491 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
492 profile.putProfileSetting('nozzle_size', '0.4')
493 profile.putMachineSetting('extruder_head_size_min_x', '75.0')
494 profile.putMachineSetting('extruder_head_size_min_y', '18.0')
495 profile.putMachineSetting('extruder_head_size_max_x', '18.0')
496 profile.putMachineSetting('extruder_head_size_max_y', '35.0')
497 profile.putMachineSetting('extruder_head_size_height', '55.0')
498 profile.putMachineSetting('has_heated_bed', 'True')
499 profile.putMachineSetting('extruder_amount', '1')
500 profile.putProfileSetting('retraction_enable', 'True')
501 elif self.LulzbotTaz4Radio.GetValue() or self.LulzbotTaz5Radio.GetValue() or self.LulzbotMiniRadio.GetValue():
502 if self.LulzbotTaz4Radio.GetValue():
503 profile.putMachineSetting('machine_width', '298')
504 profile.putMachineSetting('machine_depth', '275')
505 profile.putMachineSetting('machine_height', '250')
506 profile.putProfileSetting('nozzle_size', '0.35')
507 profile.putMachineSetting('machine_name', 'LulzBot TAZ 4')
508 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_4')
509 profile.putMachineSetting('serial_baud', '115200')
510 elif self.LulzbotTaz5Radio.GetValue():
511 profile.putMachineSetting('machine_width', '298')
512 profile.putMachineSetting('machine_depth', '275')
513 profile.putMachineSetting('machine_height', '250')
514 profile.putMachineSetting('serial_baud', '115200')
515 # Machine type and name are set in the nozzle select page
517 profile.putMachineSetting('machine_width', '155')
518 profile.putMachineSetting('machine_depth', '155')
519 profile.putMachineSetting('machine_height', '163')
520 profile.putProfileSetting('nozzle_size', '0.5')
521 profile.putMachineSetting('machine_name', 'LulzBot Mini')
522 profile.putMachineSetting('machine_type', 'lulzbot_mini')
523 profile.putMachineSetting('serial_baud', '115200')
524 profile.putMachineSetting('extruder_head_size_min_x', '40')
525 profile.putMachineSetting('extruder_head_size_max_x', '75')
526 profile.putMachineSetting('extruder_head_size_min_y', '25')
527 profile.putMachineSetting('extruder_head_size_max_y', '55')
528 profile.putMachineSetting('extruder_head_size_height', '17')
530 profile.putMachineSetting('machine_center_is_zero', 'False')
531 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
532 profile.putMachineSetting('has_heated_bed', 'True')
533 profile.putMachineSetting('extruder_head_size_min_x', '0.0')
534 profile.putMachineSetting('extruder_head_size_min_y', '0.0')
535 profile.putMachineSetting('extruder_head_size_max_x', '0.0')
536 profile.putMachineSetting('extruder_head_size_max_y', '0.0')
537 profile.putMachineSetting('extruder_head_size_height', '0.0')
538 profile.putPreference('startMode', 'Simple')
540 profile.putMachineSetting('machine_width', '80')
541 profile.putMachineSetting('machine_depth', '80')
542 profile.putMachineSetting('machine_height', '60')
543 profile.putMachineSetting('machine_name', 'reprap')
544 profile.putMachineSetting('machine_type', 'reprap')
545 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
546 profile.putPreference('startMode', 'Normal')
547 profile.putProfileSetting('nozzle_size', '0.5')
548 profile.checkAndUpdateMachineName()
549 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
551 class SelectParts(InfoPage):
552 def __init__(self, parent):
553 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
554 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."))
556 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
557 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
558 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
559 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
561 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."))
562 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
563 self.springExtruder.SetValue(True)
566 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
567 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
568 profile.putMachineSetting('has_heated_bed', 'True')
570 profile.putMachineSetting('has_heated_bed', 'False')
571 if self.dualExtrusion.GetValue():
572 profile.putMachineSetting('extruder_amount', '2')
573 profile.putMachineSetting('machine_depth', '195')
575 profile.putMachineSetting('extruder_amount', '1')
576 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
577 profile.putProfileSetting('retraction_enable', 'True')
579 profile.putProfileSetting('retraction_enable', 'False')
582 class UltimakerFirmwareUpgradePage(InfoPage):
583 def __init__(self, parent):
584 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
585 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."))
586 self.AddHiddenSeperator()
587 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
588 self.AddHiddenSeperator()
589 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."))
590 upgradeButton, skipUpgradeButton = self.AddDualButton(_('Upgrade to Marlin firmware'), _('Skip upgrade'))
591 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
592 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
593 self.AddHiddenSeperator()
594 if profile.getMachineSetting('machine_type') == 'ultimaker':
595 self.AddText(_("Do not upgrade to this firmware if:"))
596 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
597 self.AddText(_("* Build your own heated bed"))
598 self.AddText(_("* Have other changes in the firmware"))
599 # button = self.AddButton('Goto this page for a custom firmware')
600 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
605 def OnUpgradeClick(self, e):
606 if firmwareInstall.InstallFirmware():
607 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
609 def OnSkipClick(self, e):
610 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
611 self.GetParent().ShowPage(self.GetNext())
613 def OnUrlClick(self, e):
614 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
616 class UltimakerCheckupPage(InfoPage):
617 def __init__(self, parent):
618 super(UltimakerCheckupPage, self).__init__(parent, _("Ultimaker Checkup"))
620 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
621 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
622 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
623 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
624 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
625 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
626 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
627 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
628 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
629 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
632 _("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."))
633 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
634 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
635 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
637 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
638 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
639 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
641 self.infoBox = self.AddInfoBox()
642 self.machineState = self.AddText("")
643 self.temperatureLabel = self.AddText("")
644 self.errorLogButton = self.AddButton(_("Show error log"))
645 self.errorLogButton.Show(False)
647 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
649 self.xMinStop = False
650 self.xMaxStop = False
651 self.yMinStop = False
652 self.yMaxStop = False
653 self.zMinStop = False
654 self.zMaxStop = False
656 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
659 if self.comm is not None:
663 self.endstopBitmap.Show(False)
666 def OnSkipClick(self, e):
667 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
668 self.GetParent().ShowPage(self.GetNext())
670 def OnCheckClick(self, e=None):
671 self.errorLogButton.Show(False)
672 if self.comm is not None:
676 wx.CallAfter(self.OnCheckClick)
678 self.infoBox.SetBusy(_("Connecting to machine."))
679 self.commState.SetBitmap(self.unknownBitmap)
680 self.tempState.SetBitmap(self.unknownBitmap)
681 self.stopState.SetBitmap(self.unknownBitmap)
682 self.checkupState = 0
683 self.checkExtruderNr = 0
684 self.comm = machineCom.MachineCom(callbackObject=self)
686 def OnErrorLog(self, e):
687 printWindow.LogWindow('\n'.join(self.comm.getLog()))
689 def mcLog(self, message):
692 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
693 if not self.comm.isOperational():
695 if self.checkupState == 0:
696 self.tempCheckTimeout = 20
697 if temp[self.checkExtruderNr] > 70:
698 self.checkupState = 1
699 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
700 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
701 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
703 self.startTemp = temp[self.checkExtruderNr]
704 self.checkupState = 2
705 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
706 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
707 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
708 elif self.checkupState == 1:
709 if temp[self.checkExtruderNr] < 60:
710 self.startTemp = temp[self.checkExtruderNr]
711 self.checkupState = 2
712 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
713 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
714 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
715 elif self.checkupState == 2:
716 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
717 if temp[self.checkExtruderNr] > self.startTemp + 40:
718 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
719 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
720 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
721 self.checkExtruderNr = 0
722 self.checkupState = 3
723 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
724 wx.CallAfter(self.endstopBitmap.Show, True)
725 wx.CallAfter(self.Layout)
726 self.comm.sendCommand('M119')
727 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
729 self.checkupState = 0
730 self.checkExtruderNr += 1
732 self.tempCheckTimeout -= 1
733 if self.tempCheckTimeout < 1:
734 self.checkupState = -1
735 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
736 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
737 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
738 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
739 elif self.checkupState >= 3 and self.checkupState < 10:
740 self.comm.sendCommand('M119')
741 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
743 def mcStateChange(self, state):
744 if self.comm is None:
746 if self.comm.isOperational():
747 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
748 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
749 elif self.comm.isError():
750 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
751 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
752 wx.CallAfter(self.endstopBitmap.Show, False)
753 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
754 wx.CallAfter(self.errorLogButton.Show, True)
755 wx.CallAfter(self.Layout)
757 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
759 def mcMessage(self, message):
760 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
761 for data in message.split(' '):
763 tag, value = data.split(':', 1)
765 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
767 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
769 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
771 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
773 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
775 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
777 tag, value = map(str.strip, message.split(':', 1))
779 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
781 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
783 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
785 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
787 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
789 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
790 if 'z_max' in message:
791 self.comm.sendCommand('M119')
793 if self.checkupState == 3:
794 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
795 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
796 self.checkupState = 5
797 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
798 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
800 self.checkupState = 4
801 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
802 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
803 elif self.checkupState == 4:
804 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
805 self.checkupState = 5
806 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
807 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
808 elif self.checkupState == 5:
809 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
810 self.checkupState = 6
811 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
812 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
813 elif self.checkupState == 6:
814 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
815 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
816 self.checkupState = 8
817 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
818 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
820 self.checkupState = 7
821 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
822 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
823 elif self.checkupState == 7:
824 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
825 self.checkupState = 8
826 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
827 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
828 elif self.checkupState == 8:
829 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
830 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
831 self.checkupState = 10
833 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
834 wx.CallAfter(self.infoBox.SetReadyIndicator)
835 wx.CallAfter(self.endstopBitmap.Show, False)
836 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
837 wx.CallAfter(self.OnSkipClick, None)
839 self.checkupState = 9
840 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
841 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
842 elif self.checkupState == 9:
843 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
844 self.checkupState = 10
846 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
847 wx.CallAfter(self.infoBox.SetReadyIndicator)
848 wx.CallAfter(self.endstopBitmap.Show, False)
849 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
850 wx.CallAfter(self.OnSkipClick, None)
852 def mcProgress(self, lineNr):
855 def mcZChange(self, newZ):
859 class UltimakerCalibrationPage(InfoPage):
860 def __init__(self, parent):
861 super(UltimakerCalibrationPage, self).__init__(parent, _("Ultimaker Calibration"))
863 self.AddText("Your Ultimaker requires some calibration.")
864 self.AddText("This calibration is needed for a proper extrusion amount.")
866 self.AddText("The following values are needed:")
867 self.AddText("* Diameter of filament")
868 self.AddText("* Number of steps per mm of filament extrusion")
870 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
872 self.AddText("First we need the diameter of your filament:")
873 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
875 "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.")
876 self.AddText("Note: This value can be changed later at any time.")
879 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
882 class UltimakerCalibrateStepsPerEPage(InfoPage):
883 def __init__(self, parent):
884 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, _("Ultimaker Calibration"))
886 #if profile.getMachineSetting('steps_per_e') == '0':
887 # profile.putMachineSetting('steps_per_e', '865.888')
889 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
890 self.AddText(_("First remove any filament from your machine."))
891 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
892 self.AddText(_("We'll push the filament 100mm"))
893 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
894 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
895 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
896 self.AddText(_("This results in the following steps per E:"))
897 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
898 self.AddText(_("You can repeat these steps to get better calibration."))
901 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
902 self.heatButton = self.AddButton(_("Heatup for filament removal"))
904 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
905 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
906 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
908 def OnSaveLengthClick(self, e):
909 currentEValue = float(self.stepsPerEInput.GetValue())
910 realExtrudeLength = float(self.lengthInput.GetValue())
911 newEValue = currentEValue * 100 / realExtrudeLength
912 self.stepsPerEInput.SetValue(str(newEValue))
913 self.lengthInput.SetValue("100")
915 def OnExtrudeClick(self, e):
916 t = threading.Thread(target=self.OnExtrudeRun)
920 def OnExtrudeRun(self):
921 self.heatButton.Enable(False)
922 self.extrudeButton.Enable(False)
923 currentEValue = float(self.stepsPerEInput.GetValue())
924 self.comm = machineCom.MachineCom()
925 if not self.comm.isOpen():
927 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
928 'Printer error', wx.OK | wx.ICON_INFORMATION)
929 self.heatButton.Enable(True)
930 self.extrudeButton.Enable(True)
933 line = self.comm.readline()
938 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
941 self.sendGCommand('M302') #Disable cold extrusion protection
942 self.sendGCommand("M92 E%f" % (currentEValue))
943 self.sendGCommand("G92 E0")
944 self.sendGCommand("G1 E100 F600")
947 self.extrudeButton.Enable()
948 self.heatButton.Enable()
950 def OnHeatClick(self, e):
951 t = threading.Thread(target=self.OnHeatRun)
956 self.heatButton.Enable(False)
957 self.extrudeButton.Enable(False)
958 self.comm = machineCom.MachineCom()
959 if not self.comm.isOpen():
961 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
962 'Printer error', wx.OK | wx.ICON_INFORMATION)
963 self.heatButton.Enable(True)
964 self.extrudeButton.Enable(True)
967 line = self.comm.readline()
969 self.heatButton.Enable(True)
970 self.extrudeButton.Enable(True)
974 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
977 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
979 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
980 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
981 self.sendGCommand('M104 S0')
984 self.heatButton.Enable(True)
985 self.extrudeButton.Enable(True)
987 def sendGCommand(self, cmd):
988 self.comm.sendCommand(cmd) #Disable cold extrusion protection
990 line = self.comm.readline()
993 if line.startswith('ok'):
997 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
999 class Ultimaker2ReadyPage(InfoPage):
1000 def __init__(self, parent):
1001 super(Ultimaker2ReadyPage, self).__init__(parent, _("Ultimaker2"))
1002 self.AddText(_('Congratulations on your the purchase of your brand new Ultimaker2.'))
1003 self.AddText(_('Cura is now ready to be used with your Ultimaker2.'))
1006 class LulzbotReadyPage(InfoPage):
1007 def __init__(self, parent):
1008 super(LulzbotReadyPage, self).__init__(parent, _("LulzBot TAZ/Mini"))
1009 self.AddText(_('Cura is now ready to be used with your LulzBot 3D printer.'))
1011 self.AddText(_('For more information about using Cura with your LulzBot'))
1012 self.AddText(_('3D printer, please visit www.LulzBot.com/cura'))
1015 class Taz5NozzleSelectPage(InfoPage):
1016 url='http://lulzbot.com/printer-identification'
1018 def __init__(self, parent):
1019 super(Taz5NozzleSelectPage, self).__init__(parent, _("LulzBot TAZ5"))
1020 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1022 self.AddText(_(' '))
1023 self.AddText(_('Please select nozzle size:'))
1024 self.Nozzle35Radio = self.AddRadioButton("0.35 mm", style=wx.RB_GROUP)
1025 self.Nozzle35Radio.SetValue(True)
1026 self.Nozzle50Radio = self.AddRadioButton("0.5 mm")
1027 self.AddText(_(' '))
1030 self.AddText(_('If you are not sure which nozzle size you have please check this webpage: '))
1031 button = self.AddButton(Taz5NozzleSelectPage.url)
1032 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1034 def OnUrlClick(self, e):
1035 webbrowser.open(Taz5NozzleSelectPage.url)
1037 def StoreData(self):
1038 if self.Nozzle35Radio.GetValue():
1039 profile.putProfileSetting('nozzle_size', '0.35')
1040 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.35 nozzle)')
1041 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5')
1044 profile.putProfileSetting('nozzle_size', '0.5')
1045 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.5 nozzle)')
1046 profile.putMachineSetting('machine_type', 'lulzbot_TAZ_5_05nozzle')
1048 def OnPageChanging(self, e):
1049 e.GetPage().StoreData()
1051 class ConfigWizard(wx.wizard.Wizard):
1052 def __init__(self, addNew = False):
1053 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
1055 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1057 profile.setActiveMachine(profile.getMachineCount())
1059 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1060 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1061 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1063 self.machineSelectPage = MachineSelectPage(self)
1064 self.ultimakerSelectParts = SelectParts(self)
1065 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
1066 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
1067 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
1068 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
1069 self.bedLevelPage = bedLevelWizardMain(self)
1070 self.headOffsetCalibration = headOffsetCalibrationPage(self)
1071 self.printrbotSelectType = PrintrbotPage(self)
1072 self.otherMachineSelectPage = OtherMachineSelectPage(self)
1073 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
1074 self.otherMachineInfoPage = OtherMachineInfoPage(self)
1076 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
1077 self.lulzbotReadyPage = LulzbotReadyPage(self)
1078 self.taz5NozzleSelectPage = Taz5NozzleSelectPage(self)
1080 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
1081 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
1082 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
1083 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
1084 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
1085 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
1086 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
1087 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
1088 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.lulzbotReadyPage)
1090 self.FitToPage(self.machineSelectPage)
1091 self.GetPageAreaSizer().Add(self.machineSelectPage)
1093 self.RunWizard(self.machineSelectPage)
1096 def OnPageChanging(self, e):
1097 e.GetPage().StoreData()
1099 def OnPageChanged(self, e):
1100 if e.GetPage().AllowNext():
1101 self.FindWindowById(wx.ID_FORWARD).Enable()
1103 self.FindWindowById(wx.ID_FORWARD).Disable()
1104 if e.GetPage().AllowBack():
1105 self.FindWindowById(wx.ID_BACKWARD).Enable()
1107 self.FindWindowById(wx.ID_BACKWARD).Disable()
1109 def OnCancel(self, e):
1110 new_machine_index = int(profile.getPreferenceFloat('active_machine'))
1111 profile.setActiveMachine(self._old_machine_index)
1112 profile.removeMachine(new_machine_index)
1114 class bedLevelWizardMain(InfoPage):
1115 def __init__(self, parent):
1116 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1118 self.AddText(_('This wizard will help you in leveling your printer bed'))
1120 self.AddText(_('It will do the following steps'))
1121 self.AddText(_('* Move the printer head to each corner'))
1122 self.AddText(_(' and let you adjust the height of the bed to the nozzle'))
1123 self.AddText(_('* Print a line around the bed to check if it is level'))
1126 self.connectButton = self.AddButton(_('Connect to printer'))
1129 self.infoBox = self.AddInfoBox()
1130 self.resumeButton = self.AddButton(_('Resume'))
1131 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1132 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1133 self.resumeButton.Enable(False)
1135 self.upButton.Enable(False)
1136 self.downButton.Enable(False)
1137 self.upButton2.Enable(False)
1138 self.downButton2.Enable(False)
1140 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1141 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1142 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1143 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1144 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1145 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1147 def OnConnect(self, e = None):
1148 if self.comm is not None:
1152 wx.CallAfter(self.OnConnect)
1154 self.connectButton.Enable(False)
1155 self.comm = machineCom.MachineCom(callbackObject=self)
1156 self.infoBox.SetBusy(_('Connecting to machine.'))
1157 self._wizardState = 0
1159 def OnBedUp(self, e):
1160 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1161 self.comm.sendCommand('G92 Z10')
1162 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1163 self.comm.sendCommand('M400')
1165 def OnBedDown(self, e):
1166 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1167 self.comm.sendCommand('G92 Z10')
1168 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1169 self.comm.sendCommand('M400')
1171 def OnBedUp2(self, e):
1172 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1173 self.comm.sendCommand('G92 Z10')
1174 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1175 self.comm.sendCommand('M400')
1177 def OnBedDown2(self, e):
1178 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1179 self.comm.sendCommand('G92 Z10')
1180 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1181 self.comm.sendCommand('M400')
1183 def AllowNext(self):
1184 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1185 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1188 def OnResume(self, e):
1189 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1190 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1191 if self._wizardState == -1:
1192 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1193 wx.CallAfter(self.upButton.Enable, False)
1194 wx.CallAfter(self.downButton.Enable, False)
1195 wx.CallAfter(self.upButton2.Enable, False)
1196 wx.CallAfter(self.downButton2.Enable, False)
1197 self.comm.sendCommand('M105')
1198 self.comm.sendCommand('G28')
1199 self._wizardState = 1
1200 elif self._wizardState == 2:
1201 if profile.getMachineSetting('has_heated_bed') == 'True':
1202 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1203 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1204 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1205 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1206 self.comm.sendCommand('M400')
1207 self._wizardState = 3
1209 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1210 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1211 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1212 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1213 self.comm.sendCommand('M400')
1214 self._wizardState = 3
1215 elif self._wizardState == 4:
1216 if profile.getMachineSetting('has_heated_bed') == 'True':
1217 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1218 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1219 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 5, feedTravel))
1220 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1221 self.comm.sendCommand('M400')
1222 self._wizardState = 7
1224 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back right corner...'))
1225 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1226 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1227 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1228 self.comm.sendCommand('M400')
1229 self._wizardState = 5
1230 elif self._wizardState == 6:
1231 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1232 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1233 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1234 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1235 self.comm.sendCommand('M400')
1236 self._wizardState = 7
1237 elif self._wizardState == 8:
1238 wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1239 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1240 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1241 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1242 self._wizardState = 9
1243 elif self._wizardState == 10:
1244 self._wizardState = 11
1245 wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1246 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1247 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1248 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1249 w = profile.getMachineSettingFloat('machine_width') - 10
1250 d = profile.getMachineSettingFloat('machine_depth')
1251 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1252 filamentArea = math.pi * filamentRadius * filamentRadius
1253 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1257 'G1 Z2 F%d' % (feedZ),
1259 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1260 'G1 Z0.3 F%d' % (feedZ)]
1262 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1264 for i in xrange(0, 3):
1265 dist = 5.0 + 0.4 * float(i)
1266 eValue += (d - 2.0*dist) * ePerMM
1267 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1268 eValue += (w - 2.0*dist) * ePerMM
1269 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1270 eValue += (d - 2.0*dist) * ePerMM
1271 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1272 eValue += (w - 2.0*dist) * ePerMM
1273 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1275 gcodeList.append('M400')
1276 self.comm.printGCode(gcodeList)
1277 self.resumeButton.Enable(False)
1279 def mcLog(self, message):
1280 print 'Log:', message
1282 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1283 if self._wizardState == 1:
1284 self._wizardState = 2
1285 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1286 wx.CallAfter(self.resumeButton.Enable, True)
1287 elif self._wizardState == 3:
1288 self._wizardState = 4
1289 if profile.getMachineSetting('has_heated_bed') == 'True':
1290 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1292 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1293 wx.CallAfter(self.resumeButton.Enable, True)
1294 elif self._wizardState == 5:
1295 self._wizardState = 6
1296 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1297 wx.CallAfter(self.resumeButton.Enable, True)
1298 elif self._wizardState == 7:
1299 self._wizardState = 8
1300 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1301 wx.CallAfter(self.resumeButton.Enable, True)
1302 elif self._wizardState == 9:
1303 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1304 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1306 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1307 wx.CallAfter(self.resumeButton.Enable, True)
1308 self._wizardState = 10
1310 def mcStateChange(self, state):
1311 if self.comm is None:
1313 if self.comm.isOperational():
1314 if self._wizardState == 0:
1315 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1316 wx.CallAfter(self.upButton.Enable, True)
1317 wx.CallAfter(self.downButton.Enable, True)
1318 wx.CallAfter(self.upButton2.Enable, True)
1319 wx.CallAfter(self.downButton2.Enable, True)
1320 wx.CallAfter(self.resumeButton.Enable, True)
1321 self._wizardState = -1
1322 elif self._wizardState == 11 and not self.comm.isPrinting():
1323 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1324 self.comm.sendCommand('G92 E0')
1325 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1326 self.comm.sendCommand('M104 S0')
1327 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1328 wx.CallAfter(self.infoBox.SetReadyIndicator)
1329 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1330 wx.CallAfter(self.connectButton.Enable, True)
1331 self._wizardState = 12
1332 elif self.comm.isError():
1333 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1335 def mcMessage(self, message):
1338 def mcProgress(self, lineNr):
1341 def mcZChange(self, newZ):
1344 class headOffsetCalibrationPage(InfoPage):
1345 def __init__(self, parent):
1346 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1348 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1351 self.connectButton = self.AddButton(_('Connect to printer'))
1354 self.infoBox = self.AddInfoBox()
1355 self.textEntry = self.AddTextCtrl('')
1356 self.textEntry.Enable(False)
1357 self.resumeButton = self.AddButton(_('Resume'))
1358 self.resumeButton.Enable(False)
1360 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1361 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1363 def AllowBack(self):
1366 def OnConnect(self, e = None):
1367 if self.comm is not None:
1371 wx.CallAfter(self.OnConnect)
1373 self.connectButton.Enable(False)
1374 self.comm = machineCom.MachineCom(callbackObject=self)
1375 self.infoBox.SetBusy(_('Connecting to machine.'))
1376 self._wizardState = 0
1378 def OnResume(self, e):
1379 if self._wizardState == 2:
1380 self._wizardState = 3
1381 wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1383 w = profile.getMachineSettingFloat('machine_width')
1384 d = profile.getMachineSettingFloat('machine_depth')
1386 gcode = gcodeGenerator.gcodeGenerator()
1387 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1388 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1395 gcode.addMove(w/2, 5)
1396 gcode.addMove(z=0.2)
1398 gcode.addExtrude(w/2, d-5.0)
1400 gcode.addMove(5, d/2)
1402 gcode.addExtrude(w-5.0, d/2)
1403 gcode.addRetract(15)
1406 gcode.addMove(w/2, 5)
1408 gcode.addExtrude(w/2, d-5.0)
1410 gcode.addMove(5, d/2)
1412 gcode.addExtrude(w-5.0, d/2)
1413 gcode.addRetract(15)
1418 gcode.addCmd('M400')
1420 self.comm.printGCode(gcode.list())
1421 self.resumeButton.Enable(False)
1422 elif self._wizardState == 4:
1424 float(self.textEntry.GetValue())
1427 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1428 self._wizardState = 5
1429 self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1430 self.textEntry.SetValue('0.0')
1431 self.textEntry.Enable(True)
1432 elif self._wizardState == 5:
1434 float(self.textEntry.GetValue())
1437 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1438 self._wizardState = 6
1439 self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1440 self.textEntry.SetValue('')
1441 self.textEntry.Enable(False)
1442 self.resumeButton.Enable(False)
1444 x = profile.getMachineSettingFloat('extruder_offset_x1')
1445 y = profile.getMachineSettingFloat('extruder_offset_y1')
1446 gcode = gcodeGenerator.gcodeGenerator()
1447 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1448 gcode.setPrintSpeed(25)
1451 gcode.addMove(50, 40, 0.2)
1453 for n in xrange(0, 10):
1454 gcode.addExtrude(50 + n * 10, 150)
1455 gcode.addExtrude(50 + n * 10 + 5, 150)
1456 gcode.addExtrude(50 + n * 10 + 5, 40)
1457 gcode.addExtrude(50 + n * 10 + 10, 40)
1458 gcode.addMove(40, 50)
1459 for n in xrange(0, 10):
1460 gcode.addExtrude(150, 50 + n * 10)
1461 gcode.addExtrude(150, 50 + n * 10 + 5)
1462 gcode.addExtrude(40, 50 + n * 10 + 5)
1463 gcode.addExtrude(40, 50 + n * 10 + 10)
1464 gcode.addRetract(15)
1467 gcode.addMove(50 - x, 30 - y, 0.2)
1469 for n in xrange(0, 10):
1470 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1471 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1472 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1473 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1474 gcode.addMove(30 - x, 50 - y, 0.2)
1475 for n in xrange(0, 10):
1476 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1477 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1478 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1479 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1480 gcode.addRetract(15)
1482 gcode.addCmd('M400')
1483 gcode.addCmd('M104 T0 S0')
1484 gcode.addCmd('M104 T1 S0')
1485 self.comm.printGCode(gcode.list())
1486 elif self._wizardState == 7:
1488 n = int(self.textEntry.GetValue()) - 1
1491 x = profile.getMachineSettingFloat('extruder_offset_x1')
1493 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1494 self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1495 self.textEntry.SetValue('10')
1496 self._wizardState = 8
1497 elif self._wizardState == 8:
1499 n = int(self.textEntry.GetValue()) - 1
1502 y = profile.getMachineSettingFloat('extruder_offset_y1')
1504 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1505 self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1506 self.infoBox.SetReadyIndicator()
1507 self._wizardState = 8
1509 self.resumeButton.Enable(False)
1511 def mcLog(self, message):
1512 print 'Log:', message
1514 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1515 if self._wizardState == 1:
1516 if temp[0] >= 210 and temp[1] >= 210:
1517 self._wizardState = 2
1518 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1519 wx.CallAfter(self.resumeButton.Enable, True)
1520 wx.CallAfter(self.resumeButton.SetFocus)
1522 def mcStateChange(self, state):
1523 if self.comm is None:
1525 if self.comm.isOperational():
1526 if self._wizardState == 0:
1527 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1528 self.comm.sendCommand('M105')
1529 self.comm.sendCommand('M104 S220 T0')
1530 self.comm.sendCommand('M104 S220 T1')
1531 self.comm.sendCommand('G28')
1532 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1533 self._wizardState = 1
1534 if not self.comm.isPrinting():
1535 if self._wizardState == 3:
1536 self._wizardState = 4
1537 wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1538 wx.CallAfter(self.textEntry.SetValue, '0.0')
1539 wx.CallAfter(self.textEntry.Enable, True)
1540 wx.CallAfter(self.resumeButton.Enable, True)
1541 wx.CallAfter(self.resumeButton.SetFocus)
1542 elif self._wizardState == 6:
1543 self._wizardState = 7
1544 wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1545 wx.CallAfter(self.textEntry.SetValue, '10')
1546 wx.CallAfter(self.textEntry.Enable, True)
1547 wx.CallAfter(self.resumeButton.Enable, True)
1548 wx.CallAfter(self.resumeButton.SetFocus)
1550 elif self.comm.isError():
1551 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1553 def mcMessage(self, message):
1556 def mcProgress(self, lineNr):
1559 def mcZChange(self, newZ):
1562 class bedLevelWizard(wx.wizard.Wizard):
1564 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1566 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1567 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1569 self.mainPage = bedLevelWizardMain(self)
1570 self.headOffsetCalibration = None
1572 self.FitToPage(self.mainPage)
1573 self.GetPageAreaSizer().Add(self.mainPage)
1575 self.RunWizard(self.mainPage)
1578 def OnPageChanging(self, e):
1579 e.GetPage().StoreData()
1581 def OnPageChanged(self, e):
1582 if e.GetPage().AllowNext():
1583 self.FindWindowById(wx.ID_FORWARD).Enable()
1585 self.FindWindowById(wx.ID_FORWARD).Disable()
1586 if e.GetPage().AllowBack():
1587 self.FindWindowById(wx.ID_BACKWARD).Enable()
1589 self.FindWindowById(wx.ID_BACKWARD).Disable()
1591 class headOffsetWizard(wx.wizard.Wizard):
1593 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1595 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1596 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1598 self.mainPage = headOffsetCalibrationPage(self)
1600 self.FitToPage(self.mainPage)
1601 self.GetPageAreaSizer().Add(self.mainPage)
1603 self.RunWizard(self.mainPage)
1606 def OnPageChanging(self, e):
1607 e.GetPage().StoreData()
1609 def OnPageChanged(self, e):
1610 if e.GetPage().AllowNext():
1611 self.FindWindowById(wx.ID_FORWARD).Enable()
1613 self.FindWindowById(wx.ID_FORWARD).Disable()
1614 if e.GetPage().AllowBack():
1615 self.FindWindowById(wx.ID_BACKWARD).Enable()
1617 self.FindWindowById(wx.ID_BACKWARD).Disable()