结论:变道意图和车道偏离预警是两条不同的辅助链路。变道意图靠转向灯新沿、驾驶员同向扭矩与盲区位,在车速不低于 20 mph 时从 off 进入准备态;车道偏离预警则要求车速严格大于 31 mph、近 5 秒无转向灯且横向未激活。两者都只产生提示或候选,不直接授权转向或制动执行器。本文为固定源码快照 c8fb906 的静态分析。
消息与时序:本帧状态、下一帧脉冲
modeld.main() 在本帧推理前读取上一次 DH.desire,编码到 desire_pulse;ModelState.run() 只将 desire 从低到高的变化送入模型。推理后才从本帧 desireState 左右变道项之和计算 lane_change_prob,调用 DH.update(),并把更新后的状态/方向写入本帧 modelV2.meta。因此状态提示可在本帧出现,新意图要到下一帧才进入模型;不能把它们当同一时刻的闭环输出。
plannerd.main() 以 modelV2 轮询,只有该主题更新时计算 LDW 并发布 driverAssistance;消息顶层 valid=sm.all_checks(),所以计算出的左右布尔值与可供消费的有效性是两回事。服务表配置 driverAssistance 为 20 Hz,这不是端到端时延保证。desirePrediction 是 LDW 使用的另一组模型值,不能与 desireState 混写。
| 组件/入口 | 主要逻辑 | 下游或边界 |
|---|---|---|
DesireHelper.get_lane_change_direction() |
从左转向灯决定左,否则决定右;调用者先要求仅单侧灯亮。 | 准备态方向可随灯变化。 |
DesireHelper.update() |
转向灯新沿、速度、横向活动、驾驶员同向扭矩、盲区和模型完成概率推进状态。 | 只设置意图/状态,不直接写转向执行器。 |
ModelState.run() |
在推理输入中把非零 desire 的上升沿转为脉冲。 | 持续保持同一意图不会每帧重发脉冲。 |
LaneDepartureWarning.update() |
根据车速、灯冷却、横向活动、线可见度/距离及预测概率设置左右偏离。 | 仅产生布尔结果,不制动或转向。 |
Controls.state_control() |
laneChangeState!=off 时设置 carControl 转向灯请求,按有效位设置 HUD 偏离方向。 |
车型是否实现灯控需逐车型检查。 |
变道意图的状态门
DesireHelper.update() 只有横向激活、单侧转向灯出现新沿、速度不低于 20 mph,才从 off 进入 preLaneChange。准备态要求 steeringPressed 且扭矩方向与转向灯一致,并且该侧无盲区报警,才进入 laneChangeStarting。熄灯或降到门槛以下会关闭准备态;已启动后源码不再以盲区位直接撤销,而是依赖模型概率和超时等分支,因此不能把盲区位当成持续的安全许可。
完成门要求启动至少 0.5 s 且左右变道 desireState 概率和严格小于 0.02,之后若灯仍亮回准备态,否则关闭。横向失活或累计计时超过 10 s 关闭。laneChangeFinishing 虽在 log.capnp 中定义、selfdrived 也接受,本版本 helper 没有赋值该状态。五项原 DesireHelper 类假消息枚举探针确认:20 mph 恰好允许新沿进入准备态;横向失活会把上一灯沿记忆清零,再激活时即使灯一直亮也可视为新沿;同向扭矩在盲区亮时不能启动,但进入 laneChangeStarting 后熄灯/盲区亮且模型完成概率仍高时,意图继续输出。十秒上限在每次调用开头检查,首次越过十秒的该帧仍处于启动态,下一次调用才复位。
车道偏离预警的判定条件
LaneDepartureWarning.update() 要求车速严格大于 31 mph、按模型帧估算的近 5 s 内没有转向灯、carControl.latActive=False,且 desirePrediction 非空。左/右车道线各自概率大于 0.5;以相机横向偏移 0.04 m 修正后的近线条件分别是左侧 y[0]>-1.12 m、右侧 y[0]<1.04 m;对应方向的模型变道预测概率还须大于 0.1。last_blinker_frame 初值为零,冷却按 SubMaster.frame * DT_MDL 估算,不是单独的墙钟计时。四项原 LDW 类假模型字段探针确认:初始帧号 99 仍在五秒冷却内,帧号 100 恰好结束;31 mph 等值不允许 LDW,模型概率/线可见度/近线距离的等值也不触发;空 desirePrediction 会清左右状态,但非空且短于所需索引的向量直接抛 IndexError。
| 维度 | 变道意图 | 车道偏离预警 |
|---|---|---|
| 车速门槛 | 不低于 20 mph 才能进入准备态。 | 严格大于 31 mph。 |
| 转向灯 | 需要单侧灯的新沿。 | 近 5 s 内没有转向灯。 |
| 横向活动 | 要求横向激活。 | 要求 latActive=False。 |
| 驾驶员输入 | 要求 steeringPressed 且扭矩同向。 |
不依赖驾驶员扭矩,依赖线可见度与模型预测。 |
| 输出 | 变道状态/方向、转向灯请求与提示。 | 左右偏离布尔值、HUD 方向与声音提示。 |
提示与执行边界
selfdrived 仅在 IsLdwEnabled 和 driverAssistance 有效时生成 ldw;开关由参数轮询更新。该事件是 PERMANENT 小型提示及声音,不是 disengage 或执行器指令。准备变道、盲区阻挡和变道中分别是 WARNING 提示;其中盲区阻挡带提示音。controlsd 也会在 driverAssistance 有效时把左右偏离送入 HUD。
两项原消费者条件组合探针确认了旧值消费的边界:先收 driverAssistance.valid=True,随后假时钟推进到超出 20 Hz 服务的十倍存活窗口且无新消息时,updated=False、alive=False,但 valid=True 与旧左右字段保留,隔离执行 SelfdriveD.update_events() 的 LDW 分支仍会添加 ldw;若收到新消息且外层 valid=False,两个分支都跳过。转向灯、驾驶员扭矩/按压、盲区都来自车型解码,不是模型自己「看见了」即可替代,新硬件接口必须逐车型证明同向扭矩和盲区位的确切含义。
常见问题
变道是车辆自己判断安全后完成的吗?
不是。这里的变道是驾驶员参与的 L2 辅助行为,DesireHelper 只设置意图/状态,不直接写转向执行器;车型是否实现灯控还需逐车型检查。它不自动判断周围交通安全后自行变道。
为什么变道用 20 mph、LDW 用 31 mph?
两条链路的门槛是独立定义的:DesireHelper.update() 要求速度不低于 20 mph 才进入准备态;LaneDepartureWarning.update() 要求车速严格大于 31 mph。源码没有把两者合并为同一策略函数。
盲区位会一直阻止变道吗?
不会。准备态要求该侧无盲区报警,但一旦进入 laneChangeStarting,源码不再以盲区位直接撤销,而依赖模型概率和超时等分支,因此不能把盲区位当成持续的安全许可。
LDW 的 5 秒冷却按墙钟算吗?
不是。冷却按 SubMaster.frame * DT_MDL 估算,last_blinker_frame 初值为零;探针确认灯亮后的第 99 帧仍冷却、第 100 帧可再次触发。
延伸阅读
- 同一个「转向灯」在三家车厂是三种实现:车辆状态归一化的坑 —— 转向灯、扭矩与盲区信号的车型差异。
- 丰田车型状态的输入健康契约:转向、扭矩与盲区信号怎么读 —— 车型解码的具体字段来源。
- 道路模型输出契约:desirePrediction 与车道线字段的边界 —— LDW 依赖的模型输出从哪来。
- 从使能到车轮:执行链上的八道门,以及它们各自不保证什么 —— 提示与执行之间的门。
参考资料
- 项目 02 ——
openpilot-research/LANE_CHANGE_LDW_DEEP_DIVE.md(DesireHelper 状态机、LDW 阈值、消息发布与提示边界)。 - 项目 02 —— 同目录探针记录:五项 DesireHelper 状态、四项 LDW 阈值、两项 plannerd 发布、两项消费者分支隔离探针结论。
说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11
发表回复