【SUMO】SUMO停车场仿真

SUMO的停车场仿真

github地址:
https://github.com/JunXie-ZH/SUMO_Tutorial/tree/main/Parking

SUMO中实现停车场仿真需要掌握三个部分的工作(如图1),分别为:

  • 停车设施构建:在SUMO中停车设施的定义以及构建方式;
  • 停车需求加载:灵活应用各种停车需求加载方式;
  • 停车区重选择:车辆的目标车位被占时,如何找到新的停车位。

本章节将围绕这三部分工作对SUMO停车仿真进行详细介绍。

在这里插入图片描述

图1 停车仿真框架

1 停车设施构建

1.1 停车区域与停车位

在SUMO中,停车设施由元素*<parkingArea>定义,该元素定义在.add.xml*文件中。

一个元素*<parkingArea>*详细定义如下:

<parkingArea id="parkingArea_B2C2_0_0" lane="B2C2_0" startPos="20.00" endPos="80.00" roadsideCapacity="5" width="3.50">
    <space x="123.00" y="180.00"/>
    <space x="128.00" y="180.00"/>
    <space x="133.00" y="180.00"/>
    <space x="138.00" y="180.00"/>
    <space x="143.00" y="180.00"/>
    <space x="152.00" y="184.00" angle="120.00"/>
    <space x="160.00" y="184.00" angle="120.00"/>
    <space x="168.00" y="184.00" angle="120.00"/>
    <space x="176.00" y="184.00" angle="120.00"/>
    <space x="184.00" y="184.00" angle="120.00"/>
</parkingArea>

元素*<parkingArea>*包含的各个属性定义:

表1 parkingArea元素属性

属性值类型定义
id字符串停车区域ID,由用户自定义,且必须为唯一的
lane字符串停车区域所在的车道,在SUMO中停车区域通常与车道是绑定在一起的
startPos浮点数停车区域的起始位置,以车道起始点为标准,数值表示为距离车道起始点x米
endPos浮点数停车区域的终止位置,以车道起始点为标准,数值表示为距离车道起始点x米,endPos>startPos
friendlyPos布尔型变量是否自动纠正无效的停车位置(默认为false)
name字符串对停车场的描述,可以用任意文字,仅用于可视化目的。
roadsideCapacity整型该停车区域的路内停车位容量,默认值为0
onRoad布尔型变量车辆停车时是否停留在路中,默认值为false,若设置为true,则只使用roadsideccapacity,不允许定义space给车辆停车
width浮点数路内停车位的宽度
length浮点数路内停车位的长度
angle浮点数路边停车位的角度相对于车道角度,正值表示顺时针

从元素*<parkingArea>*所具备的属性,我们进行了如下的总结:

  • ①*<parkingArea>所描述的是一个停车区域,包含多个停车位,且<parkingArea>*与路段车道(lane)是绑定的;
  • ②可以定义任意停车位置和角度(angle),从而实现多种停车方式,如鱼骨式停车、平行停车等;
  • ③*<parkingArea>包含了路内停车位(roadsideCapacity)与路外停车位(<sapce>),因此一个停车区域的总容量等于roadsideCapacity的数值与<sapce>*元素的个数之和。

对于③,在示例中,roadsideCapacity=5,*<sapce>*元素个数为10个,因此该停车区域的总容量为15个车位,在仿真中的可视化如图2:

在这里插入图片描述

图2 停车区域可视化

### 1.2 构建方式

停车设施的构建可以通过netedit编辑器实现,用户可以在已有道路路网的基础上,根据使用需求在合适的区域构建停车设施。

Step 1netedit编辑器打开路网文件(.net.xml),在Network模式下,点击上方工具栏[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5vxOmxzn-1643112936687)(./pic/addtionalMode.png)] 打开Additional mode(或点击上方菜单栏 Edit–>Additional mode打开)。在界面左侧Additionals中,点击Additional elements下拉菜单选择parkingArea

在这里插入图片描述

图3 Additional elements选择

