From: Youness Alaoui Date: Fri, 6 Nov 2015 19:50:19 +0000 (-0500) Subject: Add a park toolhead on Pause feature X-Git-Tag: lulzbot-17.14~5 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=b507958d561c307063f54b0dfeee2e59938dede6;p=cura.git Add a park toolhead on Pause feature This will add a park toolhead feature when Pause is clicked. The park position is at 10 mm from the x/y limits and 10mm above the current Z unless we're 10mm away from the max height of the printer. On resume, the E position is reset, last feedrate value is restored and the toolhead is primed for new filament before being moved back into position. The print window will now also display a "Please wait" for 10 seconds while disabling the pause/resume button to avoid excessive commands being sent while the printer is still busy with a move. This also helps the user realize that pausing is not an instantenous feature. The serial connection has been fixed to send queued commands when in paused state. Feature was taken in part from the pauseAtZ plugin. Only E movements are now allowd in paused state. Hopefully fixes T220 and makes everyone happy --- diff --git a/Cura/gui/printWindow.py b/Cura/gui/printWindow.py index fc9523f9..e6ae50f0 100644 --- a/Cura/gui/printWindow.py +++ b/Cura/gui/printWindow.py @@ -346,13 +346,24 @@ class printWindowPlugin(wx.Frame): if not self._printerConnection.hasActiveConnection() or \ self._printerConnection.isActiveConnectionOpen(): if self._printerConnection.isPrinting(): - button.SetLabel(_("Pause")) + if self.pauseTimer.IsRunning(): + self.printButton.Enable(False) + self.printButton.SetLabel(_("Please wait...")) + else: + self.printButton.Enable(True) + button.SetLabel(_("Pause")) else: if self._printerConnection.isPaused(): - button.SetLabel(_("Resume")) + if self.pauseTimer.IsRunning(): + self.printButton.Enable(False) + self.printButton.SetLabel(_("Please wait...")) + else: + self.printButton.Enable(True) + button.SetLabel(_("Resume")) else: button.SetLabel(_("Print")) - button.Enable(True) + button.Enable(True) + self.pauseTimer.Stop() else: button.Enable(False) elif button.command == self.script_cancelPrint: @@ -452,6 +463,9 @@ class printWindowBasic(wx.Frame): self.errorLogButton = wx.Button(self.panel, -1, _("Error log")) self.progress = wx.Gauge(self.panel, -1, range=1000) + self.pauseTimer = wx.Timer(self) + self.Bind(wx.EVT_TIMER, self.OnPauseTimer, self.pauseTimer) + self.sizer.Add(self.powerWarningText, pos=(0, 0), span=(1, 5), flag=wx.EXPAND|wx.BOTTOM, border=5) self.sizer.Add(self.statsText, pos=(1, 0), span=(1, 5), flag=wx.LEFT, border=5) self.sizer.Add(self.connectButton, pos=(2, 0)) @@ -506,6 +520,8 @@ class printWindowBasic(wx.Frame): self._printerConnection.removeCallback(self._doPrinterConnectionUpdate) #TODO: When multiple printer windows are open, closing one will enable sleeping again. preventComputerFromSleeping(self, False) + self.powerWarningTimer.Stop() + self.pauseTimer.Stop() self.Destroy() def OnConnect(self, e): @@ -522,6 +538,14 @@ class printWindowBasic(wx.Frame): def OnPause(self, e): self._printerConnection.pause(not self._printerConnection.isPaused()) + self.pauseButton.Enable(False) + self.pauseTimer.Stop() + self.pauseTimer.Start(10000) + + def OnPauseTimer(self, e): + self.pauseButton.Enable(True) + self.pauseTimer.Stop() + self._updateButtonStates() def OnErrorLog(self, e): LogWindow(self._printerConnection.getErrorLog()) @@ -658,6 +682,9 @@ class printWindowAdvanced(wx.Frame): self.OnPowerWarningChange(None) self.powerWarningTimer.Start(10000) + self.pauseTimer = wx.Timer(self) + self.Bind(wx.EVT_TIMER, self.OnPauseTimer, self.pauseTimer) + self.connectButton = wx.Button(self.toppanel, -1, _("Connect"), size=(125, 30)) self.printButton = wx.Button(self.toppanel, -1, _("Print"), size=(125, 30)) self.cancelButton = wx.Button(self.toppanel, -1, _("Cancel"), size=(125, 30)) @@ -742,6 +769,8 @@ class printWindowAdvanced(wx.Frame): #TODO: When multiple printer windows are open, closing one will enable sleeping again. preventComputerFromSleeping(self, False) self._printerConnection.cancelPrint() + self.powerWarningTimer.Stop() + self.pauseTimer.Stop() self.Destroy() def OnPowerWarningChange(self, e): @@ -765,9 +794,17 @@ class printWindowAdvanced(wx.Frame): def OnPrint(self, e): if self._printerConnection.isPrinting() or self._printerConnection.isPaused(): self._printerConnection.pause(not self._printerConnection.isPaused()) + self.pauseTimer.Stop() + self.printButton.Enable(False) + self.pauseTimer.Start(10000) else: self._printerConnection.startPrint() + def OnPauseTimer(self, e): + self.printButton.Enable(True) + self.pauseTimer.Stop() + self._updateButtonStates() + def OnCancel(self, e): self._printerConnection.cancelPrint() @@ -796,7 +833,7 @@ class printWindowAdvanced(wx.Frame): # Prevent Z movement when paused and all moves when printing if (not self._printerConnection.hasActiveConnection() or \ self._printerConnection.isActiveConnectionOpen()) and \ - (not (self._printerConnection.isPaused() and motor == 'Z') and \ + (not (self._printerConnection.isPaused() and motor != 'E') and \ not self._printerConnection.isPrinting()): self._printerConnection.sendCommand("G91") self._printerConnection.sendCommand("G1 %s%.1f F%d" % (motor, step, feedrate)) @@ -903,13 +940,24 @@ class printWindowAdvanced(wx.Frame): if not self._printerConnection.hasActiveConnection() or \ self._printerConnection.isActiveConnectionOpen(): if self._printerConnection.isPrinting(): - self.printButton.SetLabel(_("Pause")) + if self.pauseTimer.IsRunning(): + self.printButton.Enable(False) + self.printButton.SetLabel(_("Please wait...")) + else: + self.printButton.Enable(True) + self.printButton.SetLabel(_("Pause")) else: if self._printerConnection.isPaused(): - self.printButton.SetLabel(_("Resume")) + if self.pauseTimer.IsRunning(): + self.printButton.Enable(False) + self.printButton.SetLabel(_("Please wait...")) + else: + self.printButton.SetLabel(_("Resume")) + self.printButton.Enable(True) else: self.printButton.SetLabel(_("Print")) - self.printButton.Enable(True) + self.printButton.Enable(True) + self.pauseTimer.Stop() else: self.printButton.Enable(False) if not self._printerConnection.hasActiveConnection() or \ diff --git a/Cura/util/machineCom.py b/Cura/util/machineCom.py index 0db7ecb2..0178bfb9 100644 --- a/Cura/util/machineCom.py +++ b/Cura/util/machineCom.py @@ -501,6 +501,11 @@ class MachineCom(object): self.cancelPrint() else: self._gcodePos = newPos + elif self._state == self.STATE_PAUSED: + if 'ok' in line: + timeout = time.time() + 5 + if not self._commandQueue.empty(): + self._sendCommand(self._commandQueue.get()) self._log("Connection closed, closing down monitor") @@ -584,7 +589,7 @@ class MachineCom(object): self._log("Unexpected error while writing serial port: %s" % (getExceptionString())) self._errorValue = getExceptionString() self.close(True) - + def _sendNext(self): if self._gcodePos >= len(self._gcodeList): self._changeState(self.STATE_OPERATIONAL) @@ -612,14 +617,14 @@ class MachineCom(object): self._sendCommand("N%d%s*%d" % (self._gcodePos, line, checksum)) self._gcodePos += 1 self._callback.mcProgress(self._gcodePos) - + def sendCommand(self, cmd): cmd = cmd.encode('ascii', 'replace') if self.isPrinting(): self._commandQueue.put(cmd) elif self.isOperational(): self._sendCommand(cmd) - + def printGCode(self, gcodeList): if not self.isOperational() or self.isPrinting(): return diff --git a/Cura/util/printerConnection/serialConnection.py b/Cura/util/printerConnection/serialConnection.py index 1fd0485d..92344f70 100644 --- a/Cura/util/printerConnection/serialConnection.py +++ b/Cura/util/printerConnection/serialConnection.py @@ -11,6 +11,7 @@ import os import sys import subprocess import json +import re from Cura.util import profile from Cura.util import machineCom @@ -69,6 +70,7 @@ class serialConnection(printerConnectionBase.printerConnectionBase): self._gcodeData = [] self._printProgress = 0 self._ZPosition = 0 + self._pausePosition = None #Load the data into memory for printing, returns True on success def loadGCodeData(self, dataStream): @@ -97,6 +99,7 @@ class serialConnection(printerConnectionBase.printerConnectionBase): self._process.stdin.write('START\n') self._printProgress = 0 self._ZPosition = 0 + self._pausePosition = None def coolDown(self): cooldown_toolhead = "M104 S0" @@ -116,6 +119,8 @@ class serialConnection(printerConnectionBase.printerConnectionBase): return self._process.stdin.write('STOP\n') self._printProgress = 0 + self._ZPosition = 0 + self._pausePosition = None self.coolDown() self.disableSteppers() @@ -134,9 +139,80 @@ class serialConnection(printerConnectionBase.printerConnectionBase): if not (self.isPrinting() or self.isPaused()) or self._process is None: return if value: + start_gcode = profile.getAlterationFileContents('start.gcode') + start_gcode_lines = len(start_gcode.split("\n")) + parkX = profile.getMachineSettingFloat('machine_width') - 10 + parkY = profile.getMachineSettingFloat('machine_depth') - 10 + maxZ = profile.getMachineSettingFloat('machine_height') - 10 + #retract_amount = profile.getProfileSettingFloat('retraction_amount') + retract_amount = 5.0 + moveZ = 10.0 + + if self._printProgress - 5 > start_gcode_lines: # Substract 5 because of the marlin queue + x = None + y = None + e = None + f = None + for i in xrange(self._printProgress - 1, start_gcode_lines, -1): + line = self._gcodeData[i] + if ('G0' in line or 'G1' in line) and 'X' in line and x is None: + x = float(re.search('X(-?[0-9\.]*)', line).group(1)) + if ('G0' in line or 'G1' in line) and 'Y' in line and y is None: + y = float(re.search('Y(-?[0-9\.]*)', line).group(1)) + if ('G0' in line or 'G1' in line) and 'E' in line and e is None: + e = float(re.search('E(-?[0-9\.]*)', line).group(1)) + if ('G0' in line or 'G1' in line) and 'F' in line and f is None: + f = int(re.search('F(-?[0-9\.]*)', line).group(1)) + if x is not None and y is not None and f is not None and e is not None: + break + if f is None: + f = 1200 + + if x is not None and y is not None: + # Set E relative positioning + self.sendCommand("M83") + # Retract 1mm + self.sendCommand("G1 E-%f F120" % retract_amount) + + #Move the toolhead up + newZ = self._ZPosition + moveZ + if maxZ < newZ: + newZ = maxZ + if newZ > self._ZPosition: + self.sendCommand("G1 Z%f F200\n" % (newZ)) + + #Move the head away + self.sendCommand("G1 X%f Y%f F9000\n" % (parkX, parkY)) + + #Disable the E steppers + self.sendCommand("M84 E0\n") + # Set E absolute positioning + self.sendCommand("M82\n") + + self._pausePosition = (x, y, self._ZPosition, f, e) self._process.stdin.write("PAUSE\n") else: + if self._pausePosition: + retract_amount = profile.getProfileSettingFloat('retraction_amount') + # Set E relative positioning + self.sendCommand("M83") + #Push the filament back, and retract again, the properly primes the nozzle when changing filament. + self.sendCommand("G1 E%f F120\n" % (retract_amount)) + self.sendCommand("G1 E-%f F120\n" % (retract_amount)) + + # Position the toolhead to the correct position again + self.sendCommand("G1 X%f Y%f Z%f F%d\n" % self._pausePosition[0:4]) + + # Prime the nozzle again + self.sendCommand("G1 E%f F120\n" % (retract_amount)) + # Set proper feedrate + self.sendCommand("G1 F%d\n" % (self._pausePosition[3])) + # Set E absolute position to cancel out any extrude/retract that occured + self.sendCommand("G92 E%f\n" % (self._pausePosition[4])) + # Set E absolute positioning + self.sendCommand("M82\n") self._process.stdin.write("RESUME\n") + self._pausePosition = None #Amount of progression of the current print file. 0.0 to 1.0 def getPrintProgress(self):