[英]Running different tasks simultaneously in python?
I've written a python program to continuously do the following on a Raspberry Pi 3B+: 我编写了一个python程序来在Raspberry Pi 3B +上连续执行以下操作:
The program mostly does what I intended it to do, but when I check the results in the .txt file, some results are 'impossible' and indicate I'm not reading/converting my serial data properly. 该程序主要完成了我想要的操作,但是当我检查.txt文件中的结果时,某些结果是“不可能的”,并指示我没有正确读取/转换我的串行数据。 The sensor also outputs data at 100 telegrams/second, which is nowhere near the actual rate at which the Raspberry Pi is saving results (around 2 measurements/second). 传感器还以100电报/秒的速度输出数据,这远不及Raspberry Pi保存结果的实际速率(大约2次测量/秒)。
I've tried writing a program that only reads the serial data, nothing else, and this is able to keep up with the sensor. 我尝试编写仅读取串行数据的程序,而别的什么也不能读取,并且可以跟上传感器的速度。 I also tried replacing the checking of the header with a ser.read_until() (leaving the useless headers at the end of each telegram). 我还尝试用ser.read_until()替换对标头的检查(在每个电报的末尾保留无用的标头)。 However this resulted in telegrams of varying lengths, making the parsing into the 6 variables harder. 但是,这导致电报的长度不同,这使得对6个变量的解析更加困难。 Check this link to see what a telegram consists of according to specs. 检查此链接,以查看根据规格组成的电报。 The code I use now (below) reads the telegram in pieces (2, 2, 1, 2, 2, 1 bytes) but sometimes returns values that seem misinterpreted. 我现在(下面)使用的代码以分段方式(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")
I expect the program to parse each incoming telegram into 6 pieces and translate these pieces into results (integers or floats), but sometimes the values of these results turn out way too high (impossible for the sensor). 我希望程序将每个传入的电报解析为6个部分,并将这些部分转换为结果(整数或浮点数),但有时这些结果的值会变得过高(对于传感器而言是不可能的)。 I expect this to be caused by manually reading the different bytes (taking too much time and missing parts of the telegram as the sensor continuously spits out data). 我希望这是由手动读取不同的字节引起的(由于传感器不断吐出数据,因此花费了太多时间并丢失了电报的某些部分)。
How could I ensure the correct reading and converting of the serial data? 如何确保正确读取和转换串行数据? Also if the sensor outputs data at 100 telegrams/second but the camera can't keep up with 100 pictures/second, is it possible to calculate a moving average instead of using just one of many telegrams? 同样,如果传感器以每秒100封电报的速度输出数据,但相机无法跟上每秒100张照片的速度,那么是否可以计算移动平均值而不是仅使用许多电报之一? Edit: Added picture of telegram's specifications to help understand the serial data + added complete python program. 编辑:添加了电报规范的图片,以帮助理解串行数据+添加了完整的python程序。
I would use read_until()
to read up to the three header bytes and some saner and more readable way to turn the data bytes into values. 我将使用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.