Merge pull request #2951 from carla-simulator/dsantoso/lidar-impr
Raycast parallelization
This commit is contained in:
parent
083d579961
commit
baf43b07a6
|
@ -9,12 +9,14 @@
|
||||||
* Added PythonAPI command to set multiple car light states at once
|
* Added PythonAPI command to set multiple car light states at once
|
||||||
* Added PythonAPI `carla.world.get_vehicles_light_states` to get all the car light states at once
|
* Added PythonAPI `carla.world.get_vehicles_light_states` to get all the car light states at once
|
||||||
* OpenDRIVE ingestion bugfixes
|
* OpenDRIVE ingestion bugfixes
|
||||||
|
* Improved the LiDAR and Radar sensors with a parallel implentation of the raycasting
|
||||||
* Added Dynamic Vision Sensor (DVS) camera based on ESIM simulation http://rpg.ifi.uzh.ch/esim.html
|
* Added Dynamic Vision Sensor (DVS) camera based on ESIM simulation http://rpg.ifi.uzh.ch/esim.html
|
||||||
* Added support for additional TraCI clients in Sumo co-simulation
|
* Added support for additional TraCI clients in Sumo co-simulation
|
||||||
* Added API functions `get_right_vector` and `get_up_vector`
|
* Added API functions `get_right_vector` and `get_up_vector`
|
||||||
* Added default values and a warning message for lanes missing the width parameter in OpenDRIVE
|
* Added default values and a warning message for lanes missing the width parameter in OpenDRIVE
|
||||||
* Added parameter to enable/disable pedestrian navigation in standalone mode
|
* Added parameter to enable/disable pedestrian navigation in standalone mode
|
||||||
* Improved mesh split in standalone mode
|
* Improved mesh split in standalone mode
|
||||||
|
* Fixed delay in the tcp communication from server to client, improving performance in synchronous mode in linux systems
|
||||||
* Fixed large RAM usage when loading polinomial geometry from OpenDRIVE
|
* Fixed large RAM usage when loading polinomial geometry from OpenDRIVE
|
||||||
* Fixed collision issues when debug draw(debug.draw_line) is called
|
* Fixed collision issues when debug draw(debug.draw_line) is called
|
||||||
|
|
||||||
|
|
|
@ -906,7 +906,7 @@ class CameraManager(object):
|
||||||
['sensor.camera.semantic_segmentation', cc.Raw, 'Camera Semantic Segmentation (Raw)', {}],
|
['sensor.camera.semantic_segmentation', cc.Raw, 'Camera Semantic Segmentation (Raw)', {}],
|
||||||
['sensor.camera.semantic_segmentation', cc.CityScapesPalette,
|
['sensor.camera.semantic_segmentation', cc.CityScapesPalette,
|
||||||
'Camera Semantic Segmentation (CityScapes Palette)', {}],
|
'Camera Semantic Segmentation (CityScapes Palette)', {}],
|
||||||
['sensor.lidar.ray_cast', None, 'Lidar (Ray-Cast)', {}],
|
['sensor.lidar.ray_cast', None, 'Lidar (Ray-Cast)', {'range': '50'}],
|
||||||
['sensor.camera.dvs', cc.Raw, 'Dynamic Vision Sensor', {}],
|
['sensor.camera.dvs', cc.Raw, 'Dynamic Vision Sensor', {}],
|
||||||
['sensor.camera.rgb', cc.Raw, 'Camera RGB Distorted',
|
['sensor.camera.rgb', cc.Raw, 'Camera RGB Distorted',
|
||||||
{'lens_circle_multiplier': '3.0',
|
{'lens_circle_multiplier': '3.0',
|
||||||
|
@ -925,7 +925,14 @@ class CameraManager(object):
|
||||||
for attr_name, attr_value in item[3].items():
|
for attr_name, attr_value in item[3].items():
|
||||||
bp.set_attribute(attr_name, attr_value)
|
bp.set_attribute(attr_name, attr_value)
|
||||||
elif item[0].startswith('sensor.lidar'):
|
elif item[0].startswith('sensor.lidar'):
|
||||||
bp.set_attribute('range', '50')
|
self.lidar_range = 50
|
||||||
|
|
||||||
|
for attr_name, attr_value in item[3].items():
|
||||||
|
bp.set_attribute(attr_name, attr_value)
|
||||||
|
if attr_name == 'range':
|
||||||
|
self.lidar_range = float(attr_value)
|
||||||
|
|
||||||
|
|
||||||
item.append(bp)
|
item.append(bp)
|
||||||
self.index = None
|
self.index = None
|
||||||
|
|
||||||
|
@ -974,7 +981,7 @@ class CameraManager(object):
|
||||||
points = np.frombuffer(image.raw_data, dtype=np.dtype('f4'))
|
points = np.frombuffer(image.raw_data, dtype=np.dtype('f4'))
|
||||||
points = np.reshape(points, (int(points.shape[0] / 3), 3))
|
points = np.reshape(points, (int(points.shape[0] / 3), 3))
|
||||||
lidar_data = np.array(points[:, :2])
|
lidar_data = np.array(points[:, :2])
|
||||||
lidar_data *= min(self.hud.dim) / 100.0
|
lidar_data *= min(self.hud.dim) / (2.0 * self.lidar_range)
|
||||||
lidar_data += (0.5 * self.hud.dim[0], 0.5 * self.hud.dim[1])
|
lidar_data += (0.5 * self.hud.dim[0], 0.5 * self.hud.dim[1])
|
||||||
lidar_data = np.fabs(lidar_data) # pylint: disable=E1111
|
lidar_data = np.fabs(lidar_data) # pylint: disable=E1111
|
||||||
lidar_data = lidar_data.astype(np.int32)
|
lidar_data = lidar_data.astype(np.int32)
|
||||||
|
|
|
@ -0,0 +1,505 @@
|
||||||
|
#!/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 <https://opensource.org/licenses/MIT>.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Raycast sensor profiler
|
||||||
|
|
||||||
|
This script can be used to test, visualize and profile the raycast sensors,
|
||||||
|
LiDARs and Radar (radar visualization not available, sorry).
|
||||||
|
|
||||||
|
By default, the script render one RGB Camera and three LiDARS whose output
|
||||||
|
can be visualized in a window just running:
|
||||||
|
python raycast_sensor_testing.py
|
||||||
|
|
||||||
|
For profiling, you can choose the number of LiDARs and Radars and then use
|
||||||
|
the profiling option to run a series of simulations for points from 100k
|
||||||
|
to 1.5M per second. In this mode we do not render anything but processing
|
||||||
|
of the data is done.
|
||||||
|
For example for profiling one lidar:
|
||||||
|
python raycast_sensor_testing.py -ln 1 --profiling
|
||||||
|
And for profiling one radar:
|
||||||
|
python raycast_sensor_testing.py -rn 1 --profiling
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
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
|
||||||
|
import argparse
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
import pygame
|
||||||
|
from pygame.locals import K_ESCAPE
|
||||||
|
from pygame.locals import K_q
|
||||||
|
except ImportError:
|
||||||
|
raise RuntimeError('cannot import pygame, make sure pygame package is installed')
|
||||||
|
|
||||||
|
class CustomTimer:
|
||||||
|
def __init__(self):
|
||||||
|
try:
|
||||||
|
self.timer = time.perf_counter
|
||||||
|
except AttributeError:
|
||||||
|
self.timer = time.time
|
||||||
|
|
||||||
|
def time(self):
|
||||||
|
return self.timer()
|
||||||
|
|
||||||
|
class DisplayManager:
|
||||||
|
def __init__(self, grid_size, window_size, show_window=True):
|
||||||
|
if show_window:
|
||||||
|
pygame.init()
|
||||||
|
pygame.font.init()
|
||||||
|
self.display = pygame.display.set_mode(window_size, pygame.HWSURFACE | pygame.DOUBLEBUF)
|
||||||
|
else:
|
||||||
|
self.display = None
|
||||||
|
|
||||||
|
self.grid_size = grid_size
|
||||||
|
self.window_size = window_size
|
||||||
|
self.sensor_list = []
|
||||||
|
|
||||||
|
def get_window_size(self):
|
||||||
|
return [int(self.window_size[0]), int(self.window_size[1])]
|
||||||
|
|
||||||
|
def get_display_size(self):
|
||||||
|
return [int(self.window_size[0]/self.grid_size[0]), int(self.window_size[1]/self.grid_size[1])]
|
||||||
|
|
||||||
|
def get_display_offset(self, gridPos):
|
||||||
|
dis_size = self.get_display_size()
|
||||||
|
return [int(gridPos[0] * dis_size[0]), int(gridPos[1] * dis_size[1])]
|
||||||
|
|
||||||
|
def add_sensor(self, sensor):
|
||||||
|
self.sensor_list.append(sensor)
|
||||||
|
|
||||||
|
def get_sensor_list(self):
|
||||||
|
return self.sensor_list
|
||||||
|
|
||||||
|
def render(self):
|
||||||
|
if not self.render_enabled():
|
||||||
|
return
|
||||||
|
|
||||||
|
for s in self.sensor_list:
|
||||||
|
s.render()
|
||||||
|
|
||||||
|
pygame.display.flip()
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
for s in self.sensor_list:
|
||||||
|
s.destroy()
|
||||||
|
|
||||||
|
def render_enabled(self):
|
||||||
|
return self.display != None
|
||||||
|
|
||||||
|
class SensorManager:
|
||||||
|
def __init__(self, world, display_man, sensor_type, transform, attached, sensor_options, display_pos):
|
||||||
|
self.surface = None
|
||||||
|
self.world = world
|
||||||
|
self.display_man = display_man
|
||||||
|
self.display_pos = display_pos
|
||||||
|
self.sensor = self.init_sensor(sensor_type, transform, attached, sensor_options)
|
||||||
|
self.sensor_options = sensor_options
|
||||||
|
self.timer = CustomTimer()
|
||||||
|
|
||||||
|
self.time_processing = 0.0
|
||||||
|
self.tics_processing = 0
|
||||||
|
|
||||||
|
self.display_man.add_sensor(self)
|
||||||
|
|
||||||
|
def init_sensor(self, sensor_type, transform, attached, sensor_options):
|
||||||
|
if sensor_type == 'RGBCamera':
|
||||||
|
camera_bp = self.world.get_blueprint_library().find('sensor.camera.rgb')
|
||||||
|
disp_size = self.display_man.get_display_size()
|
||||||
|
camera_bp.set_attribute('image_size_x', str(disp_size[0]))
|
||||||
|
camera_bp.set_attribute('image_size_y', str(disp_size[1]))
|
||||||
|
|
||||||
|
for key in sensor_options:
|
||||||
|
camera_bp.set_attribute(key, sensor_options[key])
|
||||||
|
|
||||||
|
camera = self.world.spawn_actor(camera_bp, transform, attach_to=attached)
|
||||||
|
camera.listen(self.save_rgb_image)
|
||||||
|
|
||||||
|
return camera
|
||||||
|
|
||||||
|
elif sensor_type == 'LiDAR':
|
||||||
|
lidar_bp = self.world.get_blueprint_library().find('sensor.lidar.ray_cast')
|
||||||
|
lidar_bp.set_attribute('range', '100')
|
||||||
|
|
||||||
|
for key in sensor_options:
|
||||||
|
lidar_bp.set_attribute(key, sensor_options[key])
|
||||||
|
|
||||||
|
lidar = self.world.spawn_actor(lidar_bp, transform, attach_to=attached)
|
||||||
|
|
||||||
|
lidar.listen(self.save_lidar_image)
|
||||||
|
|
||||||
|
return lidar
|
||||||
|
elif sensor_type == "Radar":
|
||||||
|
radar_bp = self.world.get_blueprint_library().find('sensor.other.radar')
|
||||||
|
for key in sensor_options:
|
||||||
|
radar_bp.set_attribute(key, sensor_options[key])
|
||||||
|
|
||||||
|
radar = self.world.spawn_actor(radar_bp, transform, attach_to=attached)
|
||||||
|
radar.listen(self.save_radar_image)
|
||||||
|
|
||||||
|
return radar
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_sensor(self):
|
||||||
|
return self.sensor
|
||||||
|
|
||||||
|
def save_rgb_image(self, image):
|
||||||
|
t_start = self.timer.time()
|
||||||
|
|
||||||
|
image.convert(carla.ColorConverter.Raw)
|
||||||
|
array = np.frombuffer(image.raw_data, dtype=np.dtype("uint8"))
|
||||||
|
array = np.reshape(array, (image.height, image.width, 4))
|
||||||
|
array = array[:, :, :3]
|
||||||
|
array = array[:, :, ::-1]
|
||||||
|
|
||||||
|
if self.display_man.render_enabled():
|
||||||
|
self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1))
|
||||||
|
|
||||||
|
t_end = self.timer.time()
|
||||||
|
self.time_processing += (t_end-t_start)
|
||||||
|
self.tics_processing += 1
|
||||||
|
|
||||||
|
def save_lidar_image(self, image):
|
||||||
|
t_start = self.timer.time()
|
||||||
|
|
||||||
|
disp_size = self.display_man.get_display_size()
|
||||||
|
lidar_range = 2.0*float(self.sensor_options['range'])
|
||||||
|
|
||||||
|
points = np.frombuffer(image.raw_data, dtype=np.dtype('f4'))
|
||||||
|
points = np.reshape(points, (int(points.shape[0] / 3), 3))
|
||||||
|
lidar_data = np.array(points[:, :2])
|
||||||
|
lidar_data *= min(disp_size) / lidar_range
|
||||||
|
lidar_data += (0.5 * disp_size[0], 0.5 * disp_size[1])
|
||||||
|
lidar_data = np.fabs(lidar_data) # pylint: disable=E1111
|
||||||
|
lidar_data = lidar_data.astype(np.int32)
|
||||||
|
lidar_data = np.reshape(lidar_data, (-1, 2))
|
||||||
|
lidar_img_size = (disp_size[0], disp_size[1], 3)
|
||||||
|
lidar_img = np.zeros((lidar_img_size), dtype=np.uint8)
|
||||||
|
|
||||||
|
lidar_img[tuple(lidar_data.T)] = (255, 255, 255)
|
||||||
|
|
||||||
|
if self.display_man.render_enabled():
|
||||||
|
self.surface = pygame.surfarray.make_surface(lidar_img)
|
||||||
|
|
||||||
|
t_end = self.timer.time()
|
||||||
|
self.time_processing += (t_end-t_start)
|
||||||
|
self.tics_processing += 1
|
||||||
|
|
||||||
|
def save_radar_image(self, radar_data):
|
||||||
|
t_start = self.timer.time()
|
||||||
|
#print("Hola, saving Radar data!!")
|
||||||
|
# To get a numpy [[vel, altitude, azimuth, depth],...[,,,]]:
|
||||||
|
points = np.frombuffer(radar_data.raw_data, dtype=np.dtype('f4'))
|
||||||
|
points = np.reshape(points, (len(radar_data), 4))
|
||||||
|
|
||||||
|
t_end = self.timer.time()
|
||||||
|
self.time_processing += (t_end-t_start)
|
||||||
|
self.tics_processing += 1
|
||||||
|
|
||||||
|
def render(self):
|
||||||
|
if self.surface is not None:
|
||||||
|
offset = self.display_man.get_display_offset(self.display_pos)
|
||||||
|
self.display_man.display.blit(self.surface, offset)
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
self.sensor.destroy()
|
||||||
|
|
||||||
|
def one_run(args, client):
|
||||||
|
"""This function performed one test run using the args parameters
|
||||||
|
and connecting to the carla client passed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
display_manager = None
|
||||||
|
vehicle = None
|
||||||
|
vehicle_list = []
|
||||||
|
prof_str = ""
|
||||||
|
timer = CustomTimer()
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
# Getting the world and
|
||||||
|
world = client.get_world()
|
||||||
|
|
||||||
|
if args.sync:
|
||||||
|
traffic_manager = client.get_trafficmanager(8000)
|
||||||
|
settings = world.get_settings()
|
||||||
|
traffic_manager.set_synchronous_mode(True)
|
||||||
|
settings.synchronous_mode = True
|
||||||
|
settings.fixed_delta_seconds = 0.05
|
||||||
|
world.apply_settings(settings)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Instanciating the vehicle to which we attached the sensors
|
||||||
|
bp = world.get_blueprint_library().filter('vehicle')[0]
|
||||||
|
|
||||||
|
if bp.has_attribute('color'):
|
||||||
|
color = random.choice(bp.get_attribute('color').recommended_values)
|
||||||
|
bp.set_attribute('color', color)
|
||||||
|
|
||||||
|
vehicle = world.spawn_actor(bp, world.get_map().get_spawn_points()[0])
|
||||||
|
vehicle_list.append(vehicle)
|
||||||
|
|
||||||
|
vehicle.set_autopilot(True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Display Manager organize all the sensors an its display in a window
|
||||||
|
display_manager = DisplayManager(grid_size=[2, 2], window_size=[args.width, args.height], show_window=args.render_window)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# If require, we instanciate the RGB camera
|
||||||
|
if args.render_cam:
|
||||||
|
SensorManager(world, display_manager, 'RGBCamera', carla.Transform(carla.Location(x=1.5, z=2.4)), vehicle, {}, [0, 0])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# If any, we instanciate the required lidars
|
||||||
|
lidar_points_per_second = args.lidar_points
|
||||||
|
|
||||||
|
if args.lidar_number >= 3:
|
||||||
|
SensorManager(world, display_manager, 'LiDAR', carla.Transform(carla.Location(x=0, z=2.4)), vehicle, {'channels' : '64', 'range' : '50', 'points_per_second': lidar_points_per_second}, [1, 0])
|
||||||
|
|
||||||
|
if args.lidar_number >= 2:
|
||||||
|
SensorManager(world, display_manager, 'LiDAR', carla.Transform(carla.Location(x=0, z=2.4)), vehicle, {'channels' : '64', 'range' : '100', 'points_per_second': lidar_points_per_second}, [0, 1])
|
||||||
|
|
||||||
|
if args.lidar_number >= 1:
|
||||||
|
SensorManager(world, display_manager, 'LiDAR', carla.Transform(carla.Location(x=0, z=2.4)), vehicle, {'channels' : '64', 'range' : '200', 'points_per_second': lidar_points_per_second}, [1, 1])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# If any, we instanciate the required radars
|
||||||
|
radar_points_per_second = args.radar_points
|
||||||
|
|
||||||
|
if args.radar_number >= 3:
|
||||||
|
SensorManager(world, display_manager, 'Radar', carla.Transform(carla.Location(x=0, z=2.4), carla.Rotation(pitch=5, yaw=90)), vehicle, {'points_per_second': radar_points_per_second}, [2, 2])
|
||||||
|
|
||||||
|
if args.radar_number >= 2:
|
||||||
|
SensorManager(world, display_manager, 'Radar', carla.Transform(carla.Location(x=0, z=2.4), carla.Rotation(pitch=5, yaw=-90)), vehicle, {'points_per_second': radar_points_per_second}, [2, 2])
|
||||||
|
|
||||||
|
if args.radar_number >= 1:
|
||||||
|
SensorManager(world, display_manager, 'Radar', carla.Transform(carla.Location(x=0, z=2.4), carla.Rotation(pitch=5)), vehicle, {'points_per_second': radar_points_per_second}, [2, 2])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
call_exit = False
|
||||||
|
time_init_sim = timer.time()
|
||||||
|
|
||||||
|
frame = 0
|
||||||
|
time0 = timer.time()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
frame += 1
|
||||||
|
|
||||||
|
# Carla Tick
|
||||||
|
if args.sync:
|
||||||
|
world.tick()
|
||||||
|
else:
|
||||||
|
world.wait_for_tick()
|
||||||
|
|
||||||
|
# Render received data
|
||||||
|
display_manager.render()
|
||||||
|
|
||||||
|
# Time measurement for profiling or to output
|
||||||
|
if not args.profiling:
|
||||||
|
if frame == 30:
|
||||||
|
time_frames = timer.time() - time0
|
||||||
|
time_procc = 0
|
||||||
|
for sensor in display_manager.sensor_list:
|
||||||
|
time_procc += sensor.time_processing
|
||||||
|
|
||||||
|
print("FPS: %.3f %.3f %.3f" % (time_frames, 1.0/time_frames * 30, time_procc/time_frames))
|
||||||
|
frame = 0
|
||||||
|
for sensor in display_manager.sensor_list:
|
||||||
|
sensor.time_processing = 0
|
||||||
|
sensor.tics_processing = 0
|
||||||
|
time0 = timer.time()
|
||||||
|
|
||||||
|
if args.render_window:
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == pygame.QUIT:
|
||||||
|
call_exit = True
|
||||||
|
elif event.type == pygame.KEYDOWN:
|
||||||
|
if event.key == K_ESCAPE or event.key == K_q:
|
||||||
|
call_exit = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if (timer.time() - time_init_sim) < 5.0:
|
||||||
|
frame = 0
|
||||||
|
for sensor in display_manager.sensor_list:
|
||||||
|
sensor.time_processing = 0
|
||||||
|
sensor.tics_processing = 0
|
||||||
|
time0 = timer.time()
|
||||||
|
|
||||||
|
if (timer.time() - time0) > 10.0:
|
||||||
|
time_frames = timer.time() - time0
|
||||||
|
|
||||||
|
time_procc = 0
|
||||||
|
for sensor in display_manager.sensor_list:
|
||||||
|
time_procc += sensor.time_processing
|
||||||
|
prof_str = "%-10s %-9s %-15s %-7.2f %-20.3f" % (args.lidar_number, args.radar_number, lidar_points_per_second, float(frame) / time_frames, time_procc/time_frames)
|
||||||
|
break
|
||||||
|
|
||||||
|
if call_exit:
|
||||||
|
break
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if display_manager:
|
||||||
|
display_manager.destroy()
|
||||||
|
|
||||||
|
client.apply_batch([carla.command.DestroyActor(x) for x in vehicle_list])
|
||||||
|
|
||||||
|
if args.sync:
|
||||||
|
settings = world.get_settings()
|
||||||
|
settings.synchronous_mode = False
|
||||||
|
settings.fixed_delta_seconds = None
|
||||||
|
world.apply_settings(settings)
|
||||||
|
|
||||||
|
return prof_str
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argparser = argparse.ArgumentParser(
|
||||||
|
description='CARLA Sensor tutorial')
|
||||||
|
argparser.add_argument(
|
||||||
|
'--host',
|
||||||
|
metavar='H',
|
||||||
|
default='127.0.0.1',
|
||||||
|
help='IP of the host server (default: 127.0.0.1)')
|
||||||
|
argparser.add_argument(
|
||||||
|
'-p', '--port',
|
||||||
|
metavar='P',
|
||||||
|
default=2000,
|
||||||
|
type=int,
|
||||||
|
help='TCP port to listen to (default: 2000)')
|
||||||
|
argparser.add_argument(
|
||||||
|
'--sync',
|
||||||
|
action='store_true',
|
||||||
|
help='Synchronous mode execution')
|
||||||
|
argparser.add_argument(
|
||||||
|
'--async',
|
||||||
|
dest='sync',
|
||||||
|
action='store_false',
|
||||||
|
help='Asynchronous mode execution')
|
||||||
|
argparser.set_defaults(sync=True)
|
||||||
|
argparser.add_argument(
|
||||||
|
'--res',
|
||||||
|
metavar='WIDTHxHEIGHT',
|
||||||
|
default='1280x720',
|
||||||
|
help='window resolution (default: 1280x720)')
|
||||||
|
argparser.add_argument(
|
||||||
|
'-lp', '--lidar_points',
|
||||||
|
metavar='LP',
|
||||||
|
default='100000',
|
||||||
|
help='lidar points per second (default: "100000")')
|
||||||
|
argparser.add_argument(
|
||||||
|
'-ln', '--lidar_number',
|
||||||
|
metavar='LN',
|
||||||
|
default=3,
|
||||||
|
type=int,
|
||||||
|
choices=range(0, 4),
|
||||||
|
help='Number of lidars to render (from zero to three)')
|
||||||
|
argparser.add_argument(
|
||||||
|
'-rp', '--radar_points',
|
||||||
|
metavar='RP',
|
||||||
|
default='100000',
|
||||||
|
help='radar points per second (default: "100000")')
|
||||||
|
argparser.add_argument(
|
||||||
|
'-rn', '--radar_number',
|
||||||
|
metavar='LN',
|
||||||
|
default=0,
|
||||||
|
type=int,
|
||||||
|
choices=range(0, 4),
|
||||||
|
help='Number of radars to render (from zero to three)')
|
||||||
|
argparser.add_argument(
|
||||||
|
'--camera',
|
||||||
|
dest='render_cam', action='store_true',
|
||||||
|
help='render also RGB camera (camera enable by default)')
|
||||||
|
argparser.add_argument('--no-camera',
|
||||||
|
dest='render_cam', action='store_false',
|
||||||
|
help='no render RGB camera (camera disable by default)')
|
||||||
|
argparser.set_defaults(render_cam=True)
|
||||||
|
argparser.add_argument(
|
||||||
|
'--profiling',
|
||||||
|
action='store_true',
|
||||||
|
help='Use the script in profiling mode. It measures the performance of \
|
||||||
|
the lidar for different number of points.')
|
||||||
|
argparser.set_defaults(profiling=False)
|
||||||
|
argparser.add_argument(
|
||||||
|
'--no-render-window',
|
||||||
|
action='store_false',
|
||||||
|
dest='render_window',
|
||||||
|
help='Render visualization window.')
|
||||||
|
argparser.set_defaults(render_window=True)
|
||||||
|
|
||||||
|
args = argparser.parse_args()
|
||||||
|
|
||||||
|
args.width, args.height = [int(x) for x in args.res.split('x')]
|
||||||
|
|
||||||
|
try:
|
||||||
|
client = carla.Client(args.host, args.port)
|
||||||
|
client.set_timeout(5.0)
|
||||||
|
|
||||||
|
if args.profiling:
|
||||||
|
print("-------------------------------------------------------")
|
||||||
|
print("# Running profiling with %s lidars and %s radars." % (args.lidar_number, args.radar_number))
|
||||||
|
args.render_cam = False
|
||||||
|
args.render_window = False
|
||||||
|
runs_output = []
|
||||||
|
|
||||||
|
points_range = ['100000', '200000', '300000', '400000', '500000',
|
||||||
|
'600000', '700000', '800000', '900000', '1000000',
|
||||||
|
'1100000', '1200000', '1300000', '1400000', '1500000']
|
||||||
|
for points in points_range:
|
||||||
|
args.lidar_points = points
|
||||||
|
args.radar_points = points
|
||||||
|
run_str = one_run(args, client)
|
||||||
|
runs_output.append(run_str)
|
||||||
|
|
||||||
|
print("-------------------------------------------------------")
|
||||||
|
print("# Profiling of parallel raycast sensors (LiDAR and Radar)")
|
||||||
|
try:
|
||||||
|
import multiprocessing
|
||||||
|
print("#Number of cores: %d" % multiprocessing.cpu_count())
|
||||||
|
except ImportError:
|
||||||
|
print("#Hardware information not available, please install the " \
|
||||||
|
"multiprocessing module")
|
||||||
|
|
||||||
|
print("#NumLidars NumRadars PointsPerSecond FPS PercentageProcessing")
|
||||||
|
for o in runs_output:
|
||||||
|
print(o)
|
||||||
|
|
||||||
|
else:
|
||||||
|
one_run(args, client)
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print('\nCancelled by user. Bye!')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
main()
|
|
@ -4,10 +4,13 @@
|
||||||
// This work is licensed under the terms of the MIT license.
|
// This work is licensed under the terms of the MIT license.
|
||||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||||
|
|
||||||
|
#include <PxScene.h>
|
||||||
|
|
||||||
#include "Carla.h"
|
#include "Carla.h"
|
||||||
#include "Carla/Sensor/Radar.h"
|
#include "Carla/Sensor/Radar.h"
|
||||||
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
|
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
|
||||||
#include "Kismet/KismetMathLibrary.h"
|
#include "Kismet/KismetMathLibrary.h"
|
||||||
|
#include "Runtime/Core/Public/Async/ParallelFor.h"
|
||||||
|
|
||||||
#include "carla/geom/Math.h"
|
#include "carla/geom/Math.h"
|
||||||
|
|
||||||
|
@ -89,7 +92,6 @@ void ARadar::SendLineTraces(float DeltaTime)
|
||||||
{
|
{
|
||||||
|
|
||||||
constexpr float TO_METERS = 1e-2;
|
constexpr float TO_METERS = 1e-2;
|
||||||
FHitResult OutHit(ForceInit);
|
|
||||||
const FTransform& ActorTransform = GetActorTransform();
|
const FTransform& ActorTransform = GetActorTransform();
|
||||||
const FRotator& TransformRotator = ActorTransform.Rotator();
|
const FRotator& TransformRotator = ActorTransform.Rotator();
|
||||||
const FVector& RadarLocation = GetActorLocation();
|
const FVector& RadarLocation = GetActorLocation();
|
||||||
|
@ -103,8 +105,10 @@ void ARadar::SendLineTraces(float DeltaTime)
|
||||||
const float MaxRy = FMath::Tan(FMath::DegreesToRadians(VerticalFOV * 0.5f)) * Range;
|
const float MaxRy = FMath::Tan(FMath::DegreesToRadians(VerticalFOV * 0.5f)) * Range;
|
||||||
const int NumPoints = (int)(PointsPerSecond * DeltaTime);
|
const int NumPoints = (int)(PointsPerSecond * DeltaTime);
|
||||||
|
|
||||||
for (int i = 0; i < NumPoints; i++)
|
FCriticalSection Mutex;
|
||||||
{
|
GetWorld()->GetPhysicsScene()->GetPxScene()->lockRead();
|
||||||
|
ParallelFor(NumPoints, [&](int32 idxChannel) {
|
||||||
|
FHitResult OutHit(ForceInit);
|
||||||
const float Radius = RandomEngine->GetUniformFloat();
|
const float Radius = RandomEngine->GetUniformFloat();
|
||||||
const float Angle = RandomEngine->GetUniformFloatInRange(0.0f, carla::geom::Math::Pi2<float>());
|
const float Angle = RandomEngine->GetUniformFloatInRange(0.0f, carla::geom::Math::Pi2<float>());
|
||||||
|
|
||||||
|
@ -138,14 +142,17 @@ void ARadar::SendLineTraces(float DeltaTime)
|
||||||
TransformZAxis
|
TransformZAxis
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Mutex.Lock();
|
||||||
RadarData.WriteDetection({
|
RadarData.WriteDetection({
|
||||||
RelativeVelocity,
|
RelativeVelocity,
|
||||||
AzimuthAndElevation.X,
|
AzimuthAndElevation.X,
|
||||||
AzimuthAndElevation.Y,
|
AzimuthAndElevation.Y,
|
||||||
OutHit.Distance * TO_METERS
|
OutHit.Distance * TO_METERS
|
||||||
});
|
});
|
||||||
|
Mutex.Unlock();
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
GetWorld()->GetPhysicsScene()->GetPxScene()->unlockRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
float ARadar::CalculateRelativeVelocity(const FHitResult& OutHit, const FVector& RadarLocation)
|
float ARadar::CalculateRelativeVelocity(const FHitResult& OutHit, const FVector& RadarLocation)
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
// This work is licensed under the terms of the MIT license.
|
// This work is licensed under the terms of the MIT license.
|
||||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||||
|
|
||||||
|
#include <PxScene.h>
|
||||||
|
|
||||||
#include "Carla.h"
|
#include "Carla.h"
|
||||||
#include "Carla/Sensor/RayCastLidar.h"
|
#include "Carla/Sensor/RayCastLidar.h"
|
||||||
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
|
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
|
||||||
|
@ -15,6 +17,7 @@
|
||||||
#include "DrawDebugHelpers.h"
|
#include "DrawDebugHelpers.h"
|
||||||
#include "Engine/CollisionProfile.h"
|
#include "Engine/CollisionProfile.h"
|
||||||
#include "Runtime/Engine/Classes/Kismet/KismetMathLibrary.h"
|
#include "Runtime/Engine/Classes/Kismet/KismetMathLibrary.h"
|
||||||
|
#include "Runtime/Core/Public/Async/ParallelFor.h"
|
||||||
|
|
||||||
FActorDefinition ARayCastLidar::GetSensorDefinition()
|
FActorDefinition ARayCastLidar::GetSensorDefinition()
|
||||||
{
|
{
|
||||||
|
@ -93,17 +96,30 @@ void ARayCastLidar::ReadPoints(const float DeltaTime)
|
||||||
const float AngleDistanceOfLaserMeasure = AngleDistanceOfTick / PointsToScanWithOneLaser;
|
const float AngleDistanceOfLaserMeasure = AngleDistanceOfTick / PointsToScanWithOneLaser;
|
||||||
|
|
||||||
LidarMeasurement.Reset(ChannelCount * PointsToScanWithOneLaser);
|
LidarMeasurement.Reset(ChannelCount * PointsToScanWithOneLaser);
|
||||||
|
AuxPoints.resize(ChannelCount);
|
||||||
|
|
||||||
for (auto Channel = 0u; Channel < ChannelCount; ++Channel)
|
|
||||||
{
|
GetWorld()->GetPhysicsScene()->GetPxScene()->lockRead();
|
||||||
for (auto i = 0u; i < PointsToScanWithOneLaser; ++i)
|
ParallelFor(ChannelCount, [&](int32 idxChannel) {
|
||||||
{
|
AuxPoints[idxChannel].clear();
|
||||||
|
AuxPoints[idxChannel].reserve(PointsToScanWithOneLaser);
|
||||||
|
|
||||||
|
FCriticalSection Mutex;
|
||||||
|
ParallelFor(PointsToScanWithOneLaser, [&](int32 idxPtsOneLaser) {
|
||||||
FVector Point;
|
FVector Point;
|
||||||
const float Angle = CurrentHorizontalAngle + AngleDistanceOfLaserMeasure * i;
|
const float Angle = CurrentHorizontalAngle + AngleDistanceOfLaserMeasure * idxPtsOneLaser;
|
||||||
if (ShootLaser(Channel, Angle, Point))
|
if (ShootLaser(idxChannel, Angle, Point)) {
|
||||||
{
|
Mutex.Lock();
|
||||||
LidarMeasurement.WritePoint(Channel, Point);
|
AuxPoints[idxChannel].emplace_back(Point);
|
||||||
|
Mutex.Unlock();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
GetWorld()->GetPhysicsScene()->GetPxScene()->unlockRead();
|
||||||
|
|
||||||
|
for (auto idxChannel = 0u; idxChannel < ChannelCount; ++idxChannel) {
|
||||||
|
for (auto& Pt : AuxPoints[idxChannel]) {
|
||||||
|
LidarMeasurement.WritePoint(idxChannel, Pt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ private:
|
||||||
FLidarDescription Description;
|
FLidarDescription Description;
|
||||||
|
|
||||||
TArray<float> LaserAngles;
|
TArray<float> LaserAngles;
|
||||||
|
std::vector<std::vector<FVector>> AuxPoints;
|
||||||
|
|
||||||
FLidarMeasurement LidarMeasurement;
|
FLidarMeasurement LidarMeasurement;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue