chiark / gitweb /
Add bed leveling wizard.
authordaid303 <daid303@gmail.com>
Mon, 17 Dec 2012 13:15:40 +0000 (14:15 +0100)
committerdaid303 <daid303@gmail.com>
Mon, 17 Dec 2012 13:15:40 +0000 (14:15 +0100)
Cura/gui/app.py
Cura/gui/configWizard.py
Cura/gui/mainWindow.py
Cura/util/machineCom.py

index cd7a2e8484760e15bed81bfef7dc900f29572b4e..50a7d1f4173a4a01106ecd301e6928e1637687ec 100644 (file)
@@ -15,7 +15,7 @@ from Cura.util import profile
 
 class CuraApp(wx.App):
        def __init__(self):
-               if platform.system() == "Windows":
+               if platform.system() == "Windows" and not 'PYCHARM_HOSTED' in os.environ:
                        super(CuraApp, self).__init__(redirect = True, filename = 'output.txt')
                else:
                        super(CuraApp, self).__init__(redirect = False)
index 0508f9501eeac88280ae5b0705c7a122e6648b98..af38f7f0558b1787b44610a6d5dc0a26b3764be9 100644 (file)
@@ -4,6 +4,7 @@ from __future__ import absolute_import
 import webbrowser
 import threading
 import time
+import math
 
 import wx
 import wx.wizard
@@ -69,8 +70,13 @@ class InfoBox(wx.Panel):
                self.text.SetLabel(info)
                self.extraInfoButton.Show(False)
                self.SetAttentionIndicator()
+               self.Layout()
                self.Refresh()
 
+       def SetBusy(self, info):
+               self.SetInfo(info)
+               self.SetBusyIndicator()
+
        def SetBusyIndicator(self):
                self.busyState = 0
                self.bitmap.SetBitmap(self.busyBitmap[self.busyState])
@@ -79,7 +85,7 @@ class InfoBox(wx.Panel):
                webbrowser.open(self.extraInfoUrl)
 
        def doBusyUpdate(self, e):
-               if self.busyState == None:
+               if self.busyState is None:
                        return
                self.busyState += 1
                if self.busyState >= len(self.busyBitmap):
@@ -215,6 +221,7 @@ class FirstInfoPage(InfoPage):
                self.AddText('* Configure Cura for your machine')
                self.AddText('* Upgrade your firmware')
                self.AddText('* Check if your machine is working safely')
+               self.AddText('* Level your printer bed')
 
                #self.AddText('* Calibrate your machine')
                #self.AddText('* Do your first print')
@@ -390,14 +397,13 @@ class UltimakerCheckupPage(InfoPage):
 
        def OnCheckClick(self, e=None):
                self.errorLogButton.Show(False)
-               if self.comm != None:
+               if self.comm is not None:
                        self.comm.close()
                        del self.comm
                        self.comm = None
                        wx.CallAfter(self.OnCheckClick)
                        return
-               self.infoBox.SetInfo('Connecting to machine.')
-               self.infoBox.SetBusyIndicator()
+               self.infoBox.SetBusy('Connecting to machine.')
                self.commState.SetBitmap(self.unknownBitmap)
                self.tempState.SetBitmap(self.unknownBitmap)
                self.stopState.SetBitmap(self.unknownBitmap)
@@ -449,20 +455,20 @@ class UltimakerCheckupPage(InfoPage):
                                if self.tempCheckTimeout < 1:
                                        self.checkupState = -1
                                        wx.CallAfter(self.tempState.SetBitmap, self.crossBitmap)
-                                       wx.CallAfter(self.infoBox.SetError, 'Temperature measurement FAILED!', 'http://wiki.ultimaker.com/Cura/Temperature_measurement_problems')
+                                       wx.CallAfter(self.infoBox.SetError, 'Temperature measurement FAILED!', 'http://wiki.ultimaker.com/Cura:_Temperature_measurement_problems')
                                        self.comm.sendCommand('M104 S0')
                                        self.comm.sendCommand('M104 S0')
                wx.CallAfter(self.temperatureLabel.SetLabel, 'Head temperature: %d' % (temp))
 
        def mcStateChange(self, state):
-               if self.comm == None:
+               if self.comm is None:
                        return
                if self.comm.isOperational():
                        wx.CallAfter(self.commState.SetBitmap, self.checkBitmap)
                        wx.CallAfter(self.machineState.SetLabel, 'Communication State: %s' % (self.comm.getStateString()))
                elif self.comm.isError():
                        wx.CallAfter(self.commState.SetBitmap, self.crossBitmap)
-                       wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura/Connection_problems')
+                       wx.CallAfter(self.infoBox.SetError, 'Failed to establish connection with the printer.', 'http://wiki.ultimaker.com/Cura:_Connection_problems')
                        wx.CallAfter(self.endstopBitmap.Show, False)
                        wx.CallAfter(self.machineState.SetLabel, '%s' % (self.comm.getErrorString()))
                        wx.CallAfter(self.errorLogButton.Show, True)
@@ -687,13 +693,14 @@ class configWizard(wx.wizard.Wizard):
                self.ultimakerCheckupPage = UltimakerCheckupPage(self)
                self.ultimakerCalibrationPage = UltimakerCalibrationPage(self)
                self.ultimakerCalibrateStepsPerEPage = UltimakerCalibrateStepsPerEPage(self)
+               self.bedLevelPage = bedLevelWizardMain(self)
                self.repRapInfoPage = RepRapInfoPage(self)
 
                wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.machineSelectPage)
                wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.ultimakerSelectParts)
                wx.wizard.WizardPageSimple.Chain(self.ultimakerSelectParts, self.ultimakerFirmwareUpgradePage)
                wx.wizard.WizardPageSimple.Chain(self.ultimakerFirmwareUpgradePage, self.ultimakerCheckupPage)
-               #wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.ultimakerCalibrationPage)
+               wx.wizard.WizardPageSimple.Chain(self.ultimakerCheckupPage, self.bedLevelPage)
                #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage)
 
                self.FitToPage(self.firstInfoPage)
@@ -711,3 +718,190 @@ class configWizard(wx.wizard.Wizard):
                else:
                        self.FindWindowById(wx.ID_FORWARD).Disable()
                self.FindWindowById(wx.ID_BACKWARD).Disable()
