- 删除 protocol.h,帧定义和标定命令码统一迁入 comm_protocol.h - 新增 comm_protocol.c:上行组包(CoP/标定响应)、下行解析+msgq 分发 - ble_transport 剥离所有协议解析和参数 getter,仅保留字节收发+rx 回调注册 - main.c 初始化顺序:ble_transport → comm_protocol → adv_start → cal_init - 更新 README 架构图和项目结构表,补充标定流程章节 - 更新 BALANCE_BOARD_PROTOCOL.md 增加标定命令/响应帧格式文档
11 KiB
平衡板协议说明
本文说明当前固件里的数据包格式和 BLE 通讯方式。
1. BLE 通讯方式
平衡板工作在 BLE Peripheral 角色,通过 Nordic UART Service(NUS)与基站通信。
- 上行方向:平衡板 -> 基站,使用 NUS
Notify - 下行方向:基站 -> 平衡板,使用 NUS
Write - 广播内容:包含设备名和 NUS 128-bit UUID
1.1 NUS UUID
| 项目 | UUID | 方向 | 说明 |
|---|---|---|---|
| Service | 6E400001-B5A3-F393-E0A9-E50E24DCCA9E |
- | NUS 主服务 |
| TX Characteristic | 6E400003-B5A3-F393-E0A9-E50E24DCCA9E |
平衡板 -> 基站 | Notify,上报 CoP 和编码器数据 |
| RX Characteristic | 6E400002-B5A3-F393-E0A9-E50E24DCCA9E |
基站 -> 平衡板 | Write,下发阻力参数和控制命令 |
1.2 当前连接行为
- 连接建立后,平衡板会请求
7.5-15 ms连接区间(min=6, max=12)。 - 所有数据通过 NUS 二进制帧发送,不走文本协议。
2. 数据包总览
当前协议使用双帧头 0xAA 0x55 作为包起始标记。所有多字节字段按 Little Endian 编码。
每帧末尾附加 1 字节 CRC-8/MAXIM 校验(poly=0x31, init=0x00, refin=true, refout=true, xorout=0x00)。校验范围为帧头之后、CRC 字节之前的所有字段(即跳过 sync0/sync1)。调用方式:crc8(data + 2, len - 3, 0x31, 0x00, true)。
| 类型名 | 值 | 方向 | 长度 | 频率 | 说明 |
|---|---|---|---|---|---|
PROTO_TYPE_COP |
0x01 |
平衡板 -> 基站 | 11 |
50 Hz | 压力中心帧 |
PROTO_TYPE_ENCODER |
0x02 |
平衡板 -> 基站 | 13 |
TBD | 电机编码器帧(预留) |
PROTO_TYPE_RESISTANCE |
0x10 |
基站 -> 平衡板 | 16 |
按需 | 阻力参数帧 |
PROTO_TYPE_SPOTTER |
0x11 |
基站 -> 平衡板 | 9 |
按需 | 保护模式帧 |
PROTO_TYPE_HEARTBEAT |
0x20 |
基站 -> 平衡板 | 5 |
~1 Hz | 心跳帧 |
PROTO_TYPE_CAL_CMD |
0x30 |
基站 -> 平衡板 | 10 |
按需 | 标定命令帧 |
PROTO_TYPE_CAL_RESP |
0x31 |
平衡板 -> 基站 | 14 |
按需 | 标定响应帧 |
3. 上行数据包
3.1 压力中心帧 (CoP)
CoP 帧固定 11 字节,结构如下:
| 字节偏移 | 字段 | 类型 | 值/范围 | 说明 |
|---|---|---|---|---|
0 |
sync0 |
uint8 |
0xAA |
帧头第 1 字节 |
1 |
sync1 |
uint8 |
0x55 |
帧头第 2 字节 |
2 |
type |
uint8 |
0x01 |
CoP 包类型 |
3 |
flags |
uint8 |
见下表 | 状态标志位 |
4-5 |
cop_x |
int16 LE |
- | 压力中心 X 坐标 (cm) |
6-7 |
cop_y |
int16 LE |
- | 压力中心 Y 坐标 (cm) |
8-9 |
force |
int16 LE |
- | 总重量 (kg) |
10 |
crc |
uint8 |
- | CRC-8/MAXIM 校验 |
flags 位定义
| 位 | 名称 | 说明 |
|---|---|---|
| bit0 | COP_FLAG_FORCE_VALID |
1 表示总力超过阈值,CoP 坐标有意义 |
| bit1-7 | 预留 | 填 0 |
CoP 解算公式
传感器布局(俯视):
S4 (FL) -------- S1 (FR)
| center |
S3 (BL) -------- S2 (BR)
传感器坐标(单位:cm,板面中心为原点):
| 传感器 | 位置 | X | Y |
|---|---|---|---|
| S1 | 右前 (FR) | +10 |
+10 |
| S2 | 右后 (BR) | +10 |
-10 |
| S3 | 左后 (BL) | -10 |
-10 |
| S4 | 左前 (FL) | -10 |
+10 |
计算公式:
F_total = F0 + F1 + F2 + F3
CoP_X = (F0 * x0 + F1 * x1 + F2 * x2 + F3 * x3) / F_total
CoP_Y = (F0 * y0 + F1 * y1 + F2 * y2 + F3 * y3) / F_total
当 F_total < COP_MIN_FORCE_THRESHOLD 时,CoP 坐标无意义,flags.bit0 = 0,cop_x 和 cop_y 填 0。
示例
下面是一个 CoP 帧示例(CoP 有效,cop_x=3 cm, cop_y=5 cm, force=75 kg):
AA 55 01 01 03 00 05 00 4B 00 XX
含义如下:
AA 55:双帧头01:CoP 包01:flags =force_valid03 00:cop_x = 3cm(LE int16)05 00:cop_y = 5cm(LE int16)4B 00:force = 75kg(LE uint16)XX:CRC-8/MAXIM(对字节[2..9]计算)
3.2 电机编码器帧(预留)
编码器帧固定 13 字节,结构如下。该帧目前仅在协议中预留定义,固件暂不实现。
| 字节偏移 | 字段 | 类型 | 值/范围 | 说明 |
|---|---|---|---|---|
0 |
sync0 |
uint8 |
0xAA |
帧头第 1 字节 |
1 |
sync1 |
uint8 |
0x55 |
帧头第 2 字节 |
2 |
type |
uint8 |
0x02 |
编码器包类型 |
3 |
flags |
uint8 |
0 |
预留 |
4-7 |
cable_length |
float32 LE |
- | 拉索长度 (mm) |
8-11 |
velocity |
float32 LE |
- | 拉索速度 (mm/s) |
12 |
crc |
uint8 |
- | CRC-8/MAXIM 校验 |
4. 下行数据包
4.1 阻力参数帧
阻力参数帧固定 16 字节,用于基站向平衡板下发电机阻力控制参数。
| 字节偏移 | 字段 | 类型 | 值/范围 | 说明 |
|---|---|---|---|---|
0 |
sync0 |
uint8 |
0xAA |
帧头第 1 字节 |
1 |
sync1 |
uint8 |
0x55 |
帧头第 2 字节 |
2 |
type |
uint8 |
0x10 |
阻力参数包类型 |
3-6 |
K |
float32 LE |
- | 刚度 (N/m) |
7-10 |
B |
float32 LE |
- | 阻尼 (Ns/m) |
11-14 |
Tau |
float32 LE |
- | 时间常数 (s) |
15 |
crc |
uint8 |
- | CRC-8/MAXIM 校验 |
示例
AA 55 10 00 00 C8 42 00 00 48 41 CD CC 4C 3E XX
含义如下:
AA 55 10:阻力参数帧头00 00 C8 42:K = 100.0N/m00 00 48 41:B = 12.5Ns/mCD CC 4C 3E:Tau = 0.2sXX:CRC-8/MAXIM
4.2 Spotter Mode 帧
Spotter 帧固定 9 字节,用于启用或关闭保护模式。
| 字节偏移 | 字段 | 类型 | 值/范围 | 说明 |
|---|---|---|---|---|
0 |
sync0 |
uint8 |
0xAA |
帧头第 1 字节 |
1 |
sync1 |
uint8 |
0x55 |
帧头第 2 字节 |
2 |
type |
uint8 |
0x11 |
Spotter 包类型 |
3-6 |
threshold |
float32 LE |
- | 保护力阈值 (N) |
7 |
enable |
uint8 |
0 或 1 |
0 = 关闭, 1 = 启用 |
8 |
crc |
uint8 |
- | CRC-8/MAXIM 校验 |
示例
启用 Spotter Mode,阈值 500 N:
AA 55 11 00 00 FA 43 01 XX
4.3 心跳帧
心跳帧固定 5 字节,基站以约 1 Hz 频率发送,用于活性检测。
| 字节偏移 | 字段 | 类型 | 值/范围 | 说明 |
|---|---|---|---|---|
0 |
sync0 |
uint8 |
0xAA |
帧头第 1 字节 |
1 |
sync1 |
uint8 |
0x55 |
帧头第 2 字节 |
2 |
type |
uint8 |
0x20 |
心跳包类型 |
3 |
counter |
uint8 |
0-255 |
滚动计数 |
4 |
crc |
uint8 |
- | CRC-8/MAXIM 校验 |
示例
AA 55 20 05 XX
含义:心跳包,计数 5,XX 为 CRC。
5. 标定协议
标定协议通过下行标定命令帧(0x30)和上行标定响应帧(0x31)完成传感器在线标定。标定分两级:L1 单通道零点/增益标定,L2 多点网格空间修正。
5.1 标定命令帧(下行)
标定命令帧固定 10 字节,由基站发送给平衡板:
| 字节偏移 | 字段 | 类型 | 值/范围 | 说明 |
|---|---|---|---|---|
0 |
sync0 |
uint8 |
0xAA |
帧头第 1 字节 |
1 |
sync1 |
uint8 |
0x55 |
帧头第 2 字节 |
2 |
type |
uint8 |
0x30 |
标定命令包类型 |
3 |
subcmd |
uint8 |
见下表 | 子命令码 |
4 |
target |
uint8 |
0-3 / 0-8 |
通道号或网格点号 |
5-8 |
param |
float32 LE |
- | 参数(如已知质量 kg) |
9 |
crc |
uint8 |
- | CRC-8/MAXIM 校验 |
subcmd 子命令码定义
| 子命令码 | 名称 | target 含义 | param 含义 | 说明 |
|---|---|---|---|---|
0x01 |
START_L1 |
- | - | 进入 L1 标定模式 |
0x02 |
TARE_CH |
通道号 (0-3) | - | 对指定通道执行零点标定 |
0x03 |
GAIN_CH |
通道号 (0-3) | 已知质量 (kg) | 对指定通道执行增益标定 |
0x04 |
COMMIT_L1 |
- | - | 提交 L1 标定数据到 NVS |
0x05 |
ABORT |
- | - | 中止当前标定流程 |
0x10 |
START_L2 |
- | - | 进入 L2 网格标定模式 |
0x11 |
RECORD_GRID |
网格点号 (0-8) | - | 记录当前网格点 CoP 误差 |
0x12 |
COMMIT_L2 |
- | - | 提交 L2 标定数据到 NVS |
0x20 |
ERASE |
- | - | 擦除所有标定数据 |
0x21 |
QUERY |
- | - | 查询当前标定状态 |
示例
对通道 2 执行增益标定,已知质量 10.0 kg:
AA 55 30 03 02 00 00 20 41 XX
AA 55 30:标定命令帧头03:subcmd =GAIN_CH02:target = 通道 200 00 20 41:param =10.0kg(float32 LE)XX:CRC-8/MAXIM
5.2 标定响应帧(上行)
标定响应帧固定 14 字节,平衡板在执行标定命令后回复:
| 字节偏移 | 字段 | 类型 | 值/范围 | 说明 |
|---|---|---|---|---|
0 |
sync0 |
uint8 |
0xAA |
帧头第 1 字节 |
1 |
sync1 |
uint8 |
0x55 |
帧头第 2 字节 |
2 |
type |
uint8 |
0x31 |
标定响应包类型 |
3 |
status |
uint8 |
见下表 | 结果状态码 |
4 |
subcmd |
uint8 |
- | 对应的子命令回显 |
5-12 |
data |
uint8[8] |
- | 响应数据(上下文相关) |
13 |
crc |
uint8 |
- | CRC-8/MAXIM 校验 |
状态码定义
| 状态码 | 名称 | 说明 |
|---|---|---|
0x00 |
OK |
命令执行成功 |
0x01 |
ERR_STATE |
状态机不允许此操作 |
0x02 |
ERR_NVS |
NVS 读写失败 |
0x03 |
ERR_PARAM |
参数非法 |
data 字段含义
data[8] 内容取决于子命令:
| 子命令 | data 内容 | 说明 |
|---|---|---|
TARE_CH |
data[0..3] = 零点 ADC 值 (int32 LE) |
通道去皮后的零点偏移 |
GAIN_CH |
data[0..3] = 增益 (float32 LE) |
kg/count 换算系数 |
QUERY |
data[0] = L1 zero valid, data[1] = L1 gain valid, data[2] = L2 valid |
各级标定有效性标志 |
| 其他 | 全零 | 无附加数据 |
示例
通道 2 增益标定成功,增益 = 5.322e-5 kg/count:
AA 55 31 00 03 XX XX XX XX 00 00 00 00 XX
AA 55 31:标定响应帧头00:status =OK03:subcmd =GAIN_CH(回显)- 前 4 字节 data:增益值 float32 LE
- 后 4 字节 data:填 0
- 末字节:CRC-8/MAXIM
6. 当前实现约束
- CoP 帧固定 11 字节,可在最小 ATT MTU 23(NUS 有效负载 20 字节)下传输。
- 50 Hz CoP 上行流隐式充当平衡板到基站的活性检测,因此心跳仅为下行。
- 传感器通道到物理位置的映射:MUX
{0x01, 0x23, 0x45, 0x67}→ FL/FR/BR/BL。 BOARD_HALF_WIDTH_CM = 10,BOARD_HALF_LENGTH_CM = 10(后续可能调整)。ADC_TO_FORCE_SCALE当前为占位值1.0f,待 10 kg 砝码标定后修正。- ARM Cortex-M33 为小端架构,
float32在 packed struct 中天然符合 Little Endian 要求。