簡體   English   中英

在python中同時運行不同的任務?

[英]Running different tasks simultaneously in python?

我編寫了一個python程序來在Raspberry Pi 3B +上連續執行以下操作:

  • 檢查日期/時間。
  • 檢查目錄是否可用,以當前日期/時間為名稱,如果沒有,則創建目錄。
  • 從傳感器讀取串行數據。
  • 將串行數據轉換為可讀的結果。
  • 檢查結果以獲取觸發器。
  • 檢查GPIO引腳是否有額外的外部觸發。
  • 如果已觸發:使用PiCamera模塊拍照,將帶有日期/時間作為名稱的圖片保存在目錄中,然后將結果創建/追加到.txt文件中。

該程序主要完成了我想要的操作,但是當我檢查.txt文件中的結果時,某些結果是“不可能的”,並指示我沒有正確讀取/轉換我的串行數據。 傳感器還以100電報/秒的速度輸出數據,這遠不及Raspberry Pi保存結果的實際速率(大約2次測量/秒)。

我嘗試編寫僅讀取串行數據的程序,而別的什么也不能讀取,並且可以跟上傳感器的速度。 我還嘗試用ser.read_until()替換對標頭的檢查(在每個電報的末尾保留無用的標頭)。 但是,這導致電報的長度不同,這使得對6個變量的解析更加困難。 檢查此鏈接,以查看根據規格組成的電報。 我現在(下面)使用的代碼以分段方式(2、2、1、1、2、2、1個字節)讀取電報,但有時返回的值似乎被誤解了。

#!/usr/bin/env python
import time, serial, os, sys, stat, os.path, subprocess                                 
import RPi.GPIO as GPIO
from picamera import PiCamera
from datetime import datetime

ser = serial.Serial(                                                                    
    port='/dev/serial0',
    baudrate = 19200,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=0)

signaltrigger = 60
trigger = 24
GPIO.setmode(GPIO.BCM)                                                                  
GPIO.setup(trigger, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)                                

now = datetime.now()                                                                    
data_dir = now.strftime("%d-%m-%Y")
save_path = "/home/pi/serial/"+data_dir+"/"                                            
test = os.path.isdir(save_path)                                                         
if test == False:                                                                       
    os.mkdir(save_path)                                                                 
    subprocess.call(['chmod', '-R', '777', '/home/pi/serial'])                          
else:
    pass

cam = PiCamera()                                                                        
cam.rotation = 90                                                                       
cam.resolution = (480, 360)                                                             
cam.start_preview()                                                                     
signaltriggerA = 0
signaltriggerB = 0

while 1:
    now = datetime.now()                                                                    
    time_exact = now.strftime(str(now)[11:23])                                          
    date_time = now.strftime("%d-%m-%Y %H:%M")                                          
    data_dir = now.strftime("%d-%m-%Y")                                                 
    save_path = "/home/pi/serial/"+data_dir+"/"                                         
    completename = os.path.join(save_path, date_time+".txt")                            
    namepic = str(time_exact+".jpg")
    completenamepic = os.path.join(save_path, data_dir+" "+time_exact+".jpg")           
    test = os.path.isdir(save_path)                                                     
    if test == False:                                                                   
        os.mkdir(save_path)                                                             
        subprocess.call(['chmod', '-R', '777', '/home/pi/serial'])
        pass
    else:
        pass
    x = ser.read(3)                                                                     
    if x != b'~~~':                                                                     
        print("Header mismatched")
        x = ser.read(9)                                                                 
        d = 0
        j = 0
    elif x == b'~~~':
        print("Serial communication started...")
        y = ser.read(2)                                                                 
        a = ser.read(2)
        c = ser.read(1)
        e = ser.read(2)
        g = ser.read(2)
        i = ser.read(1)
        z = int.from_bytes(y, byteorder='little', signed=False)/100                     
        b = round(int.from_bytes(a, byteorder='little', signed=True)*0.0367, 2)
        d = int.from_bytes(c, byteorder='little', signed=False)                         
        f = int.from_bytes(e, byteorder='little', signed=False)/100                     
        h = round(int.from_bytes(g, byteorder='little', signed=True)*0.0367, 2)
        j = int.from_bytes(i, byteorder='little', signed=False)                         
    if d >= signaltrigger:
        signaltriggerA = 1
    else:
        signaltriggerA = 0
    if j >= signaltrigger:
        signaltriggerB = 1
    else:
        signaltriggerB = 0
    if signaltriggerA or signaltriggerB or GPIO.input(trigger):        
        cam.capture(completenamepic)
        M = open(completename,"a+",encoding='utf-8')                                    
        M.write('[%s]: Distance(a) = %s [m], Velocity(a) = %s [km/h], Signal(a) = %s [dB], Distance(r) = %s [m], Velocity(r) = %s [km/h], Signal(r) = %s [dB]. Trigger(a) = %s, Trigger(r) = %s, Trigger(ETZ) = %s. Picture: %s\n'%(time_exact,z,b,d,f,h,j,signaltriggerA,signaltriggerB,GPIO.input(trigger),namepic))
        M.close()
        pass
    else:
        print("No triggers detected")

