使用pyserial读取多个串行设备时延迟大

Large delay when reading multiple serial devices using pyserial

我正在尝试使用 pyserial 从多个串行设备读取数据,并将所有内容同步在一起。最后我希望代码为:

- read serial from laser
- read serial from gps
- get a single string with [gps_reading, laser_reading]

GPS 刷新率高达 5hz 激光按需发送高达 20 赫兹左右的值

孤立地,它们都工作正常,我的响应时间也很快。但是,当我尝试读取多个数据时,我会出现延迟,而且延迟会随着时间的推移而增加。

代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*- 
import serial
import time
import gps
import laser

#serial
def serialGeneric(device, baudRate):
    ser = serial.Serial(
    port=device,
    baudrate=baudRate,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    )
    return ser

#Device 1
gpsSerial = serialGeneric("/dev/ttyUSB0",9600)
gps.gps_init(gpsSerial)

#Device 2
laserSerial = serialGeneric("/dev/ttyUSB1",19200)

i = 1
start_time = time.time()

while i<50:
    dis = laser.lrf_getDistance(laserSerial)
    print dis
    pos = gps.gps_getData(gpsSerial)
    print pos

    i+=1


print("--- %s seconds ---" % (time.time() - start_time))

gps 和激光功能只需发送适当的命令来请求数据: 即

#!/usr/bin/env python
# -*- coding: utf-8 -*- 
import serial

def lrf_getDistance(ser):
    i = 0
    while i == 0:
        ser.write("d\r\n")
        ser.flush()
        msg = ser.readline()
        try:
            msg = float(msg)
            i == 1
            return msg
        except ValueError:
            pass 

当 运行 编译代码时,如果我注释掉 'pos = gps.gps_getData(gpsSerial)' 和 'print pos',"laser" 设备输出几乎是立即的。取消注释后 "laser" 输出非常滞后。

以防相关,我运行在台式机上编写代码。

任何人都可以建议我如何摆脱滞后吗?

新代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*- 

import serial
import time
import threading
import gps
import laser

#serial
def serialGeneric(device, baudRate):
    ser = serial.Serial(
    port=device,
    baudrate=baudRate,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS
    #timeout=0
    )
    return ser

#Device 1
gpsSerial = serialGeneric("/dev/ttyUSB0",9600)

#Device 2
laserSerial = serialGeneric("/dev/ttyUSB1",19200)

class myThreadGPS (threading.Thread):
    def __init__(self, ser):
        threading.Thread.__init__(self)
        self.ser = ser
    def run(self):
        print "Starting GPS"
        gps.gps_getDataINF(self.ser)

class myThreadLAS (threading.Thread):
    def __init__(self, ser):
        threading.Thread.__init__(self)
        self.ser = ser
    def run(self):
        print "Starting Laser"
        laser.lrf_getDistanceINF(self.ser)
# Create new threads
thread1 = myThreadGPS(gpsSerial)
thread2 = myThreadLAS(laserSerial)

# Start new Threads
thread1.start()
thread2.start()

如评论中所述,这 "solved" 手头的问题。不幸的是,我仍然不太明白为什么需要这样做。

对于每个线程,将有以下同步资源:

  • 指示循环何时结束以及收到数据的事件
  • 共享变量,存储要打印的数据
  • 另一个指示何时可以开始新循环的事件。每个线程在开始循环之前必须等待这个标志,并且会在两个线程结束各自的任务时引发。

我没有仔细检查以下代码的语法,因此可能存在一些语法错误。基本上,线程在读取串行端口时与主例程同步。当主程序允许开始一个新的循环时,他们再次并行读取端口。

class myThreadGPS (threading.Thread):
    def __init__(self, ser, start_event, end_event, pos):
        threading.Thread.__init__(self)
        self.ser = ser
        self.start_event = start_event
        self.end_event = end_event
        self.pos = pos
    def run(self):
        self.start_event.wait()
        self.start_event.clear()
        print "Starting GPS"
        self.pos[0] = gps.gps_getDataINF(self.ser)
        self.end_event.set()

class myThreadLAS (threading.Thread):
    def __init__(self, ser, start_event, end_event, dis):
        threading.Thread.__init__(self)
        self.ser = ser
        self.start_event = start_event
        self.end_event = end_event
        self.dis = dis
    def run(self):
        self.start_event.wait()
        self.start_event.clear()
        print "Starting Laser"
        self.dis[0] = laser.lrf_getDistanceINF(self.ser)
        self.end_event.set()

#Declare the used events
gps_end_event = threading.Event()
laser_end_event = threading.Event()
gps_start_event = threading.Event()
laser_start_event = threading.Event()
#Initialize shared variables
pos = [None]
dis = [None]
# Create new threads
thread1 = myThreadGPS(gpsSerial, gps_start_event, gps_end_event, pos)
thread2 = myThreadLAS(laserSerial, laser_start_event, laser_end_event, dis)

# Start new Threads
thread1.start()
thread2.start()
#Start events initially set to True
gps_start_event.set()
laser_start_event.set()
while True:
    #Wait for both threads to end and reset them.
    gps_end_event.wait()
    gps_end_event.clear()
    laser_end_event.wait()
    laser_end_event.clear()
    #print the shared variables
    print pos[0]
    print dis[0]
    gps_start_event.set()
    laser_start_event.set()