#!/usr/bin/env python # Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma de # Barcelona (UAB). # # This work is licensed under the terms of the MIT license. # For a copy, see . """ Sensor synchronization example for CARLA The communication model for the syncronous mode in CARLA sends the snapshot of the world and the sensors streams in parallel. We provide this script as an example of how to syncrononize the sensor data gathering in the client. To to this, we create a queue that is being filled by every sensor when the client receives its data and the main loop is blocked until all the sensors have received its data. This suppose that all the sensors gather information at every tick. It this is not the case, the clients needs to take in account at each frame how many sensors are going to tick at each frame. """ import glob import os import sys 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 carla # Sensor callback. # This is where you receive the sensor data and # process it as you liked and the important part is that, # at the end, it should include an element into the sensor queue. def sensor_callback(sensor_data, sensor_queue, sensor_name): # Do stuff with the sensor_data data like save it to disk # Then you just need to add to the queue sensor_queue.put((sensor_data.frame, sensor_name)) def main(): # We start creating the client client = carla.Client('localhost', 2000) client.set_timeout(2.0) world = client.get_world() try: # We need to save the settings to be able to recover them at the end # of the script to leave the server in the same state that we found it. original_settings = world.get_settings() settings = world.get_settings() # We set CARLA syncronous mode settings.fixed_delta_seconds = 0.2 settings.synchronous_mode = True world.apply_settings(settings) # We create the sensor queue in which we keep track of the information # already received. This structure is thread safe and can be # accessed by all the sensors callback concurrently without problem. sensor_queue = Queue() # Bluepints for the sensors blueprint_library = world.get_blueprint_library() cam_bp = blueprint_library.find('sensor.camera.rgb') lidar_bp = blueprint_library.find('sensor.lidar.ray_cast') radar_bp = blueprint_library.find('sensor.other.radar') # We create all the sensors and keep them in a list for convenience. sensor_list = [] cam01 = world.spawn_actor(cam_bp, carla.Transform()) cam01.listen(lambda data: sensor_callback(data, sensor_queue, "camera01")) sensor_list.append(cam01) lidar_bp.set_attribute('points_per_second', '100000') lidar01 = world.spawn_actor(lidar_bp, carla.Transform()) lidar01.listen(lambda data: sensor_callback(data, sensor_queue, "lidar01")) sensor_list.append(lidar01) lidar_bp.set_attribute('points_per_second', '1000000') lidar02 = world.spawn_actor(lidar_bp, carla.Transform()) lidar02.listen(lambda data: sensor_callback(data, sensor_queue, "lidar02")) sensor_list.append(lidar02) radar01 = world.spawn_actor(radar_bp, carla.Transform()) radar01.listen(lambda data: sensor_callback(data, sensor_queue, "radar01")) sensor_list.append(radar01) radar02 = world.spawn_actor(radar_bp, carla.Transform()) radar02.listen(lambda data: sensor_callback(data, sensor_queue, "radar02")) sensor_list.append(radar02) # Main loop while True: # Tick the server world.tick() w_frame = world.get_snapshot().frame print("\nWorld's frame: %d" % w_frame) # Now, we wait to the sensors data to be received. # 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. # We include a timeout of 1.0 s (in the get method) and if some information is # not received in this time we continue. try: for _ in range(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) for sensor in sensor_list: sensor.destroy() if __name__ == "__main__": try: main() except KeyboardInterrupt: print(' - Exited by user.')