Files
DCU_DesktopController/docs/compose/spec/ecat-rx-stuck.md
T
cbb e91d53e0fc feat(ecat): 启动后把 ecat_native 提到 RealTime;跳拍优化实验脚本与报告
- esp32_server: Popen 后外部 SetPriorityClass(RT/High),native 自设会被钳成 High
- 入库 skip_* 标定/实验脚本与 REPORT_ecat_skip_opt_20260917
- 前端 WIP:layout/app/polling/boot_ecat/index
- 不含 lab/skip_meter 原始采样与 preview 截图
2026-09-17 02:32:20 +08:00

68 lines
3.4 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.
---
feature: ecat-rx-stuck
status: in-progress
updated: 2026-09-16
branch: main
commits:
---
# EtherCAT 从机帧接收异常(输入全 0 / 发帧后才流动)
## Report
真机验收(2026-09-16,主站 kick 已上线):`motor/start` **不发业务帧** 即
`wkc=3/3`、`rxraw.layout=dense`、magic=0xA5、gseq=429、motors=1、wr=0。
日志:`OP 后输入已流动(magic=1 diag=1 rx 431→431),踢帧 8 拍`。
## [S1] Problem
EtherCAT 进入 OP 后,主站 `/api/motor/pdoin` 与 `/api/motor/rxraw` **整包 600B 全 0**:
无 dense magic(0xA5)、gseq=0、桥 rx_count=0、段 5 诊断 seq=0、`app/load.valid=false`。
现场 `wkc=2/3`(期望 3)。用户一旦经 `/api/motor/send` 发出任意帧,输入立刻流动:
`wkc=3/3`、magic=A5、电机槽/桥状态出现。之后 `wr` 楔死恢复次数持续上涨。
真机复现(2026-09-16,GD32 APP 1.6.41 + 主站 native):
1. `motor/start` → 日志「OP 后输入无流动…重走 INIT→OP」→ 仍全 0
2. `motor/send` 一帧 → 同一秒内 pdoin 出现 dense 布局与真实电机状态
3. SPI `/spi/speedtest` 正常(ESP32↔GD32 链路本身无病)
## [S2] Design
### 根因(主)
从站 SSC 在 **SM-Synchron** 下应用与输入映射靠 SM2 事件(PDI_Isr)驱动;
MainLoop 的 free-run 分支在 `bEcatFirstOutputsReceived==TRUE` 后整段跳过。
主站 idle 输出 `seq=0` 时,从站 `processOutput`/冷启动路径迟迟不把输入 PDO
真正填进 ESC——`buildInput`+`fillDiagTail` 依赖 `EcatPdo_Process()` 被调用。
主站一旦发送(seq 沿变化)→ outputProbe 全量读 → 冷启动/应用路径苏醒 → 输入开始流动。
### 次因
1. **主站 OP 活性判据过窄**(`do_op_start`):只看两次 `pump_cycles` 之间
`bridge.rx_count` 是否变化。无 CAN 流量时 rx_count 恒 0 → 必判「无流动」→
无意义重走 INIT→OP;有流量时 12ms 窗口也可能采不到 → 同样误判。
2. **从站 1.6.33 新鲜度救援只写不填**(`EcatDbg_OpInputFreshness`):输入冻结时
只调 `PDO_InputMapping()`,从空的 `s_inBuf` 拷 0 写 ESC,等于把「冻结」固化成「全 0」。
3. 从站 1.6.41 warm-jump 跳过 RST# 的路径本身可接受(BYTE_TEST 门),但与上述
「应用未醒」叠加后,首帧前输入窗口长期全 0。
### 修复契约
| 侧 | 行为 |
|----|------|
| 主站 | 进 OP 后、起循环前:用 **dlc=0 + seq 沿** 的空输出连打数拍,制造 outputProbe 边沿、不发 CAN。活性判据改为「输入含 dense magic 或 diag seq 非 0 或 rx_count 变化」。 |
| 从站 | `EcatDbg_OpInputFreshness` 强制刷新前先 `EcatPdo_Process()`,再 `PDO_InputMapping()`。 |
| 从站版本 | patch → 1.6.42(仅救援路径,无布局变更,可与主站独立升级)。 |
## [S3] Out of Scope
- 不改 PDO 线格式 / SII / 600B 布局
- 不改 SPI 协议(0xE8 撕裂已有 ESP32 侧未提交修复,另案)
- 不回退 1.6.41 warm-jump 探针策略(BYTE_TEST 门保留)
- 不改电机/CAN 桥业务语义
## Tasks
- [x] T1: 主站 OP 后 seq 沿踢帧 + 活性判据加宽 — acceptance: 不发业务帧时 pdoin 出现 0xA5 且 gseq 可前进 (covers: S2)
- [x] T2: 从站新鲜度救援先 Process 再 InputMapping — acceptance: PDI 停摆时主站读到非全 0 输入 (covers: S2)
- [x] T3: 真机复验 start 后不 send 即有输入 — acceptance: motor/start 后 2s 内 rxraw.layout=dense (covers: S2; depends: T1)