1 from __future__ import absolute_import
\r
4 import wx, os, platform, types, webbrowser, threading, time, re
\r
7 from gui import firmwareInstall
\r
8 from gui import toolbarUtil
\r
9 from util import machineCom
\r
10 from util import profile
\r
12 class InfoBox(wx.Panel):
\r
13 def __init__(self, parent):
\r
14 super(InfoBox, self).__init__(parent)
\r
15 self.SetBackgroundColour('#FFFF80')
\r
17 self.sizer = wx.GridBagSizer(5, 5)
\r
18 self.SetSizer(self.sizer)
\r
20 self.attentionBitmap = toolbarUtil.getBitmapImage('attention.png')
\r
21 self.errorBitmap = toolbarUtil.getBitmapImage('error.png')
\r
22 self.readyBitmap = toolbarUtil.getBitmapImage('ready.png')
\r
23 self.busyBitmap = [toolbarUtil.getBitmapImage('busy-0.png'), toolbarUtil.getBitmapImage('busy-1.png'), toolbarUtil.getBitmapImage('busy-2.png'), toolbarUtil.getBitmapImage('busy-3.png')]
\r
25 self.bitmap = wx.StaticBitmap(self, -1, wx.EmptyBitmapRGBA(24, 24, red=255, green=255, blue=255, alpha=1))
\r
26 self.text = wx.StaticText(self, -1, '')
\r
27 self.sizer.Add(self.bitmap, pos=(0,0), flag=wx.ALL, border=5)
\r
28 self.sizer.Add(self.text, pos=(0,1), flag=wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL, border=5)
\r
30 self.busyState = None
\r
31 self.timer = wx.Timer(self)
\r
32 self.Bind(wx.EVT_TIMER, self.doBusyUpdate, self.timer)
\r
33 self.timer.Start(100)
\r
35 def SetInfo(self, info):
\r
36 self.SetBackgroundColour('#FFFF80')
\r
37 self.text.SetLabel(info)
\r
40 def SetError(self, info):
\r
41 self.SetBackgroundColour('#FF8080')
\r
42 self.text.SetLabel(info)
\r
43 self.SetErrorIndicator()
\r
46 def SetAttention(self, info):
\r
47 self.SetBackgroundColour('#FFFF80')
\r
48 self.text.SetLabel(info)
\r
49 self.SetAttentionIndicator()
\r
52 def SetBusyIndicator(self):
\r
54 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
\r
56 def doBusyUpdate(self, e):
\r
57 if self.busyState == None:
\r
60 if self.busyState >= len(self.busyBitmap):
\r
62 self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
\r
64 def SetReadyIndicator(self):
\r
65 self.busyState = None
\r
66 self.bitmap.SetBitmap(self.readyBitmap)
\r
68 def SetErrorIndicator(self):
\r
69 self.busyState = None
\r
70 self.bitmap.SetBitmap(self.errorBitmap)
\r
72 def SetAttentionIndicator(self):
\r
73 self.busyState = None
\r
74 self.bitmap.SetBitmap(self.attentionBitmap)
\r
76 class InfoPage(wx.wizard.WizardPageSimple):
\r
77 def __init__(self, parent, title):
\r
78 wx.wizard.WizardPageSimple.__init__(self, parent)
\r
80 sizer = wx.GridBagSizer(5, 5)
\r
82 self.SetSizer(sizer)
\r
84 title = wx.StaticText(self, -1, title)
\r
85 title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
\r
86 sizer.Add(title, pos=(0, 0), span=(1,2), flag=wx.ALIGN_CENTRE|wx.ALL)
\r
87 sizer.Add(wx.StaticLine(self, -1), pos=(1,0), span=(1,2), flag=wx.EXPAND|wx.ALL)
\r
88 sizer.AddGrowableCol(1)
\r
92 def AddText(self,info):
\r
93 text = wx.StaticText(self, -1, info)
\r
94 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,2), flag=wx.LEFT|wx.RIGHT)
\r
98 def AddSeperator(self):
\r
99 self.GetSizer().Add(wx.StaticLine(self, -1), pos=(self.rowNr, 0), span=(1,2), flag=wx.EXPAND|wx.ALL)
\r
102 def AddHiddenSeperator(self):
\r
105 def AddInfoBox(self):
\r
106 infoBox = InfoBox(self)
\r
107 self.GetSizer().Add(infoBox, pos=(self.rowNr, 0), span=(1,2), flag=wx.LEFT|wx.RIGHT|wx.EXPAND)
\r
111 def AddRadioButton(self, label, style = 0):
\r
112 radio = wx.RadioButton(self, -1, label, style=style)
\r
113 self.GetSizer().Add(radio, pos=(self.rowNr, 0), span=(1,2), flag=wx.EXPAND|wx.ALL)
\r
117 def AddCheckbox(self, label, checked = False):
\r
118 check = wx.CheckBox(self, -1)
\r
119 text = wx.StaticText(self, -1, label)
\r
120 check.SetValue(checked)
\r
121 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,1), flag=wx.LEFT|wx.RIGHT)
\r
122 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1,2), flag=wx.ALL)
\r
126 def AddButton(self, label):
\r
127 button = wx.Button(self, -1, label)
\r
128 self.GetSizer().Add(button, pos=(self.rowNr, 0), span=(1,2), flag=wx.LEFT)
\r
132 def AddDualButton(self, label1, label2):
\r
133 button1 = wx.Button(self, -1, label1)
\r
134 self.GetSizer().Add(button1, pos=(self.rowNr, 0), flag=wx.RIGHT)
\r
135 button2 = wx.Button(self, -1, label2)
\r
136 self.GetSizer().Add(button2, pos=(self.rowNr, 1))
\r
138 return button1, button2
\r
140 def AddTextCtrl(self, value):
\r
141 ret = wx.TextCtrl(self, -1, value)
\r
142 self.GetSizer().Add(ret, pos=(self.rowNr, 0), span=(1,2), flag=wx.LEFT)
\r
146 def AddLabelTextCtrl(self, info, value):
\r
147 text = wx.StaticText(self, -1, info)
\r
148 ret = wx.TextCtrl(self, -1, value)
\r
149 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,1), flag=wx.LEFT)
\r
150 self.GetSizer().Add(ret, pos=(self.rowNr, 1), span=(1,1), flag=wx.LEFT)
\r
154 def AddTextCtrlButton(self, value, buttonText):
\r
155 text = wx.TextCtrl(self, -1, value)
\r
156 button = wx.Button(self, -1, buttonText)
\r
157 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,1), flag=wx.LEFT)
\r
158 self.GetSizer().Add(button, pos=(self.rowNr, 1), span=(1,1), flag=wx.LEFT)
\r
160 return text, button
\r
162 def AddBitmap(self, bitmap):
\r
163 bitmap = wx.StaticBitmap(self, -1, bitmap)
\r
164 self.GetSizer().Add(bitmap, pos=(self.rowNr, 0), span=(1,2), flag=wx.LEFT|wx.RIGHT)
\r
168 def AddCheckmark(self, label, bitmap):
\r
169 check = wx.StaticBitmap(self, -1, bitmap)
\r
170 text = wx.StaticText(self, -1, label)
\r
171 self.GetSizer().Add(text, pos=(self.rowNr, 0), span=(1,1), flag=wx.LEFT|wx.RIGHT)
\r
172 self.GetSizer().Add(check, pos=(self.rowNr, 1), span=(1,1), flag=wx.ALL)
\r
176 def AllowNext(self):
\r
179 def StoreData(self):
\r
182 class FirstInfoPage(InfoPage):
\r
183 def __init__(self, parent):
\r
184 super(FirstInfoPage, self).__init__(parent, "First time run wizard")
\r
185 self.AddText('Welcome, and thanks for trying Cura!')
\r
186 self.AddSeperator()
\r
187 self.AddText('This wizard will help you with the following steps:')
\r
188 self.AddText('* Configure Cura for your machine')
\r
189 self.AddText('* Upgrade your firmware')
\r
190 self.AddText('* Check if your machine is working safely')
\r
191 #self.AddText('* Calibrate your machine')
\r
192 #self.AddText('* Do your first print')
\r
194 class RepRapInfoPage(InfoPage):
\r
195 def __init__(self, parent):
\r
196 super(RepRapInfoPage, self).__init__(parent, "RepRap information")
\r
197 self.AddText('RepRap machines are vastly different, and there is no\ndefault configuration in Cura for any of them.')
\r
198 self.AddText('If you like a default profile for your machine added,\nthen make an issue on github.')
\r
199 self.AddSeperator()
\r
200 self.AddText('You will have to manually install Marlin or Sprinter firmware.')
\r
201 self.AddSeperator()
\r
202 self.machineWidth = self.AddLabelTextCtrl('Machine width (mm)', '80')
\r
203 self.machineDepth = self.AddLabelTextCtrl('Machine depth (mm)', '80')
\r
204 self.machineHeight = self.AddLabelTextCtrl('Machine height (mm)', '60')
\r
205 self.nozzleSize = self.AddLabelTextCtrl('Nozzle size (mm)', '0.5')
\r
206 self.heatedBed = self.AddCheckbox('Heated bed')
\r
208 def StoreData(self):
\r
209 profile.putPreference('machine_width', self.machineWidth.GetValue())
\r
210 profile.putPreference('machine_depth', self.machineDepth.GetValue())
\r
211 profile.putPreference('machine_height', self.machineHeight.GetValue())
\r
212 profile.putProfileSetting('nozzle_size', self.nozzleSize.GetValue())
\r
213 profile.putProfileSetting('machine_center_x', profile.getPreferenceFloat('machine_width') / 2)
\r
214 profile.putProfileSetting('machine_center_y', profile.getPreferenceFloat('machine_depth') / 2)
\r
215 profile.putProfileSetting('wall_thickness', float(profile.getProfileSettingFloat('nozzle_size')) * 2)
\r
216 profile.putPreference('has_heated_bed', str(self.heatedBed.GetValue()))
\r
218 class MachineSelectPage(InfoPage):
\r
219 def __init__(self, parent):
\r
220 super(MachineSelectPage, self).__init__(parent, "Select your machine")
\r
221 self.AddText('What kind of machine do you have:')
\r
223 self.UltimakerRadio = self.AddRadioButton("Ultimaker", style=wx.RB_GROUP)
\r
224 self.UltimakerRadio.SetValue(True)
\r
225 self.UltimakerRadio.Bind(wx.EVT_RADIOBUTTON, self.OnUltimakerSelect)
\r
226 self.OtherRadio = self.AddRadioButton("Other (Ex: RepRap)")
\r
227 self.OtherRadio.Bind(wx.EVT_RADIOBUTTON, self.OnOtherSelect)
\r
229 def OnUltimakerSelect(self, e):
\r
230 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().ultimakerFirmwareUpgradePage)
\r
232 def OnOtherSelect(self, e):
\r
233 wx.wizard.WizardPageSimple.Chain(self, self.GetParent().repRapInfoPage)
\r
235 def StoreData(self):
\r
236 if self.UltimakerRadio.GetValue():
\r
237 profile.putPreference('machine_width', '205')
\r
238 profile.putPreference('machine_depth', '205')
\r
239 profile.putPreference('machine_height', '200')
\r
240 profile.putPreference('machine_type', 'ultimaker')
\r
241 profile.putProfileSetting('nozzle_size', '0.4')
\r
242 profile.putProfileSetting('machine_center_x', '100')
\r
243 profile.putProfileSetting('machine_center_y', '100')
\r
245 profile.putPreference('machine_width', '80')
\r
246 profile.putPreference('machine_depth', '80')
\r
247 profile.putPreference('machine_height', '60')
\r
248 profile.putPreference('machine_type', 'reprap')
\r
249 profile.putProfileSetting('nozzle_size', '0.5')
\r
250 profile.putProfileSetting('machine_center_x', '40')
\r
251 profile.putProfileSetting('machine_center_y', '40')
\r
252 profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
\r
254 class FirmwareUpgradePage(InfoPage):
\r
255 def __init__(self, parent):
\r
256 super(FirmwareUpgradePage, self).__init__(parent, "Upgrade Ultimaker Firmware")
\r
257 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.')
\r
258 self.AddHiddenSeperator()
\r
259 self.AddText('The firmware shipping with new Ultimakers works, but upgrades\nhave been made to make better prints, and make calibration easier.')
\r
260 self.AddHiddenSeperator()
\r
261 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.')
\r
262 upgradeButton, skipUpgradeButton = self.AddDualButton('Upgrade to Marlin firmware', 'Skip upgrade')
\r
263 upgradeButton.Bind(wx.EVT_BUTTON, self.OnUpgradeClick)
\r
264 skipUpgradeButton.Bind(wx.EVT_BUTTON, self.OnSkipClick)
\r
265 self.AddHiddenSeperator()
\r
266 self.AddText('Do not upgrade to this firmware if:')
\r
267 self.AddText('* You have an older machine based on ATMega1280')
\r
268 self.AddText('* Have other changes in the firmware')
\r
269 button = self.AddButton('Goto this page for a custom firmware')
\r
270 button.Bind(wx.EVT_BUTTON, self.OnUrlClick)
\r
272 def AllowNext(self):
\r
275 def OnUpgradeClick(self, e):
\r
276 if firmwareInstall.InstallFirmware():
\r
277 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
\r
279 def OnSkipClick(self, e):
\r
280 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
\r
282 def OnUrlClick(self, e):
\r
283 webbrowser.open('http://daid.mine.nu/~daid/marlin_build/')
\r
285 class UltimakerCheckupPage(InfoPage):
\r
286 def __init__(self, parent):
\r
287 super(UltimakerCheckupPage, self).__init__(parent, "Ultimaker Checkup")
\r
289 self.checkBitmap = toolbarUtil.getBitmapImage('checkmark.png')
\r
290 self.crossBitmap = toolbarUtil.getBitmapImage('cross.png')
\r
291 self.unknownBitmap = toolbarUtil.getBitmapImage('question.png')
\r
292 self.endStopNoneBitmap = toolbarUtil.getBitmapImage('endstop_none.png')
\r
293 self.endStopXMinBitmap = toolbarUtil.getBitmapImage('endstop_xmin.png')
\r
294 self.endStopXMaxBitmap = toolbarUtil.getBitmapImage('endstop_xmax.png')
\r
295 self.endStopYMinBitmap = toolbarUtil.getBitmapImage('endstop_ymin.png')
\r
296 self.endStopYMaxBitmap = toolbarUtil.getBitmapImage('endstop_ymax.png')
\r
297 self.endStopZMinBitmap = toolbarUtil.getBitmapImage('endstop_zmin.png')
\r
298 self.endStopZMaxBitmap = toolbarUtil.getBitmapImage('endstop_zmax.png')
\r
300 self.AddText('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.')
\r
301 b1, b2 = self.AddDualButton('Run checks', 'Skip checks')
\r
302 b1.Bind(wx.EVT_BUTTON, self.OnCheckClick)
\r
303 b2.Bind(wx.EVT_BUTTON, self.OnSkipClick)
\r
304 self.AddSeperator()
\r
305 self.commState = self.AddCheckmark('Communication:', self.unknownBitmap)
\r
306 self.tempState = self.AddCheckmark('Temperature:', self.unknownBitmap)
\r
307 self.stopState = self.AddCheckmark('Endstops:', self.unknownBitmap)
\r
308 self.AddSeperator()
\r
309 self.infoBox = self.AddInfoBox()
\r
310 self.machineState = self.AddText('')
\r
311 self.temperatureLabel = self.AddText('')
\r
312 self.AddSeperator()
\r
313 self.endstopBitmap = self.AddBitmap(self.endStopNoneBitmap)
\r
315 self.xMinStop = False
\r
316 self.xMaxStop = False
\r
317 self.yMinStop = False
\r
318 self.yMaxStop = False
\r
319 self.zMinStop = False
\r
320 self.zMaxStop = False
\r
323 if self.comm != None:
\r
326 def AllowNext(self):
\r
327 self.endstopBitmap.Show(False)
\r
330 def OnSkipClick(self, e):
\r
331 self.GetParent().FindWindowById(wx.ID_FORWARD).Enable()
\r
333 def OnCheckClick(self, e):
\r
334 if self.comm != None:
\r
337 self.infoBox.SetInfo('Connecting to machine.')
\r
338 self.infoBox.SetBusyIndicator()
\r
339 self.commState.SetBitmap(self.unknownBitmap)
\r
340 self.tempState.SetBitmap(self.unknownBitmap)
\r
341 self.stopState.SetBitmap(self.unknownBitmap)
\r
342 self.checkupState = 0
\r
343 self.comm = machineCom.MachineCom(callbackObject=self)
\r
345 def mcLog(self, message):
\r
348 def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
\r
349 if self.checkupState == 0:
\r
350 self.tempCheckTimeout = 20
\r
352 self.checkupState = 1
\r
353 wx.CallAfter(self.infoBox.SetInfo, 'Cooldown before temperature check.')
\r
354 self.comm.sendCommand('M104 S0')
\r
355 self.comm.sendCommand('M104 S0')
\r
357 self.startTemp = temp
\r
358 self.checkupState = 2
\r
359 wx.CallAfter(self.infoBox.SetInfo, 'Checking the heater and temperature sensor.')
\r
360 self.comm.sendCommand('M104 S200')
\r
361 self.comm.sendCommand('M104 S200')
\r
362 elif self.checkupState == 1:
\r
364 self.startTemp = temp
\r
365 self.checkupState = 2
\r
366 wx.CallAfter(self.infoBox.SetInfo, 'Checking the heater and temperature sensor.')
\r
367 self.comm.sendCommand('M104 S200')
\r
368 self.comm.sendCommand('M104 S200')
\r
369 elif self.checkupState == 2:
\r
370 #print "WARNING, TEMPERATURE TEST DISABLED FOR TESTING!"
\r
371 if temp > self.startTemp + 40:
\r
372 self.checkupState = 3
\r
373 wx.CallAfter(self.infoBox.SetAttention, 'Please make sure none of the endstops are pressed.')
\r
374 wx.CallAfter(self.endstopBitmap.Show, True)
\r
375 wx.CallAfter(self.Layout)
\r
376 self.comm.sendCommand('M104 S0')
\r
377 self.comm.sendCommand('M104 S0')
\r
378 self.comm.sendCommand('M119')
\r
379 wx.CallAfter(self.tempState.SetBitmap, self.checkBitmap)
\r
381 self.tempCheckTimeout -= 1
\r
382 if self.tempCheckTimeout < 1:
\r
383 self.checkupState = -1
\r
384 wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
\r
385 wx.CallAfter(self.infoBox.SetError, 'Temperature measurement FAILED!')
\r
386 self.comm.sendCommand('M104 S0')
\r
387 self.comm.sendCommand('M104 S0')
\r
388 wx.CallAfter(self.temperatureLabel.SetLabel, 'Head temperature: %d' % (temp))
\r
390 def mcStateChange(self, state):
\r
391 if self.comm == None:
\r
393 if self.comm.isOperational():
\r
394 wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
\r
395 elif self.comm.isError():
\r
396 wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
\r
397 wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.')
\r
398 wx.CallAfter(self.machineState.SetLabel, 'Communication State: %s' % (self.comm.getStateString()))
\r
400 def mcMessage(self, message):
\r
401 if self.checkupState >= 3 and self.checkupState < 10 and 'x_min' in message:
\r
402 for data in message.split(' '):
\r
404 tag, value = data.split(':', 2)
\r
406 self.xMinStop = (value == 'H')
\r
408 self.xMaxStop = (value == 'H')
\r
410 self.yMinStop = (value == 'H')
\r
412 self.yMaxStop = (value == 'H')
\r
414 self.zMinStop = (value == 'H')
\r
416 self.zMaxStop = (value == 'H')
\r
417 self.comm.sendCommand('M119')
\r
419 if self.checkupState == 3:
\r
420 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
\r
421 self.checkupState = 4
\r
422 wx.CallAfter(self.infoBox.SetAttention, 'Please press the left X endstop.')
\r
423 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMinBitmap)
\r
424 elif self.checkupState == 4:
\r
425 if self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
\r
426 self.checkupState = 5
\r
427 wx.CallAfter(self.infoBox.SetAttention, 'Please press the right X endstop.')
\r
428 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopXMaxBitmap)
\r
429 elif self.checkupState == 5:
\r
430 if not self.xMinStop and self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
\r
431 self.checkupState = 6
\r
432 wx.CallAfter(self.infoBox.SetAttention, 'Please press the front Y endstop.')
\r
433 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMinBitmap)
\r
434 elif self.checkupState == 6:
\r
435 if not self.xMinStop and not self.xMaxStop and self.yMinStop and not self.yMaxStop and not self.zMinStop and not self.zMaxStop:
\r
436 self.checkupState = 7
\r
437 wx.CallAfter(self.infoBox.SetAttention, 'Please press the back Y endstop.')
\r
438 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopYMaxBitmap)
\r
439 elif self.checkupState == 7:
\r
440 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and self.yMaxStop and not self.zMinStop and not self.zMaxStop:
\r
441 self.checkupState = 8
\r
442 wx.CallAfter(self.infoBox.SetAttention, 'Please press the top Z endstop.')
\r
443 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMinBitmap)
\r
444 elif self.checkupState == 8:
\r
445 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and self.zMinStop and not self.zMaxStop:
\r
446 self.checkupState = 9
\r
447 wx.CallAfter(self.infoBox.SetAttention, 'Please press the bottom Z endstop.')
\r
448 wx.CallAfter(self.endstopBitmap.SetBitmap, self.endStopZMaxBitmap)
\r
449 elif self.checkupState == 9:
\r
450 if not self.xMinStop and not self.xMaxStop and not self.yMinStop and not self.yMaxStop and not self.zMinStop and self.zMaxStop:
\r
451 self.checkupState = 10
\r
453 wx.CallAfter(self.infoBox.SetInfo, 'Checkup finished')
\r
454 wx.CallAfter(self.infoBox.SetReadyIndicator)
\r
455 wx.CallAfter(self.endstopBitmap.Show, False)
\r
456 wx.CallAfter(self.stopState.SetBitmap, self.checkBitmap)
\r
457 wx.CallAfter(self.OnSkipClick, None)
\r
459 def mcProgress(self, lineNr):
\r
462 def mcZChange(self, newZ):
\r
465 class UltimakerCalibrationPage(InfoPage):
\r
466 def __init__(self, parent):
\r
467 super(UltimakerCalibrationPage, self).__init__(parent, "Ultimaker Calibration")
\r
469 self.AddText("Your Ultimaker requires some calibration.")
\r
470 self.AddText("This calibration is needed for a proper extrusion amount.")
\r
471 self.AddSeperator()
\r
472 self.AddText("The following values are needed:")
\r
473 self.AddText("* Diameter of filament")
\r
474 self.AddText("* Number of steps per mm of filament extrusion")
\r
475 self.AddSeperator()
\r
476 self.AddText("The better you have calibrated these values, the better your prints\nwill become.")
\r
477 self.AddSeperator()
\r
478 self.AddText("First we need the diameter of your filament:")
\r
479 self.filamentDiameter = self.AddTextCtrl(profile.getProfileSetting('filament_diameter'))
\r
480 self.AddText("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.")
\r
481 self.AddText("Note: This value can be changed later at any time.")
\r
483 def StoreData(self):
\r
484 profile.putProfileSetting('filament_diameter', self.filamentDiameter.GetValue())
\r
486 class UltimakerCalibrateStepsPerEPage(InfoPage):
\r
487 def __init__(self, parent):
\r
488 super(UltimakerCalibrateStepsPerEPage, self).__init__(parent, "Ultimaker Calibration")
\r
490 if profile.getPreference('steps_per_e') == '0':
\r
491 profile.putPreference('steps_per_e', '865.888')
\r
493 self.AddText("Calibrating the Steps Per E requires some manual actions.")
\r
494 self.AddText("First remove any filament from your machine.")
\r
495 self.AddText("Next put in your filament so the tip is aligned with the\ntop of the extruder drive.")
\r
496 self.AddText("We'll push the filament 100mm")
\r
497 self.extrudeButton = self.AddButton("Extrude 100mm filament")
\r
498 self.AddText("Now measure the amount of extruded filament:\n(this can be more or less then 100mm)")
\r
499 self.lengthInput, self.saveLengthButton = self.AddTextCtrlButton('100', 'Save')
\r
500 self.AddText("This results in the following steps per E:")
\r
501 self.stepsPerEInput = self.AddTextCtrl(profile.getPreference('steps_per_e'))
\r
502 self.AddText("You can repeat these steps to get better calibration.")
\r
503 self.AddSeperator()
\r
504 self.AddText("If you still have filament in your printer which needs\nheat to remove, press the heat up button below:")
\r
505 self.heatButton = self.AddButton("Heatup for filament removal")
\r
507 self.saveLengthButton.Bind(wx.EVT_BUTTON, self.OnSaveLengthClick)
\r
508 self.extrudeButton.Bind(wx.EVT_BUTTON, self.OnExtrudeClick)
\r
509 self.heatButton.Bind(wx.EVT_BUTTON, self.OnHeatClick)
\r
511 def OnSaveLengthClick(self, e):
\r
512 currentEValue = float(self.stepsPerEInput.GetValue())
\r
513 realExtrudeLength = float(self.lengthInput.GetValue())
\r
514 newEValue = currentEValue * 100 / realExtrudeLength
\r
515 self.stepsPerEInput.SetValue(str(newEValue))
\r
516 self.lengthInput.SetValue("100")
\r
518 def OnExtrudeClick(self, e):
\r
519 threading.Thread(target=self.OnExtrudeRun).start()
\r
521 def OnExtrudeRun(self):
\r
522 self.heatButton.Enable(False)
\r
523 self.extrudeButton.Enable(False)
\r
524 currentEValue = float(self.stepsPerEInput.GetValue())
\r
525 self.comm = machineCom.MachineCom()
\r
526 if not self.comm.isOpen():
\r
527 wx.MessageBox("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable", 'Printer error', wx.OK | wx.ICON_INFORMATION)
\r
528 self.heatButton.Enable(True)
\r
529 self.extrudeButton.Enable(True)
\r
532 line = self.comm.readline()
\r
535 if 'start' in line:
\r
537 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
\r
540 self.sendGCommand('M302') #Disable cold extrusion protection
\r
541 self.sendGCommand("M92 E%f" % (currentEValue))
\r
542 self.sendGCommand("G92 E0")
\r
543 self.sendGCommand("G1 E100 F600")
\r
546 self.extrudeButton.Enable()
\r
547 self.heatButton.Enable()
\r
549 def OnHeatClick(self, e):
\r
550 threading.Thread(target=self.OnHeatRun).start()
\r
552 def OnHeatRun(self):
\r
553 self.heatButton.Enable(False)
\r
554 self.extrudeButton.Enable(False)
\r
555 self.comm = machineCom.MachineCom()
\r
556 if not self.comm.isOpen():
\r
557 wx.MessageBox("Error: Failed to open serial port to machine\nIf this keeps happening, try disconnecting and reconnecting the USB cable", 'Printer error', wx.OK | wx.ICON_INFORMATION)
\r
558 self.heatButton.Enable(True)
\r
559 self.extrudeButton.Enable(True)
\r
562 line = self.comm.readline()
\r
564 self.heatButton.Enable(True)
\r
565 self.extrudeButton.Enable(True)
\r
567 if 'start' in line:
\r
569 #Wait 3 seconds for the SD card init to timeout if we have SD in our firmware but there is no SD card found.
\r
572 self.sendGCommand('M104 S200') #Set the temperature to 200C, should be enough to get PLA and ABS out.
\r
573 wx.MessageBox('Wait till you can remove the filament from the machine, and press OK.\n(Temperature is set to 200C)', 'Machine heatup', wx.OK | wx.ICON_INFORMATION)
\r
574 self.sendGCommand('M104 S0')
\r
577 self.heatButton.Enable(True)
\r
578 self.extrudeButton.Enable(True)
\r
580 def sendGCommand(self, cmd):
\r
581 self.comm.sendCommand(cmd) #Disable cold extrusion protection
\r
583 line = self.comm.readline()
\r
586 if line.startswith('ok'):
\r
589 def StoreData(self):
\r
590 profile.putPreference('steps_per_e', self.stepsPerEInput.GetValue())
\r
592 class configWizard(wx.wizard.Wizard):
\r
593 def __init__(self):
\r
594 super(configWizard, self).__init__(None, -1, "Configuration Wizard")
\r
596 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
\r
597 self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
\r
599 self.firstInfoPage = FirstInfoPage(self)
\r
600 self.machineSelectPage = MachineSelectPage(self)
\r
601 self.ultimakerFirmwareUpgradePage = FirmwareUpgradePage(self)
\r
602 self.ultimakerCheckupPage = UltimakerCheckupPage(self)
\r
603 self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
\r
604 self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
\r
605 self.repRapInfoPage = RepRapInfoPage(self)
\r
607 wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
\r
608 wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerFirmwareUpgradePage)
\r
609 wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
\r
610 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.ultimakerCalibrationPage)
\r
611 #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
\r
613 self.FitToPage(self.firstInfoPage)
\r
614 self.GetPageAreaSizer().Add(self.firstInfoPage)
\r
616 self.RunWizard(self.firstInfoPage)
\r
619 def OnPageChanging(self, e):
\r
620 e.GetPage().StoreData()
\r
622 def OnPageChanged(self, e):
\r
623 if e.GetPage().AllowNext():
\r
624 self.FindWindowById(wx.ID_FORWARD).Enable()
\r
626 self.FindWindowById(wx.ID_FORWARD).Disable()
\r
627 self.FindWindowById(wx.ID_BACKWARD).Disable()
\r