4、故障检测与上报机制:故障检测的触发条件、故障码的定义与管理、故障上报的通信协议

各位同学,咱们接着聊。上一节我们把看门狗的基本原理和复位策略讲清楚了。但有个问题一直绕不开——你光知道狗咬了,可你知道它为什么咬吗?

说白了,看门狗只是最后一道防线。真正要解决问题,你得在故障发生的第一时间就把它揪出来,然后准确上报。这就是我们今天要聊的:故障检测与上报机制。

4.1 故障检测的触发条件

故障检测不是玄学,它得有明确的触发条件。我个人的习惯是把触发条件分成三类:

  • 时间类触发:比如任务超时、信号周期超限。我记得在做一个AEB项目时,雷达数据每20ms必须来一次,超过25ms没来,我就判定通信链路挂了。
  • 数值类触发:比如传感器值超出合理范围、两个冗余信号偏差过大。举个例子,车速信号来自轮速和IMU,如果两者差值超过5km/h持续200ms,那肯定有一个在撒谎。
  • 逻辑类触发:比如状态机跳到了非法状态、两个互斥的条件同时成立。嗯,这里要注意,逻辑类故障最难排查,我曾在LKA项目中遇到过转向请求和转向禁止同时为True的bug,查了三天才发现是信号取反搞错了。

核心原则:触发条件要满足「可观测、可重复、可判定」。你设计了一个检测条件,结果实车跑一万公里才触发一次,那这个条件基本等于没用。

为什么会这样?因为ADAS系统对实时性要求极高。你想想看,如果故障检测延迟了100ms,在高速场景下可能就是几米甚至十几米的制动距离差异。所以触发条件的响应时间,我个人建议控制在单个控制周期内(通常是10ms~50ms)。

4.2 故障码的定义与管理

故障码,说白了就是给每个故障贴个标签。但怎么贴、贴什么内容,这里面门道很深。

我在项目中遇到过最头疼的事:不同模块的工程师各自定义故障码,结果集成测试时发现同一个故障现象,A模块报0x1234,B模块报0x5678,C模块干脆没报。你说这怎么排查?

所以,故障码的定义必须遵循统一规范。我建议采用以下结构:

字段 位数 说明
系统标识 4 bit 区分感知、决策、执行等子系统
模块标识 6 bit 具体到某个ECU或软件组件
故障类型 4 bit 硬件故障、软件故障、通信故障、数据异常等
故障等级 2 bit 0-安全、1-警告、2-降级、3-紧急
具体故障码 16 bit 唯一标识具体故障现象

这样组合下来,一个故障码是32位,足够用了。而且通过系统标识和模块标识,你能快速定位到问题出在哪个环节。

我的经验:故障码管理一定要有「生命周期」概念。故障从产生到消失,中间可能经历「检测到→确认→上报→恢复→清除」这几个状态。我曾经见过一个项目,故障码只记录了当前状态,结果复现问题时根本不知道故障是何时消失的。后来我们加了一个历史故障码队列,保留最近100条故障记录,排查效率提升了一大截。

另外,故障等级的定义要谨慎。我曾经犯过一个错误:把所有传感器故障都定义为紧急等级。结果有一次雷达被泥巴糊住了,系统直接紧急制动,后车差点追尾。后来我学乖了——单传感器故障先降级,双传感器同时故障才触发紧急动作。你想想看,这才是合理的。

4.3 故障上报的通信协议

故障检测出来了,码也定义好了,接下来怎么上报?这里我重点讲两种主流方式:

4.3.1 基于CAN的故障上报

在传统ADAS架构中,CAN总线是主力。故障上报通常采用以下机制:

  • 周期性上报:每个故障码以固定周期(比如100ms)发送一次。好处是简单可靠,坏处是总线负载高。
  • 事件触发上报:故障发生时立即发送,之后不再重复。好处是节省带宽,坏处是如果丢帧了,上层就永远不知道这个故障。
  • 混合模式:我个人最推荐的方式。故障发生时立即发送一次,然后以较慢周期(比如1s)重复发送3~5次,之后转为低频率心跳。这样既保证了实时性,又兼顾了可靠性。
// 故障上报CAN报文示例(DBC格式)
BO_ 500 DIAG_FAULT_REPORT: 8 ECU
 SG_ FaultID : 0|32@1+ (1,0) [0|4294967295] "---" ECU
 SG_ FaultStatus : 32|4@1+ (1,0) [0|15] "---" ECU
 SG_ FaultCounter : 36|4@1+ (1,0) [0|15] "---" ECU
 SG_ Reserved : 40|24@1+ (1,0) [0|16777215] "---" ECU

4.3.2 基于SOME/IP的故障上报

到了更先进的域控架构,SOME/IP成了主流。它的优势在于:

  • 服务化接口:故障上报变成一个服务,其他模块可以订阅。
  • 事件组机制:不同等级的故障可以分到不同的事件组,紧急故障优先上报。
  • 序列化支持:可以携带更丰富的信息,比如故障发生时的环境数据、传感器原始值等。

避坑指南:我曾经在SOME/IP故障上报中踩过一个坑——序列化时忘了处理字节序。结果故障码在x86开发板上正常,部署到ARM目标板上就全乱了。嗯,从那以后我养成了一个习惯:所有跨平台通信的数据结构,一律显式指定字节序,绝不依赖编译器默认行为。

4.4 故障上报的可靠性保障

故障上报本身也可能出故障。你想想看,如果通信链路断了,故障报不上去,那检测机制再完善也没用。

我建议采用以下保障措施:

  1. 冗余上报路径:主路径走CAN,备用路径走以太网。如果主路径连续3次发送失败,自动切换。
  2. 本地日志缓存:所有故障码同时写入本地非易失存储。即使上报失败,后续诊断时也能读取。
  3. 健康检查机制:故障上报模块自身也要被监控。我习惯在故障上报模块里加一个心跳信号,如果看门狗发现心跳停了,说明故障上报模块本身已经挂了,这时候直接触发系统级安全状态。

总结一下:故障检测与上报,说白了就是给ADAS系统装上一双「眼睛」和一张「嘴」。眼睛要看得准(触发条件合理),嘴要说得清(故障码规范),还要说得出去(通信协议可靠)。这三者缺一不可。

下一节我们会聊到故障恢复机制,到时候我会详细讲怎么让系统从故障中优雅地恢复,而不是简单粗暴地复位。嗯,那才是真正考验功力的地方。