What is the Traffic Manager?
在模拟环境中,交通管理器(Traffic Manager, TM)是控制自动驾驶模式下的车辆的模块。它的目标是模拟真实的城市交通状况。用户可以自定义一些行为,例如设置特定的学习环境(learning circumstances)
Structured design
TM 建立在 CARLA 的客户端上,其执行流程被划分为多个阶段,每个阶段都有独立的操作和目标。这促进了与阶段相关(phase-related)的功能和数据结构的开发,同时提高了计算效率。每个阶段运行在不同的线程上。通过同步消息(synchronous messaging)传递管理与其他阶段的通信,其信息是单向流动的。
User customization
用户可以通过设置参数来允许、强制或鼓励某些特定行为,从而对交通流量(traffic flow)进行一些控制。此外,用户可以在线或离线修改交通行为(如:汽车可以无视限速或强制换道)。在模拟现实场景时,能够自定义(play around with)交通行为是必不可少的。驾驶系统需要在特定和非典型情况下进行训练。
Architecture
Overview
上图展示了 TM 的内部架构,每个组件的 C++ 代码可以在LibCarla/source/carla/trafficmanager
(carla 源码中)中找到。以下部分将详细解释每个组件,一个简单的逻辑概述如下:
- 存储和更新当前的模拟状态
- 代理生命周期和状态管理(ALSM)扫描世界,跟踪所有出现的车辆和行人,并清理那些不再存在的实体。所有的数据来自服务器,这些数据会通过几个阶段进行传递。ALSM是唯一一个调用服务器的组件。
- 车辆注册表(vehicle registry)包括自动驾驶车辆的数组(由 TM 控制)和不是自动控制的行人和车辆的列表(不由 TM 控制)。
- 仿真状态(simulation state)是仿真中所有车辆和行人的位置、速度和附加信息的缓存存储。
- 计算每个自动驾驶车辆的运动
TM 根据仿真状态为车辆注册表(vehicle registry)中的所有车辆生成可行的命令,每辆车的计算是分开进行的,这些计算被分为多个不同的阶段。控制循环通过在阶段之间创建同步屏蔽(synchronization barriers) 来确保所有计算是一致的。在当前阶段的所有车辆计算完成之前,没有车辆会进入下一阶段。每辆车都要经过以下几个阶段:
-
Localization Stage(定位阶段?)
路径(Paths)是使用从 In-Memory Map 中收集的附近航点(waypoints)列表动态创建的,其作为航点(waypoints)网格的简化模拟地图,交叉口的方向是随机选择的。每辆车的路径由路径缓冲器和车辆跟踪(PBVT)组件存储和维护,以便于在未来阶段访问和修改。
-
碰撞阶段
边界框(Bounding boxes)扩展到每辆车的路径上,以识别并绕过潜在的碰撞危险。
-
交通灯阶段
与碰撞阶段类似,由于交通灯影响、停车标志和路口优先级等因素的原因,影响车辆路径的潜在危险也会被识别出来。
-
运动规划阶段
车辆的移动是基于已定义的路径来计算的。PID 控制器决定如何到达目标航点(waypoints),然后将其转换为 CARLA 的命令,以便在下一步中应用。
-
车灯阶段
车灯会根据环境因素(如:阳光、雾或雨的存在)和车辆行为(如:车辆在下个路口左转/右转时,亮方向灯;刹车时,亮停止灯)动态开关。
- 在模拟中应用命令
将上一步生成的命令收集到命令数组(command array)中,批量发送到 CARLA 服务器,在同一帧中应用。下面的部分将更详细地解释上面描述的 TM 逻辑中的每个组件和阶段。
ALSM
ALSM 代表代理生命周期和状态管理,它是 TM 逻辑循环(logic cycle)的第一步,提供了仿真环境当前状态的上下文。其具有以下特点:
- 扫描世界(world),跟踪所有车辆和行人的位置和速度。如果启用了物理特性,则由
Vehicle.get_velocity()
来获取当前车辆速度。否则,速度是利用历史位置和时间来计算的。 - 在模拟状态(simulation state)组件中存储每个车辆和行人的位置、速度和附加信息(交通灯影响、边界框等)。
- 更新车辆注册表(vehicle registry)中 TM 控制车辆的名单
- 更新控制循环(control loop)和 PBVT 组件中的实体,以匹配车辆注册表。
相关 cpp 文件:ALSM.h
, ALSM.cpp
Vehicle registry
车辆注册表(vehicle registry)记录了模拟中的所有车辆和行人。其具有以下特点:
- 通过 ALSM 更新的车辆和行人名单
- 将注册到 TM 的车辆存储在一个单独的数组中,以便在控循环(control loop)期间进行迭代。
相关 cpp 文件:MotionPlannerStage.cpp
Simulation state
仿真状态(simulation state)存储关于仿真中所有车辆的信息,以便在后期方便地访问和修改。其具有以下特点:
- 接收来自 ALSM 的数据,包括当前角色(actor)位置、速度、交通灯影响、交通灯状态等。
- 将所有信息存储在缓存中,避免在控制循环(control loop)期间对服务器进行后续调用。
相关 cpp 文件:SimulationState.cpp
, SimulationState.h
Control loop
控制循环(control loop)管理所有自动驾驶车辆的下一个命令的计算,因此它们是同步执行的。其由定位,碰撞,交通灯,运动规划和车灯这五个不同的阶段组成。其具有以下特点:
- 从车辆注册表(vehicle registry)接收 TM 控制的车辆数组
- 独立地在数列上循环执行每个车辆的计算
- 将计算分为一系列阶段
- 在阶段之间创建同步屏蔽(synchronization barriers)以保证一致性。所有车辆的计算在它们进入下一阶段之前完成,确保所有车辆在同一帧中更新。
- 协调阶段之间的转换,这样所有的计算都是同步完成的
- 当最后阶段(运动规划阶段和车灯阶段)结束时,发送命令数组(command array)到服务器,这样在命令计算和命令应用之间就没有帧延迟
相关 cpp 文件:TrafficManagerLocal.cpp
In-Memory Map
In-Memory Map 是 PBVT 中包含的一个辅助模块,其在定位阶段(Localization stage)使用。具有如下特点:
- 将地图转换为离散航点(waypoints)的网格
- 在特定的数据结构中包含具有更多信息的航点,以连接航点(waypoints)和识别道路、路口等
- 用一个 ID(用来快速定位附近地区的车辆)来识别这些建筑
相关 cpp 文件:InMemoryMap.cpp
和SimpleWaypoint.cpp
PBVT
PBVT 代表路径缓冲和车辆跟踪,它也是一种数据结构,包含了每辆车的预期路径,并允许在控制循环(control loop)中轻松访问数据。其具有以下特点:
- 包含 deque 对象的映射,每个车辆有一个实体?
- 包含每个车辆的一组航点,这些点描述了其当前位置和短期路径规划
- 包含定位阶段使用的 In-Memory Map,将每辆车与最近的航点和可能重叠的路径联系起来
PID controller
PID 控制器是一个辅助模块,其在运动规划阶段执行计算。具有以下特点:
- 利用运动规划阶段收集的信息,估计油门、刹车和转向所需的输入以达到一个目标值
- 根据控制器的具体参数进行调整。如果需要,可以修改参数
相关 cpp 文件:PIDController.cpp
Command Array
命令数列(command array)是 TM 逻辑周期的最后一步,它接收所有注册车辆的命令并应用它们。其具有如下特点:
- 接收一系列来自运动规划阶段的
carla.VehicleControl
- 批量处理同一帧内应用的所有命令
- 将批处理发送到 CARLA 服务器,从而在
carla.Client
中调用apply_batch()
或apply_batch_sync()
,这取决于仿真是在异步模式还是同步模式下运行
相关 cpp 文件:TrafficManagerLocal.cpp
Stages of the Control Loop
Stage 1- Localization Stage
定位阶段定义了由 TM 控制的车辆的短期路径规划,其具有如下特点:
- 从仿真状态中获取所有车辆的位置和速度
- 使用 In-Memory Map 将每辆车与一个航点(waypoints)列表联系起来,该列表描述了它的当前位置和根据其轨迹(trajectory)得出的短期路径规划。车子开得越快,该列表就越长
- 根据规划决策(如:变道、限速、与前车距离参数化等)更新路径
- 将所有车辆的路径存储在 PBVT 模块中
- 相互比较路径,以估计可能的碰撞情况。结果被传递到碰撞阶段
相关 cpp 文件:LocalizationStage.cpp
and LocalizationUtils.cpp
Stage 2- Collision Stage
碰撞阶段触发碰撞危险,其具有如下特点:
- 从定位阶段接收车辆对(vehicle pairs)的列表,这些车辆对的路径可能重叠
- 沿着前方道路(测地线边界)为每个车辆对扩展边界框,以检查它们是否真正重叠,并确定碰撞风险是否真实存在
- 将所有可能碰撞的危险信息发送到运动规划阶段,以修改相应的路径
相关 cpp 文件:CollisionStage.cpp
Stage 3- Traffic Light Stage
由于交通监管(如:交通灯,停止标志,优先路口),交通灯阶段会引发危险。其具有如下特点:
- 如果车辆受到黄灯、红灯或停止标志的影响,则设置交通危险(hazard)
- 如果车辆在无信号路口,沿着车辆的路径扩展边界框。路径重叠的车辆按照“先进先出”的顺序移动。等待时间设置为固定值
相关 cpp 文件:TrafficLightStage.cpp
Stage 4- Motion Planner Stage
运动规划阶段产生应用于车辆的 CARLA 命令,其具有以下特点:
- 收集车辆的位置和速度(simulation state)、路径(PBVT)和危险(Collision Stage and Traffic Light Stage)
- 对车辆应该如何移动做出高层决策,例如,计算防止碰撞危险所需的刹车。用 PID 控制器根据目标值估计行为
- 将期望的动作转换为
carla.VehicleControl
应用于车辆 - 将最终产生的 CARLA 命令发送到命令数组(command array)
相关 cpp 文件:MotionPlannerStage.cpp
Stage 5- Vehicle Lights Stage
车灯阶段根据车辆的状况和周围环境激活车灯,其具有如下特点:
- 获取车辆计划的航点,有关车辆灯的信息(如:灯光状态和计划的命令应用)和天气条件
- 确定车灯新状态:
- 如车辆计划在下一个路口左转/右转,则打开转向灯
- 如果应用的命令要求车辆刹车,则打开刹车灯
- 从日落到黎明,或在大雨下,打开近光灯和位置灯
- 在浓雾条件下打开雾灯
- 如果车灯状态发生变化,则更新车灯状态
相关 cpp 文件:VehicleLightStage.cpp
Using the Traffic Manager
Vehicle behavior considerations
当您将车辆设置为自动驾驶时,TM 实现了必须考虑的一般行为模式:
- 车辆不是目标导向的(goal-oriented),它们遵循动态生成的轨迹,并在接近路口时随机选择一条路径。他们的道路是无尽的
- 车辆的目标速度是其当前速度限制的 70%,除非被设置为其他值
- 路口优先级不符合交通规则,TM 在路口使用自己的优先系统。解决这一限制的工作正在进行中。与此同时,可能会出现一些问题,例如,环岛内的车辆会避让试图进入的车辆
TM 的行为可以通过 Python API 进行调整。有关具体方法,请参阅 Python API 文档的 TM 部分。以下是通过API可以实现的一些功能:
Topic | Description |
---|---|
General: | - Create a TM instance connected to a port. - Retrieve the port where a TM is connected. |
Safety conditions: | - Set a minimum distance between stopped vehicles (for a single vehicle or for all vehicles). This will affect the minimum moving distance. - Set the desired speed as a percentage of the current speed limit (for a single vehicle or for all vehicles). - Reset traffic lights. |
Collision managing: | - Enable/Disable collisions between a vehicle and a specific actor. - Make a vehicle ignore all other vehicles. - Make a vehicle ignore all walkers. - Make a vehicle ignore all traffic lights. |
Lane changes: | - Force a lane change, ignoring possible collisions. - Enable/Disable lane changes for a vehicle. |
Hybrid physics mode: | - Enable/Disable hybrid physics mode. - Change the radius in which physics is enabled. |
Creating a Traffic Manager
TM 被设计成在同步模式下工作,在异步模式下使用 TM 可能会导致意想不到的不良结果。一个 TM 实例由 carla.Client
创建,传递要使用的端口,默认端口为 8000。可通过以下代码创建 TM 实例:
tm = client.get_trafficmanager(port)
要为一组车辆启用自动驾驶(autopilot)模式,需要获取 TM 实例的端口,并将 set_autopilot
设置为 True,同时通过 TM 端口。如果没有提供端口,它将尝试连接到默认端口 8000。如果TM不存在,它将创建一个:
tm_port = tm.get_port()
for v in vehicles_list:
v.set_autopilot(True,tm_port)
在多客户端情况下创建或连接到 TM 与上面的示例不同。/PythonAPI/examples
中的 generate_traffic.py
脚本提供了一个例子,展示如何使用一个作为脚本参数的端口创建一个 TM 实例,并通过批量设置autopilot
为 True 来注册每一辆生成的车辆:
traffic_manager = client.get_trafficmanager(args.tm-port)
tm_port = traffic_manager.get_port()
...
batch.append(SpawnActor(blueprint, transform).then(SetAutopilot(FutureActor, True,tm_port)))
...
traffic_manager.global_percentage_speed_difference(30.0)
Configuring autopilot behavior
下面的例子创建了一个 TM 实例,并为特定的车辆配置危险行为,这样它就会忽略所有的交通灯,不与其他车辆保持安全距离,并以比当前限速快 20% 的速度行驶:
tm = client.get_trafficmanager(port)
tm_port = tm.get_port()
for v in my_vehicles:
v.set_autopilot(True,tm_port)
danger_car = my_vehicles[0]
tm.ignore_lights_percentage(danger_car,100)
tm.distance_to_leading_vehicle(danger_car,0)
tm.vehicle_percentage_speed_difference(danger_car,-20)
下面的示例将相同的车辆列表设置为自动驾驶,并为它们配置适当的驾驶行为。车辆以低于当前限速 80% 的速度行驶,与其他车辆之间至少保持 5 米的距离,且不进行换道:
tm = client.get_trafficmanager(port)
tm_port = tm.get_port()
for v in my_vehicles:
v.set_autopilot(True,tm_port)
danger_car = my_vehicles[0]
tm.global_distance_to_leading_vehicle(5)
tm.global_percentage_speed_difference(80)
for v in my_vehicles:
tm.auto_lane_change(v,False)
Delegating the Traffic Manager to automatically update vehicle lights
默认情况下,TM 管理的车辆的车灯(刹车、转弯指示灯等)永远不会更新。可以委托 TM 更新给定车辆的车灯:
tm = client.get_trafficmanager(port)
for actor in my_vehicles:
tm.update_vehicle_lights(actor, True)
车辆的灯光管理必须在每辆车的基础上指定,在任何给定的时间,车辆都可以存在或不存在自动灯光管理。
Stopping a Traffic Manager
TM 不是一个需要被摧毁的 actor;当创建它的客户端关闭时,它也会关闭。这是由 API 自动管理的,用户不需要做任何事情。然而,当关闭一个 TM 时,用户必须摧毁它所控制的车辆,否则他们将在地图上保持静止。脚本 generate_traffic.py
会自动完成这个操作:
client.apply_batch([carla.command.DestroyActor(x) for x in vehicles_list])
注:关闭一个 TM-Server 将关闭连接到它的 TM-Clients
Deterministic mode
在确定模式(deterministic mode)下,TM 在相同条件下将会产生相同的结果和行为。不要把 determinism 和 recorder 混为一谈。recorder 允许存储模拟的日志以进行回放,而 determinism 则是确保只要保持相同的条件,TM 在不同的脚本执行过程中始终具有相同的输出。
确定模式(deterministic mode)仅在同步模式下可用。在异步模式下,对仿真的控制更少,无法实现 determinism 。
要启用确定模式(deterministic mode),请使用以下方法:
my_tm.set_random_device_seed(seed_value)
seed_value
是一个整数,将根据它生成随机数。值本身是不相关的,但是相同的值总是会产生相同的输出。在相同的条件下,使用相同种子值的两个模拟将是确定的(deterministic)。
为了在多次模拟运行中保持确定性(determinism),必须为每个模拟设置种子。例如,每当玩家重新加载游戏世界时,他们便需要重新设置种子:
client.reload_world()
my_tm.set_random_device_seed(seed_value)
确定模式(deterministic mode)可以在 generate_traffic.py
示例脚本中通过传递一个种子值作为参数来测试。下面的例子在同步模式下设置一个带有 50 个自动驾驶角色(actors)的地图,并将 seed 设置为任意值 9
:
cd PythonAPI/examples
python3 generate_traffic.py -n 50 --seed 9
注:在启用确定性模式(deterministic mode)之前,CARLA 服务器和 TM 必须处于同步模式。
Hybrid physics mode
混合模式(Hybrid mode)允许用户禁用所有自动驾驶车辆的大多数物理计算,或将在标记为hero
的车辆的一定半径外的自动驾驶车辆禁用物理计算?这消除了模拟中的车辆物理瓶颈(bottleneck)。物理失效的车辆将通过瞬间移动来移动。保持基本的线性加速度计算,以确保位置更新和车辆速度保持现实,车辆物理计算的切换是流动的。
混合模式(Hybrid mode)使用 Actor.set_simulate_physics()
方法来切换物理计算。默认禁用,有两个选项来启用它:
TrafficManager.set_hybrid_physics_mode(True)
—— 这个方法为调用它的 TM 对象启用混合模式。- 运行
generate_traffic.py
并附加标志--hybrid
—— 这个示例脚本创建一个 TM,并在生成 autopilot 车辆。然后,当--hybrid
标志作为脚本参数传递时,它将这些车辆设置为混合模式。
要修改混合模式的行为,可以使用以下两个参数:
- Radius(default = 50 meters) —— 半径与标记
hero
的车辆相关。在此半径内的所有车辆将启用物理效果;在半径之外的车辆物理功能将失效。使用traffic_manager.set_hybrid_physics_radius(r)
修改 radius 的大小。 - Hero vehicle —— 标记为
role_name='hero'
的车辆,作为半径的中心- 如果没有
hero vehicle
,所有车辆的物理效果将被禁用 - 如果有一个以上的
hero vehicle
,将考虑所有的半径,创造不同的影响区域,并启用物理特性
- 如果没有
下面的剪辑显示了当混合模式激活时,物理是如何启用和禁用的。英雄的车辆标有一个红色方块,物理失效的车辆被标记为蓝色方块。在英雄车的影响范围内,物理效果被激活,标签变成绿色。
Running multiple Traffic Managers
Traffic Manager servers and clients
CARLA 客户端通过向服务器指定要使用的端口来创建 TM。如果未指定端口,则使用默认的 8000。如果在同一端口上创建更多的 TM,它们将成为 TM-Clients,而原来的 TM 将成为 TM-Server。
TM-Server
TM-Server 是第一个连接到空闲端口的 TM,然后其他 TM (TM-Clients)连接到运行 TM-Server 的相同端口。TM-Server 将指示所有 TM-Clients 的行为,例如,如果 TM-Server 停止时,所有 TM-Clients 将停止。
下面的代码创建两个 TM-Server。每个都连接到一个不同的、未使用的端口:
tm01 = client01.get_trafficmanager() # tm01 --> tm01 (p=8000)
tm02 = client02.get_trafficmanager(5000) # tm02(p=5000) --> tm02 (p=5000)
TM-Client
当一个 TM 连接到另一个 TM(TM-Server)所占用的端口时,将会创建 TM-Client,TM-Client 行为将由 TM-Server 决定。下面的代码将创建两个 TM-Client,每个都连接上一节中创建的 TM-Server:
tm03 = client03.get_trafficmanager() # tm03 --> tm01 (p=8000).
tm04 = client04.get_trafficmanager(5000) # tm04(p=5000) --> tm02 (p=5000)
Multi-client simulations
在多客户端模拟中,在同一个端口上创建多个 TM。第一个创建的 TM 将作为一个 TM-Server,后面再连接到该端口的作为 TM-Clients。TM-Server 将指定所有 TM 实例的行为:
terminal 1: ./CarlaUE4.sh -carla-rpc-port=4000
terminal 2: python3 generate_traffic.py --port 4000 --tm-port 4050 # TM-Server
terminal 3: python3 generate_traffic.py --port 4000 --tm-port 4050 # TM-Client
Multi-TM simulations
在多 TM 模拟中,在不同的端口上创建多个 TM 实例。每个 TM 实例将控制它自己的行为:
terminal 1: ./CarlaUE4.sh -carla-rpc-port=4000
terminal 2: python3 generate_traffic.py --port 4000 --tm-port 4050 # TM-Server A
terminal 3: python3 generate_traffic.py --port 4000 --tm-port 4550 # TM-Server B
Multi-simulation
多仿真(Multi-simulation)是指同时运行多个 CARLA 服务器。TM 需要连接到相关的 CARLA 服务器端口,只要计算能力允许,TM 可以在同一时间运行多个模拟:
terminal 1: ./CarlaUE4.sh -carla-rpc-port=4000 # simulation A
terminal 2: ./CarlaUE4.sh -carla-rpc-port=5000 # simulation B
terminal 3: python3 generate_traffic.py --port 4000 --tm-port 4050 # TM-Server A connected to simulation A
terminal 4: python3 generate_traffic.py --port 5000 --tm-port 5050 # TM-Server B connected to simulation B
多仿真的概念独立于 TM 本身。上面的例子并行地运行了两个 CARLA 模拟,在每个模拟中,一个 TM-Server 是独立于另一个创建的。模拟 A 可以运行一个多客户端(multi-client)的 TM,而模拟 B 运行多个 TM 或者根本不运行 TM。
上述设置最可能产生的问题是,客户端试图连接到一个已经存在的 TM,而 TM 没有运行在选定的模拟上。如果发生这种情况,连接将会被中止,以防止模拟之间的干扰。
Synchronous mode
TM 被设计成在同步模式下工作,为了正常工作,CARLA 服务器和 TM 都应该设置为同步。在异步模式下使用TM可能会导致意想不到的结果。但如果需要异步模式,模拟至少应该以 20-30fps 的速度运行。
下面的脚本演示了如何将服务器和 TM 设置为同步模式:
...
# Set the simulation to sync mode
init_settings = world.get_settings()
settings = world.get_settings()
settings.synchronous_mode = True
# After that, set the TM to sync mode
my_tm.set_synchronous_mode(True)
...
# Tick the world in the same client
world.apply_settings(init_settings)
world.tick()
...
# Always disable sync mode before the script ends to prevent the server blocking whilst waiting for a tick
settings.synchronous_mode = False
my_tm.set_synchronous_mode(False)
generate_traffic.py
示例脚本启动一个 TM,并用车辆和行人填充地图。它自动将 TM 和 CARLA 服务器设置为同步模式:
cd PythonAPI/examples
python3 generate_traffic.py -n 50
如果需要异步模式,在运行上述命令时使用--async
标志
如果多个 TM 被设置为同步模式,同步将会失败。请遵循以下指引以避免该问题:
- 在多客户端(multiclient)情况下,只有 TM-Server 应该被设置为同步模式
- 在多 TM(multiTM)的情况下,只有一个 TM-Server 应该被设置为同步模式
- ScenarioRunner 模块自动运行一个 TM,ScenarioRunner 内部的 TM 将自动被设置为同步模式
Traffic manager in large maps
Hero vehicle not present
所有自动驾驶车辆都将被视为休眠角色( dormant actors)。在混合模式下,休眠的自动驾车辆会在地图上移动。车辆将不会被渲染,因为没有hero vehicle
触发地图贴图流(map tile streaming)。
Hero vehicle present
当自动驾驶车辆超过了定义的actor_active_distance
的值时,它们将休眠(dormant)。要设置此值,可使用以下 Python API:
settings = world.get_settings()
# Actors will become dormant 2km away from the ego vehicle
settings.actor_active_distance = 2000
world.apply_settings(settings)
在 TM 中,休眠角色可以被设置为在 hero vehicle
周围持续重生,而不是在地图的其他地方保持休眠状态。这个选项可以在 Python API 中使用 set_respawn_dormant_vehicles
方法配置。车辆将在hero vehicle
周围重生,其距离是在用户指定距离内。respawnable 距离的上下边界可以使用set_boundaries_respawn_dormant_vehicles
方法设置。注意,最大距离不会大于大地图的贴图流距离,最小距离是20米。
在hero vehicle
25 米和 700 米范围内,休眠车辆可以重生:
my_tm.set_respawn_dormant_vehicles(True)
my_tm.set_boundaries_respawn_dormant_vehicles(25,700)
如果碰撞阻止了休眠角色(dormant actor)被重生,TM 将在下一个模拟步骤中重试。
如果休眠车辆没有重生,它们的行为将取决于混合模式是否启用。如果混合模式已经启用,那么休眠的角色将被传送到地图上。如果不启用混合模式,那么休眠者的物理状态将不会被计算出来,它们将保持在原来的位置,直到它们不再休眠。