1. 目的
默认情况下,Carla运行在异步模式下。服务器与客户端以各自的速度运行。当客户端请求到来时,服务器相应请求,处理结束之后继续运行,并不等待客户端处理完成服务器返回的数据。
存在的问题是,当保存相机传感器在Carla中获取的场景数据时,保存的数据有可能不连续,即缺帧。
在使用Carla获取训练数据时,设置Carla的同步模式很有必要。
When you want to start producing training data or deploying an agent within the simulation, it is advised that you use the synchronous mode since this will give you more control and predictability
2. 时间步长
在设置Carla同步模式前,需要先了解Carla中的时间步长。
在Carla中,定义时间步长为服务器状态变化需要的时间。时间步长分为可变时间步长与固定时间步长。
可变时间步长中,服务器每次状态变化所需要的时间都不固定。
#在代码中设置
settings = world.get_settings()
settings.fixed_delta_seconds = None # Set a variable time-step
world.apply_settings(settings)
#使用.py文件设置
cd PythonAPI/util && python3 config.py --delta-seconds 0
固定时间步长中,服务器每次状态变化需要的时间都相同,如果服务器实际所需的时间小于用户设置的时间步长,那么服务器将进入等待。
#在代码中设置
settings = world.get_settings()
settings.fixed_delta_seconds = 0.05
world.apply_settings(settings)
#使用.py文件设置
cd PythonAPI/util && python3 config.py --delta-seconds 0.05
设置固定时间步长为0.05,表示在1秒钟的时间内,服务器状态改变1/0.05=20次。
在同步模式下,Carla官方建议使用固定时间步长
Using the same time increment on each step is the best way to gather data from the simulation.
3.设置同步
Carla中,使用布尔值表示同步模式与异步模式,True表示同步模式,False表示异步模式。
settings = world.get_settings()
settings.synchronous_mode = True # 同步模式
settings.fixed_delta_seconds = 0.05 # 固定时间步长
world.apply_settings(settings)
设置异步模式只需要修改布尔值为False
#在代码中设置
settings = world.get_settings()
settings.synchronous_mode = False# Enables synchronous mode
settings.fixed_delta_seconds = None # 可变时间步长
world.apply_settings(settings)
#使用.py文件设置
cd PythonAPI/util && python3 config.py --no-sync # Disables synchronous mode
需要注意的是,无法通过上述.py文件将Carla设置为同步模式。
虽然Carla服务器可以连接多个客户端,但在连接的客户端中,只能有一个客户端设置Carla为同步模式。
4. 完整代码
代码来自 小飞自动驾驶系列分享[四]
import glob
import os
import sys
import random
import os
from queue import Queue
from queue import Empty
import numpy as np
try:
sys.path.append(glob.glob('../carla/dist/carla-*%d.%d-%s.egg' % (
sys.version_info.major,
sys.version_info.minor,
'win-amd64' if os.name == 'nt' else 'linux-x86_64'))[0])
except IndexError:
pass
import carla
def sensor_callback(sensor_data, sensor_queue, sensor_name):
if 'lidar' in sensor_name:
sensor_data.save_to_disk(os.path.join('../outputs/output_synchronized', '%06d.ply' % sensor_data.frame))
if 'camera' in sensor_name:
sensor_data.save_to_disk(os.path.join('../outputs/output_synchronized', '%06d.png' % sensor_data.frame))
sensor_queue.put((sensor_data.frame, sensor_name))
def main():
actor_list = []
sensor_list = []
try:
# 连接Carla服务器
client = carla.Client('localhost', 2000)
client.set_timeout(10.0)
world = client.get_world()
blueprint_library = world.get_blueprint_library()
# 设置同步模式
original_settings = world.get_settings()
settings = world.get_settings()
settings.fixed_delta_seconds = 0.05
settings.synchronous_mode = True
world.apply_settings(settings)
traffic_manager = client.get_trafficmanager()
traffic_manager.set_synchronous_mode(True)
sensor_queue = Queue()
# 创建车辆
ego_vehicle_bp = blueprint_library.find('vehicle.mercedes-benz.coupe')
ego_vehicle_bp.set_attribute('color', '0, 0, 0')
transform = random.choice(world.get_map().get_spawn_points())
ego_vehicle = world.spawn_actor(ego_vehicle_bp, transform)
ego_vehicle.set_autopilot(True)
actor_list.append(ego_vehicle)
# 指定传感器数据的保存目录
output_path = '../outputs/output_synchronized'
if not os.path.exists(output_path):
os.makedirs(output_path)
# 创建相机传感器
camera_bp = blueprint_library.find('sensor.camera.rgb')
camera_transform = carla.Transform(carla.Location(x=1.5, z=2.4))
camera = world.spawn_actor(camera_bp, camera_transform, attach_to=ego_vehicle)
# 注册回调函数
camera.listen(lambda image: sensor_callback(image, sensor_queue, "camera"))
sensor_list.append(camera)
# 创建LiDAR传感器
lidar_bp = blueprint_library.find('sensor.lidar.ray_cast')
lidar_bp.set_attribute('channels', str(32))
lidar_bp.set_attribute('points_per_second', str(90000))
lidar_bp.set_attribute('rotation_frequency', str(40))
lidar_bp.set_attribute('range', str(20))
lidar_location = carla.Location(0, 0, 2)
lidar_rotation = carla.Rotation(0, 0, 0)
lidar_transform = carla.Transform(lidar_location, lidar_rotation)
lidar = world.spawn_actor(lidar_bp, lidar_transform, attach_to=ego_vehicle)
lidar.listen(
lambda point_cloud: sensor_callback(point_cloud, sensor_queue, "lidar"))
sensor_list.append(lidar)
while True:
world.tick()
# 使用queue.get()函数,在数据处理完成之前,阻止程序的推进
try:
for i in range(0, len(sensor_list)):
s_frame = sensor_queue.get(True, 1.0)
print(" Frame: %d Sensor: %s" % (s_frame[0], s_frame[1]))
except Empty:
print(" Some of the sensor information is missed")
finally:
# 恢复异步模式,否则退出之后Carla将卡死
world.apply_settings(original_settings)
print('destroying actors')
client.apply_batch([carla.command.DestroyActor(x) for x in actor_list])
for sensor in sensor_list:
sensor.destroy()
for actor in actor_list:
actor.destroy()
print('done.')
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print(' - Exited by user.')