简介#
本教程是关于如何在SUMO中使用出租车服务的示例。
- 主要内容包括
- 车辆创建
- 公交站点
- 出租车预约与接载
本教程分为两个部分。 第一部分: 创建一个简单的出租车服务,包括路网创建和出租车调度。 第二部分: 添加一小段代码。在这段代码中,将查询公交站点等待的人数。 本教程可用于当公交站点人员积压过多时,调度紧急班车进行接载。
建议先查看 traci 初学者教程。本教程是其扩展,展示了 traci 出租车的一些操作。
有用链接#
出租车服务#
在模拟开始时,创建了五个人,他们前往附近的公交站点等待班车接载。 在同一区域,经过几步后创建了一些出租车。该区域没有安排额外的公交车,因此必须对等待的人员进行紧急接载。当等待人数达到一定数量时,出租车会收到预约并分别接载每位顾客。

第一部分#
需求与创建#
路网创建#
如果您想创建图中所示的相同路网,或者想重新使用 netedit,可以参考以下动图。否则可以跳过本节。
创建基础路网。
添加人行道。
建立连接。您可以继续添加到其他连接街道的连接。
创建路径。您可以继续为车辆添加其他路径。
需求#
创建出租车和人员#
模拟中的关键参与者是等待的人员和出租车。 要创建类型为出租车的车辆,必须添加关键参数:
<!-- 路径 -->
<route edges="-gneE2 gneE0 -gneE0 gneE2 -gneE2" color="yellow" id="route_0"/>
<!-- 出租车类型 -->
<vType id="taxi" vClass="taxi" personCapacity="8">
<param key="has.taxi.device" value="true"/>
</vType>
还有其他选项可以定义出租车的行为。您可以决定出租车何时消失,或者是否应该开始在该区域绕行。在本例中,即使模拟中不再有人,出租车也会继续在该区域绕行。这是通过在模拟开始时选择调度算法来实现的,本教程稍后将讨论这一点。
接下来,您可以创建一个人员,该人员在开始时出发并前往指定的公交站点。
这里的第三行至关重要,声明该人员希望乘坐出租车前往边缘 gneE2。lines 参数在这里也很重要。
<person id="HeadingBusstop1" depart="0.00" color="green">
<walk from="-gneE1" busStop="busStop_gneE0_0_0"/>
<ride from="gneE0" to="gneE2" lines="taxi"/>
</person>
也可以定义 personTrips 用于多式联运路由或将多个人员组合在一起。
如初学者 traci 教程所示,您可以创建一个 runner.py 文件来管理项目中的出租车创建。
在示例方法中,四个出租车在给定时间被创建和调度。
# 创建 4 辆出租车
def createTaxi(time):
for i in range(0, 20, 5):
# 声明名称(唯一)、路径(来自 demand.route.xml)、车辆类型(在 demand.route.xml 中声明)、
# 出发时间和线路
traci.vehicle.add(f'taxiV{i}', 'route_0', 'taxi', depart=f'{time}', line='taxi')
调度与接载#
在本例中,我们使用 "-device.taxi.dispatch-algorithm traci"。在此算法中,必须声明哪辆出租车应接载哪些客户。这意味着您必须将现有预约传递给您希望用于接载的指定出租车。还有其他算法,如 greedy、greedyClosest 等,它们处理预约的方式不同。 接下来,出租车车队(包含地图中的所有出租车)被保存到 "fleet" 中,而所有预约则保存到 "reservations" 中。之后,调用车队中的第一辆出租车,并将 "reservation_ids" 中的第一个预约分配给它。
fleet = traci.vehicle.getTaxiFleet(0)
reservations = traci.person.getTaxiReservations(0)
reservation_ids = [r.id for r in reservations]
traci.vehicle.dispatchTaxi(fleet[0], reservation_ids[0])
有关更多输出参数,请查看文档和 Pydoc。
第二部分#
在教程的第二部分,一个公交站点积压了过多等待乘车的人员。紧急出租车被部署去接载这些顾客。
预约#
在本部分教程中,您可以添加另一个方法来监控公交站点,并在需要时启动紧急出租车功能。 在本例中,我们针对一个等待运输人员过多的公交站点。 如下面的代码所示,对于所有 personCount 等于或大于 4 的公交站点,调用 emergencyTaxi(i) 方法。
# 检查公交站点是否“积压”
def busstopCheck():
# 获取地图上所有公交站点
busstops = traci.busstop.getIDList()
# 检查等待人员的计数
for i in busstops:
if traci.busstop.getPersonCount(i) >= 4:
emergencyTaxi(i)
车队与调度#
车队仅由未占用的出租车组成。获取未占用的出租车(0)。 如果想向已分配的出租车添加更多预约,可以筛选已占用(2)或处于接载模式(1)的出租车。 相关公交站点的 ID 被传递给 emergencyTaxi 方法,以专门规划接载。
# 调度出租车以满足在公交站点等待的人员
def emergencyTaxi(busstopID):
# 获取在公交站点等待的人员的 ID 列表
peopleWaiting = traci.busstop.getPersonIDs(busstopID)
pickup = []
# 创建出租车预约列表
for i, val in enumerate(peopleWaiting):
pickup.append(traci.person.getTaxiReservations(0)[i].id)
# 如果一辆出租车要接载所有顾客,列表需要明确下车点
# 因此预约按下车顺序扩展
# pickup.extend(pickup)
try:
fleet = traci.vehicle.getTaxiFleet(0)
except (traci.exceptions.FatalTraCIError):
print("没有未占用的出租车车队!")
# 调度未占用的出租车去接载指定的顾客
for i, val in enumerate(peopleWaiting):
traci.vehicle.dispatchTaxi(fleet[i], pickup[i])
列表中位置为 i 的出租车被调度去接载 "pickup" 列表中位置为 i 的人员。
如果车辆容量足够,也可以让一辆出租车接载和送下所有人员。
pickup.extend(pickup)
可能如下所示:
pickup = [a,b,c,a,b,c]
乘客按扩展的顺序下车。
sumocfg#
在配置文件中添加了额外的行: 要能够使用 traci.taxis,必须在配置文件中添加一个算法。 此外,为了防止出租车在送下人员后立即消失,添加了声明 randomCircling 的行。在将人员送达正确位置后,出租车在短暂休息后开始在网络中绕行。
<configuration>
<input>
<net-file value="net.net.xml"/>
<route-files value="demand.rou.xml"/>
<additional-files value="add.add.xml"/>
<no-step-log value="True"/>
<time-to-teleport value="0"/>
<device.taxi.dispatch-algorithm value="traci"/>
<device.taxi.idle-algorithm value="randomCircling"/>
</input>
</configuration>
另一种使用算法的方法是将它们添加到脚本中的 traci.start:
sumoBinary = sumolib.checkBinary('sumo')
traci.start([sumoBinary,
"-c", "sumo.sumocfg",
"--tripinfo-output", "tripinfos.xml",
"--device.taxi.dispatch-algorithm", "traci",
] + sys.argv[1:])
