我在一个项目中工作,我需要通过视频实时显示外部数据(来自带有BME280传感器的ESP32)。我正在使用Python中的opencv从我的网络摄像头获取视频。 视频工作正常,直到我将获取传感器数据的代码放在视频上,它变得非常慢,每1/2秒冻结一次(与ESP32代码中的延迟有关)。 我也发现超时(在python代码中)有一个非常重要的作用。。。如果我把它放在0的视频流罚款,但数据不能正常显示。 因此,我知道我的代码中的readline()具有阻塞行为,如果它不接收行的最后一个字符(“\n”),它就不能“while”继续循环。 问题是,我如何重新定义我的代码来避免这种情况
Python代码:
import serial
import cv2 as cv
import datetime
cap = cv.VideoCapture(0)
if not cap.isOpened():
print("Camera cannot open")
exit()
arduino = serial.Serial('COM7', baudrate=115200, timeout = 0)
while True:
ret , frame= cap.read()
if not ret:
print("void frame")
break
#reading line from ESP32
rawString = str(arduino.readline())
print(rawString)
# replace "\r" and "\n" for ""
rawString = rawString.replace("\\r\\n'","")
rawString = rawString.replace("b'","")
#Add data to video (real time and sensor)
hora = str(datetime.datetime.now())
print(type(hora))
font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(frame, hora,(10,50), font, 0.8,(255,0,0),2,cv.LINE_AA)
cv.putText(frame, rawString,(10,80), font, 0.8,(255,0,0),2,cv.LINE_AA)
#show the video
cv.imshow("Video", frame)
if cv.waitKey(1) == ord('q'):
break
arduino.close()
cap.release()
cv.destroyAllWindows()
ESP32代码:
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
Adafruit_BME280 bme; // I2C
unsigned long delayTime;
void setup() {
Serial.begin(115200);
Serial.println(F("BME280 test"));
bool status;
// default settings
// (you can also pass in a Wire library object like &Wire2)
status = bme.begin(0x77);
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
Serial.println("-- Default Test --");
delayTime = 500;
}
void loop() {
printValues();
delay(delayTime);
}
void printValues() {
Serial.println(bme.readTemperature());
}
我可以马上想出三种方法来解决你的问题
简单的解决方案是以非阻塞方式从ESP32读取温度。作为一种有用的方法,您可以在创建pyserial端口时指定一个非常小的超时值,比如1毫秒。如果ESP32的串行缓冲区中没有数据,那么}
readline()
将不返回任何内容。发生这种情况时,只需跳过更新变量rawString
。见notes on ^{请注意,正确地实现非阻塞读取需要将pyserial超时参数设置为0(正如您所做的),然后使用^{} 逐字节读取ESP32从pyserial缓冲区发送的任何内容。您必须自己进行字符串处理以检测传感器数据行。这并不难,所以您可以自己实施
高级解决方案是线程
readline()
是一种阻塞操作,此类操作应该在单独的线程中运行,以避免阻塞视频处理。因此,您可以自由地启动一个新线程,并在那里运行与ESP32的所有通信。要将温度传播到主线程,只需使用一个共享全局变量或类似的东西(Python中最简单的带有原子更新的数字类型)一个糟糕的解决方案是更新ESP32,以与视频帧速率相同的频率发送温度更新。我会避免这样:)
相关问题 更多 >
编程相关推荐