使用Sumo以及traci实现交叉口信号灯自适应控制



使用Sumo以及traci实现交叉口信号灯感应控制

Sumo作为比较常用的交通仿真软件,常用于各范围的路网仿真。今天研究一下怎么通过Python和Traci结合,实现交叉口信号灯自适应控制。

一、什么是交叉口感应控制

交通信号控制方式是应用于道路交通信号控制系统,为控制和调整交通流运行状态,按照交通信号控制方案所执行的特定控制方式。国标《道路交通信号控制系统术语》(GB/T 31418-2015)、行标《《道路交通信号控制方式 第1部分:通用技术条件》(GA/T 527.1-2015)、美国《Signal Timing Mannual》对感应控制(actuated)和自适应控制(adaptive)都做了相关定义和描述。标准中对“感应控制”的描述为道路交通信号控制机根据检测器测得的交通流信息来调节信号显示时间的控制方式。

以行业标准《道路交通信号控制方式 第1部分:通用技术条件》(GA/T 527.1-2015)种描述的“单点感应控制”:根据交通流检测器测定到达交叉口进口道的交通需求,对预先设定的交通信号控制方案进行执行相位的信号配时优化调整,也可选择执行预设相位、优化相序,以减少停车延误、排队长度为目标。

根据检测器布设方式,可以将感应控制分为半感应控制和全感应控制。半感应控制只在部分进口道上设置检测器,这种情况下交叉口仅部分相位有感应请求。而全感应控制在所有进口道上都设置检测器,这种情况下交叉口所有相位均有感应请求。结合控制范围,可以将感应控制划分为单点感应控制和干线感应协调控制。自适应控制可以划分为单点自适应控制、干线自适应控制、区域自适应控制。
感应控制

二、Traci中的感应控制实现流程

1.感应控制逻辑

感应控制实现逻辑如下:

def run():
    """execute the TraCI control loop"""
    step = 0
    # we start with phase 2 where EW has green
    traci.trafficlight.setPhase("0", 2)
    while traci.simulation.getMinExpectedNumber() > 0:
        traci.simulationStep()
        if traci.trafficlight.getPhase("0") == 2:
            # we are not already switching
            if traci.inductionloop.getLastStepVehicleNumber("0") > 0:
                # there is a vehicle from the north, switch
                traci.trafficlight.setPhase("0", 3)
            else:
                # otherwise try to keep green for EW
                traci.trafficlight.setPhase("0", 2)
        step += 1
    traci.close()
    sys.stdout.flush()

当有车辆进入布设的线圈内部时,检测器检测到车辆存在,切换相位。这里对Traci中的这部分代码进行详细讲解:

traci.trafficlight.setPhase("0", 2)

这里是设置信号灯初始相位为2相位,对应的相位信息,我们可以在xml文件中进行设置,对应的trafficlight的文档中,可以看到setPhase的相关内容:
traci.trafficlight.setPhase方法
可以看到,setPhase的作用是切换相位,在相位列表中,按照每一个相位对应的索引,比如[‘南北直行放行’,‘南北左转放行’,’东西直行放行‘,‘东西左转放行’],setPhase(‘0’,2)表示对id为0的信号灯,切换到第索引为2的相位,即东西直行放行。
那么是怎么对是否有车进入线圈进行判断的,这里用的是

traci.inductionloop.getLastStepVehicleNumber()

traci.inductionloop.getLastStepVehicleNumber()方法的介绍如下:
traci.inductionloop.getLastStepVehicleNumber()方法
即参数输入为线圈id,返回为上一仿真step中在线圈内的车辆数量,这里用了一个判断,traci.inductionloop.getLastStepVehicleNumber(’0‘)>0,即还有车在上一仿真步长中在线圈内。

2.仿真过程

代码如下(示例):

#!/usr/bin/env python
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
# Copyright (C) 2009-2022 German Aerospace Center (DLR) and others.
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0/
# This Source Code may also be made available under the following Secondary
# Licenses when the conditions for such availability set forth in the Eclipse
# Public License 2.0 are satisfied: GNU General Public License, version 2
# or later which is available at
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later

# @file    runner.py
# @author  Lena Kalleske
# @author  Daniel Krajzewicz
# @author  Michael Behrisch
# @author  Jakob Erdmann
# @date    2009-03-26

from __future__ import absolute_import
from __future__ import print_function

import os
import sys
import optparse
import random

# we need to import python modules from the $SUMO_HOME/tools directory
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'")

from sumolib import checkBinary  # noqa
import traci  # noqa


def generate_routefile():
    random.seed(42)  # make tests reproducible
    N = 3600  # number of time steps
    # demand per second from different directions
    pWE = 1. / 10
    pEW = 1. / 11
    pNS = 1. / 30
    with open("data/cross.rou.xml", "w") as routes:
        print("""<routes>
        <vType id="typeWE" accel="0.8" decel="4.5" sigma="0.5" length="5" minGap="2.5" maxSpeed="16.67" \
guiShape="passenger"/>
        <vType id="typeNS" accel="0.8" decel="4.5" sigma="0.5" length="7" minGap="3" maxSpeed="25" guiShape="bus"/>

        <route id="right" edges="51o 1i 2o 52i" />
        <route id="left" edges="52o 2i 1o 51i" />
        <route id="down" edges="54o 4i 3o 53i" />""", file=routes)
        vehNr = 0
        for i in range(N):
            if random.uniform(0, 1) < pWE:
                print('    <vehicle id="right_%i" type="typeWE" route="right" depart="%i" />' % (
                    vehNr, i), file=routes)
                vehNr += 1
            if random.uniform(0, 1) < pEW:
                print('    <vehicle id="left_%i" type="typeWE" route="left" depart="%i" />' % (
                    vehNr, i), file=routes)
                vehNr += 1
            if random.uniform(0, 1) < pNS:
                print('    <vehicle id="down_%i" type="typeNS" route="down" depart="%i" color="1,0,0"/>' % (
                    vehNr, i), file=routes)
                vehNr += 1
        print("</routes>", file=routes)

# The program looks like this
#    <tlLogic id="0" type="static" programID="0" offset="0">
# the locations of the tls are      NESW
#        <phase duration="31" state="GrGr"/>
#        <phase duration="6"  state="yryr"/>
#        <phase duration="31" state="rGrG"/>
#        <phase duration="6"  state="ryry"/>
#    </tlLogic>


def run():
    """execute the TraCI control loop"""
    step = 0
    # we start with phase 2 where EW has green
    traci.trafficlight.setPhase("0", 2)
    while traci.simulation.getMinExpectedNumber() > 0:
        traci.simulationStep()
        if traci.trafficlight.getPhase("0") == 2:
            # we are not already switching
            if traci.inductionloop.getLastStepVehicleNumber("0") > 0:
                # there is a vehicle from the north, switch
                traci.trafficlight.setPhase("0", 3)
            else:
                # otherwise try to keep green for EW
                traci.trafficlight.setPhase("0", 2)
        step += 1
    traci.close()
    sys.stdout.flush()


def get_options():
    optParser = optparse.OptionParser()
    optParser.add_option("--nogui", action="store_true",
                         default=False, help="run the commandline version of sumo")
    options, args = optParser.parse_args()
    return options


# this is the main entry point of this script
if __name__ == "__main__":
    options = get_options()

    # this script has been called from the command line. It will start sumo as a
    # server, then connect and run
    if options.nogui:cr
        sumoBinary = checkBinary('sumo')
    else:
        sumoBinary = checkBinary('sumo-gui')

    # first, generate the route file for this simulation
    generate_routefile()

    # this is the normal way of using traci. sumo is started as a
    # subprocess and then the python script connects and runs
    traci.start([sumoBinary, "-c", "cross.sumocfg",
                             "--tripinfo-output", "tripinfo.xml"])
    run()

cross.sumocfg及其相关文件如下,把这些文件复制到本地,存为以下文件名,即可运行,前提是你的环境变量配置没有问题。
相关仿真文件
文件链接如下:
链接:https://pan.baidu.com/s/1IFs4UJUBPxPM_LUTSrcmSw
提取码:Sumo

欢迎交流!

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