【发布时间】:2019-11-27 10:26:57
【问题描述】:
我编写了一个 python 程序来在 Raspberry Pi 3B+ 上连续执行以下操作:
- 检查日期/时间。
- 检查以当前日期/时间为名称的目录是否可用,如果没有则创建目录。
- 从传感器读取串行数据。
- 将串行数据转换为可读结果。
- 检查触发器的结果。
- 检查 GPIO 引脚是否有额外的外部触发器。
- IF 触发:使用 PiCamera 模块拍照,将照片以日期/时间作为名称保存在目录中,创建/附加结果为 .txt 文件。
该程序主要按照我的意图执行,但是当我检查 .txt 文件中的结果时,有些结果是“不可能的”,表明我没有正确读取/转换我的串行数据。该传感器还以 100 报文/秒的速度输出数据,这与 Raspberry Pi 保存结果的实际速率(大约 2 次测量/秒)相去甚远。
我尝试编写一个只读取串行数据的程序,没有其他内容,这能够跟上传感器的速度。我还尝试用 ser.read_until() 替换对标头的检查(将无用的标头留在每个电报的末尾)。然而,这导致了不同长度的电报,使得解析成 6 个变量变得更加困难。 Check this link to see what a telegram consists of according to specs. 我现在使用的代码(如下)以片段(2、2、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程序。
【问题讨论】:
-
请问什么是“电报”?为什么要删除所有
import语句?您正在读取的传感器是什么? -
如果您测试
if x != b'~~~',则无需在您的else语句中测试相反的情况。 -
如果您与
"~~~"的三字节标头不同步,我想知道是否最好读取单个额外字符以尝试恢复同步,而不是继续读取 9 个字节当您显然不再在 9 字节边界上对齐时。我不确定……只是大声思考。 -
在您的
pass语句附近,您可能会使用if not os.path.isdir(save_path):然后使用os.mkdir(save_path)做得更好,只需省略else子句。 -
也许您可以使用子进程或不同的线程来捕获图片,以便您可以跟上主线程中传入的串行数据?
标签: python raspberry-pi raspberry-pi3 python-3.5