繁体   English   中英

解码从 arduino 发送到 TCP 服务器的字节数组 Python

[英]decoding a Byte Array sent from arduino to TCP Server made with Python

我正在将传感器数据转换为字节,并将字节数组从 arduino 写入由 Python 制作的 TCP 服务器,但数组中的传感器数据以某种方式触发解码时显示如下所示的 UTF-8 错误的变化。

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte UnicodeDecodeError: 'utf-8' codec can't decode byte 0xcf in position 1: invalid continuation byte

其中“0xcf”和“0xff”从错误变为错误。

我怀疑这是因为传感器数据有时可能是负值。 我知道一个字节不能容纳负数,而 UTF-8 可以做 0-256。 我想我必须在负值之前发送一个专用的“-”符号。 但是,我无法预测负值何时出现。 因此,必须有更好的方法来做到这一点。 我可以在不解码的情况下发送字节数组,但我怀疑这里也存在一些问题,因为前两个位置的值应该与其余 6 个位置不同,如下所示: b'\xff\x00\x00\x00\x00\x00\x00\x00' b'\x02\x00\x00\x00\x00\x00\x00\x00'

我的问题是:如何将负值作为字节发送并正确解码。

对于上下文,我将附上我的代码。 Arduino 客户:`

#include <Ethernet.h>
#include <SPI.h>
#include "AK09918.h"
#include "ICM20600.h"
#include <Wire.h>
//----------------------------------

//tiltsensor
AK09918_err_type_t err;
int32_t x, y, z;
AK09918 ak09918;
ICM20600 icm20600(true);
int16_t acc_x, acc_y, acc_z;
int32_t offset_x, offset_y, offset_z;
double roll, pitch;
//----------------------------------

//Ethernet
byte mac[] = { 0xBE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //not important if only one ethernet shield
byte ip[] = { 192, 168, X, X}; //IP of this arduino unit
byte server[] = { 192, 168, X, X}; //IP of server you want to contact
int tcp_port = 65432; // a nice port to send/acess the information on
EthernetClient client; 
//----------------------------------

//byte array
byte array[8] = {0, 0, 0, 0, 0, 0, 0, 0};
//----------------------------------

void setup()
{
  //tiltsensor
  Wire.begin();
  err = ak09918.initialize();
  icm20600.initialize();
  ak09918.switchMode(AK09918_POWER_DOWN);
  ak09918.switchMode(AK09918_CONTINUOUS_100HZ);
  Serial.begin(9600);
  err = ak09918.isDataReady();
  while (err != AK09918_ERR_OK) {
      Serial.println("Waiting Sensor");
      delay(100);
      err = ak09918.isDataReady();}
  Serial.println("Start figure-8 calibration after 2 seconds.");
  delay(2000);
  //calibrate(10000, &offset_x, &offset_y, &offset_z);
  Serial.println("");
  //----------------------------------

  //Ethernet
  Ethernet.begin(mac, ip);
  //Serial.begin(9600);
  delay(1000);
  Serial.println("Connecting...");
  if (client.connect(server, tcp_port)) { // Connection to server
    Serial.println("Connected to server.js");
    client.println();} 
  else {
    Serial.println("connection failed");}
  //----------------------------------
}

void loop()
{
  //tiltsensor
  acc_x = icm20600.getAccelerationX();
  acc_y = icm20600.getAccelerationY();
  acc_z = icm20600.getAccelerationZ();
  roll = atan2((float)acc_y, (float)acc_z) * 57.3;
  pitch = atan2(-(float)acc_x, sqrt((float)acc_y * acc_y + (float)acc_z * acc_z)) * 57.3;
  //----------------------------------

  //bytearray
  array[0] = byte(roll);
  array[1] = byte(pitch);
  //----------------------------------

  //test
  Serial.write(array, 8);
  Serial.println();
  delay(500); 
  //----------------------------------


  //Ethernet
  if (client.available()) {
      //client.print(array);
      //client.write(array[0]);
      client.write(array, 8);
      //client.write(array, 8);//((uint8_t*) array, sizeof(array));
      delay(3000); 
    }
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    for(;;)
      ;
  }
  //----------------------------------
}

`

TCP 服务器(蟒蛇):

`

# echo-server.py
import time
import socket

HOST = "192.168.X.X"  # Standard loopback interface address (localhost)
PORT = 65432  # Port to listen on (non-privileged ports are > 1023)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    conn, addr = s.accept()
    with conn:
        print(f"Connected by {addr}")
        while True:
            data = conn.recv(1024)
            #msg = s.recv(1024)
            #print(msg.decode("utf-8"))
            print(data.decode("utf-8"))
            #time.sleep(3)
            #conn.sendall(data)
            if not data:
                break
            conn.send(data)
            

`

