Taxi

引言#

自 1.5.0 版本起,SUMO 通过出租车设备支持需求响应式交通(DRT)的模拟。这使得一队出租车能够基于可配置的调度算法来响应乘客请求。

Note

由于出租车功能仍在开发中,其状态可以通过 Issue #6418 进行检查。

装备车辆#

可以通过为车辆装备 Taxi 设备,使其成为出租车队列的一部分。要将 Taxi 设备附加到车辆,可以应用标准设备装备程序,使用 <device name>=taxi

例如,可以将单个车辆配置为出租车,如下列最小示例所示:

    <vehicle id="v0" route="route0" depart="0" line="taxi">
        <param key="has.taxi.device" value="true"/>
    </vehicle>

下表列出了出租车设备的所有可能参数(所有参数名称必须以 "device.taxi" 为前缀):

参数 (Parameter) 类型 (Type) 范围 (Range) 默认值 (Default) 描述 (Description)
dispatch-algorithm enum {greedy; greedyClosest; greedyShared; routeExtension; traci} greedy 调度算法
dispatch-algorithm.output string - 将调度算法的信息写入文件
dispatch-algorithm.params string - 为 greedyShared 调度算法提供 absLossThreshold 和 relLossThreshold 阈值,格式为 KEY1:VALUE1[,KEY2:VALUE]
dispatch-period float (s) 60 连续调用调度器之间的间隔时间
idle-algorithm enum {stop; randomCircling; taxistand} stop 空闲出租车的行为
idle-algorithm.output string - 将空闲算法的信息写入文件

出租车请求#

直接叫车#

可以通过以下定义将人员定义为出租车乘客:

    <person id="p0" depart="0.00">
        <ride from="B2C2" to="A0B0" lines="taxi"/>
    </person>

多模式路径规划#

人员也可以通过在 personTrip 模式中包含出租车来使用出租车:

    <person id="p0" depart="0.00">
        <personTrip from="B2C2" to="A0B0" modes="taxi"/>
    </person>

当人员在多模式路径搜索期间进入出租车时,会应用时间惩罚以解释等待出租车和登机的预期时间损失。默认值为 300 秒,可以通过选项 --persontrip.taxi.waiting-time 进行配置。这可以防止在旅行模式之间快速切换。

人员组#

多人可以作为一个组一起出行,使用属性 group(前提是出租车有足够的容量):

    <person id="p0" depart="0.00">
        <ride from="B2C2" to="A0B0" lines="taxi" group="g0"/>
    </person>
    <person id="p1" depart="0.00">
        <ride from="B2C2" to="A0B0" lines="taxi" group="g0"/>
    </person>

预订#

直接叫车可视为自发预订。如果要在人员到达上车地点之前请求出租车,则需要进行预订。这可以通过在 ride 中指定 earliestPickupTimereservationTime 来实现。reservationTime 指定创建预订并将其提供给调度的时间,它也可以小于人员的出发时间。earliestPickupTime 指定人员准备好上车的时间。根据所使用的算法,这可能允许进行更好的调度。特别是结合通过 TraCi 的自定义调度算法,可以满足不同用例的需求。

应用:#

  • 包含人员的文件必须作为附加文件加载。
  • 必须至少指定 earliestPickupTimereservationTime 的默认值为模拟的开始时间。
  • 必须在 ride 中定义 from 属性。
  • 如果之前有定义了 arrivalPos 属性的 walk,则 ride 中的 fromPos 属性也必须定义为相同的值。

示例:#

    <person id="p0" depart="100.00">
        <ride from="B2C2" to="A0B0" lines="taxi">
            <param key="earliestPickupTime" value="100.00"/>
            <param key="reservationTime" value="50.00"/>
        </ride>
    </person>
    <person id="p1" depart="0.00">
        <walk from="B2C2" to="B1C1"/>
        <ride from="B1C1" to="A1B1" lines="taxi">
            <param key="earliestPickupTime" value="30.00"/>
        </ride>
    </person>

行为:#

  • 如果人员早于 earliestPickupTime 到达出发点,则人员在出租车到达后立即登车。
  • 如果出租车准时到达,但人员在 earliestPickupTime 之后 3 分钟内未到达出发点,则预订被取消,出租车为下一个预订服务。
  • 如果出租车晚点到达,且人员在出租车到达时间之后 3 分钟内未到达出发点,则预订被取消。
  • 如果使用 greedy 或 greedyShared 调度算法,则预订按 earliestPickupTime 的顺序处理。自发预订和预订的组合可能会导致副作用。建议通过 TraCi 使用自定义调度算法。

注意:#

  • 尚不支持合并预订和团体预订的预订。
  • 当前状态可在 Ticket 11429 中跟踪。

多个出租车队列#

