Arduino 和 Python (3.x) 之间的 Serial.read() 和 Struct.pack / 串行通信问题
Posted
技术标签:
【中文标题】Arduino 和 Python (3.x) 之间的 Serial.read() 和 Struct.pack / 串行通信问题【英文标题】:Problem with Serial.read() and Struct.pack / serial communication between Arduino and Python (3.x) 【发布时间】:2019-09-04 09:31:42 【问题描述】:我在尝试使用 串行通信 将一些值从 Python 3.x
发送到 Arduino
时遇到问题。
小于 255 时正常,大于 255 时会报错。
我在 Python 中使用 Struct.pack
,在 Arduino 中使用 Serial.read()
Python 代码:
import cv2
import numpy as np
from serial import Serial
import struct
arduinoData = Serial('com6', 9600)
cap = cv2.VideoCapture(0)
hand_cascade = cv2.CascadeClassifier('hand.xml')
while(True):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
handdetect = hand_cascade.detectMultiScale(gray, 1.6, 3)
for (x, y, w, h) in handdetect:
cv2.rectangle(frame, (x, y), (x + w, y + h), (127, 127, 0), 2)
xcenter = int(x + w/2)
ycenter = int(y + h/2)
#This is where i send values to serial port
arduinoData.write(struct.pack('>II',xcenter,ycenter))
cv2.imshow('Webcam', frame)
k = cv2.waitKey(25) & 0xff
if k == 27:
break
cap.release()
cv2.destroyAllWindows()
Arduino 代码:
int SerialData[8];
const int led = 7;
int xcenter;
int ycenter;
void setup()
Serial.begin(9600);
pinMode(led, OUTPUT);
void loop()
if (Serial.available() >= 8)
for (int i = 0; i < 8; i++)
SerialData[i] = Serial.read();
xcenter = (SerialData[0]*1000) + (SerialData[1]*100) + (SerialData[2]*10) + SerialData[3];
ycenter = (SerialData[4]*1000) + (SerialData[5]*100) + (SerialData[6]*10) + SerialData[7];
if (xcenter <= 200)
digitalWrite(led, LOW);
else if(xcenter > 200)
digitalWrite(led, HIGH);
//Serial.flush();
就像我在本主题开头所说的那样,当xcenter > 200 && xcenter <= 255
时,LED 亮起(这意味着代码工作正常)。
但是当xcenter > 255
时,LED 熄灭(这里有问题)。
我想我已经读取了 Arduino 代码中的所有 8 个字节,并在 struct.pack
中使用了 unsigned int >II
,那么我的错误是什么以及在哪里?
我很感激所有的帮助!谢谢!
编辑和修复。 “它不会将 int 打包成数字 (0-9),而是将它们打包成字节 (0-255)”_
所以这是错误的:
xcenter = (SerialData[0]*1000) + (SerialData[1]*100) + (SerialData[2]*10) + SerialData[3];
ycenter = (SerialData[4]*1000) + (SerialData[5]*100) + (SerialData[6]*10) + SerialData[7];
改成这个(对于大值):
long result = long((unsigned long(unsigned char(SerialData[0])) << 24) | (unsigned long(unsigned char(SerialData[1])) << 16)
| (unsigned long(unsigned char(SerialData[2])) << 8) | unsigned char(SerialData[3]));
或者改成这个(对于小值):
xcenter = (SerialData[2]*256) + SerialData[3];
ycenter = (SerialData[6]*256) + SerialData[7];
或者这个(也适用于小值):
int result = int((unsigned int(unsigned char(SerialData[2])) << 8) | unsigned char(SerialData[3]));
代码会完美运行!
【问题讨论】:
它不会将 int 打包成数字 (0-9),而是将它们打包成字节 (0-255)。 256 被打包到 00 00 01 00 中,您将其解压缩为 10x1,而 255 是 00 00 00 ff,在您的情况下为 1x255。将 10 的幂更改为 256 (2^8) 的幂。或者不要打包它们,只需将它们转换为字符串,例如 ":04d:04d".format(intA, intB) 感谢@IcedLance 向我展示了我的错误。我是代码新手,请问第一个字节代表什么?。 您可以查看 this link 以了解其工作原理,但简而言之:十进制(以 10 为底)从 0 变为 9,因此 356 = 3*10*10 + 5*10 + 6 而字节从 0 到 255,这意味着 03 05 06 = 3*256*256 + 5*256 + 6。我用 2 个字母写它们,因为通常用成对的十六进制数字表示字节值(基数 16 , 256=16*16)。在您的情况下,第一个字节基本上代表`xcenter /(256 * 256 * 256)。在 xcenter 大于 256^3 之前,它将为 0。 亲爱的@IcedLand,谢谢你的帮助,我已经解决了我所有的问题!你拯救了我的一天,再次感谢,祝你有美好的一天!最好的尊重。 @IcedLance 请将解决方案作为答案发布并接受! 【参考方案1】:对于较大的值,此代码将无法正常工作...
int xcenter = (SerialData[0]*256*256*256) + (SerialData[1]*256*256) + (SerialData[2]*256) + SerialData[3];
问题是输入是4字节宽,是一个长整数,而arduino上的整数大小只有2字节宽,也就是说256 * 256 = 0x10000 & 0xFFFF = 0!
为确保您不会遇到超过 2 个字节的值的问题,必须使用移位操作。
这给出了:
long result = long((unsigned long(unsigned char(SerialData[0])) << 24) | (unsigned long(unsigned char(SerialData[1])) << 16)
| (unsigned long(unsigned char(SerialData[2])) << 8) | unsigned char(SerialData[3]));
或者,如果您不期望较大的值,则仅使用输入中的两个字节。确保使用无符号值进行微积分,否则您可能会遇到问题!!!
int result = int((unsigned int(unsigned char(SerialData[2])) << 8) | unsigned char(SerialData[3]));
这非常冗长,但对所有输入类型都是安全的。例如,如果 SerialData[] 是一个 char 数组,则 OP 提出的解决方案将不起作用,它应该是,以避免浪费内存。
【讨论】:
谢谢你带给我的知识,真的对我帮助很大! 不客气。我知道这些小细节会浪费多少时间。 我已修复并将您的知识添加到我的主题中,供其他需要的人使用!再次感谢@Michael Roy以上是关于Arduino 和 Python (3.x) 之间的 Serial.read() 和 Struct.pack / 串行通信问题的主要内容,如果未能解决你的问题,请参考以下文章
使用串行通信在 python 和 arduino 之间进行同步
无法使用pyserial在arduino和python之间进行通信