☰
CommonRoad运动规划基准测试环境配置与安装避坑指南
2026/9/30 18:27:10 网站建设 项目流程

做自动驾驶运动规划这块的人,大概率会被推荐过一个词:CommonRoad。我第一次接触它,是为了给一套换道决策算法找可比对的测试场景——自己从零造场景太慢,抓一段实车数据又没法跟别人的结果放在一张表里对比,而 CommonRoad 刚好把这两件事同时解决了。简单讲,它是一套长期维护的开源场景数据集加工具箱:场景用统一的 XML 格式存放,规划算法只要遵守同一套接口,就能在成百上千个标注好的场景里跑基准测试,跑出来的指标还能直接横向比较。这篇内容我打算把这个生态掰开讲清楚——它由哪些 Python 包组成、每个包负责什么、运行环境怎么配、装完之后怎么验证自己真的装对了,以及我在 Windows 和 Linux 上装它时踩过的那一堆坑。不管你是刚入门运动规划的学生,还是要把基准测试接进自己流水线的工程师,照着走一遍应该都能把环境跑起来。

1. 先搞清楚 CommonRoad 到底是干什么的

1.1 它解决的是"没场景"和"没法比"这两个具体痛点

运动规划算法的评估一直有个尴尬:真实路测成本高、复现难,纯仿真又容易陷入"自己造的场景自己测"的循环论证。你写了一个基于采样的规划器,我写了一个基于优化的规划器,两人各自在自建场景上跑,指标好看得不行,但谁也不知道换个场景会怎样。CommonRoad 的切入点就在这里——它不提供算法,只提供"统一的考题"和"统一的评分口径"。每个场景里都预先定义好了自车初始状态、目标区域、周边车辆的历史与未来轨迹、车道拓扑和交通元素,算法要做的就是输出一条轨迹或者一串控制量。因为输入输出格式被固定死了,任何人的算法都能扔进同一批场景里跑,最后比的是成功率、碰撞次数、舒适度指标这些客观量。对做研究的人来说,这意味着论文里的实验可以被别人复现;对企业里的工程团队来说,这意味着可以拿它当回归测试集,每次代码改动都跑一遍,看看有没有把以前能过的场景跑挂了。

1.2 一份场景文件里到底装了哪些东西

很多人第一次打开场景 XML 会被劝退,因为文件动辄几千行。但只要抓住四条主线就不乱了:车道网络(lanelet network)、静态障碍物、动态障碍物、规划问题集合。车道网络是核心,它不存栅格地图,而是把道路切成一段段"车道片",每片记录左右边界线、限速、前驱后继关系,再由这些片组成车道组,红绿灯、停止线、人行横道之类的东西挂在车道组上。这种表示方式的好处是既省存储又保留拓扑关系,寻路算法可以直接在图上跑,不用去猜像素。动态障碍物里存的是每个时间步的位置、速度、朝向和形状,时间步长统一是 0.1 秒,也就是说场景里的 10 帧对应现实 1 秒。坐标系默认是投影后的平面直角坐标,同时在文件头记录一个 GPS 原点,需要经纬度时可以换算回去。规划问题则规定了自车从哪个状态出发、要到达哪块目标区域,这是算法真正要解的那道题。

1.3 "装 CommonRoad"其实要分成两件独立的事

新手最容易在这里迷糊:以为装完 Python 包就万事大吉,结果代码跑起来提示找不到场景文件。实际情况是,工具箱和场景库是两个东西。工具箱是 pip 上那几个 Python 包,负责解析、可视化、检查、路由这些功能;场景库则是一堆独立分发的 XML 文件,需要你自己从官网的场景数据库里按国家、道路类型、场景类型筛选下载,或者整包拉下来。包本身只带极少量用于单元测试的样例数据,不在你下载的场景列表里。所以我一般建议的顺序是:先把工具箱装好并用自带样例验证环境没问题,再去批量下载场景,这样一旦出问题能立刻定位到是环境问题还是数据问题,而不是两件事搅在一起排查。另外场景文件有严格的命名规范和 XML schema 校验,库在读取时会检查文件名里的国家码、地图 ID、场景 ID,改名或者截断文件名会直接导致解析失败,这一点后面还会细说。

