3. 路网基础:SUMO路网文件结构(.net.xml)、使用netedit创建简单路网、路网元素(节点、边、车道)
各位同学,欢迎来到路网基础这一章。说实话,做SUMO仿真,路网就是你的画布。没有一张好的路网,再牛的传感器算法也跑不起来。我自己刚接触SUMO那会儿,就被.net.xml这个文件结构搞得有点懵。今天咱们就把这块硬骨头啃下来。
3.1 .net.xml文件结构——SUMO路网的“骨架”
SUMO的路网文件,后缀是.net.xml。说白了,它就是一个XML格式的文本文件。你用记事本都能打开看。但别小看它,里面记录了所有路网信息。
我习惯把.net.xml比作一张城市的“电子地图”。它不光是画了几条线,而是把每条路、每个路口、每条车道甚至限速都写进去了。咱们来看看它的核心结构:
<?xml version="1.0" encoding="UTF-8"?>
<net version="1.16" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/net_file.xsd">
<!-- 1. 位置信息 -->
<location netOffset="0.00,0.00" convBoundary="0.00,0.00,1000.00,1000.00" origBoundary="0.00,0.00,1000.00,1000.00" projParameter="!"/>
<!-- 2. 边(Edge)定义 -->
<edge id="edge1" from="node1" to="node2" priority="1" numLanes="2" speed="13.89" type="highway">
<lane id="edge1_0" index="0" speed="13.89" length="500.00" shape="0.00,0.00 500.00,0.00"/>
<lane id="edge1_1" index="1" speed="13.89" length="500.00" shape="0.00,3.20 500.00,3.20"/>
</edge>
<!-- 3. 节点(Junction)定义 -->
<junction id="node1" type="priority" x="0.00" y="0.00" incLanes="" intLanes="" shape="0.00,0.00 0.00,3.20 3.20,3.20 3.20,0.00"/>
<junction id="node2" type="priority" x="500.00" y="0.00" incLanes="edge1_0 edge1_1" intLanes="" shape="500.00,0.00 500.00,3.20 503.20,3.20 503.20,0.00"/>
<!-- 4. 连接(Connection)定义 -->
<connection from="edge1" to="edge2" fromLane="0" toLane="0" via=":node2_0"/>
</net>
嗯,这里要注意几个关键点:
- location:定义路网的地理坐标偏移。说白了就是你的路网在虚拟世界里的位置。
- edge:就是一段路。它连接两个节点。每个edge可以包含多条lane(车道)。
- junction:节点,也就是路口。它记录了路口的位置和形状。
- connection:连接关系。它告诉SUMO,车辆从一条边的某条车道,怎么拐到另一条边的某条车道。
我在项目中遇到过一个问题:手动修改.net.xml时,把connection写错了。结果车辆到了路口直接“消失”了。后来排查了半天,才发现是连接关系没对上。所以,能不手写就别手写,用netedit它不香吗?
3.2 使用netedit创建简单路网——可视化操作才是王道
netedit是SUMO自带的图形化路网编辑器。我个人强烈建议,初学者先用它来创建路网。你想想看,拖拖拽拽就能生成一个路网,多省心。
咱们来创建一个最简单的十字路口路网:
- 启动netedit:在终端输入
netedit回车。或者从SUMO的安装目录里找到netedit.exe双击。 - 创建节点:点击工具栏上的“创建节点”按钮(像个圆点)。在画布上点4个点,分别作为路口的四个方向。比如:(-200, 0)、(200, 0)、(0, -200)、(0, 200)。
- 创建边:点击“创建边”按钮(像个线段)。从一个节点拖到另一个节点,就生成了一条路。把四个节点两两连接起来,形成一个十字。
- 设置车道数:双击某条边,在右侧属性面板里,把
numLanes改成2。这样这条路就有两条车道了。 - 保存路网:点击文件 -> 保存网络,起个名字比如
my_cross.net.xml。
你看,就这么简单。一个十字路口路网就出来了。我记得第一次用netedit的时候,花了不到5分钟就画了一个小县城的路网。虽然简陋,但跑仿真完全没问题。
3.3 路网元素深度解析——节点、边、车道
咱们把这三个核心元素掰开揉碎了讲。你理解了它们,就理解了SUMO路网的80%。
3.3.1 节点(Junction)
节点就是路口。它可以是十字路口、丁字路口、环岛,甚至是一条路的尽头。每个节点都有一个唯一的ID。节点的类型决定了车辆在路口的行为:
- priority:优先权路口。主路车辆优先,支路车辆等待。
- traffic_light:信号灯路口。车辆根据红绿灯通行。
- right_before_left:右侧先行。欧洲常见的规则。
- dead_end:死胡同。车辆到了这里只能掉头或消失。
我曾经在一个项目中,把路口类型设成了priority,但实际路口是有红绿灯的。结果仿真里车辆互不相让,堵成一锅粥。后来改成traffic_light才正常。所以,路口类型一定要跟实际情况匹配。
3.3.2 边(Edge)
边就是一段道路。它连接两个节点。边的属性决定了这段路的物理特性:
- id:唯一标识。比如
edge1、road_abc。 - from / to:起点节点和终点节点的ID。
- numLanes:车道数量。双向车道需要分别创建两条边。
- speed:限速,单位是m/s。比如13.89 m/s 约等于 50 km/h。
- priority:优先级。数值越高,车辆越倾向于走这条路。
- type:道路类型。比如
highway、primary、residential。
你想想看,如果一条城市道路限速设成了100 km/h,那仿真出来的车辆就跟飞一样,完全不真实。所以,限速一定要按实际来设。
3.3.3 车道(Lane)
车道是边的一部分。每条边可以有1条或多条车道。每条车道都有自己的ID,格式是 边ID_车道索引。比如 edge1_0 表示 edge1 的第0条车道(索引从0开始)。
车道的属性包括:
- index:车道索引。0是最右侧车道,依次向左递增。
- speed:该车道的限速。可以跟边的限速不同。
- length:车道长度。通常跟边的长度一致。
- shape:车道的几何形状。是一系列坐标点。
- allow / disallow:允许/禁止的车辆类型。比如可以禁止公交车走某条车道。
嗯,这里要注意:车道的索引顺序。在SUMO里,索引0永远是右侧车道。如果你在中国(靠右行驶),那索引0就是慢车道,索引1是快车道。这个跟直觉是反的,我刚用的时候经常搞混。
3.4 知识体系结构图
下面这张图,是我自己总结的SUMO路网知识体系。你看一眼,就能明白今天讲的内容在整个课程中的位置。
<connection> 标签。仿真的时候,车辆到了路口直接“卡住”,因为SUMO不知道车辆该怎么转弯。所以,用netedit创建路网后,一定要检查连接关系是否完整。你可以用 netcheck 工具来验证路网的正确性。
好了,这一章的内容就到这里。路网是仿真的基础,你花时间把它搞透,后面的传感器仿真才能跑得顺。记住:节点、边、车道,这三个元素你玩明白了,SUMO路网就没什么能难住你的了。