OMNeT++ & SUMO 学习记录(九)SUMO 交通控制接口 TraCI

一、TraCI 简介

TraCI 是交通控制接口(Traffic Control Interface)的简称,通过该接口与模拟器进行通信,可以实现对 SUMO 仿真中的实时交通信息获取和控制仿真对象的形为,与外界进行实时性的交互,极大提高了仿真性能。例如,在一个发生交通堵塞的场景中,可以通过 TraCI 接口获取当前车辆的位置和行驶路线信息,可以在线为车辆重新规划路线,调整既定信号灯相位配时等方法缓解交通拥堵。

二、TraCI 的使用

1、配置环境变量

使用 TraCI 首先要为其配置环境变量,SUMO 中的许多工具要求将环境变量 SUMO_HOME 设置为 SUMO 安装的基本目录,包含文件夹bin和tools的目录。使用命令行运行程序,必须配置 Path 变量和SUMO_HOME 变量。

打开环境变量页面,点击 “新建” ,输入变量名 SUMO_HOME ,变量值为 SUMO 的安装路径。
OMNeT++ & SUMO 学习记录(九)SUMO 交通控制接口 TraCI_第1张图片

如果已经有 Path 变量,双击变量值为其添加新的值即可,如果没有,需要新建该变量并为其添加值,变量值为 bin 文件夹的路径。
OMNeT++ & SUMO 学习记录(九)SUMO 交通控制接口 TraCI_第2张图片
至此,环境变量配置完毕。

2、接口编程语言

TraCI 接口目前支持包括 Python, Java, C++,.NET 等多种主流语言,其中 python 语言的功能最为完善,实现相对简单。

在使用 TraCI 前需要将其安装到 Python 的加载路径上,TraCI 位于 SUMO 安装目录下 tools->traci 文件夹中,打开可以看到 TraCI 的一系列功能函数,我们需要将 tools 目录加载到 Python 中。

打开 Python 安装目录,E:\python\Lib\site-packages,新建文本文档 traci.txt,在其中输入 tools 目录的位置:E:\SUMO\tools ,最后将文件后缀改为 .pth 即可。
OMNeT++ & SUMO 学习记录(九)SUMO 交通控制接口 TraCI_第3张图片
可以在命令行中检查 TraCI 是否安装成功
OMNeT++ & SUMO 学习记录(九)SUMO 交通控制接口 TraCI_第4张图片

三、TraCI 命令

TraCI 命令可以调用一系列库函数,实现仿真数据信息的获取和仿真对象的状态修改,极大程度方便了交通场景的构建,是二次开发不可或缺的重要工具。下面简单介绍各 API 的功能:

1、信息获取类

该类接口的主要功能是获取仿真对象的状态信息值,可以作为仿真输出,可以在输出数据基础上进行研究,对仿真进行改进,以达到理想的效果。下面介绍几个常用的 API :

  • 车辆信息获取(Vehicle Value Retrieval ):获取仿真中车辆的状态值,如仿真环境中的车辆数量 、ID 、行驶路线 、定位 、车速等,可满足各种仿真需求。
  • 信号灯信息获取(Traffic Lights Value Retrieval):返回仿真场景中信号灯相关数据,如返回所有的信号灯 ID 、信号灯总数 、信号灯当前相位及其剩余持续时间 、信号灯控制的车道等。需要注意的是,“getNextSwitch(self, tlsID)” 函数获取的值为信号灯切换到下一个状态的绝对时间(从模拟开始算起),要获取当前相位剩余时间,需要用(getNextSwitch()- Simulation.getTime())。

举例说明:为信号灯设置三个不同的相位,分别是 28s 、3s 和 14s ,在 0 ~ 28s 也就是第一个相位的时间内,getNextSwitch()的值恒定为 28 ,在第二个相位的时间内,getNextSwitch()的值恒定为 31(28+3) ,第三个相位 getNextSwitch()值恒定为 45(28+3+14)。这样,假设获取到了第 3s 仿真数据,信号灯剩余时间就是 28 - 3 = 25s 。
OMNeT++ & SUMO 学习记录(九)SUMO 交通控制接口 TraCI_第5张图片

  • 仿真信息获取(Simulation Value Retrieval):获取仿真过程中某个模拟变量的值,如当前仿真时间 、当前路网中车辆数及车辆 ID 、某时段内进入和离开路网的车辆数 、发生碰撞的车辆数及其 ID 等。

2、状态改变类

该类接口的主要功能是控制仿真对象的状态,例如要测试自定义的车辆在不同路况条件下的性能表现,如果需要分析某一变量对车辆的影响,需要修改该变量的值,如信号灯持续时间、周围车辆密度、道路限速限行等,这时候就可以通过该接口来修改某一变量的值,得到前后的对比实验数据,方便下一步分析改进。下面简单介绍几个常用接口功能:

  • 改变信号灯状态(Change Traffic Lights State) :可以设置信号灯的状态,进行相位切换,设置当前相位持续时间等。可以根据路况的不同和场景的需要,控制信号灯的状态,提高通行效率。
  • 改变车辆状态(Change Vehicle State) :实现车辆控制的核心,常用函数的功能描述及实现方法见下表:
