结论:CarEvents 是「车况 → 使能/退出事件」的适配层:它只把 CarState、上一帧状态与最近一次控制请求翻译成事件名,本身不发 CAN,也不替代 panda 固件安全钩子。它的判定分两级——先跑一组通用条件,再进入 5 个显式品牌分支;并且只在 CS.canValid 为真时被调用,CAN 无效时走的是另一条独立故障路径。以下为固定源码快照 c8fb906 的静态追踪。
CarEvents 在链路里的位置
card.state_update() 经车型 CarInterface.update() 形成 carState;selfdrived.update_events() 只在 CS.canValid 时调用 self.car_events.update(CS, CS_prev, sm['carControl']) 并合并返回的事件。若 CAN 无效,selfdrived 走 canError/canBusMissing 等独立故障路径,因此不能把「CarEvents 忽略无效报文」误解为此时仍可使能。
CarEvents 的输入有三层时间语义:当前 CS 是车辆观察,上一帧 CS_prev 用于巡航与转向故障等边沿判断,CC 是最近被消费的控制请求,并不代表车端执行器已按该请求动作。update() 对 body/mock 直接返回空容器,其余品牌先过通用条件,再进入本文件显式实现的品牌分支;未被显式实现的品牌并非不支持,而是使用通用条件与车型自身的 CarState/CarParams/接口规则。
通用条件 create_common_events() 覆盖什么
create_common_events() 创建一个新的 Events 容器,从车型接口的 DRIVABLE_GEARS、CP.pcmCruise 与品牌判断中决定可行驶挡位与 PCM 使能方式。它覆盖四类信息:乘员与挡位、原车辅助与模式、速度/制动/准备状态、以及用户覆盖与请求。倒挡是一个典型边界——当倒挡不属于车型 DRIVABLE_GEARS 时,源码会同时产生 wrongGear 与 reverseGear 两个事件。
速度与准备类条件里,vEgo > MAX_CTRL_SPEED 产生超速事件,brakeHoldActive、parkingBrake、accFaulted、carNotReady 各有对应事件;其中制动保持只在 openpilot 纵向控制时才加入。传感器与转向类则把 vehicleSensorsInvalid、invalidLkasSetting、lowSpeedAlert 与 steerFaultTemporary/Permanent 写成事件。
| 条件组 | 代表字段与 EventName | 状态机含义 |
|---|---|---|
| 乘员与挡位 | doorOpen、seatbeltUnlatched、wrongGear、reverseGear |
门/带/挡位常映射 NO_ENTRY 与软退出;倒挡另有用户退出。 |
| 原车辅助/模式 | cruiseState.available、nonAdaptive、espDisabled/espActive、stockFcw/stockAeb/stockLkas |
原车巡航/稳定控制状态与原车碰撞/车道功能被映射为提示或禁止使能。 |
| 速度/制动/准备 | vEgo > MAX_CTRL_SPEED、brakeHoldActive、parkingBrake、accFaulted、carNotReady |
分别产生超速、制动保持、驻车制动、ACC 故障与未就绪事件。 |
| 用户覆盖/请求 | steeringPressed、steeringDisengage 上升沿、gasPressed、buttonEnable、cancel 按钮 |
转向/油门覆盖、用户退出与启用请求分别走不同类型。 |
| 传感器/转向 | vehicleSensorsInvalid、invalidLkasSetting、lowSpeedAlert、steerFaultTemporary/Permanent |
加入传感器与转向故障事件,暂时故障另有提示强度选择。 |
PCM 启用门与边沿语义
通用 PCM 启用门的条件是 CP.pcmCruise and brand != 'honda'。原车巡航 enabled 出现上升沿且 blockPcmEnable=False 时产生 pcmEnable,未启用时产生 pcmDisable;非 PCM 车型通常由 CarState.buttonEnable 产生 buttonEnable。这些事件分别被映射到 ENABLE 或 USER_DISABLE,最终由下游状态机裁决。
这里有一个容易误判的细节:Hyundai 的 cancel 按钮只有在非 PCM 巡航时才会被本层转为 buttonCancel,因为源码明确避免把某些车的暂停/恢复复用键误作取消。同理,steeringDisengage 只在上升沿加入,不会在持续按下的每一帧重复产生。
临时转向故障为什么不是布尔映射
steerFaultTemporary 不是简单地把某个位映射成事件。steering_unpressed 记录未按方向盘的帧数,no_steer_warning 与 silent_steer_warning 决定究竟发静默的 steerTempUnavailableSilent 还是更强的 steerTempUnavailable。近 1.5 秒内有手动覆盖、静止或仍处静默阶段时偏向静默提醒;永久转向故障另发 steerUnavailable。
隔离探针给出一个可复现的数量关系:在本快照 DT_CTRL=0.01 下,静默判定对应 150 帧,即 int(1.5/DT_CTRL)。这些计数取决于控制循环节奏与上游 CarState 更新节奏,不能从车型 CAN 原始位直接推出屏幕告警强度,这个 150 也不是所有车型的告警延迟保证。
5 个品牌补充规则
品牌分支处理的是通用条件表达不了的低速与边沿特例。Chrysler 用 0.5 m/s 迟滞区间避免速度边界抖动;Honda 在品牌分支内单独处理 PCM 低速与巡航退出;Toyota 的低速判断只在 OP 纵向启用时评估;GM 在「静止且踩刹车并且网络位置为前视摄像头」时跳过低速使能事件;Volkswagen 则在控制请求使能后才额外加入 speedTooLow。
| 品牌 | 源码条件 | 产生的事件/目的 |
|---|---|---|
| Chrysler | vEgo < minSteerSpeed + 0.5 置提醒,vEgo > minSteerSpeed + 1.0 清除 |
belowSteerSpeed;0.5 m/s 区间避免边界抖动。 |
| Honda | PCM 巡航时低于 minEnableSpeed;巡航启用上升沿;巡航丢失且控制请求不在继续制动 |
belowEngageSpeed、pcmEnable、speedTooLow/cruiseDisabled;保留低速继续制动特例。 |
| Toyota | 仅 OP 纵向;standstill 且未踩刹车、控制请求 resume 或混动标志;低于最低使能速度 | resumeRequired、belowEngageSpeed;请求加速度大于 0.3 时 speedTooLow。 |
| GM | 低于 minEnableSpeed,但 standstill && brakePressed && networkLocation=fwdCamera 例外 |
通常 belowEngageSpeed;前述条件允许驻车踩刹车时不产生该事件。 |
| Volkswagen | 仅 OP 纵向;vEgo < minEnableSpeed + 0.5,且控制使能时 vEgo < minEnableSpeed |
belowEngageSpeed 和 speedTooLow。 |
要强调:以上只是 CarEvents 中的品牌分支,不是这些品牌完整的 CAN/DBC/安全策略。事件容器本身不负责禁用执行器,最终状态由 StateMachine.update() 决定,执行活动由 controlsd 决定,panda 固件仍负责独立发送限制。
常见问题
CarEvents 会直接下发 CAN 或让车退出吗?
不会。它只产生事件名交给下游:gasPressedOverride、steerOverride、buttonCancel、wrongGear 等分别被 events.py 映射到覆盖、用户退出或软退出,然后由状态机、controlsd 与 panda 固件分层决定最终行为。
为什么倒挡会同时出现两个事件?
因为当倒挡不属于车型的 DRIVABLE_GEARS 时,代码会同时产生 wrongGear 与 reverseGear。隔离探针确认了这个组合,具体结果还要看车型的 DRIVABLE_GEARS 定义。
PCM 车和非 PCM 车的启用事件一样吗?
不一样。通用 PCM 启用门是 CP.pcmCruise and brand != 'honda',PCM 车靠巡航 enabled 上升沿产生 pcmEnable;Honda 在品牌分支单独处理;非 PCM 车通常由 CarState.buttonEnable 产生 buttonEnable。
1.5 秒的静默提醒延时对每辆车都成立吗?
不成立。150 帧来自本快照 DT_CTRL=0.01 与 int(1.5/DT_CTRL),计数还取决于控制循环与上游 CarState 的更新节奏,不是所有车型实际告警延迟的保证。
延伸阅读
- selfdrived 告警仲裁:99 个 EventName 里只留 1 条上屏 —— 事件产生之后如何被仲裁成一条告警。
- 从使能到车轮:执行链上的八道门,以及它们各自不保证什么 —— CarEvents 之后还有哪些门。
- 车载信号为什么会说谎:TTL、源时间与 500 ms 新鲜度阈值 —— 车况字段为什么必须带新鲜度。
- 同一个「转向灯」在三家车厂是三种实现:车辆状态归一化的坑 —— 品牌差异在状态解析层的样子。
参考资料
- 项目 02 ——
openpilot-research/CAR_EVENTS_GATEWAY_DEEP_DIVE.md(CarEvents 的通用条件、PCM 门、临时转向故障与 5 个品牌分支)。 - 项目 02 ——
openpilot-research/同目录探针记录:五项通用条件与六项品牌契约隔离探针结论。
说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11
发表回复