Step 2 完成上一步后,即可点击某个车道构建停车区域。在SUMO中,停车区域与车道是绑定的,表示为车辆需通过该车道进入该停车区域。一个车道上可以构建多个停车区域(图4.a),也可以只构建一个停车区域(图4.b),并可以在左侧的属性栏中的修改该停车区域的属性:如id,roadsideCapacity等,详细可见表1。

在这里插入图片描述

图4 停车区域构建

***Step 3*** 上一步完成了路内停车位的构建。在部分交通场景中,某个车道除了拥有路内停车区域外,通过该车道还可以进入一些路外停车场,这部分路外停车场的构建则可以通过*\

在这里插入图片描述

图5 停车区域构建

***Step 4*** 点击构建好的*sapce*,可以通过调整其*pos*等属性,使车辆在仿真可视化时的停放排列更加规整。调整*angle*属性可以调整车位的摆放角度,实现鱼骨式停车等场景。如图6。

在这里插入图片描述

图6 sapce位置角度调整

***Step 5*** 点击保存,即可将新建立的停车设施保存为*.add.xml*文件。
<additional xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/additional_file.xsd">
    <parkingArea id="parkingArea_B2C2_0_0" lane="B2C2_0" startPos="20.00" endPos="80.00" roadsideCapacity="5" width="3.50" angle="45.00">
        <space x="123.00" y="180.00"/>
        <space x="128.00" y="180.00"/>
        <space x="133.00" y="180.00"/>
        <space x="138.00" y="180.00"/>
        <space x="143.00" y="180.00"/>
        <space x="192.00" y="184.00" angle="120.00"/>
        <space x="160.00" y="184.00" angle="120.00"/>
        <space x="168.00" y="184.00" angle="120.00"/>
        <space x="176.00" y="184.00" angle="120.00"/>
        <space x="184.00" y="184.00" angle="120.00"/>
    </parkingArea>
</additional>

2 停车需求加载

停车是出行的其中一个环节,在前面的章节中,我们介绍了如何加载车辆的出行需求,停车需求的加载则是在出行需求的基础上进行实现的。停车需求的实战加载方式如图1所示主要有三种:直接在*.rou.xml文件中编写,通过netedit编辑器加载,通过TraCI*进行动态加载。

2.1 直接在*.rou.xml*文件中编写

首先可以直接在*.rou.xml文件中编写实现停车需求的加载。停车需求在.rou.xml*文件中的编写是在出行的基础上完成的,我们以一个出行(trip)为例:

我们在一个OD级的个体出行需求的基础上,添加了一个*<stop>元素,使其要停靠在一个parkingArea中。对于parkingArea*的选择:

  • 可以选择终点路段的停车场(如上例中的parkingArea_e),则车辆行驶到终点路段后进入停车位停车,到停车时间(duration)后,车辆在终点路段行驶到尽头后消失在路网。
  • 也可以选择在非起点和终点的停车场,但一定要在车辆的行驶路径中。但由于OD级的出行需求中,车辆的行驶路径是由SUMO决定的,停车场有可能并不在SUMO所决定的行驶路径中,运行仿真后会报如下错误:

以上均是个体级的停车需求在*.rou.xml*文件中的表示,对于集计型的交通需求(OD级与路径级)同样可以加载停车需求。

OD级:

<flow id="flow_0" begin="0" end= "7200" period="10" from="a" to="e">
	<stop parkingArea="parkingArea_e" duration="100.00"/>
</flow>

路径级:

<route edges="a b c d e f g" color="yellow" id="route_0">
	<stop parkingArea="parkingArea_d" duration="100.00"/>
</route>	
<flow id="flow_0" begin="0" end= "7200" period="10" route="route_0"></flow>

2.2 通过netedit编辑器加载

netedit编辑器提供了可视化界面来进行停车需求的加载,但本质上还是为了生成一个*.rou.xml*文件来加载停车需求。

Step 1 如上所述,停车需求是在出行需求的基础上完成的,因此,首先在编辑器中加载好对应的出行需求,各粒度出行需求的编辑方式在前面已经介绍。假设已经创建了一个个体OD级出行需求,如下图:

