openpilot 的 juggle.py 详解用 PlotJuggler 可视化行驶日志、解析 CAN 与实时流数据【免费下载链接】openpilotopenpilot is an operating system for robotics. Currently, it upgrades the driver assistance system on 300 supported cars.项目地址: https://gitcode.com/GitHub_Trending/op/openpilotopenpilot 通过tools/plotjuggler/目录下的辅助脚本juggle.py把 PlotJuggler一个通用的时间序列可视化工具与 openpilot 的 cereal 日志格式打通自动下载 PlotJuggler 及其 openpilot 专用插件、解析路由/段日志、推断车型 DBC 以解码 CAN 信号并支持从 comma 设备实时串流数据。读完本文你将掌握juggle.py的全部命令行参数、14 个预置布局Layout的用途与结构以及从LogReader到.rlog再到 PlotJuggler 插件的完整源码调用链能够独立完成从回放一次行驶记录到从车机实时观察控制量的完整调试工作流。PlotJuggler 在 openpilot 中的定位openpilot 的日志是 Capn Proto 序列化、经 zstd 压缩的 cereal 消息流rlog/qlog直接读取并不直观。juggle.py解决的核心问题是把这些日志转换成 PlotJuggler 能加载的时间序列视图。comma 团队为 PlotJuggler 编写了两个关键插件随--install一起安装到openpilot/tools/plotjuggler/bin/插件目录DataLoad Rlog加载并解析 openpilot 的 rlog 文件Cereal Subscriber以 ZeroMQ 订阅 cereal 消息总线实现实时流式绘图。这两个插件 ID 直接写死在仓库自带的每个布局文件中例如 tuning.xml 末尾的Plugins plugin IDDataLoad Rlog/ plugin IDCereal Subscriber/ /Plugins因此布局文件与本地安装的插件是配套关系——这也是--install需要同时安装 PlotJuggler 和插件的原因。安装下载 PlotJuggler 与插件在 配置好 openpilot 开发环境 之后执行cd openpilot/tools/plotjuggler ./juggle.py --install从 juggle.py 的install()实现L43-L61可以看到安装细节以platform.system() platform.machine()组合出平台标识仅支持Linux-x86_64、Linux-aarch64、Darwin-arm64三种平台其他平台直接抛异常删除并重建openpilot/tools/plotjuggler/bin/安装目录从 commaai/PlotJuggler 的releases/download/latest/平台.tar.gz流式下载1MB 分块解包到bin/目录。脚本还有两条自愈逻辑保证日常无需手动维护版本若bin/plotjuggler不存在自动提示并安装L158-L160若已安装版本低于MINIMUM_PLOTJUGGLER_VERSION (3, 5, 2)通过执行plotjuggler -v解析版本号后自动更新L162-L164、L64-L67。命令行参数全解./juggle.py -h的输出README 中的快照与实际 argparse 定义一致此外当前源码中还有一个 README 帮助文本未列出的--no-migration选项。以 juggle.py 的参数定义 为准完整参数如下参数类型说明route_or_segment_name位置参数可选要绘制的路由或段名称接受 cabana 分享 URL不提供且不指定--demo时无法绘图--demo开关使用内置演示路由5beb9b58bd12b691/0000010a--a51155e496即源码常量DEMO_ROUTEL23--can开关解析 CAN 数据默认过滤掉can/sendcan消息--stream开关以流式模式启动 PlotJuggler不加载历史数据文件--layout [LAYOUT]可选值使用预定义布局文件启动如--layout layouts/tuning.xml--install开关安装或更新 PlotJuggler 插件执行完即退出--dbc DBC值指定解析 CAN 数据所用的 DBC 文件名不指定时从日志自动推断--no-migration开关跳过旧版日志字段迁移源码 L138README 帮助文本未列出另外注意不带任何参数直接运行./juggle.py时会先打印一段紫色横幅指向后继工具 JotPluggler见文末再打印帮助并退出L144-L148。路由与段的命名约定README 给出了三类典型用法5beb9b58bd12b691为设备名0000010a--a51155e496为路由 ID两者均沿用演示路由# 整个路由跨所有段合并绘制 ./juggle.py 5beb9b58bd12b691/0000010a--a51155e496 # 单个段 ./juggle.py 5beb9b58bd12b691/0000010a--a51155e496/1 # 单个段使用 qlog调试日志而非 rlog ./juggle.py 5beb9b58bd12b691/0000010a--a51155e496/1/q # 段范围 ./juggle.py 5beb9b58bd12b691/0000010a--a51155e496/0:1源码流程从路由名到绘图窗口juggle_route()juggle.py L108-L128串起了完整流程值得逐步拆解加载日志LogReader(route_or_segment_name, default_modeReadMode.AUTO_INTERACTIVE)。AUTO_INTERACTIVE模式定义在 logreader.py 中语义是优先读取 rlog缺失时与用户交互确认后回退到 qlog所以传入/1/q这样的后缀即可显式指定 qlog。多进程聚合lr.run_across_segments(24, partial(process, can))用最多 24 个进程跨段并行处理。process()L104-L105的过滤规则是不带--can时丢弃can、sendcan以及所有customReserved*开头的消息——CAN 原始报文体积大且默认无意义故被排除带--can时全部保留。日志迁移除非指定--no-migration调用 migration.py 中的migrate_all()把旧版字段名重映射为当前版本保证旧路由也能用新版布局打开。DBC 自动推断见下节。落盘临时 rlogsave_log(tmp.name, all_data, compressFalse)把聚合后的消息写入openpilot/tools/plotjuggler/下以.rlog为后缀的临时文件解压状态供 DataLoad Rlog 插件加载随后start_juggler()启动图形界面。start_juggler()L70-L101在启动前做了一件容易忽略但很关键的事在临时目录中拼出 PlotJuggler 插件所需的 Capn Proto 模式文件——复制 log.capnp、deprecated.capnp、custom.capnp 并重写其中的 import 路径/include/c.capnp→./include/c.capnp/car.capnp→car.capnp再符号链接 cereal 的include/目录与opendbc_repo/opendbc最后把该临时目录设为插件的BASEDIR环境变量。这使插件能在不依赖完整构建产物的情况下正确反序列化消息。最终执行的命令形如bin/plotjuggler --buffer_size 1000 --plugin_folders bin -d 临时rlog -l 布局文件 --window_title 路由名 (车型平台)其中--buffer_size 1000来自常量MAX_STREAMING_BUFFER_SIZE--window_title会附带推断出的车型平台名便于多窗口调试时区分。解析 CAN 数据--can 与 DBC加上--can后CAN 原始报文会进入绘图数据源但要把报文解码成有意义的信号还需要 DBC 文件。juggle_route()中的推断逻辑L116-L123为若未显式--dbc取日志中第一条carParams消息用CP.carFingerprint经MIGRATION表来自 opendbc 子模块的opendbc.car.fingerprints映射出车型平台再通过openpilot.tools.cabana.dbc.generate_dbc_json中的generate_dbc_dict()查该平台对应的 DBC 名并以环境变量DBC_NAME传给 PlotJugglerL73-L76由 CAN 解析插件据此解码。因此通常无需手动指定 DBC当路由中缺少carParams如纯 CAN 录制或推断失败时此时会打印 Failed to get DBC name from logs!才需要用--dbc显式给出 DBC 文件名或路径本地路径会被转换为绝对路径。实时流式数据--stream--stream分支跳过一切日志加载直接start_juggler(layoutargs.layout)启动 PlotJuggler在 Streaming 下拉菜单中选择Cereal Subscriber插件并点击 Start即可订阅本机 cereal 总线实时绘图L166-L167。数据源有两种从 comma 设备串流到笔记本在 comma 设备上开启 Wi-Fi 热点tetheringSSH 进入设备后执行cd /data/openpilot ./openpilot/cereal/messaging/bridge——该 bridge 二进制由 bridge.cc 构建作用是把设备本地的共享内存消息总线桥接为 ZeroMQ 对外发布笔记本连接该热点执行ZMQ1 ./juggle.py --stream找到Cereal Subscriber插件并点击Start。ZMQ1环境变量告诉消息层走 ZeroMQ 传输。从本地回放串流如果在 PC 上用 replay 工具回放路由直接运行./juggle.py --stream并启动 cereal subscriber 即可——replay 进程发布的本地消息同样会被订阅到。快速演示--demo完成安装后最快看到效果的方式是./juggle.py --demo --layoutlayouts/tuning.xml这会下载/复用内置演示路由DEMO_ROUTE加载调参布局打开 PlotJuggler。仓库的自动化测试 test_plotjuggler.py 也以{DEMO_ROUTE}/:2前 3 个段为输入验证整条链路在无显示环境下以QT_QPA_PLATFORMoffscreen启动juggle.py等待 stderr 出现插件打印的Done reading Rlog data180 秒超时再确认进程没有崩溃、输出中不含Raw file read failed。该测试依赖 Qtqmake未安装时自动跳过。Layouts14 个预置布局及其结构openpilot/tools/plotjuggler/layouts/目录内置了 14 个开箱即用的布局README 鼓励社区把自己的有用布局上游化。各布局的适用场景可从文件名与内容对应布局文件典型用途tuning.xml横向/纵向整体调参生成调参 PR 所需图表longitudinal.xml纵向控制aEgo、MPC 加速度、执行器输出、油门状态torque-controller.xml转向扭矩控制器深入调试仓库中最大的布局249 行max-torque-debug.xml最大扭矩/限幅问题排查CAN-bus-debug.xml三条 CAN 总线的 RX/TX/错误计数对累计值做 Derivative 变换得到速率can-states.xmlCAN 总线状态controls_mismatch_debug.xmlcontrols 输出不一致排查locationd_debug.xml定位模块locationd调试gps.xml / gps_vs_llk.xml / ublox-debug.xmlGNSS 信号、GPS 与里程计对比、u-blox 调试camera-timings.xml相机帧时序system_lag_debug.xml系统时延/卡顿排查thermal_debug.xml热状态排查以 tuning.xml 为例拆解布局文件以--layout layouts/tuning.xml为例布局文件是一个 PlotJuggler 的 XML 工程包含三大块tabbed_widget主窗口标签页结构。tuning 布局含Lateral、Longitudinal、Lateral Debug三个 Tab每个 Tab 内用DockSplitter把若干DockArea均分每个DockArea是一个TimeSeries折线图curve直接引用 cereal 字段路径例如/carState/vEgo、/carControl/orientationNED/0横滚角、/controlsState/lateralControlState/pidState/saturated横向 PID 饱和标志等。customMathEquations自定义数学公式区。tuning 布局中的每个公式片段snippet都实现了统一的engage_delay 5 秒逻辑当驾驶员干预steeringPressed或系统未接管enabled 0时记录last_bad_time只有距最后一次干预超过 5 秒的时段才返回真实曲率/加速度否则返回 0。这样调参图表只反映纯 openpilot 控制的片段排除人为干扰。例如engaged curvature plan取/modelV2/action/desiredCurvatureengaged_accel_plan取/longitudinalPlan/accels/0并在brakePressed/gasPressed非零时置零。Plugins声明该布局依赖DataLoad Rlog与Cereal Subscriber两个插件。测试代码 test_layouts 还规定了一个上游约束布局文件中不允许残留fileInfo或previouslyLoaded_Datafiles字段——因为 PlotJuggler 在加载引用了先前数据文件的布局时会告警这些内容必须在提交前剔除。与 JotPluggler 的过渡关系需要说明的一点是当前仓库的juggle.py每次运行时都会打印横幅提示 JotPluggler is the future 与 PlotJuggler will be deleted soonjuggle.py L31-L40并给出等价命令./openpilot/tools/jotpluggler/jotpluggler --demo --layout tuning。从源码结构看openpilot/tools/jotpluggler/ 是一套 C 实现的新版可视化工具支持相同的 demo 与 layout 概念本文所述的 PlotJuggler 工作流在过渡期内仍然完整可用且其日志解析LogReader、迁移、DBC 推断逻辑是理解 openpilot 日志生态的良好切入点。速查小结安装/更新cd openpilot/tools/plotjuggler ./juggle.py --install支持 Linux x86_64/aarch64 与 macOS arm64自动校验最低版本 3.5.2回放绘图./juggle.py 设备名/路由ID支持/段号、/段号/q、/起:止后缀接受 cabana 分享 URLCAN 调试--can [--dbc 名]DBC 默认由首条carParams自动推断实时流设备侧跑cereal/messaging/bridge 笔记本ZMQ1 ./juggle.py --stream或本地 replay ./juggle.py --stream均通过Cereal Subscriber插件订阅快速体验./juggle.py --demo --layoutlayouts/tuning.xml核心源码入口juggle.py、布局目录 layouts/、回归测试 test_plotjuggler.py、日志读取层 tools/lib/logreader.py。【免费下载链接】openpilotopenpilot is an operating system for robotics. Currently, it upgrades the driver assistance system on 300 supported cars.项目地址: https://gitcode.com/GitHub_Trending/op/openpilot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考