(八) carla中同步模式设置

(八) carla中同步模式设置

前言

由于前一段时间在 c a r l a carla carla 中采集数据时发现:采集的图片的帧数是跳帧的,不连续,通过 p y g a m e pygame pygame 也可以看到 c a r l a carla carla 服务端和客户端的频率也是不一样的。
在这里插入图片描述
那么为什么采集的相机图片存在严重的掉帧现象?
原因是服务端默认为异步模式运行,即服务端尽可能地进行仿真,根本不管客户端是否跟上它的步伐。客户端采集并保存图片比较慢,因此存在掉帧现象。
那么如何让客户端和服务端同步尼?

异步模式和同步模式

参考 link,在 s i m u l a t i o n simulation simulation 里的时间与真实世界是不同的, s i m u l a t i o n simulation simulation 里没有"一秒"的概念,只有"一个 t i m e − s t e p time-step timestep" 的概念。这个 t i m e − s t e p time-step timestep c a r l a carla carla 服务端更新两个 s t e p step step 之间的时间间隔, 相当于仿真世界里进行了一次更新,这个更新在真实世界里的时间可能只有几毫秒。
仿真世界里的 t i m e − s t e p time-step timestep 其实有两种,一种是 V a r i a b l e t i m e − s t e p Variable time-step Variabletimestep, 另一种是 F i x e d t i m e − s t e p Fixed time-step Fixedtimestep .
V a r i a b l e t i m e − s t e p Variable time-step Variabletimestep c a r l a carla carla 服务端默认的运行模式。即每次仿真的步长所需要的真实时间是不一定的,可能这一步用了 3 m s 3ms 3ms,下一步用了 5 m s 5ms 5ms
代码如下:

settings = world.get_settings()
settings.fixed_delta_seconds = None # Set a variable time-step
world.apply_settings(settings)

F i x e d t i m e − s t e p Fixed time-step Fixedtimestep即固定时间步长,在这种时间步长设置下,每次 t i m e − s t e p time-step timestep 所消耗的时间是固定的,比如设置为 5 m s 5ms 5ms

settings = world.get_settings()
settings.fixed_delta_seconds = 0.05 #20 fps, 5ms
world.apply_settings(settings)

这样设置完固定的 t i m e − s t e p time-step timestep 后,仿真的频率就一定会按照设定的来吗?
答案是不一定!存在这样的情况,在同步模式下,仿真服务端会等待客户端完成手头的工作后,再进行更新。假设设置的固定时间是 5 m s 5ms 5ms,而客户端存储操作需要 10 m s 10ms 10ms,这样的话服务端不会在 5 m s 5ms 5ms 之后就进行更新,而是等到存储操作完成后才进行下一次更新。
那么到底是怎么才能触发服务器端进行更新尼?
经过上述分析,肯定不是按照设定的时间进行更新,至于怎么触发更新,下方进行讲解。

设置同步模式

将 time-step 设置为 Fixed time-step

settings = world.get_settings()
settings.fixed_delta_seconds = 0.05
settings.synchronous_mode = True
world.apply_settings(settings)

启动 traffic manager

在同步模式下,车辆要进行自动模式必须依附于开启同步模式的 t r a f f i c m a n a g e r traffic manager trafficmanager,不然虽然开启了自动模式,车辆会一直不动。

traffic_manager = client.get_trafficmanager(8000)   traffic_manager.set_synchronous_mode(True)      
ego_vehicle = world.spawn_actor(ego_vehicle_bp, transform)
ego_vehicle.set_autopilot(True, 8000)

设置 world.tick()函数和Queue的get函数

至于怎么触发更新,上述提到不是采用固定时间进行触发的,那么如何进行触发的尼?答案就是采用 w o r l d . t i c k ( ) world.tick() world.tick() 函数以及 Q u e u e Queue Queue g e t ( ) get() get() 进行触发的。
q u e u e . g e t queue.get queue.get 函数有一个功效,就是在它把队列里所有内容都提取出来之前,会阻止任何去阻止其他进程越过这一步,相当于一个 b l o c k e r blocker blocker。如果没有这个 q u e u e queue queue ,即使设置成了同步模式,还是会自己跑自己的,不会进行同步。
可以这样理解, s e t t i n g s . s y n c h r o n o u s _ m o d e settings.synchronous\_mode settings.synchronous_mode = T r u e True True ,让仿真的更新要通过这个 c l i e n t client client 来唤醒,但这并不能保证它会等该 c l i e n t client client 其他进程运行完,必须要再加一个 q u e u e queue queue 来阻挡一下它,逼迫它等着该客户其他线程搞定。

