Files
ASER-NAV/修改建议报告.md

244 lines
8.4 KiB
Markdown
Raw Permalink 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.
# CAN/里程计频率修改建议报告
## 1. 结论
建议采用以下组合修改,而不是单独只改一边:
1. 下位机 `FDR-Core``0x200 Odom Delta` 从当前约 `60ms` 提升到 `20ms` 固定发送。
2. 上位机 `ARES``0x200` 的消费与 `Odom_Update()``monitorTask(100ms)` 挪到 `navTask(20ms)`
3. `0x182/0x183` 保持低频轮询即可,不需要跟着一起提到 `20ms`
4. 当前阶段不建议把 `0x200` 进一步提到 `10ms`,先做到 `20ms` 即可。
一句话概括:当前 odom 不够实时,不是总线带宽不够,而是“下位机发送慢 + 上位机消费慢”叠加导致的;最合适的修法是把两端都对齐到 `20ms`
## 2. 本次核对到的事实
### 2.1 下位机当前真实行为
下位机工程:`C:\Users\Falling_jasmine\CLionProjects\FDR-Core`
实际实现文件:`Core/Src/f4_can_app.c`
关键实现如下:
1. `CAN_Send_Telemetry_20ms()``20ms` 调一次。
2. `0x181` 状态帧固定每次都发。
3. `0x182 / 0x183 / 0x200` 通过 `s_telem_slot` 三选一轮询发送。
4. 所以 `0x200` 实际发送周期约为 `60ms`,不是 `20ms`
5. `0x184` 通过 `s_comm_diag_divider``100ms` 发送一次。
对应代码位置:
1. `C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:925-966`
2. `C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:907-923`
另外,下位机头文件注释和实际实现已经出现漂移:
1. `f4_can_app.h` 注释写的是 `0x181/0x182/0x183/0x200` 都在 `20ms` 周期发送。
2. 但真实代码并不是这样,而是只有 `0x181` 固定 `20ms`
对应位置:
1. `C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Inc\f4_can_app.h:165-173`
2. `C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:925-966`
### 2.2 下位机 odom 数据源没有问题
下位机 `motor.c` 中,编码器增量在控制周期中持续累加到 `s_odom_acc_ticks[]`
1. 每次电机更新时都会把四轮增量累加到 odom 累加器。
2. `CAN_Send_OdomFrame()` 发送 `0x200` 时,通过 `Motor_Get_And_Clear_Delta_Ticks()` 原子取走并清零。
这说明:
1. `0x200` 本质是“自上次发送以来的积分增量”。
2. 如果把 `0x200` 发送频率从 `60ms` 提高到 `20ms`,语义仍然正确,只是每帧覆盖的时间窗变短、实时性更高。
对应位置:
1. `C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\motor.c:225-245`
2. `C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\motor.c:263-295`
3. `C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:907-923`
### 2.3 上位机当前真实行为
上位机工程:`D:\ARES`
当前 `0x200` 的消费模型是:
1. CAN ISR 收到每帧 `0x200` 后,不直接覆盖,而是累加到 `odom_accum`
2. `monitorTask``100ms` 调用 `SNC_CAN_ConsumeOdomDelta()` 原子取走累计值。
3. 然后再调用 `Odom_Update()` 推送黑板。
4. `navTask` 本身跑在 `20ms`,但它读到的 `board.odom_vx` 很多拍都是旧值。
对应位置:
1. `D:\ARES\App\Can\snc_can_app.c:185-225`
2. `D:\ARES\App\app_tasks.c:145-167`
3. `D:\ARES\App\app_tasks.c:295-340`
## 3. 问题本质
当前 odom 实时性差,来自两个串联环节:
1. 下位机发送 `0x200` 只有约 `60ms` 一次。
2. 上位机又只在 `100ms``monitorTask` 中消费一次。
所以当前 `odom_vx` 的有效刷新节拍,不是 `navTask``20ms`,而是被这两个环节一起拖慢了。
这会直接影响:
1. `CorridorEKF_Predict()``odom_vx` 的实时性。
2. 沿程 `s` 的连续性。
3. 车体加减速或转向阶段时,状态传播的平滑度。
## 4. 是否需要把 CAN 提得更高频
当前不建议先追求高于 `20ms` 的 CAN 频率。
原因:
1. 上位机 `navTask` / EKF 当前就是 `20ms / 50Hz`
2. `0x100` 速度命令协议推荐节拍也是 `20ms`
3. `0x200` 先做到 `20ms`,就已经与主导航闭环对齐。
4. 再往 `10ms` 提,边际收益明显变小,且会引入更多调度与验证成本。
在你当前系统中,更合理的目标是:
1. `0x100` 保持 `20ms`
2. `0x181` 保持 `20ms`
3. `0x200` 提到 `20ms`
4. `0x182/0x183/0x184` 维持低频
## 5. 总线负载是否会成为问题
基于你补充的信息:总线上只有两个单片机,且 CAN 速率为 `1 Mbps`
在这个前提下,把 `0x200` 提到 `20ms` 是合理的,风险较低。
主要原因:
1. 当前实时关键帧就只有 `0x100``0x181``0x200`
2. 即便这三类帧都在 `20ms` 发送,总线占用通常仍远低于饱和。
3. 下位机当前发送代码本身也把遥测帧视为“允许丢”的低优先级消息,不会因短时发不出去而阻塞主循环。
对应代码:
1. `C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:808-821`
## 6. 推荐修改方案
### 6.1 下位机修改建议
修改文件:
1. `C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c`
2. `C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Inc\f4_can_app.h`
修改目标:
1. `0x181``20ms` 固定发送。
2. `0x200``20ms` 固定发送。
3. `0x182/0x183` 改成低频轮询发送。
4. `0x184` 继续 `100ms`
最小改法建议如下:
1. 保留 `CAN_Send_StatusFrame()` 每拍都发。
2.`CAN_Send_Telemetry_20ms()` 中,每拍额外固定调用 `CAN_Send_OdomFrame()`
3. 把原来的 `s_telem_slot` 轮询从 `0x182/0x183/0x200` 三选一,改成只在 `0x182/0x183` 两者之间轮询。
4. 更新头文件中的注释,避免文档/实现再次漂移。
推荐把 `CAN_Send_Telemetry_20ms()` 的逻辑改成:
1. 先发 `0x181`
2. 再发 `0x200`
3. 再按 slot 发 `0x182``0x183`
4. 每 5 拍发一次 `0x184`
这样改的优点:
1. `0x200` 得到稳定 `20ms` 周期。
2. `0x182/0x183` 仍然保留,但不抢实时关键链路。
3. 代码改动很小,不需要碰控制内环和接收协议。
### 6.2 上位机修改建议
修改文件:
1. `D:\ARES\App\app_tasks.c`
修改目标:
1. `SNC_CAN_ConsumeOdomDelta()` 不再由 `monitorTask(100ms)` 调用。
2. odom 消费与 `Odom_Update()` 挪到 `navTask(20ms)`
具体建议:
1. 删除 `AppTasks_RunMonitorTask()``145-167` 这段 odom 消费代码。
2.`AppTasks_RunNavTask_Impl()` 中、`Blackboard_GetSnapshot(&board)` 之前插入同样的 odom 消费逻辑。
3. 保持 `SNC_CAN_ConsumeOdomDelta()` 全系统只有一个消费者。
推荐新顺序:
1. `now_ms = HAL_GetTick()`
2. `SNC_CAN_ConsumeOdomDelta(...)`
3. `Odom_Update(...)``Odom_HandleTimeout(...)`
4. `Blackboard_GetSnapshot(&board)`
5. `CorridorPreproc_ExtractObs(...)`
6. `CorridorFilter_Update(...)`
这样可以保证:
1. `navTask` 每一拍都能第一时间消费已到达的 `0x200`
2. 当下位机把 `0x200` 提到 `20ms` 后,上位机不会再被 `100ms monitorTask` 卡住。
## 7. 不建议的修改方式
### 7.1 只改上位机,不改下位机
这样只能把 odom 的消费延迟从 `100ms` 降下来,但 `0x200` 源头仍是约 `60ms`,收益有限。
### 7.2 只改下位机,不改上位机
这样虽然 `0x200` 更快到达了,但上位机仍在 `100ms` 才取走一次,实时性改善不完整。
### 7.3 直接把 `0x200` 提到 `10ms`
现阶段不建议。原因:
1. 上位机 `navTask` 仍是 `20ms`
2. EKF 和控制链路当前主频也是 `20ms`
3. 先把 `20ms` 跑顺、验证完,再决定是否需要更高频更合理。
## 8. 推荐实施顺序
建议按下面顺序改:
1. 先改下位机 `f4_can_app.c`,让 `0x200` 固定 `20ms` 发送。
2. 同步修正下位机 `f4_can_app.h` 注释。
3. 再改上位机 `app_tasks.c`,把 odom 消费搬进 `navTask`
4. 实车或日志确认 `0x200` 到达间隔、`odom_vx` 刷新节拍和 EKF 状态表现。
## 9. 验收建议
改完后至少验证以下几点:
1. 上位机收到的 `0x200` 时间戳间隔是否接近 `20ms`
2. `SNC_CAN_ConsumeOdomDelta()` 是否只在 `navTask` 被调用一次。
3. `board.odom_vx` 是否不再长时间停留旧值。
4. `EKF``s``e_y` 传播是否更连续。
5. `s_can_tx_drop_total` 是否没有明显上升。
6. `0x181``0x184``0x100` 协议行为是否保持兼容。
## 10. 最终建议
最终建议如下:
1. 下位机把 `0x200` 改成 `20ms` 固定发送。
2. 上位机把 odom 消费改到 `navTask(20ms)`
3. `0x182/0x183` 保持低频,不必提频。
4. 先不要把 `0x200` 提到 `10ms`
这是当前这两套代码下,改动最小、收益最大、工程风险也最低的方案。