2. 工具链拆解:哪些包必须装,哪些可以缓一缓

2.1 核心三件套:io、drivability checker、route planner

commonroad-io是地基,负责文件的读写、场景对象模型、可视化渲染、坐标与时间处理。几乎所有其他包都依赖它,所以安装顺序上它必须排第一。它的依赖里比较重的是 numpy、scipy、matplotlib、lxml、shapely、networkx 这几样,shapely 负责几何运算,lxml 负责 XML 解析,networkx 负责车道图的图结构操作。commonroad-drivability-checker是性能关键模块,可行性检查、碰撞检测这些高频调用被写成了 C++ 扩展,通过 Python 绑定暴露出来,导入名是commonroad_dc。这个包是整套工具链里最容易装失败的一个,因为它是编译产物,必须有跟你 Python 版本、操作系统、CPU 架构三者都匹配的预编译轮子,版本错一个都装不上。commonroad-route-planner负责在车道网络上做路由规划,输入车道网络和一个规划问题,输出若干条候选路线,它是很多规划算法的前置模块——你得先知道"该走哪条路",才谈得上"怎么走"。

2.2 按研究方向挑着装:别一上来就全装

功能包不少,但一次性全装进来只会让依赖冲突的概率翻倍,我的习惯是按需装。做反应式规划或者跟车、换道这类局部行为研究,装commonroad-reactive-planner,它内置了状态机式的规划器,拿来当基线很方便。做搜索类或采样类算法对比,装官方的搜索算法合集,里面对 A*、RRT、混合 A* 这些都有实现,适合用来做实验对照组。想把 SUMO 或者 OpenDRIVE 的路网转成场景,需要commonroad-scenario-designer以及 sumo2cr、cr2sumo 这类转换脚本。想算指标,比如碰撞、舒适度、通行效率那套评价体系,装对应的指标工具包。想跑预测模块的训练和推理,则是另一组包。这些扩展包往往对 Python 版本和 io 版本都有更严格的上下界约束,所以正确的做法是先把核心三件套装稳、锁定版本,再逐个往里加,每加一个就pip list看一眼有没有别的包被顺带升降级。

2.3 版本兼容矩阵:装之前先对一遍表

下面这张表是我根据最近几次安装经验整理的粗略对照,实际以官方文档为准,但大方向不会错。

包名主要作用关键依赖是否含编译扩展
commonroad-io场景读写、对象模型、可视化numpy、scipy、matplotlib、lxml、shapely、networkx否
commonroad-drivability-checker可行性检查、碰撞检测需要匹配的预编译轮子是
commonroad-route-planner车道级路由规划依赖 io 与图算法库否
commonroad-reactive-planner反应式规划基线依赖 io否
commonroad-search搜索与采样算法合集依赖 io,部分子模块另有依赖否
commonroad-scenario-designer从路网生成场景依赖 io、几何工具部分

需要特别强调的是 Python 版本。老版本的 io 在 3.8 上跑得挺舒服,但新版本已经往 3.10、3.11 上靠了。如果你的 Python 太新,比如刚出的 3.13,某些依赖可能还没有现成轮子,pip 会退回去尝试源码编译,然后在编译 shapely 或者 C++ 扩展时崩掉。这个坑我在一台新发的机器上踩过一次,最后是靠装一个 3.10 的 conda 环境解决的,前后花了不到十分钟,比硬啃编译错误划算得多。

3. 动手之前:环境准备与依赖梳理

3.1 Python 版本怎么定:就选 3.10 或 3.11

我给自己团队的默认建议是 3.10,偶尔用 3.11,理由是这两个版本的第三方库覆盖度最好,遇不到轮子缺失的情况。判断依据很简单:看你打算装的 drivability checker 提供了哪些版本的轮子,它的下限基本就是你能用的最低版本。别用系统自带的 Python,Linux 发行版自带的 3.6、3.8 往往被系统工具依赖,你往里装包有可能把系统的包管理搞乱,而且很多发行版默认不允许直接往系统环境里 pip install,会报 externally-managed-environment 这类提示。也别一上来就挑战最新版本,除非你确认所有依赖都已经跟进。选版本这件事看似小,实际上决定了后面半小时是顺畅安装还是在编译报错里挣扎,值得多花两分钟确认。

