JetWave ECU 动力模组深度程序分析报告
「主控失速 + 断联 + 遥控器无法控制」根因与系统设计评审
文档版本: v1.0
生成日期: 2026-05-26
代码基线: JetWaveECU-master-2d55e90f4a54d61a83efab89195082109acd3472(2d55e90f)
前置计划: JETWAVE_ECU_POWERTRAIN_ANALYSIS_PLAN.md
关联现场: history2 / 荷兰异常报告 / App CODE_REVIEW_*
执行摘要
本报告要回答的唯一核心问题
在什么情况下,会出现:板体进入失速保护、主控与电调通信被判异常(用户感知为「断联」)、用户仍推油门但动力无法恢复——即「失速 + 断联 + 遥控器无法控制」?
从 第一性原理(水上动力安全系统)出发,控制链路应满足:
- 感知:可靠获知 RC 意图、ESC 状态、BMS/IMU 健康
- 决策:故障时进入 明确、可预测、可恢复 的安全态
- 执行:安全态下 主动切断或限制扭矩,而非仅弹窗
- 告知:向用户说明 当前能否恢复、如何恢复
对照 2d55e90f 源码与近一月轨迹数据,结论如下:
| 结论 | 严重程度 | 说明 |
|---|---|---|
| ECU 在 STALL 后仍按油门向 ESC 发非零转速 | P0 安全 | MotorSpeedControlTask 未对 ESC_FAULT_STALL_PROTECTION (0x20000) 做任何限扭/清零 |
| BLE 断链 (mode=255) 不向 ESC 发零转速 | P0 安全 | 断链只本地 MotorSpeed=0,未调用 SendSetSpeedRequest(0) |
FAULT_ESC_COMMUNICATION 可由数据路径丢帧触发 |
P0 误判 | 12s 无队列数据即置位,与 TWAI 10:1 降频、任务周期叠加 |
失速码来自 ESC running_error 高 16 位,ECU 又二次合成 bit1 |
P1 语义 | speed <= -20000 也会置位与 STALL 同位的 running_error bit1 |
| App/ECU 均无「失速恢复」状态机 | P1 体验 | 仅上报与弹窗,无强制松油门、无 ESC 复位握手 |
| 故障上报状态机单 bit 间隔约 12s | P2 | FAULT_DURATION_CYCLES 导致复合故障感知滞后 |
最重要场景(按现场频率与危害排序):
- 真失速锁死(Scenario A):ESC 固件堵转/失速保护 →
esc_event |= 0x20000→ 电机停转,但 ECU 继续发转速指令 → 用户推油门无效 → 日志表现为throttle>0 && motorSpeed=0 - 假断联叠加(Scenario B):STALL 期间 ESC 反馈变慢或队列丢包 → 12s 后
ecu_event |= FAULT_ESC_COMMUNICATION→ 用户看到「失速 + ESC 通信故障」→ 误以为主控断联,实则 RC 蓝牙可能仍连接 - 链路断链未拉闸(Scenario C):BLE/星闪断开 →
mode=255→ 不向 CAN 发零速 → 若 ESC 侧保持上一指令,存在 断链后仍驱动 风险(取决于 ESC 固件超时策略) - 升级/任务挂起(Scenario D):
MotorSpeedControlTaskSuspend()后不再发转速 → 与故障无关但表现同为「无法控制」
一、问题定义与用户语义对齐
1.1 用户口述 vs 日志字段 vs 代码枚举
| 用户说法 | 轨迹/App 典型信号 | 协议定义 (JetWave.xml) |
实际含义 |
|---|---|---|---|
| 板子失速 | escEventCode & 131072 |
ESC_FAULT_STALL_PROTECTION 0x00020000 |
电调侧堵转/失速保护,非 ECU 死机 |
| 主控断联 | ecuEventCode & 1073741824 |
FAULT_ESC_COMMUNICATION 0x40000000 |
ECU 判定 12s 未收到 ESC 运行数据,非 RC↔ECU 蓝牙断链 |
| 遥控器无法控制 | throttleLeverQuantity>0 且 motorSpeed=0 |
— | 控制意图未转化为扭矩;RC 链路可能正常 |
| 蓝牙真断链 | ECU 内部 mode=255 |
非标准 OperatingMode,为 ECU 私有约定 |
ble_server.c 断开时注入 |
关键澄清(避免排查跑偏):
- 日志里的「ECU 断联」几乎总是
FAULT_ESC_COMMUNICATION(ECU↔ESC CAN 路径),不是 遥控器与 ECU 的 BLE/星闪断开。 - 「失速」是 ESC 保护行为;「无法控制」在多数会话中是 保护未恢复 + ECU 未限扭,而非 RC 报文不到达。
1.2 核心故障码的位域编码(必须统一理解)
ECU 打包方式(ecu_manager.c):
latestEcuEventData.esc_event = (uint32_t)(escData.runningError) << 16 | escData.selfcheckError;
因此 esc_event 的 bit17(0x20000)= runningError 的 bit1(0x0002)左移 16 位。
| 字段 | 宽度 | 在 esc_event 中的位置 |
|---|---|---|
selfcheckError |
uint16 | bit 0~15 |
runningError |
uint16 | bit 16~31 |
ESC_FAULT_STALL_PROTECTION = 0x20000 只能来自 runningError 的 bit1,不可能单独由 selfcheckError 产生。
二、系统架构:控制面 vs 安全面(架构师视角)
2.1 逻辑分层与信任边界
flowchart TB
subgraph CP["控制面 Control Plane — 软实时 ~20ms"]
RC[RC App ThrottleAndGear 20ms]
BLE[BLE / NearLink MAVLink]
MSC[MotorSpeedControlTask Prio=15]
SET[SendSetSpeedRequest]
end
subgraph SP["安全面 Safety Plane — 应硬实时、fail-safe"]
ESC_HW[ESC 失速/过流/过温保护]
ECU_SYN[UpdateESCErrorCodeByRunningStatus]
COMM[FAULT_ESC_COMMUNICATION 12s]
MODE[mode 254/255 油门丢失/断链]
end
subgraph MP["监控面 Monitor Plane — 慢 ~500ms"]
HB[EcuHeatbeat 500ms]
EVT[EventCodeProcessByBit 12s/bit]
APP[App 弹窗 + 埋点]
end
RC --> BLE --> MSC --> SET --> ESC_HW
ESC_HW --> ECU_SYN --> HB
ECU_SYN --> EVT --> APP
COMM --> HB
MSC -.->|缺失:未订阅 STALL| ESC_HW
架构缺陷(第一性原理):
- 控制面(20ms 油门 → 转速)与 安全面(STALL、通信丢失)未在同一任务内闭环。
- 监控面(500ms 心跳、12s 才扫完一位故障)只负责「告知」,不具备切断扭矩的权威。
- 安全关键决策散落在:
esc_manager(部分)、ecu_manager(通信超时)、ble_server(mode)、ESC 固件(未知恢复策略)—— 无单一 Safety Supervisor。
2.2 任务、核心与优先级
| 任务 | 周期 | 优先级 | 核心 | 职责 |
|---|---|---|---|---|
MotorSpeedControlTask |
20ms | 15 | 1 | RC 油门 → SendSetSpeedRequest |
ProcessEcuDataTask |
50ms | 9 | 1 | 心跳、通信故障计数、事件状态机 |
ProcessEscDataTask |
100ms | 8 | 1 | ESC 反馈、二次故障合成、入队 |
| TWAI RX/TX | ~15ms 级 | — | — | UAVCAN 编解码 |
main 喂狗 |
1000ms | — | — | WDT |
风险: 控制任务优先级高于 ESC 数据处理任务,符合「先执行控制」直觉,但 ESC 故障反馈 最晚可滞后 100ms + 队列 + 10:1 降频,安全面信息 系统性落后于控制面。
2.3 双链路初始化(BLE vs 星闪)
main.c:NearLinkUartInit() 成功则走星闪回调注册,否则 ESP32 原生 BLE。
ecu_manager.c 运行时还可切换 NearLink SLE/BLE Server 回调(rcCallbacksRegistered)。
影响: 失速/断联问题需按 实际出货链路 分 variant 验证;星闪与 BLE 在断链时均注入 mode=0xFF,行为一致,但 RF 稳定性不同 会导致 FAULT_ESC_COMMUNICATION 发生率差异(与 RC-3000 CODE_REVIEW 结论一致)。
三、端到端数据流与状态时序
3.1 正常控制路径
RC App --[MAVLink ThrottleAndGear @~20ms]--> BLE/NearLink
--> ParseMavlinkFromRc --> SendRcThrottleAndGearCmd (queue)
--> MotorSpeedControlTask (20ms)
--> 滤波 / 模式表 maxSpeedForModes[3][16]
--> 可选 ALC 俯仰修正 (BEGINNER, gear14)
--> SendSetSpeedRequest(MotorSpeed) [@50Hz 每控制周期]
--> UAVCAN SetSpeed Request --> ESC 固件
<-- SetSpeed Response (speed, running_error, selfcheck_error, ...)
<-- uavcan_twai: 每10帧才 SendEscSpeedResponseDataToQueue 一次
--> ProcessEscDataTask (100ms)
--> UpdateEscSpeedInfo + UpdateESCErrorCodeByRunningStatus
--> SendEscRunningDataToQueue
--> ProcessEcuDataTask (50ms)
--> UpdateEcuHeatbeatDataByDevice + EventCodeProcessByBit
--> 500ms SendMavlinkToBleRC(EcuHeatbeatData)
3.2 故障路径(失速 + 通信故障叠加)
sequenceDiagram
participant U as 用户/RC
participant ECU as MotorSpeedControlTask
participant CAN as TWAI/UAVCAN
participant ESC as 电调固件
participant M as ProcessEcuDataTask
U->>ECU: 油门 > 0
ECU->>CAN: SetSpeed(N>0) 每20ms
CAN->>ESC: 转速指令
ESC-->>ESC: 堵转/失速保护触发
ESC-->>CAN: running_error bit1 置位
Note over ECU: 未检测 STALL,继续 SetSpeed(N>0)
ESC-->>CAN: speed=0 或拒绝输出
CAN-->>M: 反馈降频/偶发丢队列
M->>M: 12s 无 ReceiveEscRunningData
M->>U: ecu_event FAULT_ESC_COMMUNICATION
U->>U: 感知:失速+断联,油门仍无效
四、根因场景详解(嵌入式 / 单片机 / 底层系统视角)
Scenario A:真失速锁死 — 现场主因
触发条件(物理 + ESC 固件,ECU 仓库不可见完整逻辑):
- 螺旋桨负载突变、缠绕、高速堵转、母线低压大电流等
- ESC 固件置位
running_error对应位(映射到 MAVLink0x20000) - 荷兰样本:SN
231AAAA5C001688、长时间高速、STALL 占比 18%~32%(会话 15349/15353)
ECU 侧行为(已证实):
```425:430:JetWaveECU-master-2d55e90f4a54d61a83efab89195082109acd3472/App/src/esc_manager.c // 如果存在空转保护故障码,强制转速为0 if (LastEscSpeedData.runningError & (uint16_t)(0x0001 << 9)) { // MotorSpeed = 0; ESP_LOGD(LOG_TAG, "Idle protection in progress, speed forced to 0"); } SendSetSpeedRequest(MotorSpeed);
- 仅检查 **空转保护 bit9**,且 `MotorSpeed = 0` **被注释掉**
- **对 STALL(bit1 → esc 0x20000)无任何处理**
- 每 20ms 仍 `SendSetSpeedRequest(MotorSpeed)`,与用户油门一致
**为何「遥控器无法控制」:**
| 层级 | 行为 |
|------|------|
| RC App | 油门指令正常发出(蓝牙仍连接) |
| ECU | 正常转发转速请求 |
| ESC | 保护态拒绝输出 → `motorSpeed≈0` |
| 用户 | 推油门无效,**控制环路在 ESC 处被硬切断** |
**恢复缺失:**
- 源码 **无**「失速清除」MAVLink 命令处理
- **无**「松油门 N 秒自动清零」策略
- **无** `SendEscRebootRequest()` 与 STALL 联动
- App 侧(CODE_REVIEW)仅弹窗 + 埋点,**不切断 UI 油门显示、不强制安全模式**
---
### Scenario B:假断联(`FAULT_ESC_COMMUNICATION`)— **与失速强共现**
**置位逻辑:**
```534:556:JetWaveECU-master-2d55e90f4a54d61a83efab89195082109acd3472/App/src/ecu_manager.c
static uint32_t ESC_CommunicationFailure = 0;
if (ReceiveEscRunningDataFromQueue(&EscRunningData, 0) == pdPASS) {
...
ESC_CommunicationFailure = 0;
ecuEventCode &= ~FAULT_ESC_COMMUNICATION;
} else if (GetRcConnectionStatus()) {
ESC_CommunicationFailure ++;
if (ESC_CommunicationFailure >= 240) { // 12S
ecuEventCode |= FAULT_ESC_COMMUNICATION;
}
} else if (!GetRcConnectionStatus()) {
ESC_CommunicationFailure = 0;
ecuEventCode &= ~FAULT_ESC_COMMUNICATION;
}
条件解读:
ProcessEcuDataTask周期 50ms →240 × 50ms = 12s- 条件:RC 蓝牙仍连接 + 12s 内一次都没从
EscRunningData队列收到数据 - 不是 RC 断链检测;RC 断链反而 清除 该故障位
为何会误报/叠加:
| 因素 | 机制 |
|---|---|
| UAVCAN 接收降频 | HandleEscSetSpeedResponse 每 10 帧 才入队一次 |
ProcessEscDataTask 100ms |
消费队列慢于 20ms 控制 |
| STALL 后 ESC 可能降频/停发 Response | 队列长期空 → 12s 后置通信故障 |
SendEscRunningDataToQueue(..., 0) 非阻塞 |
队列满则丢运行数据,通信计数仍走 else 分支 |
| TWAI Bus-Off 恢复窗口 | twai_ops_esp32.c 恢复期间无有效 RX |
用户感知: App 提示「ESC 通信异常」+ 失速弹窗 → 「主控断联」;实际上 RC↔ECU 可能正常,是 ECU↔ESC 监控路径 超时。
与「无法控制」关系: 该故障位 不改变 MotorSpeedControlTask 行为(未检索 ecuEventCode),控制仍取决于 Scenario A/C。
Scenario C:BLE/星闪断链 — 安全漏洞级
断链注入(ble_server.c):
```302:306:JetWaveECU-master-2d55e90f4a54d61a83efab89195082109acd3472/Ble/src/ble_server.c rcThrottleAndGear.mode = 0xFF; ... SendRcThrottleAndGearCmd(MAVLINK_MSG_ID_ThrottleAndGear, &rcThrottleAndGear, pdMS_TO_TICKS(10));
**`MotorSpeedControlTask` 处理:**
```439:443:JetWaveECU-master-2d55e90f4a54d61a83efab89195082109acd3472/App/src/esc_manager.c
case 255: // 蓝牙断链
ESP_LOGD(LOG_TAG, "NOBLUETOOTH");
ThrottleAndGear.throttle = 0;
MotorSpeed = 0;
break; // ← 无 SendSetSpeedRequest(0)
对比 case 254(连接但 1s 无油门)会 SendSetSpeedRequest(0)。
失败模式:
- 断链前最后一帧为非零转速 → 断链后 ECU 不再向 CAN 发送任何 SetSpeed
- ESC 若依赖 持续指令 或 超时后才归零,存在 断链后短时不明输出 风险
- 这是典型的 fail-unsafe(未主动拉闸),违反安全系统设计「失联即安全」原则
注意: 断链时 GetRcConnectionStatus()==false,FAULT_ESC_COMMUNICATION 被清零,用户 看不到 ECU 通信故障提示,更易误解为「遥控器坏了」而非「板子还在按最后一档跑」。
Scenario D:油门丢失 1s — 部分安全、但仍可改进
```336:342:JetWaveECU-master-2d55e90f4a54d61a83efab89195082109acd3472/App/src/esc_manager.c } else { if (ThrottleLostCnt++ >= 50) { // 1s @20ms if (ThrottleAndGear.mode != 255) { ThrottleAndGear.mode = 254; // 蓝牙连接但不发油门 } } }
`mode 254` → `SendSetSpeedRequest(0)`。**这是 ECU 侧少数主动拉闸路径之一。**
**局限:** 若 RC **仍以 20ms 发油门**(含 STALL 后用户持续推杆),永不进入 254,Scenario A 持续。
---
### Scenario E:ECU 二次合成 `running_error` — **语义污染**
```231:237:JetWaveECU-master-2d55e90f4a54d61a83efab89195082109acd3472/App/src/esc_manager.c
if (escSpeedInfo->speed <= -20000) {
runningErrorState |= (uint16_t)(0x0001 << 1); // 置位堵转故障码
}
escSpeedInfo->runningError = runningErrorState;
- ECU 用 本地静态
runningErrorState覆盖 ESC 上报的running_error(先UpdateEscSpeedInfo拷贝,再UpdateESCErrorCodeByRunningStatus整体赋值) speed <= -20000(0.1rpm 单位 → -2000rpm)可能来自 符号/溢出/未初始化- 置位的 bit1 与 MAVLink STALL
0x20000同位 → 可能 无 ESC 真失速也报 STALL
单片机工程师关注点: runningErrorState 无 ESC 上报清除同步策略,过温/过流有滞回清除,堵转 bit1 无清除逻辑 → 一旦置位可能 锁死上报 直至重启。
Scenario F:OTA / 升级挂起控制任务
```524:529:JetWaveECU-master-2d55e90f4a54d61a83efab89195082109acd3472/App/src/esc_manager.c case MAVLINK_MSG_ID_StartUpgradeNotification: StartEscFirmwareUpgrade(); MotorSpeedControlTaskSuspend(); case MAVLINK_MSG_ID_ExitUpgrade: MotorSpeedControlTaskResume();
升级 ESC 期间 **不再发转速**。若升级异常未收到 `ExitUpgrade`,表现为 **长期无法控制**(与失速不同,需查 OTA 状态机)。
---
### Scenario G:监控面滞后 — **加剧「不可控」焦虑**
`EventCodeProcessByBit`:每个故障 bit 上报间隔 `FAULT_DURATION_CYCLES = 10000/50 = 200` tick × 50ms = **10s**(注释写 12s 含状态机切换)。
- 复合故障(STALL + COMM + OV)逐个 bit 扫描上报
- 用户可能在 **保护已触发数秒後** 才看到弹窗
- **心跳 500ms** 才更新 `motor_speed` 显示 → UI 与 20ms 控制严重不同步
---
## 五、通信子系统专项(底层驱动 / C 工程师视角)
### 5.1 TWAI / UAVCAN
| 项目 | 实现 | 风险 |
|------|------|------|
| TX | `canardRequestWithMutex`,rpm=0 时 **最高优先级** | 正常 |
| RX 降频 | 每 **10** 次 `SetSpeedResponse` 入队 1 次 | 通信故障检测 **欠采样** |
| Bus-Off | `twai_initiate_recovery()` | 恢复期间 ESC 数据空洞 → 触发 Scenario B |
| 队列深度 | `EscSpeedResponseDataQueue` 深度 **3** | 突发时 `calloc` + `xQueueSend` 失败丢帧 |
### 5.2 MAVLink / BLE
- `SendMavlinkToBleRC`:回调未注册则 **静默失败**(`ESP_FAIL`)
- RC 连接状态:`GetRcConnectionStatus()` → BLE/NearLink 回调,**与油门是否到达无关**
- 连接时注入 `mode=0xFE`(有连接、油门 0),**会** `SendSetSpeedRequest(0)`(走 254 分支需先收到 ThrottleAndGear;0xFE 不在 switch 的 BEGINNER/INTERMEDIATE/ADVANCED,走 **default** → **也不发转速**)
**补充:** `mode=0xFE` 落在 `default`,既不加速也不显式清零 → 依赖后续 RC 发正常 mode。
### 5.3 故障掩码
```41:42:JetWaveECU-master-2d55e90f4a54d61a83efab89195082109acd3472/App/src/ecu_manager.c
#define ESC_FAULT_MASK (... & ~ESC_FAULT_PWM_SIGNAL_LOST & ~ESC_FAULT_THROTTLE_SATURATION ...)
- STALL 不在掩码内 → 必上报 RC
- 掩码掉 PWM 丢失 / 油门饱和 → 现场若伴随此类故障,App 看不到,但 ESC 侧可能仍影响输出
六、控制律与逻辑(C++/控制工程师视角)
6.1 油门 → 转速映射
- 三模式 × 16 档表
maxSpeedForModes[3][16],含 14000rpm 上限档 CurrentMaxSpeed斜坡:加速 ≤20rpm/20ms,减速 ≤40rpm/20ms → 全油门到满速约 14s 级(视档位)- 倒挡
gear==15:负转速,无 STALL 特殊处理
6.2 ALC 俯仰自稳(gear14 初学)
- PID 修正叠加
MotorSpeed,限幅 ±3000(0.1rpm 单位下极大) - 失速/通信异常时 不冻结 ALC → 可能在保护态仍叠加修正,加剧 ESC 负担(待台架验证)
6.3 空转保护(半成品)
- 检测:
speed > 阈值 && bus_current < 动态阈值 && GPS vel<=2 - 置位 bit9 代码 注释掉,清除逻辑仍在
- 与 STALL 无关
七、安全风险矩阵(FMEA 简表)
| ID | 场景 | 起因 | 现有防护 | 缺口 | ASIL 类比 |
|---|---|---|---|---|---|
| R1 | STALL 后推油门无效 | ESC 保护 | 无 ECU 限扭 | 无恢复策略 | 高 |
| R2 | 断链未零速 | mode 255 | 无 | 未 SendSetSpeed(0) | 高 |
| R3 | 假 ECU 通信故障 | 队列/降频 | 无 | 误导用户/售后 | 中 |
| R4 | running_error 合成污染 | ECU 软件 | 无 | 误报 STALL | 中 |
| R5 | 升级挂起 | OTA | Suspend 任务 | 无看门狗恢复 | 中 |
| R6 | Bus-Off | EMC/线缆 | TWAI 恢复 | 恢复窗口无安全态 | 中 |
| R7 | 心跳 500ms 误导 | UI | 无 | 用户以为「还有响应」 | 低 |
八、与现场数据闭环
| 现场现象 | 本报告场景 | 证据会话 |
|---|---|---|
throttle>0 motorSpeed=0 + esc=131072 |
Scenario A | 荷兰 15349/15353;history2 多条 |
| ecu=1073741824 与 stall 同会话 | Scenario A+B | CODE_REVIEW:STALL+ECU 很少伴 OV |
| 阿姆斯特丹无 STALL | — | 非区域逻辑,支持「负载/设备」主导 |
| roll≈180° | 无关动力失控主因 | 姿态展示问题,见计划阶段 4 |
判定树(售后/研发用):
推油门无动力?
├─ escEvent & 0x20000 → Scenario A(查 ESC 固件+负载+ECU是否仍发转速)
├─ ecuEvent & 0x40000000 且无 STALL → Scenario B(查 CAN 线/降频/队列)
├─ RC 显示未连接 / mode255 → Scenario C(查断链零速补丁)
├─ 升级中 → Scenario D
└─ 以上皆否 → 查 BMS 限功率、授权过期、档位 mode 异常
九、修改建议与方案优化(按优先级)
9.1 P0 — 安全关键(建议下一版 ECU 必做)
M1:STALL 统一安全态(esc_manager.c)
// 建议在 SendSetSpeedRequest 之前:
#define ESC_RUN_ERR_STALL_BIT ((uint16_t)(1u << 1))
#define ESC_EVT_STALL (0x00020000u)
bool escStallActive = (LastEscSpeedData.runningError & ESC_RUN_ERR_STALL_BIT) != 0
|| ((LastEscSpeedData.runningError << 16 | LastEscSpeedData.selfcheckError) & ESC_EVT_STALL) != 0;
if (escStallActive) {
MotorSpeed = 0;
SendSetSpeedRequest(0);
// 可选:要求 ThrottleAndGear.throttle < 死区 持续 2s 才允许退出 STALL 态
continue; // 或 break 跳过 ALC 叠加
}
原则: 故障态扭矩权威在 ECU,不能假设 ESC 自行拒绝后 ECU 仍持续请求。
M2:mode 255/断链必须零速
case 255:
ThrottleAndGear.throttle = 0;
MotorSpeed = 0;
SendSetSpeedRequest(0); // 必须
break;
原则: 失联即安全(fail-safe)。
M3:FAULT_ESC_COMMUNICATION 判定加固(ecu_manager.c)
- 条件改为:AND 最近
SendSetSpeedRequest成功/有 TX 回包 AND 队列超时 - 或:取消 RX 10:1 降频,至少 running_error≠0 或 speed 变化 时全帧入队
- 通信故障置位时 强制
SendSetSpeedRequest(0)与 Scenario A 策略一致
M4:修复 running_error 合成(UpdateESCErrorCodeByRunningStatus)
- OR 合并 ESC 原生
running_error,勿整体覆盖 - bit1(STALL)仅信任 ESC 上报 或增加 滞回清除;删除
speed<=-20000除非经 ESC 手册确认
M5:启用空转保护清零(已写未生效)
取消注释 MotorSpeed = 0 或统一到 M1 框架。
9.2 P1 — 系统架构(1~2 个迭代)
| 编号 | 方案 | 说明 |
|---|---|---|
| A1 | SafetySupervisor 任务 | 订阅 ESC 故障 + ECU 通信 + RC 连接,输出 torque_enable 布尔,唯一写 CAN 转速 |
| A2 | 显式恢复状态机 | NORMAL → LIMP → FAULT_LATCHED → RECOVERY_PENDING → NORMAL |
| A3 | MAVLink ClearEscFault / EscRecoveryRequest |
App 引导用户松油门后点「恢复」,ECU 发 ESC 私有清除或 RestartNode |
| A4 | Ulog 强制字段 | 打开 UlogWriteRcMessage(当前注释),对齐 OSS 分析 |
| A5 | 故障上报改为事件驱动 | 故障边沿立即 SendEventToBleRc,去掉 12s/bit 扫描(保留去抖即可) |
9.3 P2 — App / 云端 / 测试
| 项 | 说明 |
|---|---|
| App | escEvent/ecuEvent 改 位运算;STALL 时 UI 灰显油门 或提示「请松开油门 3 秒」 |
| 云端 | 规则:throttle>0 && motorSpeed==0 && stall 连续 N 秒 → P0 工单 |
| 台架 | 堵转、CAN 拔线、BLE 断链、STALL 后持续推油门 四用例 |
| 回归 SN | 231AAAA5C001688、5G002872、6A000193 |
9.4 建议目标架构(架构师)
┌─────────────────────┐
│ SafetySupervisor │
│ torque_enable │
│ fault_latched │
└──────────┬──────────┘
┌───────────────────┼───────────────────┐
▼ ▼ ▼
MotorSpeedControl EscCommWatchdog RcLinkWatchdog
(desired_rpm) (RX timeout) (mode 254/255)
│ │ │
└───────────────────┴───────────────────┘
▼
SendSetSpeedRequest(actual_rpm)
▼
ESC Hardware
设计准则:
- 单点写 CAN 转速
- 任何故障进入 LIMP 默认零扭
- 恢复需显式条件(时间 + 油门 + ESC 应答)
- 监控面不得是唯一安全机制
十、验证计划(对应分析计划阶段 2、6)
| 用例 ID | 操作 | 期望(修补后) | 关联代码 |
|---|---|---|---|
| T1 | 台架堵转到 STALL | 零速指令、esc=0x20000、油门无效直至恢复流程 | M1 |
| T2 | STALL 后持续推油门 30s | ECU 不发非零 SetSpeed;日志无「油门>0 转速>0」 | M1 |
| T3 | 运行中拔 BLE | 200ms 内 CAN 零速 | M2 |
| T4 | 运行中拔 CAN 12s | 可报 COMM,且零速 | M3 |
| T5 | 注入 speed=-30000 | 不应误报 STALL(修补后) | M4 |
| T6 | 复现 15349 OSS 时间轴 | Ulog RC/ESC 与轨迹对齐 | A4 |
十一、结论(给决策层的一句话)
「主控失速 + 断联 + 遥控器无法控制」并非单一 bug,而是:ESC 真失速保护(主因)+ ECU 未在故障态切断/限制扭矩(安全设计缺口)+ ECU 用 ESC 数据超时冒充「主控断联」(语义误导)+ 断链未发零速(潜在 fail-unsafe)共同构成的系统性问题。
遥控器多数情况下 仍在正常发油门;用户「无法控制」是因为 扭矩输出层(ESC+ECU策略)未恢复且 ECU 未执行 fail-safe,而不是 RC 完全失联。
研发优先级: 先落地 M1+M2+M3(可在 ECU 单仓验证),并行抓 ESC 固件 STALL 恢复条件;App 与云端做体验与数据闭环。
附录 A:关键源码索引
| 主题 | 文件 | 行号(约) |
|---|---|---|
| 油门控制任务 | App/src/esc_manager.c |
298~457 |
| STALL 未处理 | 同上 | 425~430 |
| mode 255 无零速 | 同上 | 439~443 |
| ESC 通信故障 | App/src/ecu_manager.c |
534~556 |
| esc_event 打包 | 同上 | 107~108 |
| 故障掩码 | 同上 | 41~42 |
| 事件上报状态机 | 同上 | 178~337 |
| UAVCAN 降频 | Protocol/src/uavcan_twai.c |
58~62 |
| BLE 断链 mode | Ble/src/ble_server.c |
292~306 |
| STALL 协议定义 | Lib/JetWaveMavlink/xml/JetWave.xml |
296~298 |
| SetSpeed 响应字段 | Lib/JetWaveDsdl/esc/212.SetSpeed.uavcan |
15~16 |
附录 B:相关报告
| 文档 | 用途 |
|---|---|
JETWAVE_ECU_POWERTRAIN_ANALYSIS_PLAN.md |
分阶段执行计划 |
NETHERLANDS_ABNORMAL_REPORT_20260526_190035.md |
荷兰 STALL 样本 |
CODE_REVIEW_交互架构与问题导读.md |
App 侧故障语义 |
HISTORY2_DAILY_REPORT_20260526_092858.md |
昨日全量统计 |
本报告为静态代码审计 + 现场日志交叉结论;ESC 固件内部 STALL 置位/清除阈值需结合电调厂家文档与 CAN 抓包最终确认。