本协议用于 STM32H7 (割草机MCU) 通过 UART5 向 Python 程序发送 GPS 和 IMU 数据。
每个数据包采用如下格式:
+--------+--------+------+--------+--------+------+--------+--------+
| Header | Header | Type | Length | Length | Data | CRC16 | CRC16 |
| 0xAA | 0x55 | | Low | High | ... | Low | High |
+--------+--------+------+--------+--------+------+--------+--------+
| Footer | Footer |
| 0x0D | 0x0A |
+--------+--------+
| 字段 | 大小(字节) | 说明 |
|---|---|---|
| Header1 | 1 | 帧头1: 固定为 0xAA |
| Header2 | 1 | 帧头2: 固定为 0x55 |
| Type | 1 | 数据类型: 0x01=GPS, 0x02=IMU |
| Length | 2 | 数据长度 (小端序), 不包含帧头、类型、长度、CRC和帧尾 |
| Data | N | 数据负载 (结构体二进制) |
| CRC16 | 2 | CRC16-MODBUS校验 (小端序), 校验范围: 从Header1到Data末尾 |
| Footer1 | 1 | 帧尾1: 固定为 0x0D (CR) |
| Footer2 | 1 | 帧尾2: 固定为 0x0A (LF) |
更新频率: 10 Hz (GPS模块解析成功后立即发送)
数据结构 (56 字节, 小端序):
| 字段 | 类型 | 偏移 | 大小 | 单位 | 说明 |
|---|---|---|---|---|---|
| m_dLatitude | double | 0 | 8 | 度(°) | 纬度, 正数为北纬 |
| m_dLongitude | double | 8 | 8 | 度(°) | 经度, 正数为东经 |
| m_fHeadingAngle | float | 16 | 4 | 度(°) | 航向角, 0~360, 基于东北速度计算 |
| m_fEastVelocity | float | 20 | 4 | m/s | 东方向速度 |
| m_fNorthVelocity | float | 24 | 4 | m/s | 北方向速度 |
| m_fUpVelocity | float | 28 | 4 | m/s | 天顶方向速度 |
| m_fAltitude | float | 32 | 4 | m | 高程 |
| m_u32UTCTime | uint32 | 36 | 4 | hhmmss | UTC时间 |
| m_u8PositionQuality | uint8 | 40 | 1 | - | 0=无效, 1=单点, 2=差分, 4=固定, 5=浮点 |
| m_u8SatelliteCount | uint8 | 41 | 1 | - | 可见卫星数量 |
| m_u8Reserved | uint8[2] | 42 | 2 | - | 保留字节(对齐) |
C结构体定义 (见 FML/PythonLink.h):c typedef struct __attribute__((packed)) { HIDO_DOUBLE m_dLatitude; // 纬度(°) HIDO_DOUBLE m_dLongitude; // 经度(°) HIDO_FLOAT m_fHeadingAngle; // 航向角(°) HIDO_FLOAT m_fEastVelocity; // 东方向速度(m/s) HIDO_FLOAT m_fNorthVelocity; // 北方向速度(m/s) HIDO_FLOAT m_fUpVelocity; // 天顶方向速度(m/s) HIDO_FLOAT m_fAltitude; // 高程(m) HIDO_UINT32 m_u32UTCTime; // UTC时间 HIDO_UINT8 m_u8PositionQuality; // 定位质量 HIDO_UINT8 m_u8SatelliteCount; // 卫星数量 HIDO_UINT8 m_u8Reserved[2]; // 保留字节 } ST_PythonLink_GPS;
更新频率: 100 Hz (IMU模块解析成功后立即发送)
数据结构 (32 字节, 小端序):
| 字段 | 类型 | 偏移 | 大小 | 单位 | 说明 |
|---|---|---|---|---|---|
| m_fAccelX | float | 0 | 4 | g | X轴加速度 |
| m_fAccelY | float | 4 | 4 | g | Y轴加速度 |
| m_fAccelZ | float | 8 | 4 | g | Z轴加速度 |
| m_fGyroX | float | 12 | 4 | °/s | X轴角速度 |
| m_fGyroY | float | 16 | 4 | °/s | Y轴角速度 |
| m_fGyroZ | float | 20 | 4 | °/s | Z轴角速度 |
| m_fTemperature | float | 24 | 4 | ℃ | 传感器温度 |
| m_u32UTCTime | uint32 | 28 | 4 | ms | UTC时间(毫秒) |
C结构体定义 (见 FML/PythonLink.h):c typedef struct __attribute__((packed)) { HIDO_FLOAT m_fAccelX; // X轴加速度(g) HIDO_FLOAT m_fAccelY; // Y轴加速度(g) HIDO_FLOAT m_fAccelZ; // Z轴加速度(g) HIDO_FLOAT m_fGyroX; // X轴角速度(°/s) HIDO_FLOAT m_fGyroY; // Y轴角速度(°/s) HIDO_FLOAT m_fGyroZ; // Z轴角速度(°/s) HIDO_FLOAT m_fTemperature; // 传感器温度(℃) HIDO_UINT32 m_u32UTCTime; // UTC时间(毫秒) } ST_PythonLink_IMU;
使用标准的 CRC16-MODBUS 算法:
- 多项式: 0x8005
- 初始值: 0xFFFF
- 结果异或值: 0x0000
- 反射输入: True
- 反射输出: True
校验范围: 从帧头 (0xAA) 到数据负载末尾 (不包含CRC和帧尾)
STM32H7 (UART5 TX) ──────> Python (串口 RX)
921600 bps
GPS (10Hz) ──> GPS_ParseGPRMI() ──> PythonLink_SendGPSData() ──> UART5 TX
IMU (100Hz) ─> GPS_ParseGPIMU() ──> PythonLink_SendIMUData() ──> UART5 TX
GPS_ParseGPRMI() 解析成功后, 立即调用 PythonLink_SendGPSData() 发送GPS_ParseGPIMU() 解析成功后, 立即调用 PythonLink_SendIMUData() 发送这种机制保证了数据的**实时性** (零额外延迟), 适用于后续的电脑控制车辆实际行走场景。
参见 python/gps_imu_receiver.py
pip install -r python/requirements.txt
python python/gps_imu_receiver.py
编辑 gps_imu_receiver.py 中的 PORT 和 BAUDRATE:
# Windows
PORT = "COM3"
# Linux
PORT = "/dev/ttyUSB0"
# 波特率 (与STM32配置一致)
BAUDRATE = 921600
| 文件 | 说明 |
|---|---|
FML/PythonLink.h |
PythonLink 模块接口 |
FML/PythonLink.c |
PythonLink 模块实现 |
FML/GPS.c |
GPS解析, 添加了立即发送调用 |
HAL/Uart.h |
添加了 UART_ID_PYTHON 枚举 |
Core/Src/main.c |
注册 UART5 为 UART_ID_PYTHON |
APL/app.c |
初始化和轮询 PythonLink |
| 文件 | 说明 |
|---|---|
python/gps_imu_receiver.py |
GPS/IMU 数据接收解析器 |
python/requirements.txt |
Python依赖项 |
PROTOCOL.md |
本协议文档 |
__attribute__((packed)) 确保无填充字节协议预留了数据类型字段 (Type), 可方便扩展其他数据类型, 例如:
- 0x03: SBUS 遥控器数据
- 0x04: 车辆状态数据 (电池、电机等)
- 0x05: 控制命令 (Python -> STM32)