结论:首次引导的启动资格由三个互相独立的契约拼成:条款版本、培训版本与设备启动条件。大屏与 mici 两套 UI 都只在窗口构造时读取一次布尔快照,训练 UI 完成不等于驾驶员监测或摄像头的实车验证;hardwared 真正看的是持久键里的版本值,而不是 UI 是否关闭。
版本契约:terms_version 与 training_version
源码中 terms_version="2" 与 training_version="0.2.0" 分别与 HasAcceptedTerms、CompletedTrainingVersion 比较;两键在参数定义中标记为持久化,条款键另有一段。两套 UI 均在窗口构造时读取一次布尔快照,未完成才由主布局推入导航栈。
hardwared 把匹配条款和培训版本分别列入 accepted_terms、completed_training 启动条件,同时要求非 DoUninstall。只有 started_ts is None 时,启动条件才合入 should_start;已上路后版本变化不是这段代码的即时退场门。UI 是否关闭也不是启动条件,持久键的版本值才是跨进程依据。开发/回放夹具可直接写入这两键,因此不能把其存在视为用户真实完成培训的证明。
这里有一个容易被忽略的顺序问题:两套 UI 的 completed 属性都是构造时快照,点击后只写 Params,并不重新赋这两个布尔值。因此「本次会话里 UI 已消失」与「hardwared 下次启动会读到版本匹配」是两件事——跨进程依据只能是持久键里的版本值,而不是界面状态。
大屏函数链:图片热区与第九步
| 函数/组件 | 行为 | 边界 |
|---|---|---|
OnboardingWindow.__init__()、completed |
构造时读条款/培训版本,决定先显示条款还是培训。 | _accepted_terms、_training_done 是构造快照;点击后写 Params,但本实例不重新赋这两个布尔值。 |
_on_terms_accepted()、_on_completed_training() |
同步写对应版本值;如果培训早已完成,接受条款后直接退场。 | 这是软件版本确认,不验证摄像头、CAN 或 DMS 当前可用。 |
TrainingGuide._load_image_paths()、_preload_thread() |
从 assets/training/stepN.png 数字排序,首图立即加载,其余在线程解码并在 UI 线程上传纹理。 |
点击热区来自固定 STEP_RECTS;图片数/顺序变化必须同步热区与录音选择步号。 |
TrainingGuide._handle_mouse_release() |
命中本步热区才前进;第 9 步按额外矩形选择 RecordFront,末页可重看或完成并 pop_widget()。 |
这些是图片坐标热区,不是语义化控件;不同分辨率/素材改版需实屏验收。 |
DeclinePage._on_uninstall_clicked() |
写 DoUninstall=True 并请求关闭 UI。 |
真正卸载由 manager 观察参数、清理进程后调用硬件层卸载。 |
mici 函数链:DMS 进度与缓存状态风险
| 函数/组件 | 行为 | 边界 |
|---|---|---|
OnboardingWindow.__init__()、show_event() |
读取版本快照,创建条款/培训页面;显示时延长交互超时并提高驻车亮度。 | hide_event() 恢复覆盖设置,但子页导航也可触发隐藏回调,生命周期需实屏确认。 |
_on_terms_accepted() |
写条款版本后无条件推入培训页。 | 与大屏不同:若旧培训版本已匹配而只需重签条款,mici 仍要求再次走培训 UI。 |
TrainingGuidePreDMTutorial.show_event() |
设置 IsDriverViewEnabled=True,使驻车时可运行座舱采集/监测链。 |
此参数是预览进程门,不是模型就绪回执;close() 会写回 false。 |
TrainingGuideDMTutorial._update_state() |
曾收到 driverMonitoringState 后,用检测到人脸且朝向中心的条件累积约 4 秒进度,达到阈值才启用继续按钮。 |
只检 recv_frame != 0,没有同时要求两条 DMS 消息本帧更新、存活、有效或年龄上限;一条曾合格的缓存状态在后续 UI 帧仍可能推动进度。 |
TrainingGuideRecordFront |
接受/拒绝各写 RecordFront,随后进入完成回调。 |
RecordFront 影响座舱录制配置,不能与 DMS 必需的短时预览混为同一授权。 |
_on_completed_training()、close() |
写培训版本、关 IsDriverViewEnabled、回调主布局退场。 |
退场与 Params 写入分步完成;窗口实例的 completed 属性仍是构造时快照。 |
小屏的 DMS 教程读取左右驾驶位模型结果,并从 driverMonitoringState 读取策略与脸部状态;预览中的绿色图标还可被 set_force_active(True) 强制呈现,不能拿图标颜色证明教程输入有效。
DMS 进度的静态推论
TrainingGuideDMTutorial._update_state() 的进度累积条件值得单独强调:它只检查 recv_frame != 0,没有同时要求两条 DMS 消息本帧更新、存活、有效或年龄上限。因此一条曾合格的缓存状态在后续 UI 帧仍可能推动进度。这属于静态推论,源文档未做断流复现。
换句话说,「培训完成」这一步记录的是用户在 UI 上走完了编号图片与约 4 秒的进度条,而不是 DMS 在真实车辆环境下的可用性结论。把前者当作后者,是引导流程最常被误读的地方。
硬件与插件化要求
第一,把「用户确认的条款版本」「培训完成记录」「摄像头/DMS 当前健康」「行车启动许可」分别存储和审计,不要让 UI 插件直接伪造版本键或持有设备卸载权限。第二,小屏 DMS 进度应绑定新鲜的成对消息、相机帧 ID、有效位和单调时间,丢帧/失联时冻结或回退,并在模型/摄像头/安装支架换版后重新验收。第三,RecordFront 是独立的隐私选择,硬件设计应分别证明短时座舱预览、可选录制和远端上传的权限及启停回执;对大屏图片热区和 mici 导航栈做不同尺寸、快速连点、掉电和中途退出测试。
这三条要求背后是同一个判断:引导流程能证明的只是「用户在界面上完成了对应步骤」。它不能证明摄像头当前成像正常、DMS 模型在真实座舱光照下可用,也不能证明持久键没有被回放夹具写入。因此条款、培训、设备健康与行车许可必须各自留痕、各自可审计。
常见问题
条款和培训版本在哪里决定是否启动?
hardwared 把匹配条款和培训版本分别列入 accepted_terms、completed_training 启动条件,并要求非 DoUninstall;只有 started_ts is None 时才合入 should_start。UI 是否关闭不是启动条件。
大屏和 mici 在重签条款时的行为一致吗?
不一致。mici 的 _on_terms_accepted() 写条款版本后无条件推入培训页;即使旧培训版本已经匹配而只需重签条款,mici 仍要求再次走培训 UI。大屏则在培训早已完成时于接受条款后直接退场。
小屏 DMS 教程的进度条一定能代表监测可用吗?
不能。TrainingGuideDMTutorial._update_state() 只检 recv_frame != 0,没有同时要求两条 DMS 消息本帧更新、存活、有效或年龄上限;一条曾合格的缓存状态在后续 UI 帧仍可能推动进度,源文档也未做断流复现。
RecordFront 与 DMS 预览是同一个授权吗?
不是。RecordFront 影响座舱录制配置,是独立的隐私选择,不能与 DMS 必需的短时预览混为同一授权;两者应有各自的权限与启停回执。
延伸阅读
- 驾驶员监测策略:状态、告警与降级 —— 承接 DMS 状态如何被消费而非仅用于引导。
- 驾驶员监测模型管线 —— 说明
driverMonitoringState的产生侧边界。 - UI 运行时:布局、事件与生命周期 —— 对照两套引导 UI 的窗口与导航栈行为。
- 开发者设置与配置项边界 —— 说明持久键与启动条件的关系。
- 自车事件、状态与告警 —— 承接退场与告警的事件侧契约。
参考资料
- 项目 02 ——
openpilot-research/ONBOARDING_TERMS_TRAINING_DMS_STARTUP_GATE_DEEP_DIVE.md(取用了版本契约、启动门、大屏与 mici 函数链及 DMS 进度边界)。 - 项目 02 ——
openpilot-research/DRIVER_MONITORING_POLICY_DEEP_DIVE.md(仅用于确认 DMS 状态与策略的消费边界)。
说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11
发表回复