在这里插入图片描述

图7 加载个体OD级出行需求

***Step 2*** 在*Demand*模式下,选择[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fUf1tW6Q-1643112936688)(./pic/stopElements.png)](Edit-->Stop mode),打开添加停车需求模块。左方状态栏中,*Parent element*选择为要添加停车行为的出行需求,*Stops*选择为*stopParkingArea*,其他属性(如停留时间等)用户均可根据自身实践需求进行设定;

在这里插入图片描述

图8 设置停车需求

Step 3 将停车需求的各项属性设置好后,点击车辆在出行过程中需要停留的停车区域(需要在出行路径上),即可给该需求添加上停车行为;

在这里插入图片描述

图9 添加停车需求

Step 4 点击保存后,打开保存好的*.rou.xml*文件,可以看到,相应的停车需求生成成功。

<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/routes_file.xsd">
	<trip id="vehicle_0" depart="0" from="a" to="e">
		<stop parkingArea="parkingArea_e" duration="100.00"/>
	</trip>	
</routes>

2.3 通过TraCI动态加载

在实际的一些应用中,通过直接在*.rou.xml文件中编写和通过netedit编辑器来加载停车需求并不方便,这时候可以通过TraCI来动态加载出行需求和停车需求。TraCI动态加载需求的方式更加灵活,可以在每一个仿真步长中判断是否添加出行需求,且借助Python*的部分工具可以实现对车辆运动的精准监控。

我们以一个简单的例子来介绍如何通过TraCI动态加载停车需求。仿真时间一小时,每半分钟加载一个车辆出行需求,OD均为a–>e,并均在parkingArea_e停放100秒。应用的TraCI相关命令有traci.route.addtraci.vehicle.add以及traci.vehicle.setParkingAreaStop

for step in range(3600):            # 仿真一小时(3600s)
    if step % 30==0:                # 每半分钟添加一个出行需求,并指定其停车位置
        # 定义相关变量
        tripid="trip"+str(step)     # 出行ID
        origin="a"                  # 出发路段
        destination="e"             # 终点路段
        vehid="v"+str(step)         # 车辆ID
        parkingArea='parkingArea_e' # 停车区域
    <span class="token comment"># 添加出行需求 &amp; 停车需求</span>

3 停车区重选择

在停车场的实践过程中,经常会遇到这种情况:当车辆行驶到系统为其分配的停车区域时,发现已经无空闲的停车位。此时车辆是无法在该区域进行停车的,在这种情况下,车辆可以在道路上等待,直到该停车区域出现了可用的停车位。但是在现实场景中,司机会根据自己的需求与实际情况重新选择一个新的停车区域,因此,SUMO中也提供了让车辆重新选择一个停车区的功能。

针对停车区重选择行为,在SUMO中可以通过定义*<rerouter>中的<parkingAreaReroute>元素来实现。该元素中会定义一组可以相互用作替代的停车区,定义在.add.xml*文件中,示例如下:

<rerouter id="Rerouter_1" edges="a b c">
	<interval begin="0" end="3600">
        <parkingAreaReroute id="parkingArea_a"/>
        <parkingAreaReroute id="parkingArea_b"/>
        <parkingAreaReroute id="parkingArea_c"/>
	</interval>
</rerouter>

*<rerouter>*的相关定义属性如下:

属性值类型定义
id字符串所定义的 rerouter的ID,用户自定义
edges浮点型一个路段id或一个路段id列表,车辆在这些路段上可以触发rerouter
probability浮点型车辆触发rerouter的概率,默认为1
timeThreshold时间(秒)rerouter触发时需与上一次触发时的间隔时间(默认为0)
vTypes字符串列表该rerouter适用的车辆类型,默认为适用所有车辆类型
off布尔型变量rerouter初始是否为不活动的,默认值:false

<interval>的属性主要是begin: rerouter生效的开始时间,以及end: rerouter生效的结束时间。

