【问题标题】:How to read serial data with multiprocessing in python?如何在python中使用多处理读取串行数据?
【发布时间】:2018-04-04 21:17:07
【问题描述】:

我有一个不定期输出数据的设备。我想以 2 秒的间隔将数据写入 csv。所以我认为使用队列进行多处理可能会起作用。

在这里,我试图将数据从一个进程传递到另一个进程,但我得到了串行异常。另外,我无法在 IDLE 上运行它。所以我坚持使用终端。因此,错误消息一打开就关闭。

代码如下:

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()

当我运行一个单独的模块来收集数据时,它运行良好并收集数据。

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) 

【问题讨论】:

  • 哪个平台?这是窗户吗?在启动子进程之前,您在模块级别打开串行端口。那不应该只是在串行阅读器功能中吗?
  • Read_Data() 进程中初始化您的整个串行接口 - 一旦启动,它就不会共享在您的主进程中建立的连接。
  • 是的,我使用的是 Windows。不,它没有用。我把它放在 Read_data 函数的 try 块中。还是一样的输出

标签: multithreading python-3.x queue python-multiprocessing pyserial


【解决方案1】:

当 q.empty() 为 True 时,Disp_Data() 函数将停止运行。在我的情况下,循环立即退出。

可能有助于显示 SerialException 抛出的错误消息以查看原因:

except serial.SerialException as msg:
        print( "Error opening serial port %s" % msg)

另外,最好优雅地关闭子进程。就我而言,它们在杀死主进程后继续运行,因此 Read_Data() 进程保持端口打开。

多处理模块不喜欢酸洗 pyserial。

以下代码片段适用于我的 Windows10 机器

  • 改为使用线程。
  • 在此处和此处添加了一些打印语句以了解什么是 正在发生。
  • 使用 multiprocessing.Event() 改进关机。
  • 打印异常错误消息以查看导致串行异常的原因。
  • 串行端口上的一秒超时以允许读取循环继续。
    • 发布代码可能不需要。


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")

【讨论】:

  • 你使用线程而不是进程问题是进程不能接受serialPort作为参数,所以最好在readdata中实现serialport
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-21
  • 2017-04-14
  • 1970-01-01
相关资源
最近更新 更多