车辆状态 功能描述 python 实现
停车 使车辆停在给定的边沿,给定的位置和车道上。车辆将在给定的时间内停止。 setStop
变更车道 强制将车道更改为具有给定索引的车道;如果成功,将在给定的时间量(以秒为单位)内选择车道。 changeLane
更改目的地 给定新的目的地道路,重建行车路线 changeTarget
速度 将车辆的速度设定为给定值,车速要符合当前的速度模型 setSpeed
设置路线 为车辆设置行驶路线,车辆将沿给定的路线列表依次驶过 setRoute

四、仿真实例解析

TraCI 使用基于 TCP 的客户端/服务器体系结构来提供对 SUMO 的访问,SUMO 作为客户端,由于 TraCI 接口支持多种语言,服务器可以是由某种语言编写的脚本,通过该脚本控制仿真运行。下面的例子以 Python 脚本为例,探讨仿真运行过程和原理:

场景描述:在一个十字路口,东西方向有持续车流,南北方向间歇有车辆通过。使用 TraCI 控制信号灯在南北方向没有车辆时保持东西方向绿灯,当检测到南北方向的车辆,控制信号灯切换相位到南北方向绿灯而东西方向红灯。该例程可以在 …\doc\tutorial\traci_tls 中找到,下面代码已经简化和部分功能修改,在控制信号灯的同时打印出检测器检测到车辆信息。

代码如下,功能参考注释:

# 首先需要从 SUMO_HOME/tools 中导入一些实验用到的 python 模块
import os
import sys
import optparse
import random
import time
import traci  
from sumolib import checkBinary 

# 其次检查 SUMO_HOME 是否在系统环境变量中,这是进行下一步仿真的必要条件
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'")

# 是否打开 sumo-gui 进行可视化演示
if_show_gui = True 

if not if_show_gui:
    sumoBinary = checkBinary('sumo')
else:
    sumoBinary = checkBinary('sumo-gui')

# 指定 *.sumocfg 文件的位置
sumocfgfile = "E:\\SUMO\\doc\\tutorial\\traci_tls\\data\\cross.sumocfg"

# 接下来是 *.rou 文件的定义函数
def generate_routefile():
    
    random.seed(42)  # 设定种子值,下面使用 random() 生成的随机数是确定的,确保每次生成的 *.rou 文件相同
    
    N = 3600  # 总仿真步数
   
    pWE = 1. / 10
    pEW = 1. / 11
    pNS = 1. / 30
    
    # 打开文件,“w” 代表将进行写入操作
    with open("data/cross.rou.xml", "w") as routes:
        print("""
        
        

        
        
        """, file=routes)
        vehNr = 0 # 初始时刻车辆数为 0
        for i in range(N):
            if random.uniform(0, 1) < pWE:
                print('    ' % (
                    vehNr, i), file=routes)
                vehNr += 1
            if random.uniform(0, 1) < pEW:
                print('    ' % (
                    vehNr, i), file=routes)
                vehNr += 1
            if random.uniform(0, 1) < pNS:
                print('    ' % (
                    vehNr, i), file=routes)
                vehNr += 1
        print("", file=routes)

# 定义主函数,traci 的核心控制逻辑
def run():
    step = 0
    traci.trafficlight.setPhase("0", 2) # 设置 ID 为 “0” 的信号灯初始相位是 2,该相位下东西方向绿灯
    while traci.simulation.getMinExpectedNumber() > 0: # 获取预计仍要离开网络的车辆的最小数量
        time.sleep(0.05) # 设置时延为 50ms
        traci.simulationStep()

        if traci.inductionloop.getVehicleData("0"): # 若 ID 为 “0” 的检测器检测到车辆通过,则打印出车辆的信息

            print(traci.inductionloop.getVehicleData("0"))

        if traci.trafficlight.getPhase("0") == 2: 

            if traci.inductionloop.getLastStepVehicleNumber("0") > 0: # 检测到有南北方向的车辆

                traci.trafficlight.setPhase("0", 3) # 切换到 3 相位,南北方向绿灯,东西方向红灯
            
            else:

                traci.trafficlight.setPhase("0", 2)
        step += 1
    traci.close()

generate_routefile()
traci.start([sumoBinary, "-c", sumocfgfile]) # 启动 sumo-gui ,加载 *.sumocfg 文件
run()

运行脚本,仿真效果如下:

OMNeT++ & SUMO 学习记录(九)SUMO 交通控制接口 TraCI_第6张图片
该场景简单模拟了拥有高通行优先级的车辆在 TraCI 控制信号灯路口的优先通行权,在真实环境中,这些车辆可以是执行紧急任务的救护车、消防车、警车等,通过实时控制信号灯,节省时间的同时保证通行安全。

注:本文仅涉及 TraCI 的几个常见使用,更多功能详见官方描述文档。

你可能感兴趣的:(SUMO)