+
+class bedLevelFirstPage(InfoPage):
+       def __init__(self, parent):
+               super(bedLevelFirstPage, 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')
+
+class bedLevelWizardMain(InfoPage):
+       def __init__(self, parent):
+               super(bedLevelWizardMain, self).__init__(parent, "Bed leveling wizard")
+
+               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):
+               return False
+
+       def OnResume(self, e):
+               feedZ = profile.getProfileSettingFloat('max_z_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.getPreferenceFloat('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.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth') - 20, 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.getPreferenceFloat('machine_width'), 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
+               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 < profile.getProfileSettingFloat('print_temperature') - 5:
+                               wx.CallAfter(self.infoBox.SetInfo, 'Heating up printer: %d/%d' % (temp, profile.getProfileSettingFloat('print_temperature')))
+                       else:
+                               self._wizardState = 10
+                               wx.CallAfter(self.infoBox.SetInfo, 'Printing a square on the printer bed at 0.3mm height.')
+                               feedZ = profile.getProfileSettingFloat('max_z_speed') * 60
+                               feedPrint = profile.getProfileSettingFloat('print_speed') * 60
+                               feedTravel = profile.getProfileSettingFloat('travel_speed') * 60
+                               w = profile.getPreferenceFloat('machine_width')
+                               d = profile.getPreferenceFloat('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 += (d - 10) * ePerMM
+                               gcodeList.append('G1 X%d Y%d E%f F%d' % (5, d - 5, eValue, feedPrint))
+                               eValue += (w - 10) * ePerMM
+                               gcodeList.append('G1 X%d Y%d E%f F%d' % (w - 5, d - 5, eValue, feedPrint))
+                               eValue += (d - 10) * ePerMM
+                               gcodeList.append('G1 X%d Y%d E%f F%d' % (w - 5, 5, eValue, feedPrint))
+                               eValue += (w - 10) * ePerMM
+                               gcodeList.append('G1 X%d Y%d E%f F%d' % (5, 5, eValue, feedPrint))
+
+                               gcodeList.append('G1 X%d Y%d E%f F%d' % (5.4, 5.4, eValue, feedTravel))
+                               eValue += (d - 10.8) * ePerMM
+                               gcodeList.append('G1 X%d Y%d E%f F%d' % (5.4, d - 5.4, eValue, feedPrint))
+                               eValue += (w - 10.8) * ePerMM
+                               gcodeList.append('G1 X%d Y%d E%f F%d' % (w - 5.4, d - 5.4, eValue, feedPrint))
+                               eValue += (d - 10.8) * ePerMM
+                               gcodeList.append('G1 X%d Y%d E%f F%d' % (w - 5.4, 5.4, eValue, feedPrint))
+                               eValue += (w - 10.8) * ePerMM
+                               gcodeList.append('G1 X%d Y%d E%f F%d' % (5.4, 5.4, eValue, feedPrint))
+                               self.comm.printGCode(gcodeList)
+
+       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('G28')
+                               self._wizardState = 1
+                       elif self._wizardState == 10 and not self.comm.isPrinting():
+                               self.comm.sendCommand('G1 Z15 F%d' % (profile.getProfileSettingFloat('max_z_speed') * 60))
+                               self.comm.sendCommand('M104 S0')
+                               wx.CallAfter(self.infoBox.SetInfo, 'Calibration finished.\nThe two squares on the bed should slightly touch each other.')
+                               wx.CallAfter(self.infoBox.SetReadyIndicator)
+                               wx.CallAfter(self.GetParent().FindWindowById(wx.ID_FORWARD).Enable)
+                               self._wizardState = 11
+               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.firstInfoPage = bedLevelFirstPage(self)
+               self.mainPage = bedLevelWizardMain(self)
+
+               wx.wizard.WizardPageSimple.Chain(self.firstInfoPage, self.mainPage)
+
+               self.FitToPage(self.firstInfoPage)
+               self.GetPageAreaSizer().Add(self.firstInfoPage)
+
+               self.RunWizard(self.firstInfoPage)
+               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()
index 6e723fd06a1c5194e24cab5bf7e1a5151dc8d655..8e893342f6b7efe82b92e77f42438dd463dfa3c0 100644 (file)
@@ -99,8 +99,10 @@ class mainWindow(wx.Frame):
                i = expertMenu.Append(-1, 'Install custom firmware')
                self.Bind(wx.EVT_MENU, self.OnCustomFirmware, i)
                expertMenu.AppendSeparator()
-               i = expertMenu.Append(-1, 'ReRun first run wizard...')
+               i = expertMenu.Append(-1, 'Run first run wizard...')
                self.Bind(wx.EVT_MENU, self.OnFirstRunWizard, i)
+               i = expertMenu.Append(-1, 'Run bed leveling wizard...')
+               self.Bind(wx.EVT_MENU, self.OnBedLevelWizard, i)
                self.menubar.Append(expertMenu, 'Expert')
 
                helpMenu = wx.Menu()
@@ -383,6 +385,9 @@ class mainWindow(wx.Frame):
                configWizard.configWizard()
                self.updateProfileToControls()
 
+       def OnBedLevelWizard(self, e):
+               configWizard.bedLevelWizard()
+
        def OnExpertOpen(self, e):
                ecw = expertConfig.expertConfigWindow()
                ecw.Centre()
index 4e72610f25fa81d571a27213d210d3c069f7854f..a4fb5b5bca80c72a2475614e29a66113897e4743 100644 (file)
@@ -62,17 +62,17 @@ class VirtualPrinter():
                self.bedTargetTemp = 1.0
        
        def write(self, data):
-               if self.readList == None:
+               if self.readList is None:
                        return
                #print "Send: %s" % (data.rstrip())
                if 'M104' in data or 'M109' in data:
                        try:
-                               self.targetTemp = float(re.search('S([0-9]+)', cmd).group(1))
+                               self.targetTemp = float(re.search('S([0-9]+)', data).group(1))
                        except:
                                pass
                if 'M140' in data or 'M190' in data:
                        try:
-                               self.bedTargetTemp = float(re.search('S([0-9]+)', cmd).group(1))
+                               self.bedTargetTemp = float(re.search('S([0-9]+)', data).group(1))
                        except:
                                pass
                if 'M105' in data:
@@ -81,21 +81,21 @@ class VirtualPrinter():
                        self.readList.append("ok\n")
 
        def readline(self):
-               if self.readList == None:
+               if self.readList is None:
                        return ''
                n = 0
                timeDiff = self.lastTempAt - time.time()
                self.lastTempAt = time.time()
                if abs(self.temp - self.targetTemp) > 1:
-                       self.temp += math.copysign(timeDiff, self.targetTemp - self.temp)
+                       self.temp += math.copysign(timeDiff * 10, self.targetTemp - self.temp)
                if abs(self.bedTemp - self.bedTargetTemp) > 1:
-                       self.bedTemp += math.copysign(timeDiff, self.bedTargetTemp - self.bedTemp)
+                       self.bedTemp += math.copysign(timeDiff * 10, self.bedTargetTemp - self.bedTemp)
                while len(self.readList) < 1:
                        time.sleep(0.1)
                        n += 1
                        if n == 20:
                                return ''
-                       if self.readList == None:
+                       if self.readList is None:
                                return ''
                time.sleep(0.001)
                #print "Recv: %s" % (self.readList[0].rstrip())
@@ -450,7 +450,7 @@ class MachineCom(object):
                self.close()
        
        def _sendCommand(self, cmd):
-               if self._serial == None:
+               if self._serial is None:
                        return
                if 'M109' in cmd or 'M190' in cmd:
                        self._heatupWaitStartTime = time.time()