3.2 conda 还是 venv:看你要不要跨平台一致性

如果你在 Windows 上工作,或者需要跟别人共享一套精确复现的环境,我推荐 conda(Miniconda 就够了,Anaconda 太臃肿)。原因有两点:一是 conda 能同时管理 Python 解释器本身的版本,venv 只能基于已有的解释器建环境;二是 conda 在 Windows 上处理二进制依赖更省心,有些包通过 conda 渠道安装能直接拿到编译好的版本。如果你在 Linux 服务器上跑,环境干净、Python 版本已经就位,那 venv 更轻量,一个python -m venv cr-env加source cr-env/bin/activate就完事了,还省掉 conda 那套基础环境占的空间。我一般的做法是本地开发机用 conda,容器和服务器用 venv 或者直接基于官方镜像,两边都保留一份 requirements 文件来锁版本。关键原则只有一条:永远不要在 base 环境或系统环境里直接装,出了问题你连回滚都做不到。

3.3 Git 别忘了装:它不只是用来克隆代码

Git 在这套流程里的作用比想象中大。除了克隆示例仓库、拉取工具脚本,很多场景转换工具和辅助脚本是以仓库形式分发的,官方文档也经常让你去仓库的 examples 目录里找可以直接运行的脚本。Windows 上装 Git for Windows 就够了,安装时那几项换行符处理建议选默认的"检出时转换"和"提交时保持原样",避免跨平台协作时整个文件都被标记成修改。Linux 上用包管理器直接装,macOS 装完 Xcode 命令行工具一般就自带了。装完记得配置一下身份,git config --global user.name和user.email,不配的话提交时会报错。还有一个容易被忽略的点:如果你的项目路径里包含中文或者空格,某些工具脚本会处理失败,所以从一开始就把工作目录放在纯英文、无空格的路径下,能省掉后面很多莫名其妙的报错。

4. 安装实战:从零到跑通第一个场景

4.1 建环境、装核心包

先建一个独立环境,指定 Python 版本,然后激活它。这一步没什么花哨的,但要注意激活成功的标志是命令行提示符前面的环境名变了,如果你发现which python指向的还是系统解释器,那后面的安装就全白费了。

conda create -n commonroad python=3.10 -y conda activate commonroad python -V

确认版本对了之后,按顺序装核心包。先装 io,因为它是所有东西的地基,装完就能立刻验证环境是否正常。

pip install --upgrade pip pip install commonroad-io

如果你的网络下载比较慢,可以按所在网络环境把 pip 的索引地址指向合适的镜像源,这个属于常规操作,配置一次之后长期有效。装完先别急着装下一个,执行一遍导入测试:

python -c "import commonroad; print(commonroad.__file__)"

能打印出路径就说明 io 装好了。接着装剩下两个:

pip install commonroad-drivability-checker pip install commonroad-route-planner

drivability checker 装的时候会输出一堆下载信息,重点是看它有没有真正下载到whl文件。如果出现 "Building wheel for ..." 并且开始编译,八成是要失败了,直接中断然后去检查 Python 版本和平台是否匹配,别浪费时间等它编译完再报错。

4.2 装扩展包,并处理恼人的依赖升降级

扩展包按需装,比如:

pip install commonroad-reactive-planner pip install commonroad-search

装完每个包之后养成一个习惯,跑一次依赖检查:

pip check pip list | grep -i commonroad

pip check会告诉你有没有包的依赖被破坏了。最常见的情况是某个扩展包要求老版本的 numpy,pip 为了满足它把 numpy 降级了,结果 io 又跑不起来。这时候不要顺着 pip 的自动决策走,而是回去查两个包各自声明的版本区间,手动指定一个两边都能接受的版本,比如pip install "numpy<2"这种形式把它钉住。conda 和 pip 混用也会引发类似问题:conda 装的 numpy 和 pip 装的 numpy 可能同时存在,导入时到底用哪个取决于路径顺序,非常难查。我的经验是,一旦决定用 pip 管理这套包,那 Python 解释器之外的依赖就尽量都走 pip,别交替使用两个包管理器去装同一个库。

