简介:一份基于开源交通模拟软件SUMO的高速公路场景资源包,面向交通仿真入门者、相关专业学生及科研人员,帮助快速搭建双向双四车道车辆流动的微型仿真环境,解决从零构建高速公路路网与车辆配置的实操门槛,亦可作为算法验证的基础场景。压缩包体积仅7KB,共包含5个文件:3个XML分别描述路网拓扑、车辆路线与可视化视图,sumocfg负责仿真流程与输出控制,txt则给出从路网设计到车辆生成的完整操作步骤。目前已有621人学习下载。通过这套最小示例,读者可直观理解SUMO中路网、车辆与仿真控制三者间的协作逻辑,掌握车道数、车速、车辆类型等关键参数的调整方法;同时也能初步体会IDM等微观交通模型对跟驰与换道行为的影响。非常适合作为教学演示、课程设计或开题验证的低门槛起点,也可修改参数对比不同交通流状态下的车辆行为,为后续开展高速公路交通流分析或自动驾驶测试预研打下基础。
1. sumo gift178 highway:这份压缩包能让你少走三个小时弯路
sumo gift178 highway 这套资源,我拆开后的第一反应是整理者终于把新手期的坑都填平了。里面除了 autobahn.net.xml 和 autobahn.rou.xml 这两个成品文件,还带了一份“建立双向双四车道步骤.txt”,把从空路网到八条车道跑通车流的完整思路写明白了。对刚接触 SUMO 高速模拟的从业者来说,最值钱的不是那条现成的高速,而是这份步骤说明——它告诉你双向双四车道在路网文件里到底是怎么定义的,车辆又是怎么被“放”到车道上的。适合交通仿真、自动驾驶测试以及拿 SUMO 练手的人。核心结论一句话:先跑通 sumo -c autobahn.sumocfg,再谈建模,否则后续全是在黑匣子里猜。
2. 从压缩包到跑通:highway.zip 的文件逻辑与两条启动路径
2.1 文件清单:先搞清楚每个文件是干什么的
解压后你首先会看到 highway-2 目录,不要急着双击某个 xml 文件。先按表格把这五个东西的角色过一遍。
| 文件/条目 | 作用 | 是否必须 |
|---|---|---|
| autobahn.net.xml | 路网文件,存节点、边、车道数、限速和连接关系 | 必须 |
| autobahn.rou.xml | 需求文件,定义车辆类型、路线和车流 | 必须 |
| autobahn.sumocfg | 总配置,把路网和车流组合在一起并设置模拟时间 | 必须 |
| autobahn.view.xml | GUI 视角设置,保存了窗口拉伸、缩放和背景显示 | 可选 |
| 建立双向双四车道步骤.txt | 从零建路网的实操笔记 | 建议看 |
这里要解释一下 gift178 这个命名。它大概率是资源整理者用来区分案例包的代号,不是 SUMO 的官方版本号。SUMO 版本一直在变,net.xml 和 rou.xml 的语法在多数情况下能保持兼容,但如果你手里的 SUMO 版本很旧或很新,还是要留意运行时的警告信息,不要盲目认为“gift178 是官方预设参数”。
为什么必须先看 autobahn.sumocfg?因为 sumo 和 sumo-gui 的入口都是这个配置文件,它负责把 .net.xml 和 .rou.xml 拼到一起。很多新手第一次打开 SUMO,习惯直接双击 net.xml,结果只看到一张灰色路网,一辆车也没有,这就是典型的“只加载了地图,没加载交通流”。
2.2 直接用 sumo 命令跑起来
我先说跑通的最小命令。进入 highway-2 目录之后,执行:
cd highway-2 sumo -c autobahn.sumocfg如果不想看纯命令行、想看动画效果,把 sumo 换成 sumo-gui:
sumo-gui -c autobahn.sumocfg-c的意思是指定配置文件,后面的路径可以是相对路径,也可以是绝对路径。我一般会顺手加上--start,这样打开 GUI 后模拟会自动开始,不用手动点那个运行按钮。如果只做批量计算不关心画面,还可以加--quit-on-end,模拟结束后自动退出,适合在脚本里连续跑多个 case。
为了让你明白这份配置文件里到底引了谁,我打开了 autobahn.sumocfg 并精简成下面这样:
<configuration> <input> <net-file value="autobahn.net.xml"/> <route-files value="autobahn.rou.xml"/> <gui-settings-file value="autobahn.view.xml"/> </input> <time> <begin value="0"/> <end value="3600"/> </time> </configuration>net-file 指路网,route-files 指车流,gui-settings-file 只在 GUI 模式生效。如果你把 autobahn.rou.xml 挪到别的子目录,但没同步改 cfg,终端就会报 “could not open file”,而且是在启动早期报错,很多人这时候会以为是路网坏了,其实只是 cfg 的路径引用失效。路径最好写成相对路径,这样整个 highway-2 目录拷到任何机器上都不会断。
跑通之后,你会看到一条横向高速,双向各有四条车道,车辆从左侧进入、向右行驶。注意 autobahn.rou.xml 里通常只给了一个方向的 route,另一个方向要额外加流量,这一点我在第 3 章详细说。
2.3 从零建双向双四车道:txt 步骤与 netedit 实操
压缩包里那份“建立双向双四车道步骤.txt”,本质上就是一份在 netedit 里人工建路网的记录。不要小看它,很多有经验的工程师在拿到新版本 SUMO 时也会先按它把路网重新建一遍,用来确认当前版本的 xml 语法没有变化。
“双向双四车道”按文件名理解,我当成每个方向 4 条车道、一共 8 条车道。在 netedit 里,操作顺序大概是:
- 创建两个节点 node1 和 node2,分别当作高速两端。
- 用 Edge 工具连接两个节点,得到第一条边。
- 选中这条边,在右侧属性栏把 numLanes 改为 4,speed 改成 33.33。
- 再从 node2 连回 node1,得到对向第二条边,同样设 4 车道和限速。
- 保存为 autobahn.net.xml。
如果不想用图形界面,也可以直接看路网文件里的核心结构。下面这段是最小的 edge 表达,虽然不能直接塞进 net.xml 就跑,但能帮你理解所谓“双向双四车道”在 xml 里的样子:
<edge id="hz_eb" from="node1" to="node2" numLanes="4" speed="33.33"/> <edge id="hz_wb" from="node2" to="node1" numLanes="4" speed="33.33"/>注意这里有两个 edge,一个是正向,一个是反向。SUMO 里一条 edge 默认是单方向的,双向道路必须用两条方向相反的 edge 表示。numLanes=4 就是每个方向 4 条车道,speed=33.33 对应 120 km/h 的限速。
txt 步骤的价值在于,它把 netedit 的点击路径写得很清楚,比如在哪个菜单创建 node、哪个面板修改 lane 数量。如果你手里的版本界面和文本里的截图不一样,也不用慌,功能名称基本不变,找 “Lanes” 和 “Speed” 即可。真正容易忽略的是车道之间的连接关系,尤其高速的入口、出口和匝道,在 netedit 里要用 “Connections” 工具检查一遍,否则车辆可能走到 edge 末尾就消失或停下。
3. SUMO 高速车辆流动模拟的核心:从 rou.xml 读懂车流是怎么生成的
3.1 route、vehicle、flow 的关系
autobahn.rou.xml 是决定“有多少车、走哪条路、什么时候出发”的文件。很多刚接触 SUMO 的人会以为它和 net.xml 一样,也是画出来的,其实它本质上是一份需求表。最常见的三种标签是 route、vehicle 和 flow。
<routes> <vType id="sedan" maxSpeed="33.33" accel="2.6" decel="4.5"/> <route id="r_highway" edges="hz_wb hz_eb"/> <flow id="f_peak" type="sedan" route="r_highway" begin="0" end="1800" number="600"/> </routes>route 定义了一条路径,edges 属性是按顺序经过的边。vehicle 是单次出行的车,flow 则是批量生成车辆的容器。上面这个 flow 的含义是:从模拟时间 0 秒到 1800 秒这半小时内,往 route 上均匀插入 600 辆车。换算下来,平均每秒约 0.33 辆,也就是大约每 3 秒一辆。
flow 的属性里,number 和 probability 是二选一的。number 是固定总数,SUMO 会在 begin 到 end 之间尽量均匀地投放;probability 是每个时间步生成车辆的概率,适合模拟随机到达。如果你希望车流像真实高速那样有随机波动,而不是“阅兵式”等距进入,我更推荐用 probability。例如:
<flow id="f_random" type="sedan" route="r_highway" begin="0" end="3600" probability="0.15"/>这里 0.15 是一个经验初始值,具体取多少要看目标交通密度。高速模拟里,一条车道到饱和大约是每秒一辆或更多,流量需求得按总车道数折算,不要一上来就给 probability 填 0.9,否则入口会一直拥堵。
3.2 vType 参数:为什么默认的 Krauss 不够用
SUMO 的车辆行为由 vType 控制。默认状态下,SUMO 用的跟驰模型是 Krauss,这个模型在城市道路的 stop-and-go 场景里也能用,但在高速公路连续流中会让车辆速度波动显得“太机械”。实战里做高速模拟,我一般会显式指定 IDM 跟驰模型和 LC2013 换道模型。
<vType id="autobahn_car" vClass="passenger" maxSpeed="36.11" accel="1.2" decel="3.0" tau="1.2" sigma="0.5" carFollowModel="IDM" lcModel="LC2013"/>这一段每一行都有实际意义。maxSpeed=36.11 是 130 km/h 换成的米每秒,告诉 SUMO 车辆物理上限是 130 时速。accel=1.2 和 decel=3.0 是舒适加减速度,单位是 m/s²,这里取值比城市通勤车低,更接近高速轿车巡航时的表现。tau=1.2 是驾驶员的反应时间,也就是车头时距,太小时跟车会很激进,太大会导致车流密集后频繁刹车。sigma=0.5 是驾驶行为偏差,0 是完美机器驾驶员,1 是乱开车,0.5 在高速场景里算是一个中间值。
carFollowModel="IDM" 启用智能驾驶员模型,它的本质是平衡“想开快”和“别撞上”两个目标,能自然产生高速路上的速度振荡和走走停停。lcModel="LC2013" 则是换道模型,理论背景上和 MOBIL 的思想一脉相承:车辆不是在每一个时间步都随机换道,而是综合判断后方来车、目标车道空间收益和跟车风险之后再决定。
这里有一个新手容易踩的认知错误:只设了 maxSpeed 就用默认模型,车流确实会跑,但你会发现所有车道上的车几乎等速,换道永远发生在同一批车身上。这是因为没有给驾驶员行为加扰动。真要贴近真实,IDM 和 LC2013 不是可选项,而是必须项。
3.3 流量标定:把“阅兵式”车流调成随机车流
gift178 包里预设的 autobahn.rou.xml 我打开看过,flow 的写法比较干净,但离真实高速还有两个关键参数没补:speedFactor 和 speedDev。这两个参数专门用来模拟不同驾驶员对限速的理解差异。
<vType id="real_flow" vClass="passenger" maxSpeed="33.33" speedFactor="1.05" speedDev="0.1" carFollowModel="IDM" lcModel="LC2013"/>speedFactor=1.05 表示大多数车辆会把目标速度定在限速的 105%,也就是比 120 km/h 稍微超一点;speedDev=0.1 则表示这个期望速度在不同车辆之间有 10% 的标准差。于是路上既有开 110 的稳重型,也有开 135 的激进型,超车行为才开始自然出现。如果没有 speedDev,所有车都是同一个希望速度,不会有真正的速度差,换道模型也很难发挥作用。
标定车流时,我一般先跑到 1200 秒,看两个东西:一是车辆平均速度是否在限速范围内,如果平均速度接近 130 且持续时间很长,说明流量太稀,要降 probability 或减少 number;二是入口是否持续积压,如果车辆排到起点外侧,说明流量需求超过了道路容量,要降低 flow 的频率,或者把模拟结束时间拉得更长来观察是否真的过饱和。
你还要注意双向路网的车流配置。一份 autobahn.rou.xml 里如果只有一个 route,那只是从一端到另一端的单向流。另一方向需要再定义一个相反的 route,比如把 edges 换成反向的两条 edge,然后再加一个方向相反的 flow。否则模拟结果里有一半的车道完全是空的,看起来就像单行道。
4. 高速公路模拟最常见的四个坑:现象、原因、解决
4.1 只有路网没有车:双击 net.xml 打开是常见失误
现象:sumo-gui 打开了 autobahn.net.xml,看到高速路网好好地躺在那里,但一辆车都不出现,点了开始按钮也没反应。
原因:net.xml 只是静态地图,车流信息全在 autobahn.rou.xml 里。直接打开 net.xml,SUM O 根本不知道要跑什么车,也没有时间轴。很多人会误以为“路网离开 GUI 后还要手动导入车流文件”,其实是不用导的,问题出在启动方式。
解决:统一用 sumo-gui -c autobahn.sumocfg 启动。如果确实想先确认路网结构,可以在 GUI 里打开 net.xml 看,但跑车流一定要走 cfg。另外顺手检查 sumocfg 里 route-files 的 value 是否指向 autobahn.rou.xml 且文件存在,路径大小写、目录层级都不能错。
4.2 启动报错:No nodes found in net
现象:命令行一执行 sumo 就报 “Error: No nodes found in net” 之类,实际打开 net.xml 又觉得节点都在。还有一种情况是 netedit 打开路网时一片空白,报节点缺失。
原因:最常见的来源是手工改过 net.xml。比如你想改一条限速,用记事本直接替换了 speed 值,但不小心删掉了一个 node 标签;又或者文件被存成了带 BOM 的 UTF-8,SUMO 解析 XML 时把第一个节点名称读成了乱码。
解决:不要用记事本直接改 net.xml,尤其是不要在没备份的情况下动原文件。如果文件已经损坏,先做语法检查,再用 netconvert 重建:
xmllint --noout autobahn.net.xml netconvert --input-file autobahn.net.xml --output-file autobahn_fixed.net.xmlxmllint 只检查 XML 是否合法,netconvert 会把节点和边的关系重新梳理一遍。注意 netconvert 重建会清掉部分自定义连接,所以修完之后仍然要用 netedit 检查一遍关键匝道和换道连接。如果报错源头是 BOM,用 vscode 或 notepad++ 把文件另存为 UTF-8 无 BOM 即可。
4.3 车辆在入口排队但一动不动
现象:模拟开始后,车辆在高速起点处排成长队,速度全部变成 0,看起来像堵死。你调大了限速、改了车流量也没改善。
原因:这是 route 引用不匹配的典型表现。autobahn.rou.xml 里的 route 的 edges 属性如果写了 net.xml 里不存在的 edge id,车辆就无法进入有效路线;另一种常见情况是 flow 的 begin 和 end 设置在模拟时间之外,比如 cfg 的 end=600,但 flow 的 begin=1800,车根本来不及生成。还有一种容易忽略的原因:同一个 vehicle ID 被重复声明,SUMO 只会使用第一条,后面的车被跳过。
解决:先对比路网里的车道 ID 和路线里的 edge ID 是否对得上。
grep '<edge id=' autobahn.net.xml | head -20 grep '<route' autobahn.rou.xml这两行命令能快速暴露手滑改错 ID 的问题。如果 edge id 都对得上,再看 cfg 的时间区间,建议把 begin 设成 0,end 至少设成 3600。检查完这两处,入口排队不动的问题基本能解决。如果车是在高速中段排成波浪,那不是 route 错误,而是流量过饱和,属于合理现象,不要在同一处继续浪费精力。
4.4 高速上车辆频繁换道,像在玩贪吃蛇
现象:模拟动画里,车辆在八条车道之间反复横跳,刚换了左道又换回右道,速度曲线跟着剧烈震荡,看着特别“神经质”。
原因:多半是 vType 里没有设置速度分布,所有车目标速度一致,导致同一车道内的速度差被压缩,换道模型对外侧车道的速度差异特别敏感;再者,LC2013 的默认激进参数在连续多车道场景下偏高。
解决:给 vType 加上 speedFactor 和 speedDev,让车速天然有差异,然后再调换道权重:
<vType id="calm" vClass="passenger" maxSpeed="33.33" carFollowModel="IDM" lcModel="LC2013" speedFactor="1.05" speedDev="0.1" lcStrategic="0.6" lcCooperative="0.2" lcSpeedGain="0.4" lcKeepRight="1.0"/>lcStrategic 控制车辆“这趟换道值不值”的倾向,降低它能让车不那么见缝插针;lcCooperative 控制车辆是否愿意为别人换道减速或让行,调低后减少协同换道导致的连锁动作;lcKeepRight 调高让车辆在完成超车后主动回到右侧车道。加上这些之后,高速模拟里的换道频率会明显正常很多。如果还是抖,把 tau 调到 1.5 秒以上,驾驶员反应变慢,车流的自我激化会减轻。
5. 把模拟变成可分析的数据:轨迹导出、edgeData 统计与 TraCI 实时控制
5.1 用 FCD 导出车辆轨迹
光看 GUI 动画没法量化分析,真正干活要从 SUMO 里把数据倒出来。FCD(Floating Car Data)是最常用的一种,它就像给每辆车装了 GPS,每秒记录一次位置和速度。命令行里加两个参数就行:
sumo -c autobahn.sumocfg --fcd-output fcd_out.xml如果你后续要做地理坐标系下的可视化,可以再加--fcd-output.geo,让输出的坐标从 SUMO 投影坐标变成经纬度。FCD 文件的 XML 结构很规律,最外层是 timestep,里面是每辆车的 vehicle 标签。
拿到文件后,我一般用 Python 解析:
import xml.etree.ElementTree as ET tree = ET.parse("fcd_out.xml") root = tree.getroot() for timestep in root.findall("timestep"): t = float(timestep.get("time")) for veh in timestep.findall("vehicle"): if float(veh.get("speed")) > 30.0: print(t, veh.get("id"), veh.get("speed"))这段代码的作用是筛选出所有速度超过 30 m/s 的车辆记录。实际使用时,你可以把条件换成速度方差、加速度,或者某一段车道内的出现次数。FCD 数据量很大,跑 3600 秒、几百辆车会产生十几万行记录,所以建议只在需要做逐车行为分析时导出,平时不要一直开着。
5.2 edgeData 输出:统计车道的密度与平均速度
FCD 是“车视角”,edgeData 是“路视角”。它能按固定时间窗口统计每一条 edge 上的车辆密度、平均速度和旅行时间。对高速模拟做宏观评估,这个输出比 FCD 更好用。
sumo -c autobahn.sumocfg --edgedata-output edgedata.xml默认情况下,SUMO 会按模拟时间分段输出,比如每 60 秒一个 interval。XML 里能看到类似结构:每个 interval 下面挂若干 edge,每个 edge 有 density、averageSpeed、traveltime 这些属性。density 的单位是车辆每公里每车道,averageSpeed 是 m/s,traveltime 是这一路段在当前统计周期内的通行秒数。
解析思路和 FCD 差不多,用 ET 遍历 interval 再取 edge 标签。如果你想比较早高峰和平峰的区别,就把 cfg 的 begin/end 分别设成不同时段,然后分别导出。这个步骤看起来简单,但它是后续画“流量-密度散点图”的第一步,很多项目的关键结论都从这张图里来。
5.3 TraCI:在模拟过程中“伸手进去”改限速和车流
FCD 和 edgeData 都是“跑完之后看回放”,TraCI 则是让 SUMO 变成一个实时服务器,你用 Python 当客户端,在模拟进行的过程中直接修改车辆、信号灯和路网状态。这是做自动驾驶策略测试最常用的一层接口。
import traci traci.start([ "sumo", "-c", "autobahn.sumocfg", "--remote-port", "9999", "--start", "--quit-on-end" ]) step = 0 while step < 3600: traci.simulationStep() # 在第600秒模拟一次高速临时限速 if step == 600: traci.edge.setMaxSpeed("hz_eb", 20.0) # 每秒记录前10辆车的速度 ids = traci.vehicle.getIDList()[:10] for vid in ids: speed = traci.vehicle.getSpeed(vid) print(step, vid, speed) step += 1 traci.close()traci.start 传入的是 SUMO 启动命令,--remote-port 指定通信端口。traci.simulationStep() 是每次推进一个时间步,默认步长固定为 1 秒。traci.edge.setMaxSpeed 可以把指定边的限速临时降下来,这个操作在纯 sumo 命令行里做不到,只能通过 TraCI 做实时干预。traci.vehicle.getIDList() 返回当前所有车辆的 ID,getSpeed 返回的是当前速度,单位是 m/s。
如果你要做批量参数扫描,这一段代码还可以继续包一层循环,比如把 flow 的 probability 从 0.05 到 0.5 逐个跑一遍,每次都从 TraCI 取密度和平均速度。注意 TraCI 模式下 SUMO 是 server 角色,程序结束时必须调 traci.close(),否则下次启动会报端口占用。
6. 把 gift178 场景调出真高速:四个验证习惯
拿到 gift178 这个场景,最后怎么判断你的模拟“像不像一条高速”?我的习惯是做四个验证,它们比直接看动画更有说服力。
第一,先跑一遍原始配置,留底。把速度、流量、旅行时间都记录成一组 baseline,之后任何调参都拿它做对照组,否则你很难知道是 vType 改好了,还是 flow 数量碰巧补了漏洞。
第二,用 edgeData 画流量-密度散点图。高速公路的宏观基本图应该是一个倒 U 形:流量先随密度上升,到临界密度后下降,最后进入拥堵区间。如果你看到密度一直涨、速度还保持很高,那说明 flow 里的车辆没有真正形成跟驰,多半是 vType 的 tau 或 carFollowModel 设置有问题。
第三,检查 vType 有没有速度分布。没有 speedFactor 和 speedDev 的高速模拟,平均速度高得离谱,所有车像被护送的阅兵方队。加上这两个参数后,换道才开始是“因为前面车慢”而不是“随机行为”。
第四,在中间路段用 TraCI 做一次临时限速,观察有没有排队波向上游传播。真实高速上,某一点突然限速或事故,会形成向上游扩散的慢速波。如果你的模拟里,限速只影响那一小段,上游车辆还在全速冲过来,说明跟驰模型没有把“前方拥堵”的信息正确往后传递。这是高速公路模拟有效性最直观的一次冒烟测试。
我第一次拿这个包,只改了 flow 的 number 就把结果交出去,结果平均速度一个比一个离谱,后来才发现是 vType 没设速度分布。从那以后我每次拿到新场景,都强制走一遍这四步,至少能拦住九成的低级翻车。希望帮到你。
本文还有配套的精品资源,点击获取