默认情况下,只有一个使用线路属性 'taxi' 的出租车队列,出租车乘客使用属性 lines="taxi" 进行乘车。 允许使用前缀 'taxi:' 和任意后缀(例如 "taxi:fleetA")定义出租车的线路属性。 同样,允许使用前缀 'taxi:' 和后缀定义乘车的 lines 属性。 完成此操作后,将出租车分配给乘客时应用以下规则:

  • 线路为 'taxi:X' 的出租车只能接送具有匹配乘车属性 lines="taxi:X" 的乘客(对于任何 X 值)
  • 具有 lines="taxi" 的乘客可以使用任何出租车,无论其队列后缀如何
  • 线路为 'taxi' 的出租车可以接送任何乘客,无论其乘车队列后缀如何

调度算法#

调度算法将出租车分配给等待的乘客。算法使用选项 --device.taxi.dispatch-algorithm ALGONAME 进行选择。提供以下算法:

  • greedy:按预订顺序将出租车分配给乘客。分配距离最近(以行驶时间计)的出租车。如果预订日期太远,则推迟该乘客。
  • greedyClosest:对于每辆可用的出租车,分配距离最近(以行驶时间计)的乘客。如果预订日期太远,则推迟该乘客。
  • greedyShared:类似于 'greedy',但在将第一位乘客送达目的地的同时尝试接载另一位乘客。可以使用 --device.taxi.dispatch-algorithm.params KEY1:VALUE1[,KEY2:VALUE] 提供参数 absLossThresholdrelLossThreshold 以配置可接受的绕行。
  • routeExtension:类似于 greedy,但可以沿路线接载任何乘客,并在 personCapacity 限制内扩展原始路线。
  • traci:调度委托给 traci 控制。该算法仅跟踪待处理的预订。

Note

欢迎用户贡献的调度算法。

调度算法运行的周期可以通过选项 --device.taxi.dispatch-period 控制。默认为 60 秒。

算法输出#

可以设置选项 --device.taxi.dispatch-algorithm.output FILE 以接收来自算法的额外输出(例如用于拼车指标)。

出租车行为#

默认情况下,出租车将保留在模拟中,直到所有人员离开。要使它们在更早的时间离开模拟,可以使用其 vTypevehicle 定义中的通用参数定义结束时间:

    <vType id="taxi" vClass="taxi">
        <param key="has.taxi.device" value="true"/>
        <param key="device.taxi.end" value="3600"/>
    </vType>

空闲行为#

默认情况下,车辆在到达其最终边的末端后将离开模拟。为避免这种情况,出租车具有可配置的空闲行为,使用选项 --device.taxi.idle-algorithm

  • "stop"(默认):在运送完当前服务请求的最后一位乘客后,停在当前位置(路外)。
  • "randomCircling":继续行驶到随机的边,直到收到下一个请求。(注意:如果网络中有死胡同,出租车可能会被困住)
  • "taxistand":行驶到出租车候客处并在那里等待下一位乘客/调度。定义出租车候客处集合以及从中选择的策略如下所述。

Note

使用 "randomCircling" 时,参数 "device.taxi.end" 的默认值为车辆出发后 8 小时。

定义出租车候客处#

当使用空闲算法 taxistand 时,必须提供以下输入:

  • 每个出租车候客处必须定义为一个 parkingArea
  • 可用于特定出租车或出租车队列的 parkingArea 列表必须根据停车搜索模拟的描述 定义为 <rerouter> 元素。
  • 出租车必须定义参数 device.taxi.stands-rerouter,作为 <vehicle> 或其 <vType> 的子元素,并声明 rerouter id。

默认情况下,空闲出租车将从替代列表中选择第一个 parkingArea(<rerouter> 中的 <parkingAreaReroute 条目)。 如果在车辆或 vType 中设置了通用参数 <param key="parking.ignoreDest" value="1"/>,则根据重定向策略使用“最佳”候客处(即距离当前车辆位置最近的候客处)。

选择替代出租车候客处的策略遵循停车搜索模拟的描述(即关于剩余容量的先验知识)。

rerouter 和引用它的出租车 vType 的示例声明:

<rerouter id="rr0" edges="B0C0 E2D2" vTypes="taxi">
        <interval begin="0" end="1:0:0:0">
            <parkingAreaReroute id="pa_0"/>
            <parkingAreaReroute id="pa_1"/>
        </interval>
</rerouter>

Note

为避免警告,rerouter 的 edges 属性应与包含出租车候客处的边匹配。

<vType id="taxi" vClass="taxi">
        <param key="has.taxi.device" value="true"/>
        <param key="device.taxi.stands-rerouter" value="rr0"/>
</vType>

乘客停靠点#

出租车将停靠以上下车。停靠点的 'actType' 属性指示目的('pickup' / 'dropOff')以及乘客的 id 和他们的预订 id。可以使用出租车的 <vType><vehicle> 定义中的通用参数配置停靠点属性:

    <vType id="taxi" vClass="taxi">
        <param key="has.taxi.device" value="true"/>
        <param key="device.taxi.pickUpDuration" value="0"/>
        <param key="device.taxi.dropOffDuration" value="60"/>
        <param key="device.taxi.parking" value="false"/>
    </vType>
  • 上车停靠点的持续时间可以使用 vType/vehicle 参数 "device.taxi.pickupDuration" 配置(默认 "0")
  • 下车停靠点的持续时间可以使用 vType/vehicle 参数 "device.taxi.dropOffDuration" 配置(默认 "60")

默认情况下,车辆停靠点具有属性 parking="true",这意味着出租车不会阻塞行车道。可以通过将参数 "device.taxi.parking" 设置为 "false" 来更改此行为。

TraCI#

为了将外部调度算法耦合到 SUMO,提供了以下 TraCI 函数:

Note

要使用这些函数,必须设置选项 --device.taxi.dispatch-algorithm traci

  • traci.person.getTaxiReservations(reservationState)
  • traci.vehicle.getTaxiFleet(taxiState)
  • traci.vehicle.dispatchTaxi(vehID, reservations)

这组 API 调用可用于简化编写自定义调度算法,通过让 sumo: - 管理现有预订 - 管理出租车队列 - 通过提供预订 ID 列表来调度出租车以服务一个或多个预订(然后车辆路由和停靠是自动的)。

getTaxiReservations#

返回具有以下属性的 Reservation 对象列表

  • id
  • persons
  • group
  • state
  • fromEdge
  • toEdge
  • arrivalPos
  • departPos
  • depart
  • reservationTime
  • state(正值,见下文)

调用 traci.person.getTaxiReservations(reservationState) 时,支持以下 reservationState 参数:

  • 0:返回所有预订,无论状态如何
  • 1:仅返回新预订
  • 2:返回已检索的预订
  • 4:返回已分配给出租车的预订
  • 8:返回已被接载的预订

也支持这些值的组合。例如,发送值 3 (= 1 + 2) 将返回状态为 1 和 2 的所有预订。

getTaxiFleet#

出租车可以处于以下任何状态:

  • 0 (空闲):出租车空闲
  • 1 (接客途中):出租车正在前往接乘客的路上
  • 2 (已载客):出租车上有乘客,正在前往下车点
  • 3 (接客途中 + 已载客):出租车上有乘客,但将接载更多乘客

调用 traci.vehicle.getTaxiFleet(taxiState) 时,支持以下 taxiState 参数:

  • -1:(返回所有出租车,无论状态如何)
  • 0:仅返回空闲出租车
  • 1:返回状态为 1 和 3 的出租车
  • 2:返回状态为 2 和 3 的出租车
  • 3:返回状态为 3 的出租车

dispatchTaxi#

如果出租车是空闲的,则支持以下调度调用:

  • dispatchTaxi(vehID, [reservationID]):接载并送走属于给定预订 ID 的人员
  • 如果给出多个预订 ID,则每个单独的预订 ID 必须在列表中恰好出现两次,以便完整地上下车。ID 的第一次出现表示上车,第二次出现表示下车。

示例 1:dispatchTaxi(vehID, [a]) 表示:接载并送走 a。 示例 2:dispatchTaxi(vehID, [a, a, b, c, b, c]) 表示:接载并送走 a,然后接载 b 和 c,然后送走 b 和 c。

如果出租车不处于空闲状态,则支持以下重新调度调用:

  • 新预订与之前的预订没有重叠:将新预订附加到之前的预订
  • 新预订包含所有之前的唯一预订 ID 恰好两次:重置当前路线和停靠点,并视为完整的新调度。如果之前预订的某个人员已被接载,则忽略预订列表中该预订的第一次出现
  • 新预订包含所有之前的唯一预订 ID 一次或两次,所有提及一次的客户都已被接载:重置当前路线和停靠点,使用单次出现的 ID 作为下车点

控制空闲出租车#

默认的空闲算法("stop")旨在确保出租车不会退出模拟(如果它曾经驶过其路线的最终边,就会发生这种情况)。为此,它使出租车停在当前位置或使用出租车路线上的现有停靠点,并将其设置为 triggered="person"(这实际上使出租车无限期等待,直到下一次调度)。

为了将空闲出租车发送到另一个目的地,需要按顺序执行以下操作:

  1. 出租车需要扩展其路线(例如使用 vehicle.changeTargetvehicle.setRoute
  2. 必须使用 vehicle.resume 中止当前停靠点
  3. 必须添加新的停靠点(例如使用 vehicle.setStop)。

输出#

出租车设备在 tripinfo 输出文件中生成以下形式的输出:

    <tripinfo id="trip_0" ... >
        <taxi customers="5" occupiedDistance="6748.77" occupiedTime="595.00"/>
    </tripinfo>

参数检索#

可以通过 traci.vehicle.getParameter 检索以下参数,并通过 --fcd-output.params 写入。 也可以通过在 SUMO-GUI 'by param (numerical)' 中设置这些键来为车辆着色。

  • device.taxi.state:返回整数值(参见 #gettaxifleet)
  • device.taxi.customers:服务的乘客总数
  • device.taxi.occupiedDistance:载客行驶的总距离(米)
  • device.taxi.occupiedTime:载客行驶的总时间(秒)
  • device.taxi.currentCustomers:以空格分隔的待接载或已在车上的人员列表