4.3 搞到第一个场景文件

环境装好之后,你需要一个场景来验证。两个途径:一是从 io 包的源码仓库里找tests目录下的样例 XML,这些文件体积小、加载快,适合做冒烟测试;二是去官方场景数据库下载正式场景,按国家、道路类型、场景类型筛选,单个下载或者打包下载都行。下载下来你会看到文件名长这样:DEU_LocationA-1_1_T-1.xml,结构是"国家码_地点名-地图编号_场景编号_场景类型-规划问题编号"。这个命名不是随便起的,读取器会解析它来构造场景的 benchmark ID,所以绝对不要手动改名、加后缀、去空格,哪怕只是把下划线换成短横线,也可能导致解析失败或者 ID 错乱。我见过有人为了排序方便在前面加了序号,结果整批场景都读不进来,最后只能重新下载。把场景统一放在一个纯英文路径的目录下,比如~/commonroad/scenarios/,后续脚本里用绝对路径引用,能少踩很多坑。

4.4 写一个验证脚本,把整条链路跑通

下面这段是标准的加载加可视化流程,可以直接拿去用:

import matplotlib matplotlib.use("Agg") # 服务器无界面时使用,本地调试可去掉 import matplotlib.pyplot as plt from commonroad.common.file_reader import CommonRoadFileReader from commonroad.visualization.mp_renderer import MPRenderer file_path = "/home/user/commonroad/scenarios/DEU_LocationA-1_1_T-1.xml" scenario, planning_problem_set = CommonRoadFileReader(file_path).open() print("场景 ID:", scenario.scenario_id) print("时间步长:", scenario.dt) print("时间步数:", scenario.sce nario

上面这段只是示意结构,实际写的时候注意别把变量名敲错。完整的打印部分应该包含车道数量、动态障碍物数量、规划问题数量这几项:

print("车道片数量:", len(scenario.lanelet_network.lanelets)) print("动态障碍物数量:", len(scenario.dynamic_obstacles)) print("规划问题数量:", len(planning_problem_set.planning_problem_dict))

然后绘制出来看效果:

renderer = MPRenderer(figsize=(20, 10)) scenario.draw(renderer) planning_problem_set.draw(renderer) renderer.render() plt.savefig("preview.png", dpi=150, bbox_inches="tight")

跑完打开preview.png,如果能看到道路轮廓、车道线、障碍物方框和规划问题的目标区域,说明 io、lxml、matplotlib、shapely 这几条链路全通了。这一步非常关键,因为后面所有高级功能都建立在这个基础之上,这里通了,剩下的基本都是业务逻辑问题。

4.5 再加一步:跑路由和可行性检查

只加载场景还不够,路由和可行性检查才是日常用得最多的两个功能。路由这块大致是这样用的:

from commonroad_route_planner.route_planner import RoutePlanner route_planner = RoutePlanner( lanelet_network=scenario.lanelet_network, planning_problem=planning_problem, ) routes = route_planner.plan_routes() print("候选路线数量:", len(routes))

可行性检查用来判断你规划出来的轨迹,车辆在动力学上到底能不能执行、会不会撞上障碍物。它的接口在不同版本间有过调整,所以这里不贴死代码,建议直接参照当前版本官方仓库里的示例脚本,那个脚本是跟着版本一起维护的,比任何第三方教程都准。这两步跑通之后,你对这套工具链的掌握程度就已经超过了大部分人,可以开始真正接自己的算法了。

5. 常见问题与排查实录

5.1 安装阶段:几个把人劝退的报错

找不到匹配的发行版(No matching distribution found),九成是 Python 版本或者操作系统不匹配。drivability checker 这类编译扩展尤其明显,如果你的 Python 是 3.12 而它只发到 3.11,pip 会直接告诉你没有可用版本。解决办法不是硬试,而是降到有轮子的版本。编译到一半失败(error: command failed),通常是因为没有安装 C++ 编译工具链,或者某些头文件缺失。这条路的修复成本很高,能绕开就绕开,优先找预编译轮子。权限错误(Permission denied),说明你在往系统目录里装,回到"必须用虚拟环境"这一条。磁盘空间不足,conda 环境加上一堆科学计算库,很容易吃掉好几个 G,装之前先df -h看一眼。

