0d2fd30b3a
fix(main): 修正主循环中延时以保持程序运行
303 lines
12 KiB
Markdown
303 lines
12 KiB
Markdown
# GML670 Balance Board
|
||
|
||
> 当前目录是 `GML670x4_V2`。代码内的 CMake 项目名是 `GML670_V2`,BLE 设备名是 `GML670_System`。
|
||
>
|
||
> 这份 README 只描述当前 `V2` 工程已经落地的实现。更细的协议字段和示例帧见 [BALANCE_BOARD_PROTOCOL.md](./doc/BALANCE_BOARD_PROTOCOL.md)。
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [产品概述](#1-产品概述)
|
||
2. [硬件组成](#2-硬件组成)
|
||
3. [系统架构](#3-系统架构)
|
||
4. [功能需求与当前状态](#4-功能需求与当前状态)
|
||
5. [BLE 协议规格](#5-ble-协议规格)
|
||
6. [ADS1256 / CoP 规格](#6-ads1256--cop-规格)
|
||
7. [开发环境与板级配置](#7-开发环境与板级配置)
|
||
8. [项目结构](#8-项目结构)
|
||
9. [构建与烧录](#9-构建与烧录)
|
||
10. [日志与当前约束](#10-日志与当前约束)
|
||
|
||
---
|
||
|
||
## 1. 产品概述
|
||
|
||
本工程是平衡板的 nRF5340 App Core 固件,当前版本的主链路很简单:
|
||
|
||
- 上电后等待 2 秒,初始化 BLE NUS 传输层并启动广播
|
||
- 初始化 ADS1256,完成一次 tare 去皮
|
||
- 创建独立的传感器线程,循环读取 4 路差分输入
|
||
- 在板端完成重量换算和 CoP(Center of Pressure,压力中心)解算
|
||
- 通过 BLE NUS 持续上报 17 字节 CoP 二进制帧
|
||
- 接收基站下发的阻力参数、Spotter 参数和心跳帧,并保存在内存里
|
||
|
||
当前实现已经把采样、解算和上行链路拆成了独立模块:`main.c` 只负责启动,BLE 在 `src/ble_transport.c`,ADS1256 在 `src/ads1256.c`,采样与 CoP 在 `src/sensor.c`。
|
||
|
||
## 2. 硬件组成
|
||
|
||
当前仓库里能直接确认的硬件如下:
|
||
|
||
| 器件 | 型号 / 对象 | 接口 | 作用 | 状态 |
|
||
|------|-------------|------|------|------|
|
||
| 主控 | nRF5340 DK App Core | - | 运行 BLE、SPI 采样和 CoP 解算 | ✅ |
|
||
| ADC | ADS1256 | SPI1 | 4 路多通道采样 | ✅ |
|
||
| 传感器输入 | 4 路差分输入 | ADS1256 MUX | 用于四角重量采样 | ✅ |
|
||
| 基站链路 | Nordic UART Service | BLE | 上报 CoP、接收控制参数 | ✅ |
|
||
| 编码器链路 | 预留 | BLE 协议 | 编码器上行帧已定义,当前固件不发送 | 🔲 |
|
||
|
||
### ADS1256 相关引脚
|
||
|
||
`app.overlay` 当前把 ADS1256 接到 `spi1`,连线如下:
|
||
|
||
| 信号 | nRF5340 引脚 | 说明 |
|
||
|------|--------------|------|
|
||
| SCK | `P1.15` | `spi1` 时钟 |
|
||
| MOSI | `P1.13` | `spi1` 主发从收 |
|
||
| MISO | `P1.14` | `spi1` 主收从发 |
|
||
| CS | `P1.12` | 片选 |
|
||
| DRDY | `P1.11` | 数据就绪输入 |
|
||
| RESET | `P1.10` | ADS1256 复位控制 |
|
||
|
||
虽然 `app.overlay` 里有 `ads1256@0` 节点,但当前实现没有走单独的 Zephyr ADS1256 驱动,实际访问路径还是 `src/ads1256.c` 里直接操作 `spi1` 和 GPIO alias。
|
||
|
||
## 3. 系统架构
|
||
|
||
```text
|
||
4 路差分传感器
|
||
|
|
||
v
|
||
ADS1256 + SPI1
|
||
|
|
||
v
|
||
src/ads1256.c
|
||
|
|
||
v
|
||
src/sensor.c
|
||
|
|
||
+--> 去皮 / 17 次均值 / 死区抑制 / 重量换算 / CoP 解算
|
||
|
|
||
+--> CoP 二进制帧 --> src/ble_transport.c --> BLE NUS Notify
|
||
|
|
||
+<-- Resistance / Spotter / Heartbeat <-- BLE NUS Write
|
||
```
|
||
|
||
`src/main.c` 本身不承载采样逻辑,它只按顺序调用 `ble_transport_init()`、`ble_transport_adv_start()` 和 `sensor_init()`。
|
||
|
||
## 4. 功能需求与当前状态
|
||
|
||
### 4.1 采样与解算
|
||
|
||
| 项目 | 说明 | 状态 |
|
||
|------|------|------|
|
||
| 4 路轮询采样 | 通过 ADS1256 MUX 依次读取 `0x01 / 0x23 / 0x45 / 0x67` 四组差分通道 | ✅ |
|
||
| tare 去皮 | 每路读取 17 个样本,排序后取中位数作为零点偏移 | ✅ |
|
||
| 运行期滤波 | 每帧每通道采 17 次并取均值 | ✅ |
|
||
| 死区抑制 | 去皮后的均值落在 `-250 ~ 250` counts 时压到 `0` | ✅ |
|
||
| 重量换算 | `ADC_TO_FORCE_SCALE` 已按 GML670 50 kg 传感器参数推导 | ✅ |
|
||
| CoP 解算 | 根据四角重量计算 `cop_x / cop_y / force` | ✅ |
|
||
| 有效力阈值 | 总重量低于 `0.5 kg` 时,CoP 坐标置零并清除 `force_valid` | ✅ |
|
||
|
||
### 4.2 BLE 通信
|
||
|
||
| 项目 | 说明 | 状态 |
|
||
|------|------|------|
|
||
| BLE 角色 | `Peripheral`,使用 NUS 私有服务 | ✅ |
|
||
| 广播内容 | 广播包带 NUS UUID,扫描响应带设备名 | ✅ |
|
||
| 连接参数请求 | 连接后请求 `7.5-15 ms` 区间 | ✅ |
|
||
| CoP 上行 | 固定 17 字节二进制帧,目标频率约 `50 Hz` | ✅ |
|
||
| NUS 发送保护 | 仅在连接存在且通知已使能时发送,失败时短间隔重试 3 次 | ✅ |
|
||
| 断线重广播 | 断开 1 秒后重新广播 | ✅ |
|
||
| NUS 下行解析 | Resistance / Spotter / Heartbeat 三类帧已接收解析 | ✅ |
|
||
| 编码器上行 | 协议已预留,主循环未发送 | 🔲 |
|
||
|
||
### 4.3 控制参数与保护逻辑
|
||
|
||
| 项目 | 说明 | 状态 |
|
||
|------|------|------|
|
||
| Resistance 参数接收 | 接收 `K / B / Tau` 并保存到传输层静态变量 | ✅ |
|
||
| Spotter 参数接收 | 接收 `threshold / enable` 并保存到传输层静态变量 | ✅ |
|
||
| Heartbeat 接收 | 接收后刷新最近心跳时间戳 | ✅ |
|
||
| 阻力闭环控制 | 参数已接入协议层,控制逻辑未落地 | 🔲 |
|
||
| Spotter 保护动作 | 参数已接入协议层,保护动作未落地 | 🔲 |
|
||
|
||
## 5. BLE 协议规格
|
||
|
||
平衡板工作在 BLE `Peripheral` 角色,通过 Nordic UART Service 与基站交换二进制帧。
|
||
|
||
- 上行方向:平衡板 -> 基站,使用 NUS `Notify`
|
||
- 下行方向:基站 -> 平衡板,使用 NUS `Write`
|
||
- 广播内容:广播包带 NUS UUID,扫描响应带设备名 `GML670_System`
|
||
|
||
### 5.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,下发控制参数 |
|
||
|
||
### 5.2 连接参数
|
||
|
||
| 参数 | 当前值 | 说明 |
|
||
|------|--------|------|
|
||
| 广播模式 | `BT_LE_ADV_CONN_FAST_2` | 上电和断线后走同一入口启动 |
|
||
| 连接间隔请求 | `7.5-15 ms` | `interval_min = 6`,`interval_max = 12` |
|
||
| 从站延迟 | `0` | 不跳过连接事件 |
|
||
| 监督超时 | `4000 ms` | `timeout = 400` |
|
||
|
||
### 5.3 帧类型总览
|
||
|
||
| 类型名 | 值 | 方向 | 长度 | 频率 | 说明 |
|
||
|--------|----|------|------|------|------|
|
||
| `PROTO_TYPE_COP` | `0x01` | 平衡板 -> 基站 | `17` | 约 `50 Hz` | CoP 上行帧 |
|
||
| `PROTO_TYPE_ENCODER` | `0x02` | 平衡板 -> 基站 | `13` | TBD | 编码器上行帧,预留 |
|
||
| `PROTO_TYPE_RESISTANCE` | `0x10` | 基站 -> 平衡板 | `15` | 按需 | 阻力参数帧 |
|
||
| `PROTO_TYPE_SPOTTER` | `0x11` | 基站 -> 平衡板 | `8` | 按需 | Spotter 参数帧 |
|
||
| `PROTO_TYPE_HEARTBEAT` | `0x20` | 基站 -> 平衡板 | `4` | `~1 Hz` | 心跳帧 |
|
||
|
||
### 5.4 当前上行主帧
|
||
|
||
CoP 帧固定 17 字节,结构如下:
|
||
|
||
| 字节偏移 | 字段 | 类型 | 说明 |
|
||
|----------|------|------|------|
|
||
| `0` | `sync0` | `uint8` | 固定 `0xAA` |
|
||
| `1` | `sync1` | `uint8` | 固定 `0x55` |
|
||
| `2` | `type` | `uint8` | 固定 `0x01` |
|
||
| `3` | `seq` | `uint8` | 包序号,循环递增 |
|
||
| `4` | `flags` | `uint8` | `bit0` 表示 `force_valid` |
|
||
| `5-8` | `cop_x` | `float32 LE` | 压力中心 X 坐标,单位 mm |
|
||
| `9-12` | `cop_y` | `float32 LE` | 压力中心 Y 坐标,单位 mm |
|
||
| `13-16` | `force` | `float32 LE` | 总重量,单位 kg |
|
||
|
||
更完整的字段说明和示例帧见 [BALANCE_BOARD_PROTOCOL.md](./BALANCE_BOARD_PROTOCOL.md)。
|
||
|
||
## 6. ADS1256 / CoP 规格
|
||
|
||
### 6.1 初始化与采样流程
|
||
|
||
当前固件的 ADS1256 侧流程如下:
|
||
|
||
```text
|
||
上电
|
||
|
|
||
+-- 配置 CS / DRDY / RESET GPIO
|
||
+-- 绑定 SPI1,频率 500 kHz
|
||
+-- 硬件复位 ADS1256
|
||
+-- 发送 CMD_SDATAC,关闭连续输出模式
|
||
+-- 写寄存器: STATUS=0x06, MUX=0x01, ADCON=0x07, DRATE=0xC0
|
||
+-- 发送 CMD_SELFCAL
|
||
+-- 回读关键寄存器做校验
|
||
+-- tare 去皮
|
||
|
|
||
+-- 传感器线程循环
|
||
|
|
||
+-- 依次切换 4 路 MUX
|
||
+-- 每路读 17 次并求均值
|
||
+-- 扣除零点偏移
|
||
+-- 死区抑制
|
||
+-- 重量换算
|
||
+-- CoP 解算
|
||
+-- 打包 CoP 帧并发送
|
||
```
|
||
|
||
### 6.2 关键参数
|
||
|
||
| 项目 | 当前值 | 说明 |
|
||
|------|--------|------|
|
||
| SPI 频率 | `500 kHz` | `spi_cfg.frequency = 500000` |
|
||
| STATUS | `0x06` | `ACAL=1`,`BUFEN=1` |
|
||
| PGA | `64` | `ADCON = 0x07` |
|
||
| 采样率 | `3750 SPS` | `DRATE = 0xC0` |
|
||
| 每帧均值次数 | `17` | `AVG_COUNT = 17` |
|
||
| 去皮窗口 | `17` | 每路取 17 点,中位数为零点 |
|
||
| 死区 | `±250 counts` | `DEADZONE_THRESHOLD = 250` |
|
||
| 板面半宽 | `100 mm` | `BOARD_HALF_WIDTH_MM = 100.0f` |
|
||
| 板面半长 | `100 mm` | `BOARD_HALF_LENGTH_MM = 100.0f` |
|
||
| CoP 最小有效总重 | `0.5 kg` | `COP_MIN_FORCE_THRESHOLD = 0.5f` |
|
||
| 调试日志频率 | 每 10 帧一次 | 目标运行状态下约 `5 Hz` |
|
||
|
||
### 6.3 CoP 判定规则
|
||
|
||
- 四路去皮后的 ADC 值先乘 `ADC_TO_FORCE_SCALE`,换算成重量
|
||
- 总重量低于 `0.5 kg` 时,`cop_x` 和 `cop_y` 置 `0.0f`
|
||
- 此时 `flags.bit0 = 0`,表示 CoP 坐标没有物理意义
|
||
- 总重量达到阈值后,再根据四角坐标做加权平均
|
||
|
||
当前四路传感器与板面坐标的映射如下:
|
||
|
||
| 通道 | 位置 | X | Y |
|
||
|------|------|---|---|
|
||
| `S0` | 右前 `FR` | `+100` | `+100` |
|
||
| `S1` | 右后 `BR` | `+100` | `-100` |
|
||
| `S2` | 左后 `BL` | `-100` | `-100` |
|
||
| `S3` | 左前 `FL` | `-100` | `+100` |
|
||
|
||
## 7. 开发环境与板级配置
|
||
|
||
当前工程采用标准 Zephyr / NCS 应用结构,目标板为 `nrf5340dk/nrf5340/cpuapp`。
|
||
|
||
`prj.conf` 当前可以直接确认的配置点包括:
|
||
|
||
- `CONFIG_BT=y`,启用 BLE
|
||
- `CONFIG_BT_PERIPHERAL=y`,工作在外设角色
|
||
- `CONFIG_BT_NUS=y`,启用 Nordic UART Service
|
||
- `CONFIG_BT_DEVICE_NAME="GML670_System"`,设置广播设备名
|
||
- `CONFIG_BT_NUS_SECURITY_ENABLED=n`,关闭 NUS 安全限制
|
||
- 日志走 RTT:`CONFIG_USE_SEGGER_RTT=y`
|
||
- 关闭 UART Console:`CONFIG_CONSOLE=n`、`CONFIG_UART_CONSOLE=n`
|
||
- 关闭 UART 日志后端:`CONFIG_LOG_BACKEND_UART=n`
|
||
- 关闭串口驱动:`CONFIG_SERIAL=n`
|
||
|
||
`app.overlay` 当前只保留了 SPI1、ADS1256 设备节点和三根控制 GPIO 的定义,没有把 UART Console 复用回来。
|
||
|
||
## 8. 项目结构
|
||
|
||
当前阅读和维护时最关键的文件如下:
|
||
|
||
| 路径 | 说明 |
|
||
|------|------|
|
||
| `src/main.c` | 启动入口,负责初始化 BLE 和传感器子系统 |
|
||
| `src/ads1256.c` | ADS1256 SPI 读写、复位、寄存器配置和校验 |
|
||
| `src/sensor.c` | 采样线程、tare、均值滤波、重量换算和 CoP 打包 |
|
||
| `src/ble_transport.c` | BLE 广播、NUS 收发、断线重广播和下行参数缓存 |
|
||
| `inc/protocol.h` | 二进制协议结构、重量换算系数、几何参数和阈值 |
|
||
| `app.overlay` | SPI1、CS、DRDY、RESET 的板级连线 |
|
||
| `prj.conf` | BLE、日志和控制台相关配置 |
|
||
| `BALANCE_BOARD_PROTOCOL.md` | 协议专项说明、字段表和示例帧 |
|
||
|
||
## 9. 构建与烧录
|
||
|
||
在已经配置好 Zephyr / NCS 环境的前提下,可以直接在工程根目录执行:
|
||
|
||
```bash
|
||
west build -b nrf5340dk/nrf5340/cpuapp -p always .
|
||
west flash
|
||
```
|
||
|
||
如果只是重新编译当前应用,默认目标仍然是 `nrf5340dk/nrf5340/cpuapp`。
|
||
|
||
## 10. 日志与当前约束
|
||
|
||
### 10.1 日志
|
||
|
||
当前日志走 RTT,不占用 UART Console。启动后可以看到如下类型的信息:
|
||
|
||
- 启动 banner
|
||
- BLE transport 初始化结果
|
||
- ADS1256 关键寄存器回读结果
|
||
- tare 开始和结束
|
||
- Resistance / Spotter 下行参数日志
|
||
- 周期性的四角重量、总重、CoP 和帧耗时日志
|
||
|
||
Heartbeat 接收路径已经接入,但默认 `DBG` 级别下才单独打印。
|
||
|
||
### 10.2 当前约束
|
||
|
||
- 阻力参数、Spotter 参数和 Heartbeat 目前只做到协议接收、内存保存和日志留痕
|
||
- 编码器上行帧只在协议头里预留,当前没有实际数据源
|
||
- 传感器线程没有额外 `k_msleep()` 节流,实际帧率由 ADS1256 采样和 BLE 发送耗时共同决定
|
||
- README 中的频率描述按当前 `3750 SPS + 4 通道 * 17 次均值` 这套实现估算,目标运行频率约 `50 Hz`
|
||
- 当前实现默认四角传感器是固定几何布局,半宽和半长都是 `100 mm`
|