我能够建立与服务器的连接,并且客户端可以写入它。 但是,我得到UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa4 in position 0: invalid start byte type 错误。

我能够取得一些进步,

对于 Arduino:

#include <Ethernet.h>
#include <SPI.h>
#include "AK09918.h"
#include "ICM20600.h"
#include <Wire.h>
//----------------------------------

//tiltsensor
AK09918_err_type_t err;
int32_t x, y, z;
AK09918 ak09918;
ICM20600 icm20600(true);
int16_t acc_x, acc_y, acc_z;
int32_t offset_x, offset_y, offset_z;
double roll, pitch;
//----------------------------------

//Ethernet
byte mac[] = { 0xBE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //not important if only one ethernet shield
byte ip[] = { 192, 168, X, XX}; //IP of this arduino unit
byte server[] = { 192, 168, X, XX}; //IP of server you want to contact
int tcp_port = 65432; // a nice port to send/acess the information on
EthernetClient client; 
//----------------------------------


//byte array
union some_data{  //convert a float to 4 bytes
  float tobytes;
  byte bytearray[4];
};

byte array[14] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //intial array
//----------------------------------

void setup()
{
  //tiltsensor
  Wire.begin();
  err = ak09918.initialize();
  icm20600.initialize();
  ak09918.switchMode(AK09918_POWER_DOWN);
  ak09918.switchMode(AK09918_CONTINUOUS_100HZ);
  Serial.begin(9600);
  err = ak09918.isDataReady();
  while (err != AK09918_ERR_OK) {
      Serial.println("Waiting Sensor");
      delay(100);
      err = ak09918.isDataReady();}
  Serial.println("Start figure-8 calibration after 2 seconds.");
  delay(2000);
  //calibrate(10000, &offset_x, &offset_y, &offset_z);
  Serial.println("");
  //----------------------------------

  //Ethernet
  Ethernet.begin(mac, ip);
  //Serial.begin(9600);
  delay(1000);
  Serial.println("Connecting...");
  if (client.connect(server, tcp_port)) { // Connection to server
    Serial.println("Connected to server.js");
    client.println();} 
  else {
    Serial.println("connection failed");}
  //----------------------------------

  //byte array

  //----------------------------------
}

void loop()
{
  //tiltsensor
  acc_x = icm20600.getAccelerationX();
  acc_y = icm20600.getAccelerationY();
  acc_z = icm20600.getAccelerationZ();
  roll = atan2((float)acc_y, (float)acc_z) * 57.3;
  pitch = atan2(-(float)acc_x, sqrt((float)acc_y * acc_y + (float)acc_z * acc_z)) * 57.3;
  //----------------------------------


  //bytearray
   if (roll < 0) {array[0] = 0;}  //put identifier for positive or negative value in specific posision in byte array
  else {array[0] = 1;}

  if (pitch < 0) {array[5] = 0;} // same for second sensor value
  else {array[5] = 1;}

  union some_data sensor1;  //use the union function separately
  union some_data sensor2;

  sensor1.tobytes =abs(roll); //get byte array for sensor value
  sensor2.tobytes =abs(pitch); //get byte array for sensor value

  for (int i=0; i<sizeof sensor1.bytearray/sizeof sensor1.bytearray[0]; i++) {   //put sensor value byte array into main byte array
    array[1+i] =  sensor1.bytearray[i];
    array[6+i] =  sensor2.bytearray[i];
    }
  //----------------------------------

  //test
  Serial.write(array, sizeof array);
  Serial.println();
  delay(500); 
  //----------------------------------


  //Ethernet
  if (client.available()) {
      //client.print(array);
      //client.write(array[0]);
      client.write(array, sizeof array);
      //client.write(array, 8);//((uint8_t*) array, sizeof(array));
      delay(3000); 
    }
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    for(;;)
      ;
  }
  //----------------------------------
}

对于 python TCP 服务器。

# echo-server.py
import time
import socket

HOST = "192.168.XX.XX"  # Standard loopback interface address (localhost)
PORT = 65432  # Port to listen on (non-privileged ports are > 1023)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    conn, addr = s.accept()
    with conn:
        print(f"Connected by {addr}")
        while True:
            data = conn.recv(1024)
            #msg = s.recv(1024)
            #print(msg.decode("utf-8"))
            print(data)#.decode("utf-8"))
            #time.sleep(3)
            #conn.sendall(data)
            if not data:
                break
            conn.send(data)
        

正如@hcheung 在评论中提到的,在 Arduino 端你可以简单地使用

Serial.write(&roll, 4);
Serial.wirte(&pitch,4);

该符号已作为第一位编码在这些字节中。 例如参见维基

在您的 python 方面,我建议您查看struct模块

对于您的具体情况,只需使用

roll, pitch = struct.unpack("dd", data)

其中"dd"描述了你的两个d double 的格式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM