You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Python向Arduino高效发送数据结构体?

用struct序列化实现Python与Arduino的串口命令传输

你可以通过struct模块在Python端将命令打包成固定格式的字节流,Arduino端按对应格式解析字节,完全替代字符串解析的繁琐步骤,以下是具体实现:


Python端:打包命令并发送

用struct.pack()将命令类型和参数转换成统一字节格式,确保和Arduino端的数据类型、字节序一致:

import serial
import struct

# 串口初始化(根据你的端口调整)
ser = serial.Serial('COM3', 9600, timeout=1)

# 命令类型定义(和Arduino端完全对应)
CMD_MOVE = 0x01
CMD_REQUEST_DATA = 0x02

# 发送MOVE命令:传入左右电机速度
def send_move(speed_left, speed_right):
    # 打包格式:<Bhh(小端模式:1字节命令 + 2个16位整数速度)
    packet = struct.pack('<Bhh', CMD_MOVE, speed_left, speed_right)
    ser.write(packet)

# 发送REQUEST_DATA命令
def send_request_data():
    packet = struct.pack('<B', CMD_REQUEST_DATA)
    ser.write(packet)

# 示例调用
send_move(60, 70)
# send_request_data()

Arduino端:解析字节流并执行命令

定义对应的数据结构体,按字节读取串口数据并重构为命令结构,处理不同指令:

#include <HardwareSerial.h>

// 命令类型和Python端严格一致
#define CMD_MOVE 0x01
#define CMD_REQUEST_DATA 0x02

// 对应MOVE命令的结构体(字节布局和Python打包格式匹配)
struct MoveCommand {
  uint8_t cmd;
  int16_t speed_left;
  int16_t speed_right;
};

void setup() {
  Serial.begin(9600);
  // 初始化电机驱动引脚(根据你的硬件调整)
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
}

void loop() {
  if (Serial.available() > 0) {
    uint8_t cmd = Serial.read();
    switch(cmd) {
      case CMD_MOVE:
        {
          MoveCommand move_cmd;
          move_cmd.cmd = cmd;
          // 按小端模式读取剩余4字节(两个16位整数)
          Serial.readBytes((uint8_t*)&move_cmd.speed_left, sizeof(move_cmd.speed_left));
          Serial.readBytes((uint8_t*)&move_cmd.speed_right, sizeof(move_cmd.speed_right));
          
          // 执行电机驱动逻辑
          driveMotor(9, move_cmd.speed_left);
          driveMotor(10, move_cmd.speed_right);
          break;
        }
      case CMD_REQUEST_DATA:
        {
          // 模拟获取传感器数据
          float battery_voltage = 12.3;
          float gps_lat = 39.9042;
          float gps_lon = 116.4074;
          
          // 打包返回数据(同样用字节流发送)
          Serial.write((uint8_t*)&battery_voltage, sizeof(battery_voltage));
          Serial.write((uint8_t*)&gps_lat, sizeof(gps_lat));
          Serial.write((uint8_t*)&gps_lon, sizeof(gps_lon));
          break;
        }
      default:
        // 未知命令,清空串口缓存避免残留数据干扰
        while(Serial.available()) Serial.read();
        break;
    }
  }
}

// 电机驱动示例函数(根据你的硬件修改)
void driveMotor(int pin, int16_t speed) {
  int pwm_val = abs(speed);
  pwm_val = constrain(pwm_val, 0, 255); // 限制PWM范围0-255
  analogWrite(pin, pwm_val);
  // 若需正反转,可添加方向引脚控制逻辑
}

关键注意事项

  • 字节序统一:Python用<指定小端模式,Arduino的AVR系列默认是小端,确保两边一致。
  • 数据类型匹配:Python的h对应Arduino的int16_t,B对应uint8_t,所有类型必须严格对应。
  • 波特率一致:Python和Arduino的串口波特率必须相同(示例中为9600)。
  • 缓存处理:遇到未知命令时清空串口缓存,避免残留数据破坏后续解析。

内容的提问来源于stack exchange,提问作者Dinh Trung Che

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 17:40:18