refactor(protocol): CoP 帧字段从 float 改为整型,单位 mm→cm / kg

cop_x/cop_y 改为 int16_t (cm),force 改为 uint16_t (kg),
帧长 17→11 字节,降低带宽占用;1 cm 精度满足平衡板场景需求。
This commit is contained in:
2026-05-12 16:11:19 +08:00
parent b72ea5334f
commit f0072c3bd0
3 changed files with 29 additions and 29 deletions
+13 -13
View File
@@ -31,7 +31,7 @@
| 类型名 | 值 | 方向 | 长度 | 频率 | 说明 | | 类型名 | 值 | 方向 | 长度 | 频率 | 说明 |
|--------|----|------|------|------|------| |--------|----|------|------|------|------|
| `PROTO_TYPE_COP` | `0x01` | 平衡板 -> 基站 | `17` | 50 Hz | 压力中心帧 | | `PROTO_TYPE_COP` | `0x01` | 平衡板 -> 基站 | `11` | 50 Hz | 压力中心帧 |
| `PROTO_TYPE_ENCODER` | `0x02` | 平衡板 -> 基站 | `13` | TBD | 电机编码器帧(预留) | | `PROTO_TYPE_ENCODER` | `0x02` | 平衡板 -> 基站 | `13` | TBD | 电机编码器帧(预留) |
| `PROTO_TYPE_RESISTANCE` | `0x10` | 基站 -> 平衡板 | `16` | 按需 | 阻力参数帧 | | `PROTO_TYPE_RESISTANCE` | `0x10` | 基站 -> 平衡板 | `16` | 按需 | 阻力参数帧 |
| `PROTO_TYPE_SPOTTER` | `0x11` | 基站 -> 平衡板 | `9` | 按需 | 保护模式帧 | | `PROTO_TYPE_SPOTTER` | `0x11` | 基站 -> 平衡板 | `9` | 按需 | 保护模式帧 |
@@ -41,7 +41,7 @@
### 3.1 压力中心帧 (CoP) ### 3.1 压力中心帧 (CoP)
CoP 帧固定 17 字节,结构如下: CoP 帧固定 11 字节,结构如下:
| 字节偏移 | 字段 | 类型 | 值/范围 | 说明 | | 字节偏移 | 字段 | 类型 | 值/范围 | 说明 |
|----------|------|------|---------|------| |----------|------|------|---------|------|
@@ -49,10 +49,10 @@ CoP 帧固定 17 字节,结构如下:
| `1` | `sync1` | `uint8` | `0x55` | 帧头第 2 字节 | | `1` | `sync1` | `uint8` | `0x55` | 帧头第 2 字节 |
| `2` | `type` | `uint8` | `0x01` | CoP 包类型 | | `2` | `type` | `uint8` | `0x01` | CoP 包类型 |
| `3` | `flags` | `uint8` | 见下表 | 状态标志位 | | `3` | `flags` | `uint8` | 见下表 | 状态标志位 |
| `4-7` | `cop_x` | `float32 LE` | - | 压力中心 X 坐标 (mm) | | `4-5` | `cop_x` | `int16 LE` | - | 压力中心 X 坐标 (cm) |
| `8-11` | `cop_y` | `float32 LE` | - | 压力中心 Y 坐标 (mm) | | `6-7` | `cop_y` | `int16 LE` | - | 压力中心 Y 坐标 (cm) |
| `12-15` | `force` | `float32 LE` | - | 总压力 (N) | | `8-9` | `force` | `uint16 LE` | - | 总重量 (kg) |
| `16` | `crc` | `uint8` | - | CRC-8/MAXIM 校验 | | `10` | `crc` | `uint8` | - | CRC-8/MAXIM 校验 |
#### flags 位定义 #### flags 位定义
@@ -93,10 +93,10 @@ CoP_Y = (F0 * y0 + F1 * y1 + F2 * y2 + F3 * y3) / F_total
#### 示例 #### 示例
下面是一个 CoP 帧示例(CoP 有效): 下面是一个 CoP 帧示例(CoP 有效cop_x=3 cm, cop_y=5 cm, force=75 kg):
```text ```text
AA 55 01 01 00 00 F0 41 00 00 48 42 00 80 BB 44 XX AA 55 01 01 03 00 05 00 4B 00 XX
``` ```
含义如下: 含义如下:
@@ -104,10 +104,10 @@ AA 55 01 01 00 00 F0 41 00 00 48 42 00 80 BB 44 XX
- `AA 55`:双帧头 - `AA 55`:双帧头
- `01`CoP 包 - `01`CoP 包
- `01`flags = `force_valid` - `01`flags = `force_valid`
- `00 00 F0 41``cop_x = 30.0` mmLE float32 - `03 00``cop_x = 3` cmLE int16
- `00 00 48 42``cop_y = 50.0` mmLE float32 - `05 00``cop_y = 5` cmLE int16
- `00 80 BB 44``force = 1500.0` NLE float32 - `4B 00``force = 75` kgLE uint16
- `XX`CRC-8/MAXIM(对字节 `[2..15]` 计算) - `XX`CRC-8/MAXIM(对字节 `[2..9]` 计算)
### 3.2 电机编码器帧(预留) ### 3.2 电机编码器帧(预留)
@@ -196,7 +196,7 @@ AA 55 20 05 XX
## 5. 当前实现约束 ## 5. 当前实现约束
- CoP 帧固定 17 字节,可在最小 ATT MTU 23(NUS 有效负载 20 字节)下传输。 - CoP 帧固定 11 字节,可在最小 ATT MTU 23(NUS 有效负载 20 字节)下传输。
- 50 Hz CoP 上行流隐式充当平衡板到基站的活性检测,因此心跳仅为下行。 - 50 Hz CoP 上行流隐式充当平衡板到基站的活性检测,因此心跳仅为下行。
- 传感器通道到物理位置的映射:MUX `{0x01, 0x23, 0x45, 0x67}` → FL/FR/BR/BL。 - 传感器通道到物理位置的映射:MUX `{0x01, 0x23, 0x45, 0x67}` → FL/FR/BR/BL。
- `BOARD_HALF_WIDTH_MM = 200``BOARD_HALF_LENGTH_MM = 200`(后续可能调整)。 - `BOARD_HALF_WIDTH_MM = 200``BOARD_HALF_LENGTH_MM = 200`(后续可能调整)。
+10 -10
View File
@@ -42,19 +42,19 @@
/* 总重低于此值时 CoP 无意义(除零保护),单位 kg */ /* 总重低于此值时 CoP 无意义(除零保护),单位 kg */
#define COP_MIN_FORCE_THRESHOLD 0.5f #define COP_MIN_FORCE_THRESHOLD 0.5f
/* ─── 上行: CoP 帧 (17 bytes, 50 Hz) ─── /* ─── 上行: CoP 帧 (11 bytes, 50 Hz) ───
* *
* [AA 55 01 flags cop_x(4) cop_y(4) force(4) crc] * [AA 55 01 flags cop_x(2) cop_y(2) force(2) crc]
*/ */
struct cop_frame_t { struct cop_frame_t {
uint8_t sync0; /* = PROTO_SYNC0 */ uint8_t sync0; /* = PROTO_SYNC0 */
uint8_t sync1; /* = PROTO_SYNC1 */ uint8_t sync1; /* = PROTO_SYNC1 */
uint8_t type; /* = PROTO_TYPE_COP */ uint8_t type; /* = PROTO_TYPE_COP */
uint8_t flags; /* bit0: force_valid */ uint8_t flags; /* bit0: force_valid */
float cop_x; /* 压力中心 X (mm),板面坐标系 */ int16_t cop_x; /* 压力中心 X (cm),板面坐标系 */
float cop_y; /* 压力中心 Y (mm),板面坐标系 */ int16_t cop_y; /* 压力中心 Y (cm),板面坐标系 */
float force; /* 总重量 (kg) */ uint16_t force; /* 总重量 (kg) */
uint8_t crc; /* CRC-8/MAXIM, 校验 type~force */ uint8_t crc; /* CRC-8/MAXIM, 校验 type~force */
} __attribute__((packed)); } __attribute__((packed));
union cop_pkt_t { union cop_pkt_t {
+6 -6
View File
@@ -201,9 +201,9 @@ static void sensor_thread_fn(void *p1, void *p2, void *p3) {
pkt.frame.sync1 = PROTO_SYNC1; pkt.frame.sync1 = PROTO_SYNC1;
pkt.frame.type = PROTO_TYPE_COP; pkt.frame.type = PROTO_TYPE_COP;
pkt.frame.flags = valid ? COP_FLAG_FORCE_VALID : 0; pkt.frame.flags = valid ? COP_FLAG_FORCE_VALID : 0;
pkt.frame.cop_x = cop_x; pkt.frame.cop_x = (int16_t)(cop_x * 0.1f);
pkt.frame.cop_y = cop_y; pkt.frame.cop_y = (int16_t)(cop_y * 0.1f);
pkt.frame.force = force; pkt.frame.force = (uint16_t)force;
pkt.frame.crc = crc8(pkt.bytes + 2, sizeof(pkt.bytes) - 3, 0x31, 0x00, true); pkt.frame.crc = crc8(pkt.bytes + 2, sizeof(pkt.bytes) - 3, 0x31, 0x00, true);
/* 发送 */ /* 发送 */
@@ -213,9 +213,9 @@ static void sensor_thread_fn(void *p1, void *p2, void *p3) {
if (++debug_log_divider >= 10) { if (++debug_log_divider >= 10) {
debug_log_divider = 0; debug_log_divider = 0;
LOG_INF( LOG_INF(
"FR=%.2f BR=%.2f BL=%.2f FL=%.2f | total=%.2f kg | cop=(%.1f,%.1f) mm | %s", (double)filtered[0], "FR=%.2f BR=%.2f BL=%.2f FL=%.2f | total=%.2f kg | cop=(%.1f,%.1f) cm | %s", (double)filtered[0],
(double)filtered[1], (double)filtered[2], (double)filtered[3], (double)force, (double)cop_x, (double)filtered[1], (double)filtered[2], (double)filtered[3], (double)force,
(double)cop_y, valid ? "VALID" : "low"); (double)(cop_x * 0.1f), (double)(cop_y * 0.1f), valid ? "VALID" : "low");
LOG_INF("timing: acq=%lld total=%lld ms/frame", (long long)(t1 - t0), (long long)frame_ms); LOG_INF("timing: acq=%lld total=%lld ms/frame", (long long)(t1 - t0), (long long)frame_ms);
} }
} }