Fixed temperature extraction regular expression

This commit is contained in:
Jaime van Kessel 2015-04-03 10:45:08 +02:00
parent e82fa17548
commit 208e9d28bf

View File

@ -4,6 +4,7 @@ import serial
import threading import threading
import time import time
import queue import queue
import re
class PrinterConnection(): class PrinterConnection():
def __init__(self, serial_port): def __init__(self, serial_port):
@ -16,8 +17,14 @@ class PrinterConnection():
self._connect_thread = threading.Thread(target = self._connect) self._connect_thread = threading.Thread(target = self._connect)
self._connect_thread.daemon = True self._connect_thread.daemon = True
# Printer is connected
self._is_connected = False self._is_connected = False
# Printer is in the process of connecting
self._is_connecting = False self._is_connecting = False
# The baud checking is done by sending a number of m105 commands to the printer and waiting for a readable
# response. If the baudrate is correct, this should make sense, else we get giberish.
self._required_responses_auto_baud = 10 self._required_responses_auto_baud = 10
self._listen_thread = threading.Thread(target=self._listen) self._listen_thread = threading.Thread(target=self._listen)
@ -37,13 +44,27 @@ class PrinterConnection():
## Keep track where in the provided g-code the print is ## Keep track where in the provided g-code the print is
self._gcode_position = 0 self._gcode_position = 0
# List of gcode lines to be printed
self._gcode = None self._gcode = None
# Number of extruders
self._extruder_count = 1 self._extruder_count = 1
# Temperatures of all extruders
self._extruder_temperatures = [0] * self._extruder_count self._extruder_temperatures = [0] * self._extruder_count
# Target temperatures of all extruders
self._target_extruder_temperatures = [0] * self._extruder_count self._target_extruder_temperatures = [0] * self._extruder_count
#Target temperature of the bed
self._target_bed_temperature = 0 self._target_bed_temperature = 0
# Temperature of the bed
self._bed_temperature = 0 self._bed_temperature = 0
# Current Z stage location
self._current_z = 0
# In order to keep the connection alive we request the temperature every so often from a different extruder. # In order to keep the connection alive we request the temperature every so often from a different extruder.
# This index is the extruder we requested data from the last time. # This index is the extruder we requested data from the last time.
self._temperature_requested_extruder_index = 0 self._temperature_requested_extruder_index = 0
@ -59,9 +80,9 @@ class PrinterConnection():
def isPrinting(self): def isPrinting(self):
if not self._is_connected or self._serial is None: if not self._is_connected or self._serial is None:
return False return False
return self._is_printing return self._is_printing
## Provide a list of G-Codes that need to be printed
def printGCode(self, gcode_list): def printGCode(self, gcode_list):
if self.isPrinting() or not self._is_connected: if self.isPrinting() or not self._is_connected:
return return
@ -71,19 +92,22 @@ class PrinterConnection():
self._is_printing = True self._is_printing = True
self._print_start_time = time.time() self._print_start_time = time.time()
for i in range(0, 4): #Push first 4 entries before accepting other inputs for i in range(0, 4): #Push first 4 entries before accepting other inputs
self._sendNextGcodeLine() self._sendNextGcodeLine()
## Get the serial port string of this connection.
# \return serial port
def getSerialPort(self): def getSerialPort(self):
return self._serial_port return self._serial_port
## Try to connect the serial. This simply starts the thread. ## Try to connect the serial. This simply starts the thread, which runs _connect.
def connect(self): def connect(self):
self._connect_thread.start() if not self._connect_thread.isAlive():
self._connect_thread.start()
## Private connect function run by thread. Can be started by calling connect.
def _connect(self): def _connect(self):
self._is_connecting = True self._is_connecting = True
programmer = stk500v2.Stk500v2() programmer = stk500v2.Stk500v2()
try: try:
programmer.connect(self._serial_port) #Connect with the serial, if this succeeds, it's an arduino based usb device. programmer.connect(self._serial_port) #Connect with the serial, if this succeeds, it's an arduino based usb device.
self._serial = programmer.leaveISP() self._serial = programmer.leaveISP()
@ -94,36 +118,39 @@ class PrinterConnection():
except: except:
Logger.log('i', "Could not establish connection on %s, unknown reasons. Device is not arduino based." % self._serial_port) Logger.log('i', "Could not establish connection on %s, unknown reasons. Device is not arduino based." % self._serial_port)
for baud_rate in self._getBaudrateList(): # If the programmer connected, we know its an atmega based version. Not all that usefull, but it does give some debugging information.
timeout_time = time.time() + 20 for baud_rate in self._getBaudrateList(): #Cycle all baud rates (auto detect)
if self._serial is None: if self._serial is None:
self._serial = serial.Serial(str(self._serial_port), baud_rate, timeout=3, writeTimeout=10000) self._serial = serial.Serial(str(self._serial_port), baud_rate, timeout=3, writeTimeout=10000)
else: else:
if not self.setBaudRate(baud_rate): if not self.setBaudRate(baud_rate):
continue #Could not set the baud rate, go to the next continue #Could not set the baud rate, go to the next
time.sleep(1.5) #Ensure that w are not talking to the bootloader time.sleep(1.5) #Ensure that we are not talking to the bootloader. 1.5 sec seems to be the magic number
sucesfull_responses = 0 sucesfull_responses = 0
timeout_time = time.time() + 5
self._serial.write(b"\n") self._serial.write(b"\n")
self._sendCommand("M105") self._sendCommand("M105") #Request temperature, as this should (if baudrate is correct) result in a command with 'T:' in it
while timeout_time > time.time(): while timeout_time > time.time():
line = self._readline() line = self._readline()
if b"T:" in line: if b"T:" in line:
self._serial.timeout = 0.5 self._serial.timeout = 0.5
self._serial.write(b"\n") self._serial.write(b"\n")
self._sendCommand("M105") # Request temperature, as this should (if baudrate is correct) result in a command with 'T:' in it self._sendCommand("M105")
sucesfull_responses += 1 sucesfull_responses += 1
if sucesfull_responses >= self._required_responses_auto_baud: if sucesfull_responses >= self._required_responses_auto_baud:
self._serial.timeout = 2 self._serial.timeout = 2 #Reset serial timeout
self.setIsConnected(True) self.setIsConnected(True)
return return
self.setIsConnected(False) self.setIsConnected(False)
## Set the baud rate of the serial. This can cause exceptions, but we simply want to ignore those.
def setBaudRate(self, baud_rate): def setBaudRate(self, baud_rate):
try: try:
self._serial.baudrate = baud_rate self._serial.baudrate = baud_rate
return True return True
except Exception as e: except Exception as e:
print(e)
return False return False
def setIsConnected(self, state): def setIsConnected(self, state):
@ -135,7 +162,8 @@ class PrinterConnection():
if self._is_connected: if self._is_connected:
self._listen_thread.start() #Start listening self._listen_thread.start() #Start listening
## Close the printer connection
def close(self): def close(self):
if self._serial != None: if self._serial != None:
self._serial.close() self._serial.close()
@ -145,6 +173,8 @@ class PrinterConnection():
def isConnected(self): def isConnected(self):
return self._is_connected return self._is_connected
## Directly send the command, withouth checking connection state (eg; printing).
# \param cmd string with g-code
def _sendCommand(self, cmd): def _sendCommand(self, cmd):
if self._serial is None: if self._serial is None:
return return
@ -163,7 +193,7 @@ class PrinterConnection():
self._target_bed_temperature = float(re.search('S([0-9]+)', cmd).group(1)) self._target_bed_temperature = float(re.search('S([0-9]+)', cmd).group(1))
except: except:
pass pass
Logger.log('i','Sending: %s' % (cmd)) #Logger.log('i','Sending: %s' % (cmd))
try: try:
command = (cmd + '\n').encode() command = (cmd + '\n').encode()
self._serial.write(command) self._serial.write(command)
@ -179,22 +209,26 @@ class PrinterConnection():
Logger.log('e',"Unexpected error while writing serial port %s" % e) Logger.log('e',"Unexpected error while writing serial port %s" % e)
self.close() self.close()
## Ensure that close gets called when object is destroyed
def __del__(self): def __del__(self):
self.close() self.close()
## Send a command to printer.
# \param cmd string with g-code
def sendCommand(self, cmd): def sendCommand(self, cmd):
if self.isPrinting(): if self.isPrinting():
self._command_queue.put(cmd) self._command_queue.put(cmd)
elif self.isConnected(): elif self.isConnected():
self._sendCommand(cmd) self._sendCommand(cmd)
## Listen thread function.
def _listen(self): def _listen(self):
temperature_request_timeout = time.time()
while self._is_connected: while self._is_connected:
line = self._readline() line = self._readline()
print("listening: " ,line.decode('utf-8',"replace")) #print("listening: " ,line.decode('utf-8',"replace"))
if line is None: if line is None:
break #None is only returned when something went wrong. Stop listening break #None is only returned when something went wrong. Stop listening
if line.startswith(b'Error:'): if line.startswith(b'Error:'):
#Oh YEAH, consistency. #Oh YEAH, consistency.
# Marlin reports an MIN/MAX temp error as "Error:x\n: Extruder switched off. MAXTEMP triggered !\n" # Marlin reports an MIN/MAX temp error as "Error:x\n: Extruder switched off. MAXTEMP triggered !\n"
@ -208,23 +242,37 @@ class PrinterConnection():
self._error_state = line[6:] self._error_state = line[6:]
elif b' T:' in line or line.startswith(b'T:'): #Temperature message elif b' T:' in line or line.startswith(b'T:'): #Temperature message
try: try:
print("TEMPERATURE", float(re.search("T: *([0-9\.]*)", line).group(1))) print("TEMPERATURE", float(re.search(b"T: *([0-9\.]*)", line).group(1)))
self._extruder_temperatures[self._temperatureRequestExtruder] = float(re.search("T: *([0-9\.]*)", line).group(1)) self._extruder_temperatures[self._temperatureRequestExtruder] = float(re.search(b"T: *([0-9\.]*)", line).group(1))
except: except:
pass pass
if b'B:' in line: #Check if it's a bed temperature if b'B:' in line: #Check if it's a bed temperature
try: try:
print("BED TEMPERATURE" ,float(re.search("B: *([0-9\.]*)", line).group(1))) print("BED TEMPERATURE" ,float(re.search(b"B: *([0-9\.]*)", line).group(1)))
except: except:
pass pass
#TODO: temperature changed callback #TODO: temperature changed callback
if self._is_printing: if self._is_printing:
if time.time() > temperature_request_timeout: #When printing, request temperature every 5 seconds.
if self._extruderCount > 0:
self._temperatureRequestExtruder = (self._temperatureRequestExtruder + 1) % self._extruderCount
self.sendCommand("M105 T%d" % (self._temperatureRequestExtruder))
else:
self.sendCommand("M105")
temperature_request_timeout = time.time() + 5
if b'ok' in line: if b'ok' in line:
if not self._commandQueue.empty(): if not self._commandQueue.empty():
self._sendCommand(self._commandQueue.get()) self._sendCommand(self._commandQueue.get())
else: else:
self._sendNextGcodeLine() self._sendNextGcodeLine()
elif b"resend" in line.lower() or b"rs" in line:
try:
self._gcode_position = int(line.replace("N:"," ").replace("N"," ").replace(":"," ").split()[-1])
except:
if b"rs" in line:
self._gcode_position = int(line.split()[1])
else: #Request the temperature on comm timeout (every 2 seconds) when we are not printing.) else: #Request the temperature on comm timeout (every 2 seconds) when we are not printing.)
if line == b'': if line == b'':
@ -233,7 +281,7 @@ class PrinterConnection():
self.sendCommand("M105 T%d" % self._temperature_requested_extruder_index) self.sendCommand("M105 T%d" % self._temperature_requested_extruder_index)
else: else:
self.sendCommand("M105") self.sendCommand("M105")
## Send next Gcode in the gcode list
def _sendNextGcodeLine(self): def _sendNextGcodeLine(self):
if self._gcode_position >= len(self._gcode_list): if self._gcode_position >= len(self._gcode_list):
#self._changeState(self.STATE_OPERATIONAL) #self._changeState(self.STATE_OPERATIONAL)