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 &gt; 200 &amp;&amp; xcenter &lt;= 255 时,LED 亮起(这意味着代码工作正常)。 但是当xcenter &gt; 255 时,LED 熄灭(这里有问题)。 我想我已经读取了 Arduino 代码中的所有 8 个字节,并在 struct.pack 中使用了 unsigned int &gt;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之间进行通信

Arduino和Python之间的串行通信发送/接收数据

python到arduino串口读写

Python 串行读取线是不是会中断 Arduino 循环?

翻译: Python 2.7.x和Python 3.x之间的主要区别(包括示例)