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('extruder_head_size_min_x', '40')
522 profile.putMachineSetting('extruder_head_size_max_x', '75')
523 profile.putMachineSetting('extruder_head_size_min_y', '25')
524 profile.putMachineSetting('extruder_head_size_max_y', '55')
525 profile.putMachineSetting('extruder_head_size_height', '17')
527 profile.putMachineSetting('machine_center_is_zero', 'False')
528 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
529 profile.putMachineSetting('has_heated_bed', 'True')
530 profile.putMachineSetting('extruder_head_size_min_x', '0.0')
531 profile.putMachineSetting('extruder_head_size_min_y', '0.0')
532 profile.putMachineSetting('extruder_head_size_max_x', '0.0')
533 profile.putMachineSetting('extruder_head_size_max_y', '0.0')
534 profile.putMachineSetting('extruder_head_size_height', '0.0')
535 profile.putPreference('startMode', 'Simple')
537 profile.putMachineSetting('machine_width', '80')
538 profile.putMachineSetting('machine_depth', '80')
539 profile.putMachineSetting('machine_height', '60')
540 profile.putMachineSetting('machine_name', 'reprap')
541 profile.putMachineSetting('machine_type', 'reprap')
542 profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
543 profile.putPreference('startMode', 'Normal')
544 profile.putProfileSetting('nozzle_size', '0.5')
545 profile.checkAndUpdateMachineName()
546 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
548 class SelectParts(InfoPage):
549 def __init__(self, parent):
550 super(SelectParts, self).__init__(parent, _("Select upgraded parts you have"))
551 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."))
553 self.springExtruder = self.AddCheckbox(_("Extruder drive upgrade"))
554 self.heatedBedKit = self.AddCheckbox(_("Heated printer bed (kit)"))
555 self.heatedBed = self.AddCheckbox(_("Heated printer bed (self built)"))
556 self.dualExtrusion = self.AddCheckbox(_("Dual extrusion (experimental)"))
558 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."))
559 self.AddText(_("This upgrade can be bought from the Ultimaker webshop\nor found on thingiverse as thing:26094"))
560 self.springExtruder.SetValue(True)
563 profile.putMachineSetting('ultimaker_extruder_upgrade', str(self.springExtruder.GetValue()))
564 if self.heatedBed.GetValue() or self.heatedBedKit.GetValue():
565 profile.putMachineSetting('has_heated_bed', 'True')
567 profile.putMachineSetting('has_heated_bed', 'False')
568 if self.dualExtrusion.GetValue():
569 profile.putMachineSetting('extruder_amount', '2')
570 profile.putMachineSetting('machine_depth', '195')
572 profile.putMachineSetting('extruder_amount', '1')
573 if profile.getMachineSetting('ultimaker_extruder_upgrade') == 'True':
574 profile.putProfileSetting('retraction_enable', 'True')
576 profile.putProfileSetting('retraction_enable', 'False')
579 class UltimakerFirmwareUpgradePage(InfoPage):
580 def __init__(self, parent):
581 super(UltimakerFirmwareUpgradePage, self).__init__(parent, _("Upgrade Ultimaker Firmware"))
582 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."))
583 self.AddHiddenSeperator()
584 self.AddText(_("The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier."))
585 self.AddHiddenSeperator()
586 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."))
587 upgradeButton, skipUpgradeButton = self.AddDualButton(_('Upgrade to Marlin firmware'), _('Skip upgrade'))
588 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
589 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
590 self.AddHiddenSeperator()
591 if profile.getMachineSetting('machine_type') == 'ultimaker':
592 self.AddText(_("Do not upgrade to this firmware if:"))
593 self.AddText(_("* You have an older machine based on ATMega1280 (Rev 1 machine)"))
594 self.AddText(_("* Build your own heated bed"))
595 self.AddText(_("* Have other changes in the firmware"))
596 # button = self.AddButton('Goto this page for a custom firmware')
597 # button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
602 def OnUpgradeClick(self, e):
603 if firmwareInstall.InstallFirmware():
604 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
606 def OnSkipClick(self, e):
607 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
608 self.GetParent().ShowPage(self.GetNext())
610 def OnUrlClick(self, e):
611 webbrowser.open('http://marlinbuilder.robotfuzz.com/')
613 class UltimakerCheckupPage(InfoPage):
614 def __init__(self, parent):
615 super(UltimakerCheckupPage, self).__init__(parent, _("Ultimaker Checkup"))
617 self.checkBitmap = wx.Bitmap(resources.getPathForImage('checkmark.png'))
618 self.crossBitmap = wx.Bitmap(resources.getPathForImage('cross.png'))
619 self.unknownBitmap = wx.Bitmap(resources.getPathForImage('question.png'))
620 self.endStopNoneBitmap = wx.Bitmap(resources.getPathForImage('endstop_none.png'))
621 self.endStopXMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmin.png'))
622 self.endStopXMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_xmax.png'))
623 self.endStopYMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymin.png'))
624 self.endStopYMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_ymax.png'))
625 self.endStopZMinBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmin.png'))
626 self.endStopZMaxBitmap = wx.Bitmap(resources.getPathForImage('endstop_zmax.png'))
629 _("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."))
630 b1, b2 = self.AddDualButton(_("Run checks"), _("Skip checks"))
631 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
632 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
634 self.commState = self.AddCheckmark(_("Communication:"), self.unknownBitmap)
635 self.tempState = self.AddCheckmark(_("Temperature:"), self.unknownBitmap)
636 self.stopState = self.AddCheckmark(_("Endstops:"), self.unknownBitmap)
638 self.infoBox = self.AddInfoBox()
639 self.machineState = self.AddText("")
640 self.temperatureLabel = self.AddText("")
641 self.errorLogButton = self.AddButton(_("Show error log"))
642 self.errorLogButton.Show(False)
644 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
646 self.xMinStop = False
647 self.xMaxStop = False
648 self.yMinStop = False
649 self.yMaxStop = False
650 self.zMinStop = False
651 self.zMaxStop = False
653 self.Bind(wx.EVT_BUTTON, self.OnErrorLog, self.errorLogButton)
656 if self.comm is not None:
660 self.endstopBitmap.Show(False)
663 def OnSkipClick(self, e):
664 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
665 self.GetParent().ShowPage(self.GetNext())
667 def OnCheckClick(self, e=None):
668 self.errorLogButton.Show(False)
669 if self.comm is not None:
673 wx.CallAfter(self.OnCheckClick)
675 self.infoBox.SetBusy(_("Connecting to machine."))
676 self.commState.SetBitmap(self.unknownBitmap)
677 self.tempState.SetBitmap(self.unknownBitmap)
678 self.stopState.SetBitmap(self.unknownBitmap)
679 self.checkupState = 0
680 self.checkExtruderNr = 0
681 self.comm = machineCom.MachineCom(callbackObject=self)
683 def OnErrorLog(self, e):
684 printWindow.LogWindow('\n'.join(self.comm.getLog()))
686 def mcLog(self, message):
689 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
690 if not self.comm.isOperational():
692 if self.checkupState == 0:
693 self.tempCheckTimeout = 20
694 if temp[self.checkExtruderNr] > 70:
695 self.checkupState = 1
696 wx.CallAfter(self.infoBox.SetInfo, _("Cooldown before temperature check."))
697 self.comm.sendCommand("M104 S0 T%d" % (self.checkExtruderNr))
698 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
700 self.startTemp = temp[self.checkExtruderNr]
701 self.checkupState = 2
702 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
703 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
704 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
705 elif self.checkupState == 1:
706 if temp[self.checkExtruderNr] < 60:
707 self.startTemp = temp[self.checkExtruderNr]
708 self.checkupState = 2
709 wx.CallAfter(self.infoBox.SetInfo, _("Checking the heater and temperature sensor."))
710 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
711 self.comm.sendCommand('M104 S200 T%d' % (self.checkExtruderNr))
712 elif self.checkupState == 2:
713 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
714 if temp[self.checkExtruderNr] > self.startTemp + 40:
715 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
716 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
717 if self.checkExtruderNr < int(profile.getMachineSetting('extruder_amount')):
718 self.checkExtruderNr = 0
719 self.checkupState = 3
720 wx.CallAfter(self.infoBox.SetAttention, _("Please make sure none of the endstops are pressed."))
721 wx.CallAfter(self.endstopBitmap.Show, True)
722 wx.CallAfter(self.Layout)
723 self.comm.sendCommand('M119')
724 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
726 self.checkupState = 0
727 self.checkExtruderNr += 1
729 self.tempCheckTimeout -= 1
730 if self.tempCheckTimeout < 1:
731 self.checkupState = -1
732 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
733 wx.CallAfter(self.infoBox.SetError, _("Temperature measurement FAILED!"), 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
734 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
735 self.comm.sendCommand('M104 S0 T%d' % (self.checkExtruderNr))
736 elif self.checkupState >= 3 and self.checkupState < 10:
737 self.comm.sendCommand('M119')
738 wx.CallAfter(self.temperatureLabel.SetLabel, _("Head temperature: %d") % (temp[self.checkExtruderNr]))
740 def mcStateChange(self, state):
741 if self.comm is None:
743 if self.comm.isOperational():
744 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
745 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
746 elif self.comm.isError():
747 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
748 wx.CallAfter(self.infoBox.SetError, _("Failed to establish connection with the printer."), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
749 wx.CallAfter(self.endstopBitmap.Show, False)
750 wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
751 wx.CallAfter(self.errorLogButton.Show, True)
752 wx.CallAfter(self.Layout)
754 wx.CallAfter(self.machineState.SetLabel, _("Communication State: %s") % (self.comm.getStateString()))
756 def mcMessage(self, message):
757 if self.checkupState >= 3 and self.checkupState < 10 and ('_min' in message or '_max' in message):
758 for data in message.split(' '):
760 tag, value = data.split(':', 1)
762 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
764 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
766 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
768 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
770 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
772 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
774 tag, value = map(str.strip, message.split(':', 1))
776 self.xMinStop = (value == 'H' or value == 'TRIGGERED')
778 self.xMaxStop = (value == 'H' or value == 'TRIGGERED')
780 self.yMinStop = (value == 'H' or value == 'TRIGGERED')
782 self.yMaxStop = (value == 'H' or value == 'TRIGGERED')
784 self.zMinStop = (value == 'H' or value == 'TRIGGERED')
786 self.zMaxStop = (value == 'H' or value == 'TRIGGERED')
787 if 'z_max' in message:
788 self.comm.sendCommand('M119')
790 if self.checkupState == 3:
791 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
792 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
793 self.checkupState = 5
794 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
795 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
797 self.checkupState = 4
798 wx.CallAfter(self.infoBox.SetAttention, _("Please press the right X endstop."))
799 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
800 elif self.checkupState == 4:
801 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
802 self.checkupState = 5
803 wx.CallAfter(self.infoBox.SetAttention, _("Please press the left X endstop."))
804 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
805 elif self.checkupState == 5:
806 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
807 self.checkupState = 6
808 wx.CallAfter(self.infoBox.SetAttention, _("Please press the front Y endstop."))
809 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
810 elif self.checkupState == 6:
811 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
812 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
813 self.checkupState = 8
814 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
815 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
817 self.checkupState = 7
818 wx.CallAfter(self.infoBox.SetAttention, _("Please press the back Y endstop."))
819 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
820 elif self.checkupState == 7:
821 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
822 self.checkupState = 8
823 wx.CallAfter(self.infoBox.SetAttention, _("Please press the top Z endstop."))
824 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
825 elif self.checkupState == 8:
826 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
827 if profile.getMachineSetting('machine_type') == 'ultimaker_plus':
828 self.checkupState = 10
830 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
831 wx.CallAfter(self.infoBox.SetReadyIndicator)
832 wx.CallAfter(self.endstopBitmap.Show, False)
833 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
834 wx.CallAfter(self.OnSkipClick, None)
836 self.checkupState = 9
837 wx.CallAfter(self.infoBox.SetAttention, _("Please press the bottom Z endstop."))
838 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
839 elif self.checkupState == 9:
840 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
841 self.checkupState = 10
843 wx.CallAfter(self.infoBox.SetInfo, _("Checkup finished"))
844 wx.CallAfter(self.infoBox.SetReadyIndicator)
845 wx.CallAfter(self.endstopBitmap.Show, False)
846 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
847 wx.CallAfter(self.OnSkipClick, None)
849 def mcProgress(self, lineNr):
852 def mcZChange(self, newZ):
856 class UltimakerCalibrationPage(InfoPage):
857 def __init__(self, parent):
858 super(UltimakerCalibrationPage, self).__init__(parent, _("Ultimaker Calibration"))
860 self.AddText("Your Ultimaker requires some calibration.")
861 self.AddText("This calibration is needed for a proper extrusion amount.")
863 self.AddText("The following values are needed:")
864 self.AddText("* Diameter of filament")
865 self.AddText("* Number of steps per mm of filament extrusion")
867 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
869 self.AddText("First we need the diameter of your filament:")
870 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
872 "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.")
873 self.AddText("Note: This value can be changed later at any time.")
876 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
879 class UltimakerCalibrateStepsPerEPage(InfoPage):
880 def __init__(self, parent):
881 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, _("Ultimaker Calibration"))
883 #if profile.getMachineSetting('steps_per_e') == '0':
884 # profile.putMachineSetting('steps_per_e', '865.888')
886 self.AddText(_("Calibrating the Steps Per E requires some manual actions."))
887 self.AddText(_("First remove any filament from your machine."))
888 self.AddText(_("Next put in your filament so the tip is aligned with the\ntop of the extruder drive."))
889 self.AddText(_("We'll push the filament 100mm"))
890 self.extrudeButton = self.AddButton(_("Extrude 100mm filament"))
891 self.AddText(_("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)"))
892 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton("100", _("Save"))
893 self.AddText(_("This results in the following steps per E:"))
894 self.stepsPerEInput = self.AddTextCtrl(profile.getMachineSetting('steps_per_e'))
895 self.AddText(_("You can repeat these steps to get better calibration."))
898 _("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:"))
899 self.heatButton = self.AddButton(_("Heatup for filament removal"))
901 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
902 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
903 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
905 def OnSaveLengthClick(self, e):
906 currentEValue = float(self.stepsPerEInput.GetValue())
907 realExtrudeLength = float(self.lengthInput.GetValue())
908 newEValue = currentEValue * 100 / realExtrudeLength
909 self.stepsPerEInput.SetValue(str(newEValue))
910 self.lengthInput.SetValue("100")
912 def OnExtrudeClick(self, e):
913 t = threading.Thread(target=self.OnExtrudeRun)
917 def OnExtrudeRun(self):
918 self.heatButton.Enable(False)
919 self.extrudeButton.Enable(False)
920 currentEValue = float(self.stepsPerEInput.GetValue())
921 self.comm = machineCom.MachineCom()
922 if not self.comm.isOpen():
924 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
925 'Printer error', wx.OK | wx.ICON_INFORMATION)
926 self.heatButton.Enable(True)
927 self.extrudeButton.Enable(True)
930 line = self.comm.readline()
935 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
938 self.sendGCommand('M302') #Disable cold extrusion protection
939 self.sendGCommand("M92 E%f" % (currentEValue))
940 self.sendGCommand("G92 E0")
941 self.sendGCommand("G1 E100 F600")
944 self.extrudeButton.Enable()
945 self.heatButton.Enable()
947 def OnHeatClick(self, e):
948 t = threading.Thread(target=self.OnHeatRun)
953 self.heatButton.Enable(False)
954 self.extrudeButton.Enable(False)
955 self.comm = machineCom.MachineCom()
956 if not self.comm.isOpen():
958 _("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable"),
959 'Printer error', wx.OK | wx.ICON_INFORMATION)
960 self.heatButton.Enable(True)
961 self.extrudeButton.Enable(True)
964 line = self.comm.readline()
966 self.heatButton.Enable(True)
967 self.extrudeButton.Enable(True)
971 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
974 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
976 'Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)',
977 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
978 self.sendGCommand('M104 S0')
981 self.heatButton.Enable(True)
982 self.extrudeButton.Enable(True)
984 def sendGCommand(self, cmd):
985 self.comm.sendCommand(cmd) #Disable cold extrusion protection
987 line = self.comm.readline()
990 if line.startswith('ok'):
994 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
996 class Ultimaker2ReadyPage(InfoPage):
997 def __init__(self, parent):
998 super(Ultimaker2ReadyPage, self).__init__(parent, _("Ultimaker2"))
999 self.AddText(_('Congratulations on your the purchase of your brand new Ultimaker2.'))
1000 self.AddText(_('Cura is now ready to be used with your Ultimaker2.'))
1003 class LulzbotReadyPage(InfoPage):
1004 def __init__(self, parent):
1005 super(LulzbotReadyPage, self).__init__(parent, _("LulzBot TAZ/Mini"))
1006 self.AddText(_('Cura is now ready to be used with your LulzBot 3D printer.'))
1008 self.AddText(_('For more information about using Cura with your LulzBot'))
1009 self.AddText(_('3D printer, please visit www.LulzBot.com/cura'))
1012 class Taz5NozzleSelectPage(InfoPage):
1013 url='http://lulzbot.com/fakeurl'
1015 def __init__(self, parent):
1016 super(Taz5NozzleSelectPage, self).__init__(parent, _("LulzBot TAZ5"))
1017 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1019 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1020 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
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.Bind(wx.EVT_RADIOBUTTON, self.OnNozzleSelect)
1026 self.Nozzle50Radio = self.AddRadioButton("0.5 mm")
1027 self.Nozzle50Radio.Bind(wx.EVT_RADIOBUTTON, self.OnNozzleSelect)
1028 self.Nozzle50Radio.SetValue(True)
1029 self.AddText(_(' '))
1032 self.AddText(_('If you are not sure which nozzle size you have please check this webpage: '))
1033 button = self.AddButton(Taz5NozzleSelectPage.url)
1034 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
1036 def OnUrlClick(self, e):
1037 webbrowser.open(Taz5NozzleSelectPage.url)
1039 def OnNozzleSelect(self, e):
1040 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().lulzbotReadyPage)
1042 def StoreData(self):
1043 if self.Nozzle35Radio.GetValue():
1044 profile.putProfileSetting('nozzle_size', '0.35')
1045 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.35 nozzle)')
1046 #TODO: Use existing profiles
1048 profile.putProfileSetting('nozzle_size', '0.5')
1049 profile.putMachineSetting('machine_name', 'LulzBot TAZ 5 (0.5 nozzle)')
1050 #TODO: Use new profiles
1053 def OnPageChanging(self, e):
1054 e.GetPage().StoreData()
1056 def OnCancel(self, e):
1057 profile.setActiveMachine(self._old_machine_index)
1059 class ConfigWizard(wx.wizard.Wizard):
1060 def __init__(self, addNew = False):
1061 super(ConfigWizard, self).__init__(None, -1, _("Configuration Wizard"))
1063 self._old_machine_index = int(profile.getPreferenceFloat('active_machine'))
1065 profile.setActiveMachine(profile.getMachineCount())
1067 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1068 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1069 self.Bind(wx.wizard.EVT_WIZARD_CANCEL, self.OnCancel)
1071 self.machineSelectPage = MachineSelectPage(self)
1072 self.ultimakerSelectParts = SelectParts(self)
1073 self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
1074 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
1075 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
1076 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
1077 self.bedLevelPage = bedLevelWizardMain(self)
1078 self.headOffsetCalibration = headOffsetCalibrationPage(self)
1079 self.printrbotSelectType = PrintrbotPage(self)
1080 self.otherMachineSelectPage = OtherMachineSelectPage(self)
1081 self.customRepRapInfoPage = CustomRepRapInfoPage(self)
1082 self.otherMachineInfoPage = OtherMachineInfoPage(self)
1084 self.ultimaker2ReadyPage = Ultimaker2ReadyPage(self)
1085 self.lulzbotReadyPage = LulzbotReadyPage(self)
1086 self.taz5NozzleSelectPage = Taz5NozzleSelectPage(self)
1088 #wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimaker2ReadyPage)
1089 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
1090 wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
1091 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
1092 wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
1093 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
1094 wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage)
1095 wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage)
1096 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.taz5NozzleSelectPage)
1097 wx.wizard.WizardPageSimple.Chain(self.taz5NozzleSelectPage, self.lulzbotReadyPage)
1099 self.FitToPage(self.machineSelectPage)
1100 self.GetPageAreaSizer().Add(self.machineSelectPage)
1102 self.RunWizard(self.machineSelectPage)
1105 def OnPageChanging(self, e):
1106 e.GetPage().StoreData()
1108 def OnPageChanged(self, e):
1109 if e.GetPage().AllowNext():
1110 self.FindWindowById(wx.ID_FORWARD).Enable()
1112 self.FindWindowById(wx.ID_FORWARD).Disable()
1113 if e.GetPage().AllowBack():
1114 self.FindWindowById(wx.ID_BACKWARD).Enable()
1116 self.FindWindowById(wx.ID_BACKWARD).Disable()
1118 def OnCancel(self, e):
1119 profile.setActiveMachine(self._old_machine_index)
1121 class bedLevelWizardMain(InfoPage):
1122 def __init__(self, parent):
1123 super(bedLevelWizardMain, self).__init__(parent, _("Bed leveling wizard"))
1125 self.AddText(_('This wizard will help you in leveling your printer bed'))
1127 self.AddText(_('It will do the following steps'))
1128 self.AddText(_('* Move the printer head to each corner'))
1129 self.AddText(_(' and let you adjust the height of the bed to the nozzle'))
1130 self.AddText(_('* Print a line around the bed to check if it is level'))
1133 self.connectButton = self.AddButton(_('Connect to printer'))
1136 self.infoBox = self.AddInfoBox()
1137 self.resumeButton = self.AddButton(_('Resume'))
1138 self.upButton, self.downButton = self.AddDualButton(_('Up 0.2mm'), _('Down 0.2mm'))
1139 self.upButton2, self.downButton2 = self.AddDualButton(_('Up 10mm'), _('Down 10mm'))
1140 self.resumeButton.Enable(False)
1142 self.upButton.Enable(False)
1143 self.downButton.Enable(False)
1144 self.upButton2.Enable(False)
1145 self.downButton2.Enable(False)
1147 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1148 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1149 self.Bind(wx.EVT_BUTTON, self.OnBedUp, self.upButton)
1150 self.Bind(wx.EVT_BUTTON, self.OnBedDown, self.downButton)
1151 self.Bind(wx.EVT_BUTTON, self.OnBedUp2, self.upButton2)
1152 self.Bind(wx.EVT_BUTTON, self.OnBedDown2, self.downButton2)
1154 def OnConnect(self, e = None):
1155 if self.comm is not None:
1159 wx.CallAfter(self.OnConnect)
1161 self.connectButton.Enable(False)
1162 self.comm = machineCom.MachineCom(callbackObject=self)
1163 self.infoBox.SetBusy(_('Connecting to machine.'))
1164 self._wizardState = 0
1166 def OnBedUp(self, e):
1167 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1168 self.comm.sendCommand('G92 Z10')
1169 self.comm.sendCommand('G1 Z9.8 F%d' % (feedZ))
1170 self.comm.sendCommand('M400')
1172 def OnBedDown(self, e):
1173 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1174 self.comm.sendCommand('G92 Z10')
1175 self.comm.sendCommand('G1 Z10.2 F%d' % (feedZ))
1176 self.comm.sendCommand('M400')
1178 def OnBedUp2(self, e):
1179 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1180 self.comm.sendCommand('G92 Z10')
1181 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1182 self.comm.sendCommand('M400')
1184 def OnBedDown2(self, e):
1185 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1186 self.comm.sendCommand('G92 Z10')
1187 self.comm.sendCommand('G1 Z20 F%d' % (feedZ))
1188 self.comm.sendCommand('M400')
1190 def AllowNext(self):
1191 if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
1192 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
1195 def OnResume(self, e):
1196 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1197 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1198 if self._wizardState == -1:
1199 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer...'))
1200 wx.CallAfter(self.upButton.Enable, False)
1201 wx.CallAfter(self.downButton.Enable, False)
1202 wx.CallAfter(self.upButton2.Enable, False)
1203 wx.CallAfter(self.downButton2.Enable, False)
1204 self.comm.sendCommand('M105')
1205 self.comm.sendCommand('G28')
1206 self._wizardState = 1
1207 elif self._wizardState == 2:
1208 if profile.getMachineSetting('has_heated_bed') == 'True':
1209 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back center...'))
1210 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1211 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') / 2.0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1212 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1213 self.comm.sendCommand('M400')
1214 self._wizardState = 3
1216 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back left corner...'))
1217 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1218 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
1219 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1220 self.comm.sendCommand('M400')
1221 self._wizardState = 3
1222 elif self._wizardState == 4:
1223 if profile.getMachineSetting('has_heated_bed') == 'True':
1224 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front 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, 5, feedTravel))
1227 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1228 self.comm.sendCommand('M400')
1229 self._wizardState = 7
1231 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to back 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, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
1234 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1235 self.comm.sendCommand('M400')
1236 self._wizardState = 5
1237 elif self._wizardState == 6:
1238 wx.CallAfter(self.infoBox.SetBusy, _('Moving head to front right corner...'))
1239 self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
1240 self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
1241 self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
1242 self.comm.sendCommand('M400')
1243 self._wizardState = 7
1244 elif self._wizardState == 8:
1245 wx.CallAfter(self.infoBox.SetBusy, _('Heating up printer...'))
1246 self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
1247 self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
1248 self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
1249 self._wizardState = 9
1250 elif self._wizardState == 10:
1251 self._wizardState = 11
1252 wx.CallAfter(self.infoBox.SetInfo, _('Printing a square on the printer bed at 0.3mm height.'))
1253 feedZ = profile.getProfileSettingFloat('print_speed') * 60
1254 feedPrint = profile.getProfileSettingFloat('print_speed') * 60
1255 feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
1256 w = profile.getMachineSettingFloat('machine_width') - 10
1257 d = profile.getMachineSettingFloat('machine_depth')
1258 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1259 filamentArea = math.pi * filamentRadius * filamentRadius
1260 ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
1264 'G1 Z2 F%d' % (feedZ),
1266 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
1267 'G1 Z0.3 F%d' % (feedZ)]
1269 gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
1271 for i in xrange(0, 3):
1272 dist = 5.0 + 0.4 * float(i)
1273 eValue += (d - 2.0*dist) * ePerMM
1274 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
1275 eValue += (w - 2.0*dist) * ePerMM
1276 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
1277 eValue += (d - 2.0*dist) * ePerMM
1278 gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
1279 eValue += (w - 2.0*dist) * ePerMM
1280 gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
1282 gcodeList.append('M400')
1283 self.comm.printGCode(gcodeList)
1284 self.resumeButton.Enable(False)
1286 def mcLog(self, message):
1287 print 'Log:', message
1289 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1290 if self._wizardState == 1:
1291 self._wizardState = 2
1292 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.'))
1293 wx.CallAfter(self.resumeButton.Enable, True)
1294 elif self._wizardState == 3:
1295 self._wizardState = 4
1296 if profile.getMachineSetting('has_heated_bed') == 'True':
1297 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back screw of your printer bed\nSo the nozzle just hits the bed.'))
1299 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.'))
1300 wx.CallAfter(self.resumeButton.Enable, True)
1301 elif self._wizardState == 5:
1302 self._wizardState = 6
1303 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.'))
1304 wx.CallAfter(self.resumeButton.Enable, True)
1305 elif self._wizardState == 7:
1306 self._wizardState = 8
1307 wx.CallAfter(self.infoBox.SetAttention, _('Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.'))
1308 wx.CallAfter(self.resumeButton.Enable, True)
1309 elif self._wizardState == 9:
1310 if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
1311 wx.CallAfter(self.infoBox.SetInfo, _('Heating up printer: %d/%d') % (temp[0], profile.getProfileSettingFloat('print_temperature')))
1313 wx.CallAfter(self.infoBox.SetAttention, _('The printer is hot now. Please insert some PLA filament into the printer.'))
1314 wx.CallAfter(self.resumeButton.Enable, True)
1315 self._wizardState = 10
1317 def mcStateChange(self, state):
1318 if self.comm is None:
1320 if self.comm.isOperational():
1321 if self._wizardState == 0:
1322 wx.CallAfter(self.infoBox.SetAttention, _('Use the up/down buttons to move the bed and adjust your Z endstop.'))
1323 wx.CallAfter(self.upButton.Enable, True)
1324 wx.CallAfter(self.downButton.Enable, True)
1325 wx.CallAfter(self.upButton2.Enable, True)
1326 wx.CallAfter(self.downButton2.Enable, True)
1327 wx.CallAfter(self.resumeButton.Enable, True)
1328 self._wizardState = -1
1329 elif self._wizardState == 11 and not self.comm.isPrinting():
1330 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1331 self.comm.sendCommand('G92 E0')
1332 self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
1333 self.comm.sendCommand('M104 S0')
1334 wx.CallAfter(self.infoBox.SetInfo, _('Calibration finished.\nThe squares on the bed should slightly touch each other.'))
1335 wx.CallAfter(self.infoBox.SetReadyIndicator)
1336 wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
1337 wx.CallAfter(self.connectButton.Enable, True)
1338 self._wizardState = 12
1339 elif self.comm.isError():
1340 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1342 def mcMessage(self, message):
1345 def mcProgress(self, lineNr):
1348 def mcZChange(self, newZ):
1351 class headOffsetCalibrationPage(InfoPage):
1352 def __init__(self, parent):
1353 super(headOffsetCalibrationPage, self).__init__(parent, _("Printer head offset calibration"))
1355 self.AddText(_('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine'))
1358 self.connectButton = self.AddButton(_('Connect to printer'))
1361 self.infoBox = self.AddInfoBox()
1362 self.textEntry = self.AddTextCtrl('')
1363 self.textEntry.Enable(False)
1364 self.resumeButton = self.AddButton(_('Resume'))
1365 self.resumeButton.Enable(False)
1367 self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
1368 self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
1370 def AllowBack(self):
1373 def OnConnect(self, e = None):
1374 if self.comm is not None:
1378 wx.CallAfter(self.OnConnect)
1380 self.connectButton.Enable(False)
1381 self.comm = machineCom.MachineCom(callbackObject=self)
1382 self.infoBox.SetBusy(_('Connecting to machine.'))
1383 self._wizardState = 0
1385 def OnResume(self, e):
1386 if self._wizardState == 2:
1387 self._wizardState = 3
1388 wx.CallAfter(self.infoBox.SetBusy, _('Printing initial calibration cross'))
1390 w = profile.getMachineSettingFloat('machine_width')
1391 d = profile.getMachineSettingFloat('machine_depth')
1393 gcode = gcodeGenerator.gcodeGenerator()
1394 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1395 gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
1402 gcode.addMove(w/2, 5)
1403 gcode.addMove(z=0.2)
1405 gcode.addExtrude(w/2, d-5.0)
1407 gcode.addMove(5, d/2)
1409 gcode.addExtrude(w-5.0, d/2)
1410 gcode.addRetract(15)
1413 gcode.addMove(w/2, 5)
1415 gcode.addExtrude(w/2, d-5.0)
1417 gcode.addMove(5, d/2)
1419 gcode.addExtrude(w-5.0, d/2)
1420 gcode.addRetract(15)
1425 gcode.addCmd('M400')
1427 self.comm.printGCode(gcode.list())
1428 self.resumeButton.Enable(False)
1429 elif self._wizardState == 4:
1431 float(self.textEntry.GetValue())
1434 profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
1435 self._wizardState = 5
1436 self.infoBox.SetAttention(_('Please measure the distance between the horizontal lines in millimeters.'))
1437 self.textEntry.SetValue('0.0')
1438 self.textEntry.Enable(True)
1439 elif self._wizardState == 5:
1441 float(self.textEntry.GetValue())
1444 profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
1445 self._wizardState = 6
1446 self.infoBox.SetBusy(_('Printing the fine calibration lines.'))
1447 self.textEntry.SetValue('')
1448 self.textEntry.Enable(False)
1449 self.resumeButton.Enable(False)
1451 x = profile.getMachineSettingFloat('extruder_offset_x1')
1452 y = profile.getMachineSettingFloat('extruder_offset_y1')
1453 gcode = gcodeGenerator.gcodeGenerator()
1454 gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
1455 gcode.setPrintSpeed(25)
1458 gcode.addMove(50, 40, 0.2)
1460 for n in xrange(0, 10):
1461 gcode.addExtrude(50 + n * 10, 150)
1462 gcode.addExtrude(50 + n * 10 + 5, 150)
1463 gcode.addExtrude(50 + n * 10 + 5, 40)
1464 gcode.addExtrude(50 + n * 10 + 10, 40)
1465 gcode.addMove(40, 50)
1466 for n in xrange(0, 10):
1467 gcode.addExtrude(150, 50 + n * 10)
1468 gcode.addExtrude(150, 50 + n * 10 + 5)
1469 gcode.addExtrude(40, 50 + n * 10 + 5)
1470 gcode.addExtrude(40, 50 + n * 10 + 10)
1471 gcode.addRetract(15)
1474 gcode.addMove(50 - x, 30 - y, 0.2)
1476 for n in xrange(0, 10):
1477 gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
1478 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
1479 gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
1480 gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
1481 gcode.addMove(30 - x, 50 - y, 0.2)
1482 for n in xrange(0, 10):
1483 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
1484 gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1485 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
1486 gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
1487 gcode.addRetract(15)
1489 gcode.addCmd('M400')
1490 gcode.addCmd('M104 T0 S0')
1491 gcode.addCmd('M104 T1 S0')
1492 self.comm.printGCode(gcode.list())
1493 elif self._wizardState == 7:
1495 n = int(self.textEntry.GetValue()) - 1
1498 x = profile.getMachineSettingFloat('extruder_offset_x1')
1500 profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
1501 self.infoBox.SetAttention(_('Which horizontal line number lays perfect on top of each other? Front most line is zero.'))
1502 self.textEntry.SetValue('10')
1503 self._wizardState = 8
1504 elif self._wizardState == 8:
1506 n = int(self.textEntry.GetValue()) - 1
1509 y = profile.getMachineSettingFloat('extruder_offset_y1')
1511 profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
1512 self.infoBox.SetInfo(_('Calibration finished. Offsets are: %s %s') % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
1513 self.infoBox.SetReadyIndicator()
1514 self._wizardState = 8
1516 self.resumeButton.Enable(False)
1518 def mcLog(self, message):
1519 print 'Log:', message
1521 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
1522 if self._wizardState == 1:
1523 if temp[0] >= 210 and temp[1] >= 210:
1524 self._wizardState = 2
1525 wx.CallAfter(self.infoBox.SetAttention, _('Please load both extruders with PLA.'))
1526 wx.CallAfter(self.resumeButton.Enable, True)
1527 wx.CallAfter(self.resumeButton.SetFocus)
1529 def mcStateChange(self, state):
1530 if self.comm is None:
1532 if self.comm.isOperational():
1533 if self._wizardState == 0:
1534 wx.CallAfter(self.infoBox.SetInfo, _('Homing printer and heating up both extruders.'))
1535 self.comm.sendCommand('M105')
1536 self.comm.sendCommand('M104 S220 T0')
1537 self.comm.sendCommand('M104 S220 T1')
1538 self.comm.sendCommand('G28')
1539 self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
1540 self._wizardState = 1
1541 if not self.comm.isPrinting():
1542 if self._wizardState == 3:
1543 self._wizardState = 4
1544 wx.CallAfter(self.infoBox.SetAttention, _('Please measure the distance between the vertical lines in millimeters.'))
1545 wx.CallAfter(self.textEntry.SetValue, '0.0')
1546 wx.CallAfter(self.textEntry.Enable, True)
1547 wx.CallAfter(self.resumeButton.Enable, True)
1548 wx.CallAfter(self.resumeButton.SetFocus)
1549 elif self._wizardState == 6:
1550 self._wizardState = 7
1551 wx.CallAfter(self.infoBox.SetAttention, _('Which vertical line number lays perfect on top of each other? Leftmost line is zero.'))
1552 wx.CallAfter(self.textEntry.SetValue, '10')
1553 wx.CallAfter(self.textEntry.Enable, True)
1554 wx.CallAfter(self.resumeButton.Enable, True)
1555 wx.CallAfter(self.resumeButton.SetFocus)
1557 elif self.comm.isError():
1558 wx.CallAfter(self.infoBox.SetError, _('Failed to establish connection with the printer.'), 'http://wiki.ultimaker.com/Cura:_Connection_problems')
1560 def mcMessage(self, message):
1563 def mcProgress(self, lineNr):
1566 def mcZChange(self, newZ):
1569 class bedLevelWizard(wx.wizard.Wizard):
1571 super(bedLevelWizard, self).__init__(None, -1, _("Bed leveling wizard"))
1573 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1574 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1576 self.mainPage = bedLevelWizardMain(self)
1577 self.headOffsetCalibration = None
1579 self.FitToPage(self.mainPage)
1580 self.GetPageAreaSizer().Add(self.mainPage)
1582 self.RunWizard(self.mainPage)
1585 def OnPageChanging(self, e):
1586 e.GetPage().StoreData()
1588 def OnPageChanged(self, e):
1589 if e.GetPage().AllowNext():
1590 self.FindWindowById(wx.ID_FORWARD).Enable()
1592 self.FindWindowById(wx.ID_FORWARD).Disable()
1593 if e.GetPage().AllowBack():
1594 self.FindWindowById(wx.ID_BACKWARD).Enable()
1596 self.FindWindowById(wx.ID_BACKWARD).Disable()
1598 class headOffsetWizard(wx.wizard.Wizard):
1600 super(headOffsetWizard, self).__init__(None, -1, _("Head offset wizard"))
1602 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
1603 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
1605 self.mainPage = headOffsetCalibrationPage(self)
1607 self.FitToPage(self.mainPage)
1608 self.GetPageAreaSizer().Add(self.mainPage)
1610 self.RunWizard(self.mainPage)
1613 def OnPageChanging(self, e):
1614 e.GetPage().StoreData()
1616 def OnPageChanged(self, e):
1617 if e.GetPage().AllowNext():
1618 self.FindWindowById(wx.ID_FORWARD).Enable()
1620 self.FindWindowById(wx.ID_FORWARD).Disable()
1621 if e.GetPage().AllowBack():
1622 self.FindWindowById(wx.ID_BACKWARD).Enable()
1624 self.FindWindowById(wx.ID_BACKWARD).Disable()