Serial.read() 和 Struct.pack / Arduino 和 Python (3.x) 之间的串行通信有问题

Problem with Serial.read() and Struct.pack / serial communication between Arduino and Python (3.x)

我在尝试使用 串行通信 .
将一些值从 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,那么我的错误是什么?
感谢所有帮助!谢谢!


编辑并修复。
"It doesn't pack int into digits (0-9), it packs them into bytes (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 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 提供的解决方案将不起作用,它应该是,以避免浪费内存。