Reputation: 21
I have a device that outputs data at irregular intervals. I want to write data onto a csv in 2 second intervals. So I figured multiprocessing with a queue might work.
Here I'm trying to just pass data from one process to another but I get Serial Exception. Also, I'm unable to run it on IDLE. So I'm stuck with using the terminal. As a result, the error message closes as soon as it opens.
Here's the code:
import multiprocessing
import time
import datetime
import serial
try:
fio2_ser = serial.Serial("COM3",
baudrate=2400,
bytesize=serial.EIGHTBITS,
parity =serial.PARITY_ODD)
except serial.SerialException:
print("FiO2 Analyser Device not detected")
def Read_Data(q):
global fio2_ser
while True:
try:
fio2_data = fio2_ser.readline().decode('utf-8')
fio2_data = str(fio2_data).replace("\r\n","")
fio2_data = fio2_data.replace("\x000","")
except:
fio2_data = "FiO2 Data Unavailable"
q.put(fio2_data)
def Disp_Data(q):
while q.empty() is False:
fio2_data = q.get()
print(fio2_data)
time.sleep(2)
if __name__ == "__main__":
q = multiprocessing.Queue()
p1 = multiprocessing.Process(target=Read_Data, args=(q,))
p2 = multiprocessing.Process(target=Disp_Data, args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
When I run a separate module to collect data, it runs fine and collects data.
import serial
try:
fio2_ser = serial.Serial("COM3",
baudrate=2400,
bytesize=serial.EIGHTBITS,
parity =serial.PARITY_ODD)
except serial.SerialException:
print("FiO2 Analyser Device not detected")
def Reader():
global fio2_ser
try:
fio2_data = fio2_ser.readline().decode('utf-8')
fio2_data = str(fio2_data).replace("\r\n","")
fio2_data = fio2_data.replace("\x000","")
return fio2_data
except:
return "FiO2 Data Unavailable"
if __name__ =='__main__':
value = Reader()
print(value)
Upvotes: 1
Views: 8566
Reputation: 367
The Disp_Data() function will stop running when q.empty() is True. In my case the loop exits immediately.
Might be useful to display the error message thrown by SerialException to see the cause:
except serial.SerialException as msg:
print( "Error opening serial port %s" % msg)
Also, it would be better to gracefully shut down the child-processes. In my case, they kept running after killing the main process, so the Read_Data() process keeps the port open.
The multiprocessing module doesn't like pickling pyserial.
This following code snip works on my Windows10 box
import threading, multiprocessing
import time
import serial
import sys
def OpenSerialPort(port=""):
print ("Open port %s" % port)
fio2_ser = None
try:
fio2_ser = serial.Serial(port,
baudrate=2400,
bytesize=serial.EIGHTBITS,
parity =serial.PARITY_ODD)
except serial.SerialException as msg:
print( "Error opening serial port %s" % msg)
except:
exctype, errorMsg = sys.exc_info()[:2]
print ("%s %s" % (errorMsg, exctype))
return fio2_ser
def Read_Data(queue, serialPort, stopped):
print ("Start reading data.")
serialPort.timeout = 1.0
while not stopped.is_set():
fio2_data = ''
try:
#print "Reading port..."
fio2_data = serialPort.readline()
except:
exctype, errorMsg = sys.exc_info()[:2]
print ("Error reading port - %s" % errorMsg)
stopped.set()
break
if len(fio2_data) > 0:
fio2_data = fio2_data.decode('utf-8')
fio2_data = str(fio2_data).replace("\r\n","")
fio2_data = fio2_data.replace("\x000","")
queue.put(fio2_data)
else:
queue.put("Read_Data() no Data")
serialPort.close()
print ("Read_Data finished.")
def Disp_Data(queue, stopped):
print ("Disp_Data started")
while not stopped.is_set():
#print "Check message queue."
if queue.empty() == False:
fio2_data = queue.get()
print(fio2_data)
print ("Disp_Data finished")
if __name__ == "__main__":
#serialPort = OpenSerialPort('/dev/ttyUSB0')
serialPort = OpenSerialPort('COM3')
if serialPort == None: sys.exit(1)
queue = multiprocessing.Queue()
stopped = threading.Event()
p1 = threading.Thread(target=Read_Data, args=(queue, serialPort, stopped,))
p2 = threading.Thread(target=Disp_Data, args=(queue, stopped,))
p1.start()
p2.start()
loopcnt = 20
while (loopcnt > 0) and (not stopped.is_set()):
loopcnt -= 1
print ("main() %d" % loopcnt)
try:
time.sleep(1)
except KeyboardInterrupt: #Capture Ctrl-C
print ("Captured Ctrl-C")
loopcnt=0
stopped.set()
stopped.set()
loopcnt=0
print ("Stopped")
p1.join()
p2.join()
serialPort.close()
print ("Done")
Upvotes: 1