Files
linux_sentry_chassis/docs/architecture.md
T

163 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 架构设计
## 分层
```
┌────────────────┐ ┌──────────────────────┐ ┌─────────────────────────┐
│ chassisd │ │ chassis-tune │ │ chassis-bench │
│ 守护进程 │ │ 自动整定(搜索/报告) │ │ 台架(激励/包络/采样) │
│ 1kHz 循环 / 安全│ │ sim ↓ bench ↓ │ │ chassis-spin 等 │
└───┬────────┬───┘ └────┬──────────┬──────┘ └────┬───────────────────┘
│ │ │ │ │
│ │ │ └───────┬───────┘
▼ ▼ ▼ ▼
┌───────────┐ ┌──────────────────┐ ┌───────────────────────┐
│ mecanum │ │ dji-esc-sim │ │ dji-esc-slcan │
│ 麦轮运动学 │ │ 被控对象 / 场景 │ │ dji-esc-socketcan │
└───────────┘ │ 离线 harness │ │ 真实总线 ↔ CanLink │
│ 异步假电调 │ └──────────┬────────────┘
└────────┬─────────┘ │
│ CanLink(tokio mpsc 通道对)
▼ ▼
┌────────────────────┐ ┌──────────────────┐
│ motor-core │◄─│ dji-esc │
│ 能力 trait / Pid │ │ C620/C610 协议 │
│ VelocityGains │ │ EscBus 异步驱动 │
└────────────────────┘ └──────────────────┘
┌────────────────────┐
│ chassis-config │ chassis.toml schema(chassisd + chassis-tune 共用)
└────────────────────┘
```
核心解耦点:`CanLink` 是一对 tokio 通道(发送 / 接收 `CanFrame`)。`dji-esc` 的协议状态机
只面向通道工作,因此:
- 闭环仿真由 `dji-esc-sim` 提供两条路径:**异步假电调**(挂在同一对通道上,`chassisd --mock`
与集成测试用)与**同步 harness**(纯浮点积分、无任务无通道,自动整定用,可并行上千次);
- `dji-esc-socketcan`(板载原生 SocketCAN)与 `dji-esc-slcan`(CANable 等 USB 适配器,
串口 Lawicel 协议)只把真实总线桥接到通道,**不含任何应用逻辑**;应用住在 `chassis-bench`
(台架)与 `chassis-tune`(整定);
- 未来更换总线介质(串口转 CAN、MCU 转发)只需新增一个桥接 crate。
## 被控对象模型(dji-esc-sim)
逐拍离散(`dt` 秒),电调坐标系(正电流 → 正转速):
1. **命令延迟**:`current_raw` 进 FIFO,`delay_ticks` 拍后才作用(链路 + 采样延迟);
2. **摩擦**:运动时 `net = u − sign(rpm)·coulomb − viscous·rpm`;静止且 `|u| > static` 时
`net = u − sign(u)·coulomb`;静止且 `|u| ≤ static` 时 `net = 0`(粘住);
3. **一阶转速**:`rpm_target = clamp(net × gain, ±max_rpm) − load_rpm`,
以时间常数 `tau` 一阶趋近;
4. **量化**:机械角按转速积分并对 8192 取模,反馈帧是 `EscFeedback`,
因此角度被截断为 `u16`、转速为 `i16`——量化由协议类型自带。
`PlantParams::gm3508()` 是**无摩擦无延迟**的理想模型(`chassisd --mock` 与历史闭环测试依赖它,
行为逐位不变);`PlantParams::gm3508_bench()` 叠加静 / 库仑摩擦(400~600 raw 量级,
取自台架实测)与 2 拍延迟,是整定的默认被控对象。
单点模型整定出来的增益往往对增益 / 时间常数 / 延迟高度敏感,因此 `chassis-tune` 默认在
`PlantEnsemble`(域随机化:增益 ±20%、时间常数 ±30%、延迟 0~3 拍、摩擦 ±50%)上做鲁棒优化,
而不是针对一条理想曲线做最优化。
## 自动整定(chassis-tune)
两阶段搜索:
1. **粗扫**:Latin Hypercube 分层采样 + `rayon` 并行评估,用有限次数铺满四维空间;
2. **精修**:以成本最低的 top-k 为起点,在**坐标空间**(对数刻度,增益恒正)做多起点
`argmin` 局部搜索(Nelder-Mead 默认,可选 PSO)。
成本 = 归一化加权(调节时间 / 超调 / IAE / 电流);**硬约束不进权重**:过速、饱和占比过高、
不收敛直接给罚值并记录判定——否则搜索会主动挑一个会飞车的解。
可复现性:每个候选的随机性只来自 `(种子, 候选下标)` 派生的独立 RNG,粗扫结果排序后再取 top-k,
因此同 seed 两次运行**逐位一致**(CI 的 `just tune-smoke` 依赖这一点)。
超参数(参数空间 / 场景 / 权重 / 验收阈值 / 搜索预算 / 被控对象 / 真机安全包络)不在命令行
默认值里散着,而是版本化在 `config/tune.toml` 的具名预设中(见
[`preset.rs`](../crates/chassis-tune/src/preset.rs))。优先级为
**内置默认 < 预设文件 < 显式 CLI**,逐字段覆盖;`current_limit` / `direction` / `gear_ratio`
不是预设字段,写进预设文件会直接报错(安全参数不允许被预设绕过)。
真机后端(`--backend bench`)与仿真后端实现同一个 `Evaluator` trait,区别只是"评估一组增益"
从浮点积分换成真机试验:打开链路 → 上电门控(反馈新鲜)→ 逐次热更新增益
(`EscMotor::set_velocity_gains`,不重启总线)→ 逐拍重发设定值 + 安全包络 → 任何退出路径
先 0 电流 → 试验间静默。搜索强制单线程,因为只有一条总线。
## 命令租约与链路深度(实车踩过的坑)
1. **命令是租约**:`EscBus` 在 `command_timeout`(默认 50ms)内没收到新命令就强制 0 输出
(防上层任务死亡后旧指令持续输出)。所以 `set_velocity` 不是"设一次就完事",上层必须
逐拍重发;只在开头下发一次的台架脚本会在 50ms 后自动失电。
2. **命令队列必须浅**:驱动按 1kHz 生产命令,而 slcan 一次 write 在 CDC ACM 上约 2ms,
下行只有几百帧/秒。若 `CanLink` 命令方向缓冲很深(早期是 512),队列会被过时命令灌满,
ESC 执行的是**一秒多以前**算出的电流——速度环等于开了 1.4s 延迟,轮子必然跑飞。
现在 slcan 桥的 `CHANNEL_BOUND = 8`:`send().await` 立即回压,每一帧都按最新反馈现算。
反馈方向是采样流,来不及就丢(`try_send`),绝不阻塞泵线程。
3. **桥的两个方向不能互相饿死**:发送要有上界(`TX_BURST`)并在一帧写不动时立刻让位,
接收要批量排空(`RX_BURST`)。`serial` crate 的 `TTYPort` 读写共用同一个超时,
写超时属正常现象,不能当致命错误(否则一次写超时就会把接收方向一起带停)。
## DJI 电调 CAN 协议要点(C620 手册)
| 项目 | 值 |
| --- | --- |
| 控制帧 ID | `0x200`(电调 1–4)、`0x1FF`(电调 5–8) |
| 控制帧格式 | 8 字节 = 4 × i16 大端电流命令,按电调 ID 顺序 |
| C620 电流标度 | ±16384 ↔ ±20 A |
| C610 电流标度 | ±10000 ↔ ±10 A(M2006 组合,接硬件前需核对) |
| 反馈帧 ID | `0x200 + 电调ID`(`0x201`–`0x208`) |
| 反馈帧格式 | u16 角度(0..8191) + i16 转速rpm + i16 转矩电流 + i8 温度℃,均大端 |
| 反馈频率 | 每电调 1kHz |
C620 内部**只闭电流环**:转速 / 位置环由主控侧 PID 实现(`motor-core::Pid`,
挂在 `EscBus` 的 1kHz 发送节拍上)。GM3508 减速比 3591 / 187 ≈ 19.203。
## 单位与方向约定
- 机器人坐标系:ISO 约定——x 前、y 左、ω 逆时针为正(见 `mecanum`)。
- `Motor` 接口呈现的是**物理量**(安装方向修正后):
`EscConfig::direction = -1` 时,驱动层在写命令与读反馈时统一翻转符号,
上层永远以"轮子正转 = 底盘前进方向"的正向工作。
- `MotorState::rotor_speed_rpm` 为电机转子转速;轮端转速 = 转子转速 / 减速比。
- 电流一律以协议原始值(raw)为主,安培换算通过 `EscModel` 常量提供。
## 安全设计
1. **上电门控**:底盘循环在收到任一电机首帧反馈前不下发速度命令。
2. **反馈离线**:任一电机反馈超时(默认 100ms)→ 该电机命令强制 0 电流并告警。
3. **命令超时**:上层 twist 命令超时(默认 200ms)→ 目标速度归零。
4. 所有超时可经 `chassis.toml` 配置。
## 测试策略
| 层级 | 内容 | 平台 |
| --- | --- | --- |
| 单元测试 | 帧编解码字节级样例 / 饱和、多圈回绕、PID(阶跃、抗饱和、滤波)、运动学解析解 + 属性测试、slcan 帧形状过滤 | 全平台 |
| 闭环仿真 | 内存通道 + 一阶电机模型:4 电机速度环收敛、群帧组装、离线安全、**命令租约到期与续租**、**增益热更新**、守护进程全链路 | 全平台 |
| 模型一致性 | 同步 harness 与 `EscBus` 异步闭环在同一组增益下的稳态 / effort 对齐(防止"对着错模型调参") | 全平台 |
| 整定 | 指标(合成轨迹解析解)、参数空间(界内 / 确定性 / 对数分布 / 分层覆盖)、成本(硬约束罚值)、搜索(同 seed 逐位复现、优于手调基线)、报告(CSV/TOML/JSON 往返) | 全平台(CI 跑 `just tune-smoke`) |
| 超参数预设 | schema 往返、逐字段覆盖与优先级、未知键 / 越界 / 缺失报错、`config/tune.toml` 全部预设可解算、命名与后端一致、安全参数不可注入 | 全平台 |
| vcan 集成 | vcan0 双 socket 收发,真实内核 CAN 栈 | Linux(`#[ignore]`,CI 显式跑) |
| 实车台架 | `chassis-spin`(`chassis-bench`)四轮定速旋转:链路/反馈、方向、转速稳态、过速保护、安全停机;`chassis-tune --backend bench` 逐次试验 + 重复性复验 | armv7 目标板 + slcan/SocketCAN(人工) |
| 交叉检查 | `aarch64-unknown-linux-gnu` 全 workspace check | CI |
## 部署
`chassisd` 为单二进制守护进程:`--interface can0 --config /etc/chassisd/chassis.toml`。
systemd 样例见 `deploy/chassisd.service`。板端 CAN 两条路径:
- **SocketCAN**:USB 转 CAN(gs_usb / candleLight)或 SPI CAN HAT(MCP2515)驱动加载后的 `can0`;
- **slcan**:USB 适配器(CANable2 等)在 CDC ACM 下枚举为 `/dev/ttyACM0`,由
[`dji-esc-slcan`](../crates/dji-esc-slcan) 在用户态处理(不需 `ip link`,也绕开了
gs_usb 驱动)。台架工具 `chassis-spin`([`chassis-bench`](../crates/chassis-bench))与
自动整定的真机后端走这条路径。整定工具本身是宿主机 / 板端通用的纯 Rust 程序,
`current_limit` 等安全参数由 CLI 显式给出,不参与搜索。
## 相关文档
- [底盘开发文档](chassis.md)——接线 / 标定 / 上车流程 / 自动整定与超参数预设 / 故障排查
- [整体架构规划](../ARCHITECTURE.md)——全系统分层与阶段计划