+
+class bedLevelWizardMain(InfoPage):
+ def __init__(self, parent):
+ super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
+
+ self.AddText('This wizard will help you in leveling your printer bed')
+ self.AddSeperator()
+ self.AddText('It will do the following steps')
+ self.AddText('* Move the printer head to each corner')
+ self.AddText(' and let you adjust the height of the bed to the nozzle')
+ self.AddText('* Print a line around the bed to check if it is level')
+ self.AddSeperator()
+
+ self.connectButton = self.AddButton('Connect to printer')
+ self.comm = None
+
+ self.infoBox = self.AddInfoBox()
+ self.resumeButton = self.AddButton('Resume')
+ self.resumeButton.Enable(False)
+
+ self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
+ self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
+
+ def OnConnect(self, e = None):
+ if self.comm is not None:
+ self.comm.close()
+ del self.comm
+ self.comm = None
+ wx.CallAfter(self.OnConnect)
+ return
+ self.connectButton.Enable(False)
+ self.comm = machineCom.MachineCom(callbackObject=self)
+ self.infoBox.SetBusy('Connecting to machine.')
+ self._wizardState = 0
+
+ def AllowNext(self):
+ if self.GetParent().headOffsetCalibration is not None and int(profile.getMachineSetting('extruder_amount')) > 1:
+ wx.wizard.WizardPageSimple.Chain(self, self.GetParent().headOffsetCalibration)
+ return True
+
+ def OnResume(self, e):
+ feedZ = profile.getProfileSettingFloat('print_speed') * 60
+ feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
+ if self._wizardState == 2:
+ wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back left corner...')
+ self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
+ self.comm.sendCommand('G1 X%d Y%d F%d' % (0, profile.getMachineSettingFloat('machine_depth'), feedTravel))
+ self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
+ self.comm.sendCommand('M400')
+ self._wizardState = 3
+ elif self._wizardState == 4:
+ wx.CallAfter(self.infoBox.SetBusy, 'Moving head to back right corner...')
+ self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
+ self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, profile.getMachineSettingFloat('machine_depth') - 25, feedTravel))
+ self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
+ self.comm.sendCommand('M400')
+ self._wizardState = 5
+ elif self._wizardState == 6:
+ wx.CallAfter(self.infoBox.SetBusy, 'Moving head to front right corner...')
+ self.comm.sendCommand('G1 Z3 F%d' % (feedZ))
+ self.comm.sendCommand('G1 X%d Y%d F%d' % (profile.getMachineSettingFloat('machine_width') - 5.0, 20, feedTravel))
+ self.comm.sendCommand('G1 Z0 F%d' % (feedZ))
+ self.comm.sendCommand('M400')
+ self._wizardState = 7
+ elif self._wizardState == 8:
+ wx.CallAfter(self.infoBox.SetBusy, 'Heating up printer...')
+ self.comm.sendCommand('G1 Z15 F%d' % (feedZ))
+ self.comm.sendCommand('M104 S%d' % (profile.getProfileSettingFloat('print_temperature')))
+ self.comm.sendCommand('G1 X%d Y%d F%d' % (0, 0, feedTravel))
+ self._wizardState = 9
+ elif self._wizardState == 10:
+ self._wizardState = 11
+ wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
+ feedZ = profile.getProfileSettingFloat('print_speed') * 60
+ feedPrint = profile.getProfileSettingFloat('print_speed') * 60
+ feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
+ w = profile.getMachineSettingFloat('machine_width')
+ d = profile.getMachineSettingFloat('machine_depth')
+ filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
+ filamentArea = math.pi * filamentRadius * filamentRadius
+ ePerMM = (profile.calculateEdgeWidth() * 0.3) / filamentArea
+ eValue = 0.0
+
+ gcodeList = [
+ 'G1 Z2 F%d' % (feedZ),
+ 'G92 E0',
+ 'G1 X%d Y%d F%d' % (5, 5, feedTravel),
+ 'G1 Z0.3 F%d' % (feedZ)]
+ eValue += 5.0
+ gcodeList.append('G1 E%f F%d' % (eValue, profile.getProfileSettingFloat('retraction_speed') * 60))
+
+ for i in xrange(0, 3):
+ dist = 5.0 + 0.4 * float(i)
+ eValue += (d - 2.0*dist) * ePerMM
+ gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, d - dist, eValue, feedPrint))
+ eValue += (w - 2.0*dist) * ePerMM
+ gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, d - dist, eValue, feedPrint))
+ eValue += (d - 2.0*dist) * ePerMM
+ gcodeList.append('G1 X%f Y%f E%f F%d' % (w - dist, dist, eValue, feedPrint))
+ eValue += (w - 2.0*dist) * ePerMM
+ gcodeList.append('G1 X%f Y%f E%f F%d' % (dist, dist, eValue, feedPrint))
+
+ gcodeList.append('M400')
+ self.comm.printGCode(gcodeList)
+ self.resumeButton.Enable(False)
+
+ def mcLog(self, message):
+ print 'Log:', message
+
+ def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
+ if self._wizardState == 1:
+ self._wizardState = 2
+ wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front left screw of your printer bed\nSo the nozzle just hits the bed.')
+ wx.CallAfter(self.resumeButton.Enable, True)
+ elif self._wizardState == 3:
+ self._wizardState = 4
+ wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back left screw of your printer bed\nSo the nozzle just hits the bed.')
+ wx.CallAfter(self.resumeButton.Enable, True)
+ elif self._wizardState == 5:
+ self._wizardState = 6
+ wx.CallAfter(self.infoBox.SetAttention, 'Adjust the back right screw of your printer bed\nSo the nozzle just hits the bed.')
+ wx.CallAfter(self.resumeButton.Enable, True)
+ elif self._wizardState == 7:
+ self._wizardState = 8
+ wx.CallAfter(self.infoBox.SetAttention, 'Adjust the front right screw of your printer bed\nSo the nozzle just hits the bed.')
+ wx.CallAfter(self.resumeButton.Enable, True)
+ elif self._wizardState == 9:
+ if temp[0] < profile.getProfileSettingFloat('print_temperature') - 5:
+ wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp[0], profile.getProfileSettingFloat('print_temperature')))
+ else:
+ wx.CallAfter(self.infoBox.SetAttention, 'The printer is hot now. Please insert some PLA filament into the printer.')
+ wx.CallAfter(self.resumeButton.Enable, True)
+ self._wizardState = 10
+
+ def mcStateChange(self, state):
+ if self.comm is None:
+ return
+ if self.comm.isOperational():
+ if self._wizardState == 0:
+ wx.CallAfter(self.infoBox.SetInfo, 'Homing printer...')
+ self.comm.sendCommand('M105')
+ self.comm.sendCommand('G28')
+ self._wizardState = 1
+ elif self._wizardState == 11 and not self.comm.isPrinting():
+ self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
+ self.comm.sendCommand('G92 E0')
+ self.comm.sendCommand('G1 E-10 F%d' % (profile.getProfileSettingFloat('retraction_speed') * 60))
+ self.comm.sendCommand('M104 S0')
+ wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe squares on the bed should slightly touch each other.')
+ wx.CallAfter(self.infoBox.SetReadyIndicator)
+ wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
+ wx.CallAfter(self.connectButton.Enable, True)
+ self._wizardState = 12
+ elif self.comm.isError():
+ wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
+
+ def mcMessage(self, message):
+ pass
+
+ def mcProgress(self, lineNr):
+ pass
+
+ def mcZChange(self, newZ):
+ pass
+
+class headOffsetCalibrationPage(InfoPage):
+ def __init__(self, parent):
+ super(headOffsetCalibrationPage, self).__init__(parent, "Printer head offset calibration")
+
+ self.AddText('This wizard will help you in calibrating the printer head offsets of your dual extrusion machine')
+ self.AddSeperator()
+
+ self.connectButton = self.AddButton('Connect to printer')
+ self.comm = None
+
+ self.infoBox = self.AddInfoBox()
+ self.textEntry = self.AddTextCtrl('')
+ self.textEntry.Enable(False)
+ self.resumeButton = self.AddButton('Resume')
+ self.resumeButton.Enable(False)
+
+ self.Bind(wx.EVT_BUTTON, self.OnConnect, self.connectButton)
+ self.Bind(wx.EVT_BUTTON, self.OnResume, self.resumeButton)
+
+ def OnConnect(self, e = None):
+ if self.comm is not None:
+ self.comm.close()
+ del self.comm
+ self.comm = None
+ wx.CallAfter(self.OnConnect)
+ return
+ self.connectButton.Enable(False)
+ self.comm = machineCom.MachineCom(callbackObject=self)
+ self.infoBox.SetBusy('Connecting to machine.')
+ self._wizardState = 0
+
+ def OnResume(self, e):
+ if self._wizardState == 2:
+ self._wizardState = 3
+ wx.CallAfter(self.infoBox.SetBusy, 'Printing initial calibration cross')
+
+ w = profile.getMachineSettingFloat('machine_width')
+ d = profile.getMachineSettingFloat('machine_depth')
+
+ gcode = gcodeGenerator.gcodeGenerator()
+ gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
+ gcode.setPrintSpeed(profile.getProfileSettingFloat('bottom_layer_speed'))
+ gcode.addCmd('T0')
+ gcode.addPrime(15)
+ gcode.addCmd('T1')
+ gcode.addPrime(15)
+
+ gcode.addCmd('T0')
+ gcode.addMove(w/2, 5)
+ gcode.addMove(z=0.2)
+ gcode.addPrime()
+ gcode.addExtrude(w/2, d-5.0)
+ gcode.addRetract()
+ gcode.addMove(5, d/2)
+ gcode.addPrime()
+ gcode.addExtrude(w-5.0, d/2)
+ gcode.addRetract(15)
+
+ gcode.addCmd('T1')
+ gcode.addMove(w/2, 5)
+ gcode.addPrime()
+ gcode.addExtrude(w/2, d-5.0)
+ gcode.addRetract()
+ gcode.addMove(5, d/2)
+ gcode.addPrime()
+ gcode.addExtrude(w-5.0, d/2)
+ gcode.addRetract(15)
+ gcode.addCmd('T0')
+
+ gcode.addMove(z=25)
+ gcode.addMove(0, 0)
+ gcode.addCmd('M400')
+
+ self.comm.printGCode(gcode.list())
+ self.resumeButton.Enable(False)
+ elif self._wizardState == 4:
+ try:
+ float(self.textEntry.GetValue())
+ except ValueError:
+ return
+ profile.putPreference('extruder_offset_x1', self.textEntry.GetValue())
+ self._wizardState = 5
+ self.infoBox.SetAttention('Please measure the distance between the horizontal lines in millimeters.')
+ self.textEntry.SetValue('0.0')
+ self.textEntry.Enable(True)
+ elif self._wizardState == 5:
+ try:
+ float(self.textEntry.GetValue())
+ except ValueError:
+ return
+ profile.putPreference('extruder_offset_y1', self.textEntry.GetValue())
+ self._wizardState = 6
+ self.infoBox.SetBusy('Printing the fine calibration lines.')
+ self.textEntry.SetValue('')
+ self.textEntry.Enable(False)
+ self.resumeButton.Enable(False)
+
+ x = profile.getMachineSettingFloat('extruder_offset_x1')
+ y = profile.getMachineSettingFloat('extruder_offset_y1')
+ gcode = gcodeGenerator.gcodeGenerator()
+ gcode.setExtrusionRate(profile.getProfileSettingFloat('nozzle_size') * 1.5, 0.2)
+ gcode.setPrintSpeed(25)
+ gcode.addHome()
+ gcode.addCmd('T0')
+ gcode.addMove(50, 40, 0.2)
+ gcode.addPrime(15)
+ for n in xrange(0, 10):
+ gcode.addExtrude(50 + n * 10, 150)
+ gcode.addExtrude(50 + n * 10 + 5, 150)
+ gcode.addExtrude(50 + n * 10 + 5, 40)
+ gcode.addExtrude(50 + n * 10 + 10, 40)
+ gcode.addMove(40, 50)
+ for n in xrange(0, 10):
+ gcode.addExtrude(150, 50 + n * 10)
+ gcode.addExtrude(150, 50 + n * 10 + 5)
+ gcode.addExtrude(40, 50 + n * 10 + 5)
+ gcode.addExtrude(40, 50 + n * 10 + 10)
+ gcode.addRetract(15)
+
+ gcode.addCmd('T1')
+ gcode.addMove(50 - x, 30 - y, 0.2)
+ gcode.addPrime(15)
+ for n in xrange(0, 10):
+ gcode.addExtrude(50 + n * 10.2 - 1.0 - x, 140 - y)
+ gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 140 - y)
+ gcode.addExtrude(50 + n * 10.2 - 1.0 + 5.1 - x, 30 - y)
+ gcode.addExtrude(50 + n * 10.2 - 1.0 + 10 - x, 30 - y)
+ gcode.addMove(30 - x, 50 - y, 0.2)
+ for n in xrange(0, 10):
+ gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 - y)
+ gcode.addExtrude(160 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
+ gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 5.1 - y)
+ gcode.addExtrude(30 - x, 50 + n * 10.2 - 1.0 + 10 - y)
+ gcode.addRetract(15)
+ gcode.addMove(z=15)
+ gcode.addCmd('M400')
+ gcode.addCmd('M104 T0 S0')
+ gcode.addCmd('M104 T1 S0')
+ self.comm.printGCode(gcode.list())
+ elif self._wizardState == 7:
+ try:
+ n = int(self.textEntry.GetValue()) - 1
+ except:
+ return
+ x = profile.getMachineSettingFloat('extruder_offset_x1')
+ x += -1.0 + n * 0.1
+ profile.putPreference('extruder_offset_x1', '%0.2f' % (x))
+ self.infoBox.SetAttention('Which horizontal line number lays perfect on top of each other? Front most line is zero.')
+ self.textEntry.SetValue('10')
+ self._wizardState = 8
+ elif self._wizardState == 8:
+ try:
+ n = int(self.textEntry.GetValue()) - 1
+ except:
+ return
+ y = profile.getMachineSettingFloat('extruder_offset_y1')
+ y += -1.0 + n * 0.1
+ profile.putPreference('extruder_offset_y1', '%0.2f' % (y))
+ self.infoBox.SetInfo('Calibration finished. Offsets are: %s %s' % (profile.getMachineSettingFloat('extruder_offset_x1'), profile.getMachineSettingFloat('extruder_offset_y1')))
+ self.infoBox.SetReadyIndicator()
+ self._wizardState = 8
+ self.comm.close()
+ self.resumeButton.Enable(False)
+
+ def mcLog(self, message):
+ print 'Log:', message
+
+ def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
+ if self._wizardState == 1:
+ if temp[0] >= 210 and temp[1] >= 210:
+ self._wizardState = 2
+ wx.CallAfter(self.infoBox.SetAttention, 'Please load both extruders with PLA.')
+ wx.CallAfter(self.resumeButton.Enable, True)
+ wx.CallAfter(self.resumeButton.SetFocus)
+
+ def mcStateChange(self, state):
+ if self.comm is None:
+ return
+ if self.comm.isOperational():
+ if self._wizardState == 0:
+ wx.CallAfter(self.infoBox.SetInfo, 'Homing printer and heating up both extruders.')
+ self.comm.sendCommand('M105')
+ self.comm.sendCommand('M104 S220 T0')
+ self.comm.sendCommand('M104 S220 T1')
+ self.comm.sendCommand('G28')
+ self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('print_speed') * 60))
+ self._wizardState = 1
+ if not self.comm.isPrinting():
+ if self._wizardState == 3:
+ self._wizardState = 4
+ wx.CallAfter(self.infoBox.SetAttention, 'Please measure the distance between the vertical lines in millimeters.')
+ wx.CallAfter(self.textEntry.SetValue, '0.0')
+ wx.CallAfter(self.textEntry.Enable, True)
+ wx.CallAfter(self.resumeButton.Enable, True)
+ wx.CallAfter(self.resumeButton.SetFocus)
+ elif self._wizardState == 6:
+ self._wizardState = 7
+ wx.CallAfter(self.infoBox.SetAttention, 'Which vertical line number lays perfect on top of each other? Leftmost line is zero.')
+ wx.CallAfter(self.textEntry.SetValue, '10')
+ wx.CallAfter(self.textEntry.Enable, True)
+ wx.CallAfter(self.resumeButton.Enable, True)
+ wx.CallAfter(self.resumeButton.SetFocus)
+
+ elif self.comm.isError():
+ wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
+
+ def mcMessage(self, message):
+ pass
+
+ def mcProgress(self, lineNr):
+ pass
+
+ def mcZChange(self, newZ):
+ pass
+
+class bedLevelWizard(wx.wizard.Wizard):
+ def __init__(self):
+ super(bedLevelWizard, self).__init__(None, -1, "Bed leveling wizard")
+
+ self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
+ self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
+
+ self.mainPage = bedLevelWizardMain(self)
+ self.headOffsetCalibration = None
+
+ self.FitToPage(self.mainPage)
+ self.GetPageAreaSizer().Add(self.mainPage)
+
+ self.RunWizard(self.mainPage)
+ self.Destroy()
+
+ def OnPageChanging(self, e):
+ e.GetPage().StoreData()
+
+ def OnPageChanged(self, e):
+ if e.GetPage().AllowNext():
+ self.FindWindowById(wx.ID_FORWARD).Enable()
+ else:
+ self.FindWindowById(wx.ID_FORWARD).Disable()
+ self.FindWindowById(wx.ID_BACKWARD).Disable()
+
+class headOffsetWizard(wx.wizard.Wizard):
+ def __init__(self):
+ super(headOffsetWizard, self).__init__(None, -1, "Head offset wizard")
+
+ self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
+ self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
+
+ self.mainPage = headOffsetCalibrationPage(self)
+
+ self.FitToPage(self.mainPage)
+ self.GetPageAreaSizer().Add(self.mainPage)
+
+ self.RunWizard(self.mainPage)
+ self.Destroy()
+
+ def OnPageChanging(self, e):
+ e.GetPage().StoreData()
+
+ def OnPageChanged(self, e):
+ if e.GetPage().AllowNext():
+ self.FindWindowById(wx.ID_FORWARD).Enable()
+ else:
+ self.FindWindowById(wx.ID_FORWARD).Disable()
+ self.FindWindowById(wx.ID_BACKWARD).Disable()