SUMO TraCI使用示例:TraCIPedCrossing

严正声明:本文系作者davidhopper原创,未经许可,不得转载。

SUMO全称Simulation of Urban Mobility,是一个开源、微观、多模态交通仿真模拟软件。TraCI是“Traffic Control Interface”(交通控制接口)的缩写,包含在SUMO内部, 可以通过访问正在执行的道路交通仿真情景,获取仿真对象的值并“在线”操纵其行为。简而言之,TraCI是一个用于外部算法在线操作SUMO仿真器的接口工具。本文以TraCIPedCrossing为例,简介TraCI的使用方法。
使用该示例之前,请按照我的博客Ubuntu 16.04系统中SUMO安装方法及简单示例安装SUMO并配置环境变量SUMO_HOME,参照另一篇博客Ubuntu 16.04系统中基于OSM创建并运行SUMO网络模型,将SUMO源代码中的data目录复制到/usr/share/sumo目录。

一、将示例代码TraCIPedCrossing复制到工作目录

如果使用apt-get方法安装SUMO,则示例代码TraCIPedCrossing默认位于/usr/share/doc/sumo-doc/tutorial目录,使用Ctrl+Alt+T打开一个命令终端,通过如下命令将其复制到你自己的工作目录(我使用~/code/sumo-exercise):

# 进入示例目录
cd /usr/share/doc/sumo-doc/tutorial

# 将traci_pedestrian_crossing目录复制到~/code/sumo-exercise目录
# ~/code/sumo-exercise目录是我的工作目录,你可以根据需要选择其他目录
cp -r traci_pedestrian_crossing ~/code/sumo-exercise

# 进入traci_pedestrian_crossing目录
cd ~/code/sumo-exercise/traci_pedestrian_crossing

# 刚复制过来的目录中有几个gz压缩包,需要将其解压
gzip -d runner.py.gz
gzip -d data/viewsettings.xml.gz

二、运行示例

在命令行终端中执行如下命令,运行示例:

python runner.py 

此时会弹出一个SUMO-GUI窗口,点击其中的绿色播放按钮,即可看到行人过马路的仿真场景:
SUMO TraCI使用示例:TraCIPedCrossing_第1张图片

三、信号逻辑及runner.py代码解释

TraCIPedCrossing示例中,行人过马路的红绿灯信号逻辑如下所示(见data/pedcrossing.tll.xml):

<tlLogic id="C" type="static" programID="custom" offset="0">
     <phase duration="100000" state="GGGGr"/> 
     <phase duration="4" state="yyyyr"/>
     <phase duration="10" state="rrrrG"/>
     <phase duration="10" state="rrrrr"/> 
tlLogic>

默认状态是"GGGGr"phase = 0)表示由绿灯转换为红灯,绿灯时间100000秒,表明该状态不会自动切换至其他状态。状态中的小写字母表示车流必须减速
状态"yyyyr"phase = 1)表示由黄灯转换为红灯,黄灯持续时间4秒;
状态"rrrrG"phase = 2)表示由红灯转换为绿灯,红灯持续时间10秒;
状态"rrrrr"phase = 3)表示由红灯持续状态,维持时间10秒,用于行人完全通过交叉路口。
上述状态除了phase = 0切换到phase = 1需要人工指定外,其余情况都会在每个状态指定的持续时间后自动切换到后续状态。
我个人认为:phase = 2phase = 3写反了,正确的信号逻辑应该如下所示:

<tlLogic id="C" type="static" programID="custom" offset="0">
     <phase duration="100000" state="GGGGy"/> 
     <phase duration="4" state="yyyyr"/>
     <phase duration="10" state="rrrrr"/>
     <phase duration="10" state="rrrrG"/> 
tlLogic>

参照如下代码块中的注释,了解TraCI的一般调用过程:

# 为兼容python 2.7所做的措施
from __future__ import absolute_import
from __future__ import print_function

# 导入相关包
import os
import sys
import optparse
import subprocess
import random


# 本脚本文件所在的目录
THISDIR = os.path.dirname(__file__)

# 需要从$SUMO_HOME/tools目录导入相关包,为此需要先设置环境变量SUMO_HOME,
# 若未设置,请设置之。
try:
    # tutorial in tests
    sys.path.append(os.path.join(THISDIR, '..', '..', '..', '..', "tools"))
    # tutorial in docs
    sys.path.append(os.path.join(os.environ.get("SUMO_HOME", os.path.join(
        THISDIR, "..", "..", "..")), "tools"))  
    import traci
    from sumolib import checkBinary  # noqa
    import randomTrips
