ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

CommonRoad运动规划基准测试环境配置与安装避坑指南

CommonRoad运动规划基准测试环境配置与安装避坑指南 做自动驾驶运动规划这块的人大概率会被推荐过一个词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 plannercommonroad-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 提供了哪些版本的轮子它的下限基本就是你能用的最低版本。别用系统自带的 PythonLinux 发行版自带的 3.6、3.8 往往被系统工具依赖你往里装包有可能把系统的包管理搞乱而且很多发行版默认不允许直接往系统环境里 pip install会报 externally-managed-environment 这类提示。也别一上来就挑战最新版本除非你确认所有依赖都已经跟进。选版本这件事看似小实际上决定了后面半小时是顺畅安装还是在编译报错里挣扎值得多花两分钟确认。3.2 conda 还是 venv看你要不要跨平台一致性如果你在 Windows 上工作或者需要跟别人共享一套精确复现的环境我推荐 condaMiniconda 就够了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 python3.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-plannerdrivability checker 装的时候会输出一堆下载信息重点是看它有没有真正下载到whl文件。如果出现 Building wheel for ... 并且开始编译八成是要失败了直接中断然后去检查 Python 版本和平台是否匹配别浪费时间等它编译完再报错。4.2 装扩展包并处理恼人的依赖升降级扩展包按需装比如pip install commonroad-reactive-planner pip install commonroad-search装完每个包之后养成一个习惯跑一次依赖检查pip check pip list | grep -i commonroadpip check会告诉你有没有包的依赖被破坏了。最常见的情况是某个扩展包要求老版本的 numpypip 为了满足它把 numpy 降级了结果 io 又跑不起来。这时候不要顺着 pip 的自动决策走而是回去查两个包各自声明的版本区间手动指定一个两边都能接受的版本比如pip install numpy2这种形式把它钉住。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, dpi150, bbox_inchestight)跑完打开preview.png如果能看到道路轮廓、车道线、障碍物方框和规划问题的目标区域说明 io、lxml、matplotlib、shapely 这几条链路全通了。这一步非常关键因为后面所有高级功能都建立在这个基础之上这里通了剩下的基本都是业务逻辑问题。4.5 再加一步跑路由和可行性检查只加载场景还不够路由和可行性检查才是日常用得最多的两个功能。路由这块大致是这样用的from commonroad_route_planner.route_planner import RoutePlanner route_planner RoutePlanner( lanelet_networkscenario.lanelet_network, planning_problemplanning_problem, ) routes route_planner.plan_routes() print(候选路线数量:, len(routes))可行性检查用来判断你规划出来的轨迹车辆在动力学上到底能不能执行、会不会撞上障碍物。它的接口在不同版本间有过调整所以这里不贴死代码建议直接参照当前版本官方仓库里的示例脚本那个脚本是跟着版本一起维护的比任何第三方教程都准。这两步跑通之后你对这套工具链的掌握程度就已经超过了大部分人可以开始真正接自己的算法了。5. 常见问题与排查实录5.1 安装阶段几个把人劝退的报错找不到匹配的发行版No matching distribution found九成是 Python 版本或者操作系统不匹配。drivability checker 这类编译扩展尤其明显如果你的 Python 是 3.12 而它只发到 3.11pip 会直接告诉你没有可用版本。解决办法不是硬试而是降到有轮子的版本。编译到一半失败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 和示例脚本那里的信息比绝大多数教程都更新也更容易对上你手里的版本。
返回列表