bin
包含了一些可执行文件 主要包含了 netedit.exe, sumo-gui.exe,netconvert.exe(用于把网上下载下来的地图转成路网文件),jtrrouter.exe (可使用车流量、各个路口的转弯xx来实现仿真)
data
包含了一些 sumo软件需要的配置 ,比如字体、logo
doc
包含了一些案例,教程,文档
tools
包含了一些工具,比如traci ( sumo dos 的python的包 可以对仿真软件实时交互,控制红绿灯 车辆行驶状态)
打开OpenStreetMap官网 https://www.openstreetmap.org/
点击导出(Export)
如果觉得这个范围不满意,那么可以手动选择不同的区域(Manually select a different area)
来到下载路径,我们唤出cmd
输入命令
netconvert --osm-files OSM文件路径 -o 路网存储路径
例如
netconvert --osm-files gdut.osm -o gdut.net.xml
会发现有新的路网文件“gdut.net.xml”生成
即可打开生成的路网文件
File tab: 包含了新建网络、新建窗口、打开网络、打开Netconvert 配置、导入外部网络等功能
Modes tab: 这里包含了很多模式,后面使用到会有讲解
点击创造边模式
在我们新建的network上点出有4条边 中心点为同一个点的图形
选择检查模式 inspect
分别为中间点(0,0),其他点为(0,100),(0,-100),(100,0),(-100,0)
点击某一条边,右击它,选择边操作edge operations,里面会有很多边相关的操作
这里我们试着使用 Add reverse direction for edge在这两个点中间添加一条和我们选中的边相反方向的路
然后我们进行保存,我这边保存名为test.net.xml
,可以看到network生成了一个十字路口
我们可以试着编辑车道,使用inspect模式点击某一条边,修改他的numLanes参数
比如说我希望他车道数为3,那我们就把numLanes设置为3
我们把全部方向的路设置为三车道后,按下保存按钮 就会生成新的交叉口
我们取消掉 Select edges or lanes
这样子我们可以选择单个车道
我们可以设置单个车道的速度 宽度等属性,这里我们设置速度上限为16,宽度为6米,可以看出这条车道明显的比其他车道粗
我们可以设置每一条车道可以往哪一条车道走,即可以设置它为直行道还是左转直行、右转执行等等车道
我们选用连接模式(Set connection mode)
选用某一条路道,这里我们选择上方最左的路道,点击它
蓝色是源车道(Source lane),也就是当前车道
黑色是对向车道
黄色的车道是冲突车道(Conflict),是sumo禁止前往的车道,但是我们可以通过按住ctrl加点击强制使其变成Target lane
浅绿色是目标车道(Target lane),是sumo规定可以选择前往的,用户也规定可以前往的车道
深绿色是可能车道(Possible Target),是sumo规定可以选择前往的,用户规定不可以前往的车道。
点击绿色的车道可以改变其深浅色,也就是改变是否可以前往该车道。
这里我点击了左侧最上的车道,可以看见原本的左侧最上车道是target lane ,现在变成了possible lane
我们再强制把下方车道都变成targe lane,按住ctrl 点击下方的黄色车道
可以看出conflict车道也可以变成target lane
我们需要选择红绿灯模式Set traffic light mode
点击十字路口(深红色部分)
从左边编辑栏中 我们可以看到这是J4红绿灯,我们选择Create来创建一个红绿灯程序
我们可以看到左下角相位(Phases)这一栏 已经帮我们设计了一个简单的4相位交通灯
可以依次点击它们查看不同的相位
我们可能好奇相位里的dur和state是什么内容
dur即duration,延时 就是该状态的时间
state即状态 表示不同车道的状态,我们可以选择一条路道进行查看
我们先回到相位1 ,再点击上方最左的车道到左方最上的车道 这条线,右击它
我们可以看到这个相位中 J4 红绿灯 0车道的状态是Red,也就是红灯,
我们解释一下几个常用的颜色
我们把这里设置为Green-Major
可以看到相位1的state中的0车道的状态已经从r变成G
我们可以使用公交车操作(Set additional mode)来给某一条边添加公交车
我们选择公交车操作后 点击一条边
就会在这条边上添加一个公交车站,切换到检查模式 inspect,点击公交车站
可以看到busstop的属性 比如起始位置 结束位置(指的是在这条车道的哪个位置)等等 我们可以进行修改
在netedit中,人行横道需要在点(两边或多边之间)上才可以生成,这里我们分别介绍在已有路口插入人行横道和在马路中插入人行横道
我们首先需要选用人行横道模式(set crossing mode)
点击红色的路口
选择边进行生成,这里我们选择了E6和-E6,可以看到E6和-E6变成了浅绿色,也就是左下方解释的Selected选中模式,而其他深绿色的就还依然是Candidate候选模式
点击Create crossing,创建一条人行横道
接下来我将介绍如何在马路中插入人行横道,假设我们希望在此处插入人行横道
我们在这中间再添加一个点,使这里变成E6和E0、-E6和-E0的交接口,然后再添加一个人行横道即可
人工定义路网 需要大量人工编写xml 既复杂 又容易出错
netconvert不仅仅为我们提供了从osm路网文件转换为sumo路网文件的功能,还为我们提供了通过节点(node)、边(edge)、类型(type)文件生成路网文件或者节点、边、连接(connection)生成路网文件等等的功能。
我们打开sumo软件的源目录,来到doc\examples\netconvert\types\cross_notypes
文件夹,
可以看到他为我们准备了三个文件
我们输入以下命令
netconvert --node-files=input_nodes.nod.xml --edge-files=input_edges.edg.xml --type-files=input_types.typ.xml --output-file=BiangTest.net.xml
生成一个名为BiangTest.net.xml
的路网
语法格式如下
netconvert --node-files=点文件 --edge-files=边文件 --type-files=类型文件 --output-file=输出路径
我们打开sumo软件的源目录,来到doc\examples\connections\cross3l_edge2edge_conns
文件夹,
可以看到他为我们准备了三个文件
这里我教大家如何查看该怎么生成路网的文档
我们打开netconvert的官方文档
官方文档: https://sumo.dlr.de/docs/netconvert.html
在下方input的表格中我们可以找到这三个文件对应的文件类型,
而output和我们之前一样,也是使用以下命令参数
于是我们的命令也就诞生了
netconvert -n=点文件 -e=边文件 -x=连接文件 -o=输出路径
带入内容
netconvert -n=input_nodes.nod.xml -e=input_edges.edg.xml -x=input_connections.con.xml -o=BiangTest.net.xml
输入cmd 按下回车运行
可以看到生成了BiangTest.net.xml
文件
现在我们有了路网文件,距离可以进行车辆仿真就只差路由文件了
路由文件中的边id需要基于路网文件
我们选择第3节中路网文件为本节的路网文件,我们想要做出三辆车 从左侧下方的边 到 右侧下方的边,
我们先在该路网同目录下新建一个文本文件 叫routes.rou.xml
这就是路由文件
路由文件中,根节点是routes
可以在根节点中定义交通工具的类型(vType
),以及交通工具的声明(vehicle
)
在仿真前我们还需要一个sumoconfig文件,这个文件用于规定路网文件、路由文件以及 起始时间、终止时间,我们把这个文件放在路网文件、路由文件的同目录下,起名为example.sumocfg
,内容如下。
<configuration>
<input>
<net-file value="test.net.xml"/>
<route-files value="routes.rou.xml"/>
input>
<time>
<begin value="0"/>
<end value="10000"/>
time>
configuration>
保存后,使用sumo-gui的仿真simulation打开这个文件,修改延时后,点击绿色三角形的运行键,即可开始仿真。
我们先定义一种交通工具,这里用到了vType
元素
字段 | 含义 | 示范值 |
---|---|---|
id | 这种交通工具的id | myType |
vClass | 交通工具的类型 | taxi |
accel | acceleration 加速度(单位 m/s^2) | 0.8 |
decel | deceleration 减速度(单位 m/s^2) | 4.5 |
sigma | 一个在0到1之间的float数值 , 该参数会引入一些随机行为,我估摸着应该像是随机种子 | 0.0 |
length | 交通工具的长度(单位 m) | 5 |
maxSpeed | 交通工具的最大速度(单位 m/s) | 50 |
carFollowModel | 跟车模型 可以使用C++进行自定义 详见:https://sumo.dlr.de/docs/Developer/How_To/Car-Following_Model.html | |
laneChangeModel | 换道模型 | |
tau | 司机期望的最小时距,用于用于维持前一辆交通工具和本体后保险杠的距离,保证最小时距足以及时刹车(单位s) | 1.4 |
actionStepLength | 司机的反应时间长度(单位s) | 1 |
<routes>
<vType id="myType" vClass="taxi" accel="0.8" delcel="4.5" sigma="0.0" length="5" maxSpeed="50" carFollowModel="IDM" actionStepLength="1" tau="1.4" laneChangeModel="SL2015"/>
routes>
有了vType的定义之后我们需要声明它们,于是我们需要用到vehicle
元素
字段 | 含义 | 示范值 |
---|---|---|
id | 这个交通工具的id | veh0 |
type | 规定是哪一种已经定义的交通工具 | myType |
depart | 交通工具在哪一个时间步进入网络 | 0 |
departLane | 交通工具在哪一条车道上被插入 | 1 |
departPos | 交通工具进入路网的位置(和边沿的距离) | 0 |
arrivalLane | 交通工具在哪一条车道上被驶出 | 0 |
arrivalPos | 交通工具离开路网的位置(和边沿的距离 max则从最远处消失,0则从该边的入口消失) | max |
color | 这个交通工具的颜色 | 1,0,0 |
departSpeed | 交通工具进入网络的速度 | 20 |
我们发现这只规定了车道,没有规定边,在不同的边上这辆车的表现也是不同的,我们需要给交通工具们提供一条路径
于是我们给vehicle
添加一个子元素route
指导这辆交通工具选择边的路径
字段 | 含义 | 示范值 |
---|---|---|
id | 这个路由的id | rou0 |
edges | 路线 用途经的边的id作为值,中间用空格隔开 | E8 -E7 |
这里讲一讲E8 -E7的由来,我们打开netedit,选择inspecti模式点击左侧下方的边 和 右侧下方的边 依次可以看到它们的edge id 是E8 和 -E7
于是我们得出我们的路线是“E8 -E7”
<routes>
<vType id="myType" vClass="taxi" accel="0.8" delcel="4.5" sigma="0.0" length="5" maxSpeed="50" carFollowModel="IDM" actionStepLength="1" tau="1.4" laneChangeModel="SL2015"/>
<vehicle id="veh0" type="myType" depart="0" departLane="1" departPos="0" arrivalLane="0" arrivalPos="max" color="1,0,0" departspeed="20">
<route edges="E8 -E7"/>
vehicle>
routes>
我们先在此阶段试着仿真一下,点击绿色三角形的运行键,可以看到一辆红色的车从E8驶向-E7
我们想要做出的是三辆车,希望它们都从E8到-E7,那么我们就可以把route提出去,设置一个id,然后把这个作为route属性给到vehicle
<routes>
<vType id="myType" vClass="taxi" accel="0.8" delcel="4.5" sigma="0.0" length="5" maxSpeed="50" carFollowModel="IDM" actionStepLength="1" tau="1.4" laneChangeModel="SL2015"/>
<route id="rou1" edges="E8 -E7"/>
<vehicle id="veh0" route="rou1" type="myType" depart="0" departLane="1" departPos="0" arrivalLane="0" arrivalPos="max" color="1,0,0" departspeed="20"/>
routes>
我们现在只有一辆车,我们希望做出的是三辆车,于是我们把代码修改为
<routes>
<vType id="myType" vClass="taxi" accel="0.8" delcel="4.5" sigma="0.0" length="5" maxSpeed="50" carFollowModel="IDM" actionStepLength="1" tau="1.4" laneChangeModel="SL2015"/>
<route id="rou1" edges="E8 -E7"/>
<vehicle id="veh0" route="rou1" type="myType" depart="0" departLane="0" departPos="0" arrivalLane="0" arrivalPos="max" color="1,0,0" departspeed="20"/>
<vehicle id="veh1" route="rou1" type="myType" depart="1" departLane="1" departPos="0" arrivalLane="0" arrivalPos="max" color="0,1,0" departspeed="20"/>
<vehicle id="veh2" route="rou1" type="myType" depart="2" departLane="2" departPos="0" arrivalLane="0" arrivalPos="max" color="0,0,1" departspeed="20"/>
routes>
值得注意的是如果这三辆交通工具departLane的值都是一样的,即使depart值都一样,也会按照从上到下顺序依次出现,不会出现立刻相撞的现象,但是我们还是尽量不要这么做,应当严格控制好depart的顺序。
而且,如果depart的值没有按照顺序从上到下从小到大的话,只要存在上面的一个vehicle的depart大于本身的,那么本身的vehicle就不会被仿真,像以下这样
<routes>
<vType id="myType" vClass="taxi" accel="0.8" delcel="4.5" sigma="0.0" length="5" maxSpeed="50" carFollowModel="IDM" actionStepLength="1" tau="1.4" laneChangeModel="SL2015"/>
<route id="rou1" edges="E8 -E7"/>
<vehicle id="veh0" route="rou1" type="myType" depart="1" departLane="0" departPos="0" arrivalLane="0" arrivalPos="max" color="1,0,0" departspeed="20"/>
<vehicle id="veh1" route="rou1" type="myType" depart="2" departLane="1" departPos="0" arrivalLane="0" arrivalPos="max" color="0,1,0" departspeed="20"/>
<vehicle id="veh2" route="rou1" type="myType" depart="0" departLane="2" departPos="0" arrivalLane="0" arrivalPos="max" color="0,0,1" departspeed="20"/>
routes>
veh2不会被仿真
既然三辆车的行为都大致一致,我们便可以用车流来形容它们,我们便可以使用flow
元素来实现这一功能
字段 | 含义 | 示范值 |
---|---|---|
id | 这个flow的id | flo0 |
number | 出来多少俩交通工具 | 3 |
period | 出来交通工具的周期 | 1 |
begin | 第一辆交通工具出现在路网的时间 | 0 |
end | 生成交通工具的总时间 原文: end of departure interval | 1000 |
flow
元素可以使用vehicle
的属性
<routes>
<vType id="myType" vClass="taxi" accel="0.8" delcel="4.5" sigma="0.0" length="5" maxSpeed="50" carFollowModel="IDM" actionStepLength="1" tau="1.4" laneChangeModel="SL2015"/>
<route id="rou1" edges="E8 -E7"/>
<flow id="flo0" type="myType" route="rou1" number="3" period="1" departPos="0" departLane="random"/>
routes>
如果我们想要修改一下目的地,不再让它从E8到-E7,而是希望它可以按照某个概率分布去到-E7、E3(上方右侧)或者 E6(下方左侧)
在本例中我们选择使用flow文件和turn文件通过jtrrouter来生成route文件
官方文档:https://sumo.dlr.de/docs/Demand/Routing_by_Turn_Probabilities.html
我们新建flow文件 input_flows.flows.xml
,内容如下
<routes>
<flow id="flo0" from="E8" begin="0" end="1000" number="100" arrivalPos="max"/>
routes>
再新建turn文件 input_turns.turns.xml
,内容如下
<edgeRelations>
<interval begin="0" end="10000">
<edgeRelation from="E8" to="-E7" probability=".3"/>
<edgeRelation from="E8" to="E3" probability=".4"/>
<edgeRelation from="E8" to="E6" probability=".3"/>
interval>
<sink edges="-E7"/>
<sink edges="E3"/>
<sink edges="E6"/>
edgeRelations>
解释起来也很容易 ,在interval
元素中 属性包括了这个转向的起始时间以及结束时间,edgeRelation
元素指明了是从哪个边起始,往哪个边去,概率为多少,下方的sink
元素规定了可以以-E7、E3和E6三条边作为目的地。
使用下方命令,生成路网文件
jtrrouter --route-files=input_flows.flows.xml --turn-ratio-files=input_turns.turns.xml --net=test.net.xml --output-file=routes.rou.xml
事实上我们也可以不用jtrrouter生成路由文件,我们可以直接修改sumoconfig文件,像以下这样
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/jtrrouterConfiguration.xsd">
<input>
<net-file value="test.net.xml"/>
<route-files value="input_flows.flows.xml"/>
<turn-ratio-files value="input_turns.turns.xml"/>
input>
<output>
<output-file value="routes.rou.xml"/>
output>
configuration>
使用sumo-gui仿真可以看到,车辆往不同方向开去了
这一节我们讲讲公共交通,先放上官方文档
官方文档:https://sumo.dlr.de/docs/Simulation/Public_Transport.html
我们以公交车为例,我们知道,如果没有公交站,公交车就只是一辆长一些的车,不是所谓的公共交通,所以我们首先需要添加一个公交车站
语法如下:
<busStop id="" lane="" startPos="" endPos="" [lines="[ ]*" ]/>
字段 | 含义 | 示范值 |
---|---|---|
id | 这个busStop的id | bussto1 |
lane | 公交车站所在的车道 | E7_0 |
line | 几号线经停 | 100 101 102 |
像这样
<busStop id="bussto1" lane="E7_0" startPos="35" endPos="50" lines="100 101 102"/>
startPos和endPos在 3.2 netedit路网编辑 公交车操作 中提到过,就是起始地点和结束地点,也就是这个公交车的范围
有了车站没有公交车也是徒劳。这里我们需要介绍vehicle
的新属性line,这个属性则表示该车是几号线;我们还需要知道一个新的元素stop
,这个元素被包含在vehicle
元素中,可以给这个交通工具或者行人有停止功能。
像如下这样,公交车们都在bussto1经停,并停止30秒
<vType id="BUS" accel="2.6" decel="4.5" sigma="0" length="12" minGap="3" maxSpeed="70" color="1,0,0" guiShape="bus"/>
<vehicle id="veh0" type="BUS" depart="0" color="1,1,0" line="100">
<route edges="E7 E6 E0"/>
<stop busStop="bussto1" duration="30"/>
vehicle>
<vehicle id="veh1" type="BUS" depart="35" color="1,0,1" line="101">
<route edges="E7 E6 E0"/>
<stop busStop="bussto1" duration="30"/>
vehicle>
<vehicle id="veh2" type="BUS" depart="70" color="0,1,1" line="102">
<route edges="E7 E6 E0"/>
<stop busStop="bussto1" duration="30"/>
vehicle>
这里的vType使用了一个之前没有用过的属性guiShape,这个属性可以让这辆车的外形发生变化,这里我让他变成一辆公交车
我们新建一个input_additional.add.xml
文件,给里面添加以下内容,(其实就是上面的内容)
<additional xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/additional_file.xsd">
<busStop id="bussto1" lane="E7_0" startPos="35" endPos="50" lines="100 101 102"/>
<vType id="BUS" accel="2.6" decel="4.5" sigma="0" length="12" minGap="3" maxSpeed="70" guiShape="bus"/>
<vehicle id="veh0" type="BUS" depart="0" color="1,1,0" line="100">
<route edges="E7 E6"/>
<stop busStop="bussto1" duration="30"/>
vehicle>
<vehicle id="veh1" type="BUS" depart="35" color="1,0,1" line="101">
<route edges="E7 E6"/>
<stop busStop="bussto1" duration="30"/>
vehicle>
<vehicle id="veh2" type="BUS" depart="70" color="0,1,1" line="102">
<route edges="E7 E6"/>
<stop busStop="bussto1" duration="30"/>
vehicle>
additional>
这里我们需要注意的是,我们需要将additional文件的路径写入sumoconfig文件,即需要把sumoconfig文件修改为下面的样子
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/sumoConfiguration.xsd">
<input>
<net-file value="test.net.xml"/>
<route-files value="routes.rou.xml"/>
<additional-files value="input_additional.add.xml"/>
input>
<time>
<begin value="0"/>
<end value="10000"/>
time>
configuration>
随后开始仿真
可以看到有三辆就会从E7 开到公交车站然后停止30秒后,继续开往E6
我们这个小节介绍行人的行为,本小节中我们将实现召唤行人从E8到-E7,在E7坐102号车到E0等等这一行为
官方文档:https://sumo.dlr.de/docs/Specification/Persons.html
行人的行为我们写在route文件中 ,routes
元素下
<person id="person0" depart="51.00" color="0,0,1">
<walk from="E8" to="-E7"/>
person>
<person id="person1" depart="55.00" color="0,1,0">
<walk from="-E7" to="E8"/>
person>
<person id="person2" depart="59.00" color="1,0,0">
<walk from="E8" to="-E7"/>
person>
其中person的行为被包在person
元素中,walk
定义了从哪里走到哪里,ride
定义了从哪里坐车到哪里,坐几号线
<person id="person2" depart="0.00" color="1,0,0">
<walk from="E3" to="E7"/>
<ride from="E7" to="E0" lines="101"/>
<walk from="E0" to="-E6"/>
person>
<person id="person0" depart="51.00" color="0,0,1">
<walk from="E8" to="-E7"/>
person>
<person id="person1" depart="55.00" color="0,1,0">
<ride from="E7" to="E0" lines="102"/>
person>
记得 在同一个文件中的person和vehicle depart顺序需要严格遵守从上到下从小到大
这里input_additional.add.xml
也需要相应的修改,不然这些person可能还没坐上公交车,车就先跑路了
<additional xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/additional_file.xsd">
<busStop id="bussto1" lane="E7_0" startPos="35" endPos="50" lines="100 101 102"/>
<vType id="BUS" accel="2.6" decel="4.5" sigma="0" length="12" minGap="3" maxSpeed="70" guiShape="bus"/>
<vehicle id="veh0" type="BUS" depart="0" color="1,1,0" line="100">
<route edges="E7 E6 E0"/>
<stop busStop="bussto1" duration="30"/>
vehicle>
<vehicle id="veh1" type="BUS" depart="35" color="1,0,1" line="101">
<route edges="E7 E6 E0"/>
<stop busStop="bussto1" duration="30"/>
vehicle>
<vehicle id="veh2" type="BUS" depart="70" color="0,1,1" line="102">
<route edges="E7 E6 E0"/>
<stop busStop="bussto1" duration="30"/>
vehicle>
additional>
让我们仿真看一下效果
像这个案例中,行人person2会先从E3走到E7,再从E7坐101号车到E0,这里需要注意的是,由于我们的公交车站只有一个站,所以person2会在公交车离开仿真后,出现在E0尽头,再走到-E6
这一节我们讲讲物流运输Logistics
官方文档:https://sumo.dlr.de/docs/Specification/Logistics.html
containerStop 集装箱站/容器站在sumo中可以被用来存储货物。和busStop公交车站可以容纳person人类似,containerStop可以容纳container集装箱。containerStop和busStop都需要车辆先靠近才可以进行相关行为。
containerStop在additional文件中的定义如下:
<additional>
<containerStop id="" lane="" startPos="" endPos="" [line="[ ]*" ]/>
...
additional>
属性上和busStop无差,这里我就不赘述。
举个例子,我们希望在车道E3_0上50到64的位置上创建一个集装箱站,线路号包含400 401 402。
<containerStop id="containerstop1" lane="E3_0" startPos="50" endPos="64" lines="400 401 402"/>
我们再加上一辆会停靠在这个containerstop1的卡车,如何定义卡车呢?和bus一样,只需要修改vehicle的vType的length和guiShape属性即可
<vType id="truck" accel="2.6" decel="4.5" sigma="0" length="12" minGap="3" maxSpeed="70" guiShape="truck"/>
<vehicle id="veh3" type="truck" depart="0" color="1,1,1" line="400">
<route edges="-E0 -E6 E3"/>
<stop containerStop="containerstop1" duration="20"/>
vehicle>
记得将additional文件绑定到sumoconfig文件中,开始仿真
可以看到一辆卡车从-E0驶向-E6又驶向E3,并在E3_0的containerstop1停下20秒,然后再离开
更多内容还得查看文档,这里就不赘诉
官方文档:https://sumo.dlr.de/docs/Definition_of_Vehicles%2C_Vehicle_Types%2C_and_Routes.html
除了我们前面有讲到的netconvert、jtrrouter以外,sumo还提供了非常多的有用的工具,我们将在这一章节举几个常用的进行讲解。
工具duaIterate.py可用于计算(近似)动态用户平衡。
官方文档:https://sumo.dlr.de/docs/Demand/Dynamic_User_Assignment.html
DUA即Dynamic User Assignment,动态用户分配
我们首先需要知道什么是用户分配。根据官方文档,
The problem of determining suitable routes that take into account travel times in a traffic-loaded network is called user assignment.
也就是说 在一个交通负荷路网中,考虑通行时间的来确定合适的路线的问题就叫做用户分配 。
duaIterate试图计算一个用户平衡,它将尝试为各个交通工具找到一个路线使得找不到另外一条路线能够让他们的出行成本(往往是时间)降低。
它通过以下两个步骤迭代
值得注意的是,以上两个操作的反复迭代需要占用大量的磁盘空间
我们可以在sumo文件夹下使用以下命令来调用duaIterate
python tools/assign/duaIterate.py -n -t -l
这里nr-of-iterations指的是the number of iterations ,即迭代次数
在DUAIterate中的算法这里就不详细解释,后续有机会会专门出一篇来讲
DUArouter是动态用户分配路由,用于在具有最后已知边的成本的网络中给交通工具们找路线。
官方文档:https://sumo.dlr.de/docs/duarouter.html
Duarouter 有两个主要目的:
它可以根据根据需求定义构建车辆路线,可以在用户分配期间计算路由,还能修复现有路由文件中的连接问题
我们打开sumo源目录下的doc\examples\duarouter\flows2routes
,简单的尝试一下理解这个工具的作用
已知我们有input_flows.flows.xml、input_net.net.xml文件,我们想要生成一个路由文件routes.rou.xml
我们可以使用命令
duarouter -n input_net.net.xml --route-files input_flows.flows.xml -o routes.rou.xml
-n属性指的是路网文件,–route-files属性放的是flow文件或者route文件,-o属性指的是输出的路由文件
执行成功后可以看到生成两个文件,分别是routes.rou.alt.xml、routes.rou.xml
这个alt路由文件被称为备选路由文件(route alternative file )。它不仅用于记录当前的最佳路线,还用于记录之前计算的替代路线。这些路线收集在路线分布中,并在决定在下一个模拟步骤中行驶的实际路线时使用。这并不总是当前成本最低的,而是通过可配置算法从替代路线的分布中抽样出来的。 它为每辆车保存一个 routeDistribution。这样的routeDistribution可以在DUAIterate做动态用户分配期间使用,但也可以直接加载到sumo中。
如果觉得使用命令有些繁琐,可以选择它提供的配置文件方式。即现在配置文件中把参数写好,再使用命令调用配置文件运行。
在该目录下我们看到还有一个文件test.duarcfg,这就是我们说的配置文件
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/duarouterConfiguration.xsd">
<input>
<net-file value="input_net.net.xml"/>
<route-files value="input_flows.flows.xml"/>
input>
<output>
<output-file value="routes.rou.xml"/>
<write-license value="true"/>
output>
<report>
<no-step-log value="true"/>
report>
configuration>
在配置文件中我们规定好了输入的路网文件以及flow文件,以及输出的路由文件的路径,我们使用以下命令运行调用这段配置文件
duarouter -c test.duarcfg
结果和我们直接使用命令一样
在我们进行各种算法的实验的时候,我们一般不希望一直对着sumo的这些xml进行操作,这么做是繁琐而且效率低下的,我们一般希望可以通过别的编程语言来对其进行自动化的仿真,那么TraCI便可以满足你的想法
官方文档:https://sumo.dlr.de/docs/TraCI.html
TraCI是Traffic Control Interface 的简写,意为交通控制接口。提供一个对运行中的道路交通仿真的访问的方法,它可以检索仿真中物体的数据以及实时操作它们的行为
TraCI使用的是一种和TCP客户端服务器一样类似的架构来提供对sumo的访问,其中sumo扮演的是服务器。把sumo作为库来调用的话可以节省socket通信的开销。当我们下载sumo时, C++, Java 和 Python 的相关库都也被下载下来了
接下来我们简单的使用Python语言来对TraCI进行交互
从文档中我们看到
- Python: the package tools/traci allows to interact with sumo using Python (This library is tested daily and supports all TraCI commands).
对于Python语言来说,sumo安装目录下tools/traci
这个包可以让我们用Python来语sumo交互,并且支持所有的TraCI 命令
我们可以先在sumo目录下的tools\traci
找到traci的python库,我们记住这个路径
那首先假设我们以及安装好了一个Python / anaconda 环境,我们首先来到该路径下
在Lib\site-packages
目录下新建一个traci.pth文件
并在里面放刚刚说的traci的python库的路径,并保存。
我们可以在命令行中测试traci库是否以及导入到python中
打开我们的PyCharm(大家喜欢用什么就用什么,只是说我喜欢用PyCharm)
我这边用Jupyter notebook演示基本功能
首先是导入需要用的包
import traci
import os
import time
import sys
from sumolib import checkBinary
其次检查是否存在SUMO_HOME的环境变量(sumo安装时会自己生成)
if "SUMO_HOME" in os.environ:
tools = os.path.join(os.environ['SUMO_HOME'],'tools')
sys.path.append(tools)
else:
sys.exit("please declare environment variable 'SUMO_HOME'")
相关的配置的声明,比如运行的是哪一个sumocfg,是否要有GUI(Graphical User Interface 图形化用户接口)
show_gui = True
sumoconfig_path = r'D:\sumo\files\networks\6 traCI\example.sumocfg'
根据是否要用GUI我们选择对应的命令
if not show_gui:
sumoBinary = checkBinary('sumo')
else:
sumoBinary = checkBinary('sumo-gui')
开始运行,并且实时监控,由于traci架构类似于TCP/IP,所以我们运行结束后需要进行连接的终止,所以我们需要记得进行连接终止
traci.start([sumoBinary,'-c',sumoconfig_path])
for step in range(0,200):
time.sleep(1)
#操控时间
traci.simulationStep(step + 1)
simulation_current_time=traci.simulation.getTime()
print("仿真时间是",simulation_current_time)
#获取所有车的ID
all_vehicle_id = traci.vehicle.getIDList()
#获取所有车的position
all_vehicle_position = [(i,traci.vehicle.getPosition(i))for i in all_vehicle_id]
#获取所有车是否经过过车线
print(all_vehicle_position)
traci.close()
运行后会发现,sumo-gui虽然打开了 但是并没有开始运行 于是我们在对应的sumocfg文件的configuration
元素的末端添加以下代码
<gui_only>
<start value="t"/>
<quit-on-end value="e"/>
gui_only>
让它可以在一开始打开便运行