*<parkingAreaReroute>*的各个属性含义如下表所示:

属性值类型定义
id字符串已经定义好的停车区域ID
probability浮点型每个可选方案(即备用停车区域被选中概率)被选中的概率(默认为1)。在重路由中,所有定义的概率都自动归一化。
visible布尔型在车辆到达停车区域所在路段之前,是否知道该停车区的占用情况

通常而言,在以下两种情况时会触发停车的rerouter:

  • 当车辆到达停车区域并且由于容量不足而无法停车时;
  • 当*<parkingAreaReroute>元素具有属性 visible="true"时,车辆在没到达目标停车区域时就可知道目标停车区域的情况。若目标停车区域已满,且车辆位于<rerouter>元素中edge*属性中的路段时,车辆则会在备选停车区域中重新选择一个进行停车。

由于备选停车区域可能有多个,如上例,加入车辆初始的目标停车区域为parkingArea_a,若该停车区域已满,那么车辆则会根据一些因素的权重设置,选择parkingArea_b与parkingArea_c其中一个进行停车。相关的因素如下表:

属性默认值定义值是否越大越好
parking.probability.weight0parkingAreaReroute元素中所定义的probabilityyes
parking.capacity.weight0备选停车区域的总容量yes
parking.absfreespace.weight0备选停车区域的绝对空闲车位数yes
parking.relfreespace.weight0备选停车区域的相对空闲车位数yes
parking.distanceto.weight1车辆到达备选停车区域的距离no
parking.timeto.weight0车辆到达备选停车区域所要花费的时间(假设值)no
parking.distancefrom.weight0备选停车区域到车辆目的地的距离no
parking.timefrom.weight0备选停车区域到车辆目的地的行驶时间(假设值)no

SUMO会根据每个备选停车位的上述因子相对应的属性值,最终得出一个评估值 Pi=j=0nαjfj
若用户未对这部分因子进行设置,则默认parking.distanceto.weight因子的权重为1,其余因子的权重均为0,即可只有parking.distanceto.weight生效。另外需要注意得是,当*<parkingAreaReroute>*元素具有属性 visible="true"时,因子的值均是准确的;若visible=“false”,各项因子的值均为一个随机数,即便一个备选停车区域停满了也很有可能被选中作为重新选择的停车区域。

用户定义这些因子的权重,可以在*<vehicle>元素或<vType>*元素中定义:

<vehicle id="v0" route="route0" depart="0">
	<param key="parking.capacity.weight" value="0.5"/>
    <param key="parking.timeto.weight" value="0.1"/>
    ......
</vehicle>
<vType id="veh_1" width="1.5" length="3.50" maneuverAngleTimes="10 3.0 4.0,80 1.6 11.0,110 11.0 2.0,170 8.1 3.0,181 3.0 4.0">
    <param key="parking.distanceto.weight" value="0"/>
    <param key="parking.distancefrom.weight" value="0.2"/>
    <param key="parking.absfreespace.weight" value="0.8"/>
    ......
</vType>

4 停车场景仿真实例

在本章节的实例中,我们来实现一个简单的智能停车场管理系统

4.1 路网与停车设施构建

我们首先构建如图11所示的停车场路网,出入口分别有两个。

在这里插入图片描述

图11 停车场路网

在该路网的基础上,在部分路段中构建停车区域,如图11所示:

在这里插入图片描述

图12 停车场设施构建

4.2 停车场状态感知模块

本场景中,分别实现了两种程度的停车场状态感知模块:半感知与全感知。

  • 半感知:仅感知当前停车场内所有区域的占用状态;
  • 全感知:能感知当前停车场内所有区域的占用状态以及车辆的停车动向。
