2017-01-04 41 views
0

我試圖從多個串行設備使用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',「激光」設備輸出即時。取消註釋後,「激光」輸出非常滯後。

如果相關,我在臺式機上運行代碼。

任何人都可以請建議如何擺脫滯後?

  • 編輯:我已更改代碼以在多個線程中運行這兩個函數。在python的多線程tutorialspoint教程之後。

新的代碼如下:

#!/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() 

正如評論所說,這個在手「解決」問題。不幸的是,我仍然不明白爲什麼這是必要的。

+0

你怎麼知道這是激光指令變慢而不是註釋和未註釋激光指示?對於你所說的,看起來gps指令是緩慢的 – Jalo

+0

請注意,你沒有設置任何超時,因此它將無限期地等待,直到讀取到的值爲 – Jalo

+0

Hi Jalo,謝謝你的評論,我只是進行測試以檢查「GPS」並且讀數不滯後,GPS給我時間並且我可以看到沒有滯後。相對於「激光」(能夠在20Hz採樣),GPS確定地較慢(5Hz)。 – Khris

回答

1

對於每個線程,將有下面的同步資源:

  • 指示何時週期已經結束,並且將數據接收
  • 共享變量,其中要被打印的數據被存儲的事件
  • 另一個事件表明何時可以開始一個新的循環。每個線程在開始循環之前都必須等待該標誌,並在兩個線程結束其各自任務時提升。

我沒有仔細檢查以下代碼的語法,因此可能會出現一些語法錯誤。基本上,線程在讀取串行端口時與主程序同步。當主程序允許開始一個新的循環時,他們再次並行讀取端口。

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

謝謝,我現在就試試這個,讓你知道。只是爲了讓我明白。在主循環中。我們首先將它們設置爲假,然後我們將它們設置爲true?該事件的默認行爲是否爲真? – Khris

+0

默認情況下,它們被設置爲False。因此,開始事件必須在開始時設置爲True,我將改變 – Jalo

+0

我現在可以看到以線程運行的兩個事件,但dis和pos總是看起來是「無」,並且線程總是讀取值(不停止更新值dis和pos,而不是等待)。這可能是因爲我的功能? 高清lrf_getDistanceINF(SER): \t而真: \t \t味精= lrf_getDistance(SER) – Khris