4. 路网编辑进阶:添加车道数、设置车道方向、配置限速和优先权规则
好,咱们继续。上一章我们把路网的基本骨架搭起来了,说白了就是画了几条路,让车能跑起来。但真实的路网哪有这么简单?你想想看,城市主干道至少双向四车道吧,有的路口只能右转,有的路段限速60,有的路口谁先走谁后走……这些才是自动驾驶仿真里真正要较真的细节。
我个人习惯,在SUMO里编辑路网,从来不用那个图形界面点点点——太慢了,而且不好复现。我更喜欢直接撸XML,或者用netedit配合命令行。今天咱们就聊聊,怎么给路网“加料”。
4.1 添加车道数:别让车堵在一条道上
默认情况下,你在SUMO里画一条边(edge),它只有一条车道。这在测试单车道乡村道路时没问题,但你要模拟城市快速路,一条车道肯定不够。
在.net.xml文件里,每条边由<edge>标签定义,车道信息藏在<lane>子标签里。但更直接的方式,是在定义边的时候指定numLanes属性。
核心参数:
numLanes:车道数量,整数。speed:该车道允许的最大速度,单位m/s。length:边的长度,单位米。
举个例子,我想建一条双向六车道的城市主干道,单向三车道,限速60km/h(约16.67m/s)。代码长这样:
<edge id="main_road_east" from="node1" to="node2" numLanes="3" speed="16.67" />
<edge id="main_road_west" from="node2" to="node1" numLanes="3" speed="16.67" />
嗯,这里要注意:SUMO里边的方向是单向的。你要做双向路,就得定义两条方向相反的边。我在项目里见过新手只定义了一条边,结果车全往一个方向跑,另一个方向空空如也——那仿真肯定不对。
小技巧: 如果你用netedit图形界面,选中一条边,在右侧属性面板里直接改numLanes就行。但我还是推荐写脚本批量生成,尤其是大路网,手点能点到手抽筋。
4.2 设置车道方向:哪个车道能左转?哪个只能直行?
车道方向,专业术语叫“转向连接”(turn connections)。它决定了车辆在路口能不能左转、右转、直行或者掉头。
我曾经在一个项目中,因为没配转向连接,所有车到了路口全部直行,死活不转弯。排查了半天,才发现是连接没定义。说白了,SUMO默认路口所有方向都禁止通行,你得手动“放行”。
转向连接定义在<connection>标签里,放在<edge>下面。基本语法:
<connection from="edge_in" to="edge_out" fromLane="0" toLane="0" dir="r" />
参数说明:
| 属性 | 含义 | 取值示例 |
|---|---|---|
from |
进入路口的边ID | main_road_east |
to |
离开路口的边ID | side_road_north |
fromLane |
从哪条车道出来(从0开始) | 0, 1, 2 |
toLane |
进入目标边的哪条车道 | 0, 1 |
dir |
转向方向 | s(直行), l(左转), r(右转), t(掉头) |
举个例子,一个十字路口,东向西方向最左侧车道(车道0)允许左转,中间车道(车道1)允许直行:
<connection from="east_in" to="north_out" fromLane="0" toLane="0" dir="l" />
<connection from="east_in" to="west_out" fromLane="1" toLane="0" dir="s" />
避坑指南: 我曾经犯过一个错——把fromLane和toLane搞反了。结果车从最右侧车道左转,直接骑到对向车道上去。记住:fromLane是当前边的车道编号,toLane是目标边的车道编号。车道编号都是从0开始,最右侧是0。
4.3 配置限速:不同车道不同速度
限速这事,在SUMO里可以精细到每条车道。你想想看,城市快速路最左侧车道限速100,最右侧因为有汇入车辆,限速80,这很常见吧?
在<lane>标签里直接设置speed属性即可。如果你用<edge>的speed属性,那所有车道速度都一样。要精细控制,就得显式写出每个<lane>。
<edge id="highway_east" from="n1" to="n2" numLanes="3">
<lane index="0" speed="22.22" /> <!-- 最右侧,限速80km/h -->
<lane index="1" speed="25.00" /> <!-- 中间,限速90km/h -->
<lane index="2" speed="27.78" /> <!-- 最左侧,限速100km/h -->
</edge>
注意,SUMO里速度单位是m/s,别直接写80。换算公式:km/h ÷ 3.6 = m/s。80km/h ≈ 22.22m/s。我刚开始做的时候,直接写了个80,结果车跑得跟飞机一样快……
4.4 优先权规则:谁先走谁后走
优先权,说白了就是路权。没有信号灯的路口,谁该让谁?SUMO里用priority属性来控制。
优先权值越高,在该路口越有优先通行权。默认值是-1,表示未定义。通常主路优先权高,支路优先权低。
设置方式有两种:
- 在
<edge>上设置:该边所有车道统一优先权。 - 在
<junction>的<request>里设置:更精细,可以控制每个转向的优先级。
简单场景,我们直接在边上设:
<edge id="main_road" from="n1" to="n2" priority="3" />
<edge id="side_road" from="n3" to="n4" priority="1" />
这样,主路上的车在路口不用让行,支路上的车必须等主路没车了才能走。
实际项目经验: 我在做园区无人配送车仿真时,就靠这个优先权规则模拟了“主路先行”的场景。配送车从支路出来,遇到主路有车就自动停车等待,效果非常真实。但要注意,优先权只适用于无信号灯路口。如果有红绿灯,优先权设置会被覆盖。
4.5 知识体系总览
说了这么多,咱们用一张图把今天的内容串起来。这张图是我自己画的知识结构,你一看就明白这些参数之间的关系了。
这张图把今天讲的四个核心点串起来了。你配置路网的时候,按这个顺序来,基本不会漏东西。
4.6 实战小练习
光看不练假把式。我给你留个小任务:
- 创建一个十字路口,东西方向是双向四车道主路(限速60km/h),南北方向是双向两车道支路(限速40km/h)。
- 配置转向连接:主路最左侧车道可以左转,中间两车道直行,最右侧车道右转。
- 设置优先权:主路优先权为3,支路为1。
做完这个练习,你对路网编辑的基本功就算扎实了。下次咱们聊信号灯和检测器,那又是另一番天地。
最后说一句: 路网编辑这事,熟能生巧。我刚开始也是对着XML一行行改,后来写了个Python脚本批量生成,效率高多了。等你把基础搞熟了,也可以试试自动化生成路网。