(1)半感知
class Half_perception:
	# 感知停车场桩体,以“停车区域--占有率”表示
    def Perceived_occupancy(self):
        # 获取所有停车区域的ID
        ParkingAreaList=traci.parkingarea.getIDList()
        
        # 遍历所有停车区域,获取每一个区域的占有率
        Occ=list(map(lambda x: float(traci.simulation.getParameter(x, 
            "parkingArea.occupancy")), ParkingAreaList))

        # 构建一个datafrmame来存储“停车区域--占有率”
        ParkingOcc=pd.DataFrame({"ParkingArea":ParkingAreaList,"Occupancy":Occ})

        return ParkingOcc
    
    # 获取可用停车区域
    def get_AvailableParking(self):
        # 获取“停车区域--占有率”关系表
        ParkingOcc=self.Perceived_occupancy()
        
        # 获取占有率小于1的停车区域列表
        AvailableParking=list(ParkingOcc[ParkingOcc["Occupancy"]< 1]["ParkingArea"])
        
        return AvailableParking

  
  
(2)全感知

我们定义了另一个类Com_perception来实现全感知模块。

class Com_perception:
    def __init__(self):
        # 获取所有停车区域的ID
        ParkingAreaList=traci.parkingarea.getIDList()
        
        # 遍历所有停车区域,获取每一个区域的总容量
        Capacity=list(map(lambda x: float(traci.simulation.getParameter(x,                                                          "parkingArea.capacity")),ParkingAreaList))
        
        # 构建一个datafrmame来存储“停车区域--容量”
		self.ParkingCapacity=pd.DataFrame
            ({"ParkingArea":ParkingAreaList,"Capacity":Capacity})

    # 函数Add_update用于当车辆决定选择某个停车区域后,更新停车区域的剩余容量,即使该车辆还未行驶到停车区
    def Add_update(self,parkingArea):
        # 车辆进入停车场后,选择停在parkingArea(可用),则parkingArea的容量减1
        self.ParkingCapacity.loc[(self.ParkingCapacity.ParkingArea == parkingArea), 
                                 'Capacity'] -= 1

    # 函数Leave_update用于当车辆离开停车位时,更新停车区域的剩余容量
    # parkInformation为存储的“车辆--停车区域”关系表,即每个车辆停在了哪个停车区
    def Leave_update(self,VehiclePark): 
        
        # traci.simulation.getStopEndingVehiclesIDList()获取准备离开停车位的车辆列表
        for veh in list(traci.simulation.getStopEndingVehiclesIDList()):
            # 获取这些车辆所停的停车区域
            parkingArea=VehiclePark[VehiclePark.Veh==veh]["park"].values[0]
            
            # 更新该区域容量
            self.ParkingCapacity.loc[(self.ParkingCapacity.ParkingArea == parkingArea), 
                                     'Capacity'] += 1
    
    # 获取“停车区域--剩余容量”
    def get_ParkingCapacity(self):
        
        return self.ParkingCapacity
    
    # 获取可用停车区域
    def get_AvailableParking(self):
        # 获取“停车区域--剩余容量”关系表
        ParkingCapacity=self.get_ParkingCapacity()

        # 获取剩余容量大于0的停车区域列表
        AvailableParking=list(ParkingCapacity[ParkingCapacity["Capacity"]>0]
                              ["ParkingArea"])

        return AvailableParking

    
    

4.3 车位选择模块

(1)随机策略

在这里插入图片描述

图13 随机策略流程图

class Allocation:
    def __init__(self):
        # 实例化感知模块
        # self.Perception=Half_perception()      # 半感知
        self.Perception = Com_perception()   # 全感知

    # 随机策略
    def Random_allocation(self):
        # 获取可用的停车区域列表
        AvailableParking=self.Perception.get_AvailableParking()
		
        # 利用random.choice从AvailableParking中随机选取一个可用的停车区域
        TargetParking=random.choice(AvailableParking)
        
        return TargetParking

      
      
(2)贪婪策略

贪婪策略

最终的效果动画:

![最终的效果图](https://img-blog.csdnimg.cn/70811a42be2c4965b5447009a8d14357.gif)

转载原文地址:

https://blog.csdn.net/weixin_41270146/article/details/122691500

github源码:

https://github.com/JunXie-ZH/SUMO_Tutorial/tree/main/Parking
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值