4. ADAS决策层数据:规划、控制、执行器状态记录

各位工程师朋友,今天我们聊聊ADAS决策层的数据记录。说实话,这个层面是EDR数据中最容易被忽视,但又是最关键的环节。为什么?因为传感器看得再准,感知层算得再快,最终车辆怎么动,全看决策层怎么发号施令。

我个人习惯把决策层数据分成三块:规划数据控制数据执行器状态数据。这三块数据串起来,才能完整还原事故前车辆到底想干什么、实际干了什么。

4.1 规划数据:车辆想怎么走

规划层,说白了就是车辆的「大脑」。它根据感知结果,决定接下来几秒钟的行驶轨迹。EDR需要记录哪些规划数据?我列一下关键项:

  • 目标路径点序列:未来3-5秒的期望轨迹,通常每100ms一个点
  • 期望车速曲线:每个时间点对应的目标车速
  • 期望加速度:纵向和横向的期望加速度值
  • 变道意图标志:是否正在执行变道、汇入、避让等操作
  • 规划时间戳:每个规划周期的绝对时间

我在项目中遇到过一个问题:某次事故分析时,发现规划层明明输出了「紧急制动」指令,但车辆没有减速。后来查EDR数据才发现,规划时间戳和实际执行时间戳差了200ms。嗯,这就是典型的规划延迟问题。

关键点:规划数据必须包含时间戳,而且时间戳精度要到毫秒级。否则你根本分不清是规划没输出,还是执行没跟上。

4.2 控制数据:车辆实际怎么动

控制层是规划的「执行者」。它把规划轨迹转换成具体的油门、刹车、转向指令。EDR需要记录的控制数据包括:

数据项 说明 记录频率
方向盘转角指令 控制层发出的目标转角 50Hz
制动压力指令 目标制动主缸压力 50Hz
驱动扭矩指令 目标电机/发动机扭矩 50Hz
控制模式状态 如:ACC、LKA、AEB等模式 10Hz
控制输出限幅值 当前允许的最大/最小输出 10Hz

你想想看,如果只记录规划数据,不记录控制数据,你根本不知道车辆实际执行了没有。我曾经处理过一个案例:EDR显示规划层发出了「向左避让」指令,但控制层因为某个安全限幅条件,实际只输出了很小的转角。结果车辆没躲开障碍物。这就是控制限幅导致的问题。

避坑指南:我曾经在调试时发现控制输出限幅值被意外设成了0。原因是某个标定参数在OTA升级后被覆盖了。所以EDR一定要记录限幅值,这是排查「指令发了但没执行」的关键线索。

4.3 执行器状态:车辆实际做了什么

执行器状态,是决策层数据的最后一环。它告诉你车辆实际响应了多少。说白了,控制层发了100%的制动指令,但执行器可能只响应了80%。为什么?因为制动系统有延迟、有磨损、有温度影响。

需要记录的执行器状态数据:

  • 实际方向盘转角:传感器测量的真实转角
  • 实际制动压力:轮缸压力传感器实测值
  • 实际驱动扭矩:电机/发动机实际输出扭矩
  • 执行器响应时间:从指令发出到执行器开始动作的时间差
  • 执行器故障状态:如制动系统故障、转向系统故障等

注意:执行器状态数据必须和指令数据对齐。我见过最坑的情况是:EDR里指令数据是50Hz,执行器状态数据是10Hz。分析时根本对不上时间轴。所以记录频率一定要一致,或者至少能通过时间戳精确对齐。

4.4 决策层数据的时间对齐

这是整个决策层数据记录的核心难点。规划、控制、执行器三个层面的数据,各自有不同的时间基准和采样频率。怎么对齐?

我建议的做法是:

  1. 统一时间源:所有数据使用同一个GPS时间或网络时间
  2. 记录发送-接收时间戳:每个指令记录「发送时间」和「接收时间」
  3. 插值对齐:对于不同频率的数据,使用线性插值对齐到统一时间轴

下面是一个简单的数据对齐伪代码:

// 决策层数据对齐示例
struct DecisionData {
    uint64_t timestamp;      // 统一时间戳
    float target_steering;   // 规划目标转角
    float cmd_steering;      // 控制指令转角
    float actual_steering;   // 实际转角
    float target_brake;      // 规划目标制动
    float cmd_brake;         // 控制指令制动
    float actual_brake;      // 实际制动压力
    uint8_t control_mode;    // 控制模式
    uint8_t actuator_status; // 执行器状态
};

// 对齐函数:将不同频率数据插值到统一时间轴
void align_decision_data(
    const vector<PlanningData>& plan,
    const vector<ControlData>& ctrl,
    const vector<ActuatorData>& act,
    uint64_t align_interval_ms,
    vector<DecisionData>& output
) {
    // 以10ms为间隔对齐
    for (uint64_t t = start_time; t < end_time; t += align_interval_ms) {
        DecisionData d;
        d.timestamp = t;
        // 线性插值规划数据
        d.target_steering = interpolate(plan, t);
        d.target_brake = interpolate(plan, t);
        // 查找最近的控制指令
        d.cmd_steering = find_nearest(ctrl, t);
        d.cmd_brake = find_nearest(ctrl, t);
        // 查找最近的执行器状态
        d.actual_steering = find_nearest(act, t);
        d.actual_brake = find_nearest(act, t);
        output.push_back(d);
    }
}

个人经验:我建议对齐间隔不要超过20ms。因为ADAS控制周期通常是10-20ms,间隔太大你会丢失关键信息。另外,插值算法建议用线性插值就够了,高阶插值反而可能引入虚假数据。

4.5 决策层数据的典型故障模式

根据我多年的EDR数据分析经验,决策层数据最常见的故障模式有这几种:

  • 规划-控制不匹配:规划输出紧急制动,但控制模式还在ACC巡航状态
  • 控制-执行器延迟:控制指令发出后,执行器响应时间超过100ms
  • 执行器饱和:控制指令要求100%制动,但执行器只能输出80%
  • 模式切换冲突:AEB和ACC同时请求控制权,导致控制混乱

我记得有个案例特别典型:一辆车在高速上突然加速,司机说是「刹车失灵」。我们调出EDR数据一看,规划层输出的是「减速」,控制层也发了「制动指令」,但执行器状态显示「制动压力为0」。再往下查,发现制动系统的CAN总线在事故前3秒出现了通信故障。这就是执行器状态数据立功了。

总结一下:决策层数据是EDR分析中最能还原「车辆意图」的部分。规划数据告诉你车辆想干什么,控制数据告诉你车辆指令了什么,执行器状态告诉你车辆实际干了什么。三个层面缺一不可,而且必须精确对齐时间轴。

ADAS决策层数据记录框架 规划数据(车辆想怎么走) • 目标路径点序列(未来3-5秒轨迹) • 期望车速曲线 / 期望加速度 • 变道意图标志 / 规划时间戳 控制数据(车辆指令了什么) • 方向盘转角指令 / 制动压力指令 / 驱动扭矩指令 • 控制模式状态(ACC/LKA/AEB) • 控制输出限幅值(安全边界) 执行器状态(车辆实际干了什么) • 实际方向盘转角 / 实际制动压力 / 实际驱动扭矩 • 执行器响应时间(指令到动作的延迟) • 执行器故障状态(制动/转向系统故障) 记录频率:10-50Hz 记录频率:50Hz 记录频率:50Hz 核心原则:统一时间源 + 精确对齐 + 毫秒级精度

好了,关于决策层数据记录,核心就是这三层结构。记住:规划是意图,控制是指令,执行器是结果。三个数据串起来,才能完整还原事故前车辆的决策和执行过程。


专注资料整理