openpilot 新手开发实战:从零搭建环境,把 UI 速度数字改成蓝色并部署到实车
本文基于 openpilot 官方入门指南 turn-the-speed-blue.md,带你完成 openpilot 开发者第一次完整的「环境搭建 → 本地回放 → 修改 UI 源码 → 重新构建 → 部署到实车」闭环。读完本文,你将掌握 openpilot 的构建体系(scons)、基于 route 消息回放(replay)的 UI 调试方法,以及 HUD 速度渲染函数的定位与改色实现,并了解如何将你的 fork 部署到 comma 设备上进行真机验证。
1. 搭建 openpilot 开发环境
官方给出一条命令式的一键安装路径:克隆 openpilot 仓库并安装全部依赖。
bash <(curl -fsSL openpilot.comma.ai)
该命令拉取的脚本对应仓库中的 tools/setup.sh,它负责安装系统依赖、Python 虚拟环境与 C++ 工具链。克隆完成后,进入仓库目录并激活 Python 虚拟环境:
cd openpilot
source .venv/bin/activate
然后编译 openpilot:
scons
关于 scons 这一步,可以从源码结构看到它并非简单的 Python 打包。构建入口 SConstruct 是一个 SCons 脚本,它会:
- 通过
COMMA_HARDWARE = os.path.isfile('/AGNOS')判断当前是否运行在 comma 硬件上,从而切换构建目标; - 把
msgq_repo、opendbc_repo、rednose_repo、teleoprtc_repo、tinygrad_repo等子模块目录插入sys.path,这些正是 openpilot 消息总线、车辆接口等底层库; - 提供
--minimal、--ccflags、--verbose等选项,在非设备上默认构建包含测试与工具的完整版本。
UI 相关的大部分 C++ 扩展(如 replay 二进制、编码器)都由这一步构建产物提供,因此在修改 UI 前完成 scons 是必要前提。
2. 运行 replay:用消息回放驱动 UI
UI 不是孤立的 Qt 程序,它依赖 carState、controlsState、modelV2 等实时消息流。没有车、没有摄像头时,openpilot 提供了 replay 工具来重放一次真实行车录制(route)中的全部消息,让系统"看起来像在真实行驶"。
按官方指南,在两个终端中分别执行:
# in terminal 1
openpilot/tools/replay/replay --demo
# in terminal 2
./openpilot/selfdrive/ui/ui.py
replay 的 C++ 入口是 openpilot/tools/replay/main.cc,它是一个 getopt 解析的命令行程序,--demo 参数会加载一条内置的演示 route。--demo 只是最简用法,完整的选项清单可在 replay 的 README 中查到,常用的几个包括:
-x <speed>:回放倍速,0.2~3 倍之间可调;--data_dir <path>:回放本地目录下的 route 文件,免去从服务器下载;--cabin/--wide-road:同时加载座舱与广角摄像头画面;--no-loop:route 播放到结尾即停止(默认循环回放);-a / -b:按服务名白名单/黑名单过滤要发出的消息。
如果你有 comma 设备并上传过行车数据,可以把 --demo 换成自己账号下的一条 route 名称。回放自己的 route 前,需要先通过 openpilot/tools/lib/auth.py 完成账号认证,以便从服务器拉取路线数据。
ui.py 是 UI 进程入口(openpilot/selfdrive/ui/ui.py),它初始化 gui_app 窗口、根据大/小屏选择 MainLayout 或 MiciMainLayout,并以 CTRL_HIGH 实时优先级绑定到 CPU 核 5 上渲染。当 replay 在后台发出录制消息后,UI 会像真车一样显示 HUD——此时屏幕上看到的当前车速,就是接下来要改的地方。
3. 定位速度渲染代码并改成蓝色
官方指南建议用 git grep 定位负责渲染当前车速的函数:
git grep "_draw_current_speed" openpilot/selfdrive/ui/onroad/hud_renderer.py
该函数位于 openpilot/selfdrive/ui/onroad/hud_renderer.py,HudRenderer._draw_current_speed 负责在 HUD 顶部中央绘制车速数字:
def _draw_current_speed(self, rect: rl.Rectangle) -> None:
"""Draw the current vehicle speed and unit."""
speed_text = str(round(self.speed))
speed_text_size = measure_text_cached(self._font_bold, speed_text, FONT_SIZES.current_speed)
speed_pos = rl.Vector2(rect.x + rect.width / 2 - speed_text_size.x / 2, 180 - speed_text_size.y / 2)
rl.draw_text_ex(self._font_bold, speed_text, speed_pos, FONT_SIZES.current_speed, 0, COLORS.white) # <- this sets the speed text color
结合当前仓库源码,这段代码有几个值得注意的细节:
- 车速来自
_update_state中对carState.vEgoCluster(仪表车速)或carState.vEgo(车身估计车速)的取值,并按公英制换算(见 hud_renderer.py); - 字体尺寸
FONT_SIZES.current_speed = 176定义在文件顶部的FontSizesdataclass 中,速度数字垂直居中于 y=180 处; - 颜色来自同一文件的
Colors常量类(hud_renderer.py#L37-L56),它集中定义了ENGAGED(绿色,128,216,166)、DISENGAGED(灰绿)、GREY、WHITE等 HUD 主题色,文件末尾以COLORS = Colors()实例化供渲染函数使用。
按指南,把绘制速度数字那一行的白色改成柔和的蓝色 #8080FF 即可(以当前仓库中的写法为例):
- rl.draw_text_ex(self._font_bold, speed_text, speed_pos, FONT_SIZES.current_speed, 0, COLORS.WHITE)
+ rl.draw_text_ex(self._font_bold, speed_text, speed_pos, FONT_SIZES.current_speed, 0, rl.Color(0x80, 0x80, 0xFF, 255))
注意:仓库演进中该常量的命名可能随版本变化(早期为
COLORS.white,当前为COLORS.WHITE),以你 checkout 的代码为准,认准draw_text_ex的最后一个参数——那才是速度文本的颜色。
这里只改"当前车速"一行即可;同文件中 _draw_set_speed 还绘制了设定车速(MAX 框),颜色状态机依赖 UIStatus.ENGAGED/DISENGAGED/OVERRIDE,属于状态指示语义,不建议随手改动。
4. 重新运行 UI 验证效果
修改保存后,重新运行 UI 进程即可看到变化(replay 终端保持运行,UI 会自动重新连接消息流):
./openpilot/selfdrive/ui/ui.py
在 demo route 回放期间,屏幕顶部中央的车速数字应显示为柔和的蓝色,而单位(km/h / mph)仍保持半透明白色(COLORS.WHITE_TRANSLUCENT),两者颜色对比正好能证明你只改对了那一行。
5. 把改动推送到你自己的 fork
要让 comma 设备能够安装你的版本,改动必须先托管到可访问的 fork 上。流程是:
- 在你的代码托管账号中 fork openpilot 仓库;
- 将本地仓库的
origin远程指向你自己的 fork,然后提交并推送:
git remote rm origin
git remote add origin <你托管的 openpilot fork 地址>
git add .
git commit -m "Make the speed display blue"
git push --set-upstream origin master
openpilot 的主开发分支为 master,推送前建议先同步上游最新代码,避免设备安装时因版本过旧而构建失败。
6. 在 comma 设备上运行你的 fork
如果你的设备是 comma four(或其他支持刷机安装的 comma 设备),操作方式为:
- 在设备设置界面中卸载(Uninstall)已安装的 Openpilot;
- 重新安装时,指定你自己 fork 的地址而不是官方源。安装入口由 UI 安装器(openpilot/selfdrive/ui/installer)与 system/ui 下的更新程序实现,官方源格式为
installer.comma.ai/<账号>/<分支>,将其中的账号与分支换成你 fork 的账号与master分支即可:
installer.comma.ai/<你的账号名>/master
设备会从你的 fork 拉取代码并完成构建安装。安装完成后上车启动,打开自动辅助驾驶,就能看到 HUD 上的当前车速以蓝色显示——这是你在真车上验证的第一个 openpilot 改动。
7. 小结与延伸阅读
走完这篇指南,你实际上已经建立了 openpilot 开发的核心工作流:
- 环境:
bash <(curl -fsSL openpilot.comma.ai)+source .venv/bin/activate+scons; - 本地调试:
replay --demo提供消息与画面回放,./openpilot/selfdrive/ui/ui.py渲染 HUD; - 改代码:HUD 渲染集中在 openpilot/selfdrive/ui/onroad/ 下的
HudRenderer(速度)、ModelRenderer(模型画面)、AlertRenderer(告警)等文件,颜色与尺寸常量统一在文件头部维护; - 部署:fork → 推送 master → 设备上按
installer.comma.ai/<账号>/master重装。
如果想继续深入,建议阅读:
- replay 的完整文档:本地 route 回放、ZMQ 消息、与 plotjuggler/watch3 的组合用法;
- docs/how-to/replay-a-drive.md:如何回放你自己的行车记录;
- docs/how-to/connect-to-comma.md:设备与仓库的远程连接方式,方便你直接从电脑上调试车机上的进程;
- docs/contributing/architecture.md:openpilot 各守护进程(d)的整体架构,帮助理解 UI 与 replay 之外还有 controlsd、modeld 等在回放时如何协同工作。
安全提示:openpilot 是驾驶员辅助系统,在真车上测试任何修改前,请确认理解 docs/SAFETY.md 与 docs/DEBUGGING_SAFETY.md 中的约束,并始终做好随时接管车辆的准备。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00