def sensor_callback(sensor_data, sensor_queue, sensor_name):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))
# create sensor queue
sensor_queue = Queue()
# 设置传感器,比如相机,然后
# set the callback function
camera.listen(lambda image: sensor_callback(image, sensor_queue, "camera"))
while True:world.tick()sensor_queue.get(True)

所以,总结下来,让服务端学会等待客户端的必要条件有三个,如下:

settings.synchronous_mode = True
world.tick()
Thread Blocker(such as Queue)

结束销毁

在设置了同步模式的 c l i e n t client client 完成了它的任务准备停止/销毁时,千万别忘了将世界设置回异步模式,否则 s e r v e r server server 会因为找不到它的同步客户而卡死。

try:.......
finally:settings = world.get_settings()settings.synchronous_mode = Falsesettings.fixed_delta_seconds = Noneworld.apply_settings(settings)

经过上述设置过程,可以实现同步模式。

示例

如下示例中,在车辆上安装了相机和雷达,然后同时采集数据,可以发现:采集的数据不存在掉帧现象,并且相机和雷达数据也会同步。

import random
import os
import sys
import glob
from queue import Queue
from queue import Empty
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 carladef 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:# First of all, we need to create the client that will send the requests, assume port is 2000client = carla.Client('localhost', 2000)client.set_timeout(2.0)# Retrieve the world that is currently runningworld = client.get_world()# world = client.load_world('Town02') # you can also retrive another world by specifically definingblueprint_library = world.get_blueprint_library()# Set weather for your worldweather = carla.WeatherParameters(cloudiness=10.0,precipitation=10.0,fog_density=10.0)world.set_weather(weather)# set synchorinized mode,将time-step设置为Fixed time-steporiginal_settings = world.get_settings()settings = world.get_settings()settings.fixed_delta_seconds = 0.05settings.synchronous_mode = Trueworld.apply_settings(settings)#将同步模式设置为True#因为同步模式下车辆要使用自动模式必须开启同步模式的traffic manager。traffic_manager = client.get_trafficmanager()traffic_manager.set_synchronous_mode(True)# create sensor queuesensor_queue = Queue()# create the ego vehicleego_vehicle_bp = blueprint_library.find('vehicle.mercedes-benz.coupe')# black colorego_vehicle_bp.set_attribute('color', '0, 0, 0')# get a random valid occupation in the worldtransform = random.choice(world.get_map().get_spawn_points())# spawn the vehilceego_vehicle = world.spawn_actor(ego_vehicle_bp, transform)# set the vehicle autopilot modeego_vehicle.set_autopilot(True)# collect all actors to destroy when we quit the scriptactor_list.append(ego_vehicle)# create directory for outputsoutput_path = './outputs/output_synchronized'if not os.path.exists(output_path):os.makedirs(output_path)# add a cameracamera_bp = blueprint_library.find('sensor.camera.rgb')# camera relative position related to the vehiclecamera_transform = carla.Transform(carla.Location(x=1.5, z=2.4))camera = world.spawn_actor(camera_bp, camera_transform, attach_to=ego_vehicle)# set the callback functioncamera.listen(lambda image: sensor_callback(image, sensor_queue, "camera"))sensor_list.append(camera)# we also add a lidar on itlidar_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))# set the relative locationlidar_location = carla.Location(0, 0, 2)lidar_rotation = carla.Rotation(0, 0, 0)lidar_transform = carla.Transform(lidar_location, lidar_rotation)# spawn the lidarlidar = 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()函数,只出现于同步模式,意思是让simulation更新一次。world.tick()# set the sectator to follow the ego vehiclespectator = world.get_spectator()transform = ego_vehicle.get_transform()spectator.set_transform(carla.Transform(transform.location + carla.Location(z=20),carla.Rotation(pitch=-90)))# As the queue is blocking, we will wait in the queue.get() methods# until all the information is processed and we continue with the next frame.try:#sensor_queue.get()函数的强制功能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: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()print('done.')if __name__ == '__main__':try:main()except KeyboardInterrupt:print(' - Exited by user.')


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部