我希望程序將每個傳入的電報解析為6個部分,並將這些部分轉換為結果(整數或浮點數),但有時這些結果的值會變得過高(對於傳感器而言是不可能的)。 我希望這是由手動讀取不同的字節引起的(由於傳感器不斷吐出數據,因此花費了太多時間並丟失了電報的某些部分)。
如何確保正確讀取和轉換串行數據? 同樣,如果傳感器以每秒100封電報的速度輸出數據,但相機無法跟上每秒100張照片的速度,那么是否可以計算移動平均值而不是僅使用許多電報之一? 編輯:添加了電報規范的圖片,以幫助理解串行數據+添加了完整的python程序。

我將使用read_until()讀取最多三個標頭字節,以及將數據字節轉換為值的更簡潔,更易讀的方法。

#!/usr/bin/env python3
from ctypes import LittleEndianStructure, c_int16, c_uint16, c_uint8, sizeof
from datetime import datetime
import os


class SensorData(LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        ('_distance', c_uint16),
        ('_velocity', c_int16),
        ('signal_strength', c_uint8),
    ]

    @property
    def distance(self):
        return self._distance / 100

    @property
    def velocity(self):
        return self._velocity * 0.0367

    def to_string(self, name):
        return (
            f'Distance({name}) = {self.distance} [m],'
            f' Velocity({name}) = {self.velocity} [km/h],'
            f' Signal({name}) = {self.signal_strength} [dB]'
        )


class Message(LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        ('sensor_a', SensorData),
        ('sensor_b', SensorData),
    ]


def main():
    # ...

    while True:
        now = datetime.now()
        save_path = f'/home/pi/serial/{now:%d-%m-%Y}'
        log_path = os.path.join(save_path, f'{now:%d-%m-%Y %H:%M}.txt')
        picture_filename = f'{now:%H:%M:%S.%f}.jpg'
        picture_path = os.path.join(save_path, picture_filename)
        os.makedirs(save_path, exist_ok=True)

        ser.read_until(b'~~~')
        message = Message.from_buffer_copy(ser.read(sizeof(Message)))
        signal_trigger_a = message.sensor_a.signal_strength >= signal_trigger
        signal_trigger_b = message.sensor_b.signal_strength >= signal_trigger
        gpio_trigger = GPIO.input(trigger)
        if signal_trigger_a or signal_trigger_b or gpio_trigger:
            cam.capture(picture_path)
            with open(log_path, 'a', encoding='utf-8') as log_file:
                log_file.write(
                    f'[{now}]:'
                    f' {message.sensor_a.to_string("a")},'
                    f' {message.sensor_a.to_string("r")}.'
                    f' Trigger(a) = {signal_trigger_a},'
                    f' Trigger(r) = {signal_trigger_b},'
                    f' Trigger(ETZ) = {gpio_trigger}.'
                    f' Picture: {picture_filename}\n'
                )
        else:
            print('No triggers detected')


if __name__ == '__main__':
    main()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM