SUMO 交通控制接口 —— TraCI

引言

SUMO 本身可以實現(xiàn)很多實際交通場景的模擬。當(dāng) SUMO 被用作智能交通控制算法的測試平臺時,需要其與外界程序/算法實現(xiàn)很好的互動,例如用戶自定義的控制算法可以從 SUMO 獲取實時交通信息,然后對其中車輛狀態(tài)、信號燈狀態(tài)等進行實時控制。TraCI 就是實現(xiàn)這類互動的接口。

TraCI: Traffic Control Interface. 交通控制接口。

作用:獲取 SUMO 交通模擬環(huán)境中的數(shù)據(jù),并實時修改、控制。

目前該接口支持多種主流語言,包括 python, c++, .NET, MATLAB, Java,其中 python 版本的 TraCI 功能最全面。下面就以 python 版本的 TraCI 為例,介紹一下如何實現(xiàn) SUMO 與外部控制算法的互動。關(guān)于 TraCI 中類、函數(shù)的詳細(xì)說明,可以參考官方文檔。

Demo: 通過 TraCI 控制 SUMO 中的交通燈狀態(tài)

來自 SUMO 官網(wǎng)教程。所有程序可以在 https://github.com/eclipse/sumo/tree/master/tests/complex/tutorial/traci_tls 中找到。

考慮如下所示路口:

SUMO_TraCI1.png

基礎(chǔ)信號燈變換順序如下:

<tlLogic id="0" type="static" programID="0" offset="0">
   <phase duration="31" state="GrGr"/>
   <phase duration="6" state="yryr"/>
   <phase duration="31" state="rGrG"/>
   <phase duration="6" state="ryry"/>
</tlLogic>

其中各參數(shù)含義可以參考本博客中另一篇文章

然后,希望通過 TraCI 修改信號燈轉(zhuǎn)換機制:

  • 當(dāng)南北方向沒有車輛過來時,東西方向一直保持綠燈

  • 當(dāng)南北方向有車過來時,切換信號燈,東西方向黃燈 6 s,然后變紅,同時南北方向變綠,持續(xù) 31 s,然后變黃,再變紅,東西方向變綠。

  • 重復(fù)上述兩個過程

現(xiàn)在假設(shè) net.xml 文件已經(jīng)得到。實際上,通過 netedit 可以很容易的構(gòu)造上述交通路網(wǎng)。

SUMO 與 TraCI 的交互是在文件 runner.py 中實現(xiàn)的,主要包括如下內(nèi)容:

  1. 首先檢查系統(tǒng)路徑,以便后續(xù) python 的 module 調(diào)用,主要是調(diào)用 traci
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'")

import traci  
  1. 定義函數(shù) generate_routefile(),用來創(chuàng)建 .rou.xml 文件
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)

運行上述函數(shù)之后,會在 data/ 目錄下生成 cross.rou.xml 文件,里面包含了由東向西、由西向東、由北向南的交通流信息。

  1. 從 SUMO 中獲取交通信息,然后對交通燈狀態(tài)施加控制
def run():
     """execute the TraCI control loop"""
     step = 0
     traci.trafficlight.setPhase("0", 2)  # 這里 0 是 traffic light 的 ID,四個 phase 依次編號為 0, 1, 2, 3,初始時設(shè)置 phase 為 2,即 東西道路為 G,南北道路為 r。
     while traci.simulation.getMinExpectedNumber() > 0:  # 該函數(shù)得到當(dāng)前 net 中的車輛數(shù)目加上還沒有進入 net 的車輛數(shù)目。只要該數(shù)值 > 0,就表明還有車輛需要處理。
         traci.simulationStep()  # 運行一步仿真
         if traci.trafficlight.getPhase("0") == 2:
             if traci.inductionloop.getLastStepVehicleNumber("0") > 0:  # 在上一步仿真中,經(jīng)過 induction loop 的汽車數(shù)量
                 traci.trafficlight.setPhase("0", 3)  # 如果有車進來,則切換 phase
             else:
                 traci.trafficlight.setPhase("0", 2)  # 否則依然保持 phase。注意,這里是重置了 phase, 所以會重新計時。
         step += 1
     traci.close()
  1. 運行主程序
if __name__ == "__main__":
     generate_routefile()
     traci.start(["sumo-gui", "-c", "data/cross.sumocfg",
     "--tripinfo-output", "tripinfo.xml"])  # tripinfo 中記錄了每一輛車在網(wǎng)絡(luò)中的行駛信息,包括出發(fā)時間、出發(fā)車道、到達(dá)時間、等待時間、車輛類型等等。
     run()

首先是生成 .rou.xml 文件,然后運行已經(jīng)設(shè)置好的 sumocfg 文件,里面實際上是調(diào)用了 .net.xml 文件、.rou.xml 文件以及感應(yīng)線圈的設(shè)置文件,通過 traci.start 啟動 SUMO,建立 traci 與 SUMO 的通信連接。最后運行 run 函數(shù),實現(xiàn)兩者的交互。

在官方給出的程序中,并沒有直接調(diào)用 sumo-gui ,而是通過 sumolib 中的 checkBinary 函數(shù)先查找 sumo-gui 程序的位置,然后再運行它。這兩者效果是一樣的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容