5.2 运行阶段:代码能跑但结果不对

场景读不进来,第一反应先查文件名是否符合规范,再看 XML 本身有没有被编辑器改坏。中文路径导致读取失败,把项目挪到纯英文路径下基本就好了。图形界面报错,比如提示无法连接显示服务,说明你在无界面的服务器上跑了带plt.show()的代码,改成 Agg 后端加保存文件即可。渲染出来一片空白,多半是坐标范围问题,试着调整draw_params里的视野范围参数,或者先把场景对象的边界打印出来看看数值正不正常。内存占用飙升,绘制大场景时如果逐个元素精细渲染会非常吃资源,可以关掉一些装饰性图层,只画关心的部分,出图速度能快好几倍。

5.3 问题速查表

现象大概率原因处理方式
No matching distributionPython 版本或平台无轮子降到有轮子的 Python 版本
编译中途失败缺少编译工具链换预编译版本,避免源码编译
场景解析报错文件名被改动恢复原始命名,不要加前缀
读取报编码错误路径含中文或特殊字符挪到纯英文无空格路径
图上什么都没有坐标范围或图层设置问题打印边界,调整视野参数
导入时报 DLL 相关错误运行库缺失安装对应运行库后重试
依赖被莫名降级扩展包版本约束冲突手动钉住关键包版本
无界面环境绘图崩溃默认后端需要显示服务切换到 Agg 后端

6. 跑通之后可以继续做的几件事

6.1 场景批量管理与命名规范

单个场景跑通只是起点,真正做实验要面对几十上百个场景。这时候建议写一个遍历脚本,把场景目录下的文件全部读进来,用 benchmark ID 当键做索引,遇到解析失败的单独记录到日志里。这么做有两个好处:一是能提前发现哪些文件下载不完整,二是能在实验报告里精确引用场景 ID,别人按图索骥就能找到同一个场景。另外要注意,场景库里的场景是有版本更新的,同一 ID 在不同时期可能内容有细微差别,如果你的实验需要长期可比,最好在本地留一份快照,记录下下载的时间点和来源分类,别指望半年后还能下到一模一样的文件。

6.2 跟外部仿真和地图工具的衔接

CommonRoad 本身不做物理仿真,它管的是场景表示和算法接口。所以真正做闭环测试时,往往要和外部仿真器配合:把场景转成仿真器能吃的路网格式,让被控车辆在里面跑,再把轨迹回收成 CommonRoad 的格式做可行性检查。转换工具官方提供了一些,但每个转换器都有自己的限制,比如某些交通元素转不过去、坐标系原点的处理方式不一致,这些都需要提前验证。我的做法是拿一个最简单、只有直道的场景先跑通全流程,确认每一步的输入输出都对得上,再上复杂场景,否则出了问题根本不知道是转换环节、仿真环节还是检查环节的锅。

6.3 把环境固化下来

最后一件容易被忽略的事:把环境固化。跑通的当天就把依赖导出成文件:

pip freeze > requirements.lock

同时把 Python 版本、操作系统、conda 环境名记在项目 README 里。这么做看起来啰嗦,但当你三个月后换了台机器、或者要给同事复现实验时,会庆幸当初多花了这两分钟。我吃过这个亏,一个实验做到一半换了电脑,重新装环境时因为没锁版本,某个包升了小版本导致接口微调,代码直接报错,排查了半天才发现问题不在代码而在环境。从那以后,我对所有依赖重的项目都坚持当天锁版本。

我个人在这套工具链上折腾下来最大的体会是:九成的问题都出在环境而不是代码。真正难的是把 Python 版本、包版本、平台这三者对齐,一旦环境干净了,官方示例几乎都能直接跑出结果。所以别急着写算法,先老老实实花半小时把环境验证透,把那个可视化脚本跑出图来,后面的一切都会顺很多。另外一个小建议,遇到报错时优先去看包源码仓库里的 issue 和示例脚本,那里的信息比绝大多数教程都更新,也更容易对上你手里的版本。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询