except ImportError:
    sys.exit(
        "please declare environment variable 'SUMO_HOME' as the root directory of your sumo installation (it should contain folders 'bin', 'tools' and 'docs')")

# 车辆的最短绿灯时间
MIN_GREEN_TIME = 15
# 红绿灯仿真计划的初始状态,参见'pedcrossing.tll.xml'    
VEHICLE_GREEN_PHASE = 0
# 红绿灯的ID(仅包含一个),默认情况下它与受控交叉路口的ID相同。
TLSID = 'C'

# 受控交叉口的人行横道边界
WALKINGAREAS = [':C_w0', ':C_w1']
CROSSINGS = [':C_c0']

# TraCI控制主循环过程
def run():   
    # 记录允许车辆通行的绿灯持续时间    
    greenTimeSoFar = 0

    # 行人过马路按钮是否按下
    activeRequest = False

    # 主循环。在每个仿真步骤中执行某些操作,直到场景中没有新的车辆加入或现有车辆行驶
    while traci.simulation.getMinExpectedNumber() > 0:
        traci.simulationStep()

        # 如果车辆的绿灯时间超过最短绿灯时间,则确定是否有等待过马路的行人,并切换信号灯状态
        if not activeRequest:
            activeRequest = checkWaitingPersons()
        if traci.trafficlight.getPhase(TLSID) == VEHICLE_GREEN_PHASE:
            greenTimeSoFar += 1
            if greenTimeSoFar > MIN_GREEN_TIME:

                # 检测行人是否按下了过马路按钮
                if activeRequest:
                    # 信号灯切换至另一个状态,即非绿灯状态
                    # VEHICLE_GREEN_PHASE + 1表明切换到黄灯转红灯状态
                    traci.trafficlight.setPhase(
                        TLSID, VEHICLE_GREEN_PHASE + 1)
                    # 复位相关变量
                    activeRequest = False
                    greenTimeSoFar = 0

    sys.stdout.flush()
    traci.close()

# 检测是否有行人需要过马路
def checkWaitingPersons():

    # 检测路口两侧的行人
    for edge in WALKINGAREAS:
        peds = traci.edge.getLastStepPersonIDs(edge)

        # 检测是否有人在路口等待
        # 我们假设行人在等待1秒后,才按下过马路按钮
        for ped in peds:
            if (traci.person.getWaitingTime(ped) == 1 and
                    traci.person.getNextEdge(ped) in CROSSINGS):
                print("%s pushes the button" % ped)
                return True
    return False

# 定义本脚本文件及从命令行中解析得到的参数
def get_options():

    optParser = optparse.OptionParser()
    # 增加一个"--nogui"选项,默认值为False,即默认使用图形化界面
    optParser.add_option("--nogui", action="store_true",
                         default=False, help="run the commandline version of sumo")
    options, args = optParser.parse_args()
    return options


# 本脚本文件主入口
if __name__ == "__main__":

    # 获取程序运行的参数
    options = get_options()

    # 确定是调用sumo还是sumo-gui
    if options.nogui:
        sumoBinary = checkBinary('sumo')
    else:
        sumoBinary = checkBinary('sumo-gui')

    net = 'pedcrossing.net.xml'
    # 借助工具软件netconvert,从普通的xml输入构建多模态网络
    subprocess.call([checkBinary('netconvert'),
                     '-c', os.path.join('data', 'pedcrossing.netccfg'),
                     '--output-file', net],
                    stdout=sys.stdout, stderr=sys.stderr)

    # 随机生成仿真中的行人
    randomTrips.main(randomTrips.get_options([
        '--net-file', net,
        '--output-trip-file', 'pedestrians.trip.xml',
        '--seed', '42',  # make runs reproducible
        '--pedestrians',
        '--prefix', 'ped',
        # prevent trips that start and end on the same edge
        '--min-distance', '1',
        '--trip-attributes', 'departPos="random" arrivalPos="random"',
        '--binomial', '4',
        '--period', '35']))

    # 这是启动TraCI的一般方法。sumo作为子进程启动,然后使用本脚本文件连接该子进程  
    traci.start([sumoBinary, '-c', os.path.join('data', 'run.sumocfg')])
    # 调用TraCI控制主循环过程
    run()

你可能感兴趣的:(SUMO)