diff --git a/PythonClient/carla/benchmarks/corl_2017.py b/PythonClient/carla/benchmarks/corl_2017.py index 55a12b46c..5989ee1d2 100644 --- a/PythonClient/carla/benchmarks/corl_2017.py +++ b/PythonClient/carla/benchmarks/corl_2017.py @@ -138,7 +138,7 @@ class CoRL2017(Benchmark): # This single RGB camera is used on every experiment camera = Camera('CameraRGB') - camera.set(CameraFOV=100) + camera.set(FOV=100) camera.set_image_size(800, 600) diff --git a/PythonClient/carla/client.py b/PythonClient/carla/client.py index 80fed70eb..57ed04542 100644 --- a/PythonClient/carla/client.py +++ b/PythonClient/carla/client.py @@ -11,7 +11,6 @@ import struct from contextlib import contextmanager from . import sensor -from . import settings from . import tcp from . import util @@ -20,6 +19,11 @@ try: except ImportError: raise RuntimeError('cannot import "carla_server_pb2.py", run the protobuf compiler to generate this file') +try: + import numpy +except ImportError: + raise RuntimeError('cannot import numpy, make sure numpy package is installed.') + VehicleControl = carla_protocol.Control @@ -40,7 +44,7 @@ class CarlaClient(object): self._control_client = tcp.TCPClient(host, world_port + 2, timeout) self._current_settings = None self._is_episode_requested = False - self._sensor_names = [] + self._sensors = {} def connect(self, connection_attempts=10): """ @@ -69,7 +73,6 @@ class CarlaClient(object): self._current_settings = carla_settings return self._request_new_episode(carla_settings) - def start_episode(self, player_start_index): """ Start the new episode at the player start given by the @@ -120,8 +123,7 @@ class CarlaClient(object): pb_message = carla_protocol.Measurements() pb_message.ParseFromString(data) # Read sensor data. - raw_sensor_data = self._stream_client.read() - return pb_message, self._parse_raw_sensor_data(raw_sensor_data) + return pb_message, dict(x for x in self._read_sensor_data()) def send_control(self, *args, **kwargs): """ @@ -159,40 +161,66 @@ class CarlaClient(object): raise RuntimeError('failed to read data from server') pb_message = carla_protocol.SceneDescription() pb_message.ParseFromString(data) - self._sensor_names = settings.get_sensor_names(carla_settings) + self._sensors = dict((sensor.id, sensor) \ + for sensor in _make_sensor_parsers(pb_message.sensors)) self._is_episode_requested = True return pb_message - def _parse_raw_sensor_data(self, raw_data): - """Return a dict of {'sensor_name': sensor_data, ...}.""" - return dict((name, data) for name, data in zip( - self._sensor_names, - self._iterate_sensor_data(raw_data))) + def _read_sensor_data(self): + while True: + data = self._stream_client.read() + if not data: + raise StopIteration + yield self._parse_sensor_data(data) - @staticmethod - def _iterate_sensor_data(raw_data): - image_types = ['None', 'SceneFinal', 'Depth', 'SemanticSegmentation', 'Lidar'] - gettype = lambda id: image_types[id] if len(image_types) > id else 'Unknown' - getint = lambda index: struct.unpack(' id else 'Unknown' + getint = lambda data, index: struct.unpack('= (3, 0): text = io.StringIO() @@ -140,29 +113,3 @@ class CarlaSettings(object): ini.write(text) return text.getvalue().replace(' = ', '=') - - -def get_sensor_names(settings): - """ - Return a list with the names of the sensors defined in the settings object. - The settings object can be a CarlaSettings or an INI formatted string. - """ - if isinstance(settings, CarlaSettings): - # pylint: disable=protected-access - return [camera.CameraName for camera in settings._cameras] + \ - [lidar.LidarName for lidar in settings._lidars] - ini = ConfigParser() - if sys.version_info >= (3, 2): - ini.read_string(settings) - elif sys.version_info >= (3, 0): - ini.readfp(io.StringIO(settings)) # pylint: disable=deprecated-method - else: - ini.readfp(io.BytesIO(settings)) # pylint: disable=deprecated-method - - section_name = 'CARLA/SceneCapture' - option_name = 'Cameras' - - if ini.has_section(section_name) and ini.has_option(section_name, option_name): - cameras = ini.get(section_name, option_name) - return cameras.split(',') - return [] diff --git a/PythonClient/client_example.py b/PythonClient/client_example.py index 3883c6980..fc22420e4 100755 --- a/PythonClient/client_example.py +++ b/PythonClient/client_example.py @@ -22,7 +22,7 @@ from carla.tcp import TCPConnectionError from carla.util import print_over_same_line -def run_carla_client(host, port, autopilot_on, save_images_to_disk, image_filename_format, lidar_filename_format, settings_filepath): +def run_carla_client(args): # Here we will run 3 episodes with 300 frames each. number_of_episodes = 3 frames_per_episode = 300 @@ -32,13 +32,13 @@ def run_carla_client(host, port, autopilot_on, save_images_to_disk, image_filena # context manager, it creates a CARLA client object and starts the # connection. It will throw an exception if something goes wrong. The # context manager makes sure the connection is always cleaned up on exit. - with make_carla_client(host, port) as client: + with make_carla_client(args.host, args.port) as client: print('CarlaClient connected') for episode in range(0, number_of_episodes): # Start a new episode. - if settings_filepath is None: + if args.settings_filepath is None: # Create a CarlaSettings object. This object is a wrapper around # the CarlaSettings.ini file. Here we set the configuration we @@ -70,23 +70,23 @@ def run_carla_client(host, port, autopilot_on, save_images_to_disk, image_filena camera1.set_position(30, 0, 130) settings.add_sensor(camera1) - lidar0 = Lidar('Lidar32') - lidar0.set_position(0, 0, 250) - lidar0.set_rotation(0, 0, 0) - lidar0.set( - Channels = 32, - Range = 5000, - PointsPerSecond = 100000, - RotationFrequency = 10, - UpperFovLimit = 10, - LowerFovLimit = -30, - ShowDebugPoints = False) - settings.add_sensor(lidar0) + if args.lidar: + lidar = Lidar('Lidar32') + lidar.set_position(0, 0, 250) + lidar.set_rotation(0, 0, 0) + lidar.set( + Channels=32, + Range=5000, + PointsPerSecond=100000, + RotationFrequency=10, + UpperFovLimit=10, + LowerFovLimit=-30) + settings.add_sensor(lidar) else: # Alternatively, we can load these settings from a file. - with open(settings_filepath, 'r') as fp: + with open(args.settings_filepath, 'r') as fp: settings = fp.read() # Now we load these settings into the server. The server replies @@ -115,12 +115,13 @@ def run_carla_client(host, port, autopilot_on, save_images_to_disk, image_filena print_measurements(measurements) # Save the images to disk if requested. - if save_images_to_disk: + if args.save_images_to_disk: for name, measurement in sensor_data.items(): if isinstance(measurement, LidarMeasurement): - measurement.save_to_disk(lidar_filename_format.format(episode, name, frame)) + filename = args.lidar_filename_format else: - measurement.save_to_disk(image_filename_format.format(episode, name, frame)) + filename = args.image_filename_format + measurement.save_to_disk(filename.format(episode, name, frame)) # We can access the encoded data of a given image as numpy # array using its "data" property. For instance, to get the @@ -134,7 +135,7 @@ def run_carla_client(host, port, autopilot_on, save_images_to_disk, image_filena # If we are in synchronous mode the server will pause the # simulation until we send this control. - if not autopilot_on: + if not args.autopilot: client.send_control( steer=random.uniform(-1.0, 1.0), @@ -199,13 +200,19 @@ def main(): '-a', '--autopilot', action='store_true', help='enable autopilot') + argparser.add_argument( + '-l', '--lidar', + action='store_true', + help='enable Lidar') argparser.add_argument( '-i', '--images-to-disk', action='store_true', - help='save images to disk') + dest='save_images_to_disk', + help='save images (and Lidar data if active) to disk') argparser.add_argument( '-c', '--carla-settings', metavar='PATH', + dest='settings_filepath', default=None, help='Path to a "CarlaSettings.ini" file') @@ -216,17 +223,13 @@ def main(): logging.info('listening to server %s:%s', args.host, args.port) + args.image_filename_format = '_out/episode_{:0>4d}/{:s}/{:0>6d}.png' + args.lidar_filename_format = '_out/episode_{:0>4d}/{:s}/{:0>6d}.ply' + while True: try: - run_carla_client( - host=args.host, - port=args.port, - autopilot_on=args.autopilot, - save_images_to_disk=args.images_to_disk, - image_filename_format='_out/episode_{:0>4d}/{:s}/{:0>6d}.png', - lidar_filename_format='_out/episode_{:0>4d}/{:s}/{:0>6d}.json', - settings_filepath=args.carla_settings) + run_carla_client(args) print('Done.') return diff --git a/PythonClient/manual_control.py b/PythonClient/manual_control.py index 6970dda3c..0eabdcc19 100755 --- a/PythonClient/manual_control.py +++ b/PythonClient/manual_control.py @@ -68,7 +68,7 @@ MINI_WINDOW_WIDTH = 320 MINI_WINDOW_HEIGHT = 180 -def make_carla_settings(): +def make_carla_settings(enable_lidar): """Make a CarlaSettings object with the settings we need.""" settings = CarlaSettings() settings.set( @@ -93,19 +93,18 @@ def make_carla_settings(): camera2.set_position(200, 0, 140) camera2.set_rotation(0.0, 0.0, 0.0) settings.add_sensor(camera2) - lidar0 = sensor.Lidar('Lidar32') - lidar0.set_position(0, 0, 250) - lidar0.set_rotation(0, 0, 0) - lidar0.set( - Channels = 32, - Range = 5000, - PointsPerSecond = 100000, - RotationFrequency = 10, - UpperFovLimit = 10, - LowerFovLimit = -30, - ShowDebugPoints = False) - settings.add_sensor(lidar0) - + if enable_lidar: + lidar = sensor.Lidar('Lidar32') + lidar.set_position(0, 0, 250) + lidar.set_rotation(0, 0, 0) + lidar.set( + Channels=32, + Range=5000, + PointsPerSecond=100000, + RotationFrequency=10, + UpperFovLimit=10, + LowerFovLimit=-30) + settings.add_sensor(lidar) return settings @@ -130,13 +129,14 @@ class Timer(object): class CarlaGame(object): - def __init__(self, carla_client, city_name=None): + def __init__(self, carla_client, enable_lidar=False, city_name=None): self.client = carla_client self._timer = None self._display = None self._main_image = None self._mini_view_image1 = None self._mini_view_image2 = None + self._enable_lidar = enable_lidar self._lidar_measurement = None self._map_view = None self._is_on_reverse = False @@ -175,7 +175,7 @@ class CarlaGame(object): self._on_new_episode() def _on_new_episode(self): - scene = self.client.load_settings(make_carla_settings()) + scene = self.client.load_settings(make_carla_settings(self._enable_lidar)) number_of_player_starts = len(scene.player_start_spots) player_start = np.random.randint(number_of_player_starts) print('Starting new episode...') @@ -191,7 +191,8 @@ class CarlaGame(object): self._main_image = sensor_data['CameraRGB'] self._mini_view_image1 = sensor_data['CameraDepth'] self._mini_view_image2 = sensor_data['CameraSemSeg'] - self._lidar_measurement = sensor_data['Lidar32'] + if self._enable_lidar: + self._lidar_measurement = sensor_data['Lidar32'] # Print measurements every second. if self._timer.elapsed_seconds_since_lap() > 1.0: @@ -222,9 +223,9 @@ class CarlaGame(object): # Set the player position if self._city_name is not None: self._position = self._map.convert_to_pixel([ - measurements.player_measurements.transform.location.x, - measurements.player_measurements.transform.location.y, - measurements.player_measurements.transform.location.z]) + measurements.player_measurements.transform.location.x, + measurements.player_measurements.transform.location.y, + measurements.player_measurements.transform.location.z]) self._agent_positions = measurements.non_player_agents if control is None: @@ -261,7 +262,8 @@ class CarlaGame(object): map_position, lane_orientation): message = 'Step {step} ({fps:.1f} FPS): ' - message += 'Map Position ({map_x:.1f},{map_y:.1f}) Lane Orientation ({ori_x:.1f},{ori_y:.1f}) ' + message += 'Map Position ({map_x:.1f},{map_y:.1f}) ' + message += 'Lane Orientation ({ori_x:.1f},{ori_y:.1f}) ' message += '{speed:.2f} km/h, ' message += '{other_lane:.0f}% other lane, {offroad:.0f}% off-road' message = message.format( @@ -311,8 +313,7 @@ class CarlaGame(object): surface, (2 * gap_x + MINI_WINDOW_WIDTH, mini_image_y)) if self._lidar_measurement is not None: - - lidar_data = np.array(self._lidar_measurement.data['points'][:, :, :2]) + lidar_data = np.array(self._lidar_measurement.data[:, :2]) lidar_data /= 50.0 lidar_data += 100.0 lidar_data = np.fabs(lidar_data) @@ -322,22 +323,22 @@ class CarlaGame(object): lidar_img_size = (200, 200, 3) lidar_img = np.zeros(lidar_img_size) lidar_img[tuple(lidar_data.T)] = (255, 255, 255) - surface = pygame.surfarray.make_surface( - lidar_img - ) + surface = pygame.surfarray.make_surface(lidar_img) self._display.blit(surface, (10, 10)) if self._map_view is not None: array = self._map_view array = array[:, :, :3] - new_window_width =(float(WINDOW_HEIGHT)/float(self._map_shape[0]))*float(self._map_shape[1]) + new_window_width = \ + (float(WINDOW_HEIGHT) / float(self._map_shape[0])) * \ + float(self._map_shape[1]) surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)) w_pos = int(self._position[0]*(float(WINDOW_HEIGHT)/float(self._map_shape[0]))) h_pos = int(self._position[1] *(new_window_width/float(self._map_shape[1]))) - pygame.draw.circle(surface, [255, 0, 0, 255], (w_pos,h_pos), 6, 0) + pygame.draw.circle(surface, [255, 0, 0, 255], (w_pos, h_pos), 6, 0) for agent in self._agent_positions: if agent.HasField('vehicle'): agent_position = self._map.convert_to_pixel([ @@ -348,7 +349,7 @@ class CarlaGame(object): w_pos = int(agent_position[0]*(float(WINDOW_HEIGHT)/float(self._map_shape[0]))) h_pos = int(agent_position[1] *(new_window_width/float(self._map_shape[1]))) - pygame.draw.circle(surface, [255, 0, 255, 255], (w_pos ,h_pos), 4, 0) + pygame.draw.circle(surface, [255, 0, 255, 255], (w_pos, h_pos), 4, 0) self._display.blit(surface, (WINDOW_WIDTH, 0)) @@ -374,11 +375,16 @@ def main(): default=2000, type=int, help='TCP port to listen to (default: 2000)') + argparser.add_argument( + '-l', '--lidar', + action='store_true', + help='enable Lidar') argparser.add_argument( '-m', '--map-name', metavar='M', default=None, - help='plot the map of the current city (needs to match active map in server, options: Town01 or Town02)') + help='plot the map of the current city (needs to match active map in ' + 'server, options: Town01 or Town02)') args = argparser.parse_args() log_level = logging.DEBUG if args.debug else logging.INFO @@ -392,7 +398,7 @@ def main(): try: with make_carla_client(args.host, args.port) as client: - game = CarlaGame(client, args.map_name) + game = CarlaGame(client, args.lidar, args.map_name) game.execute() break diff --git a/PythonClient/point_cloud_example.py b/PythonClient/point_cloud_example.py index b597e1085..50c53867c 100755 --- a/PythonClient/point_cloud_example.py +++ b/PythonClient/point_cloud_example.py @@ -51,17 +51,13 @@ def run_carla_client(host, port, far): WeatherId=random.choice([1, 3, 7, 8, 14])) settings.randomize_seeds() - camera1 = Camera( - 'CameraDepth', PostProcessing='Depth', CameraFOV=fov - ) + camera1 = Camera('CameraDepth', PostProcessing='Depth', FOV=fov) camera1.set_image_size(*image_size) camera1.set_position(*camera_local_pos) camera1.set_rotation(*camera_local_rotation) settings.add_sensor(camera1) - camera2 = Camera( - 'CameraRGB', PostProcessing='SceneFinal', CameraFOV=fov - ) + camera2 = Camera('CameraRGB', PostProcessing='SceneFinal', FOV=fov) camera2.set_image_size(*image_size) camera2.set_position(*camera_local_pos) camera2.set_rotation(*camera_local_rotation) diff --git a/PythonClient/test/unit_tests/Basic.py b/PythonClient/test/unit_tests/Basic.py index 9197c1241..ab1d1630e 100644 --- a/PythonClient/test/unit_tests/Basic.py +++ b/PythonClient/test/unit_tests/Basic.py @@ -13,6 +13,7 @@ import carla from carla.client import CarlaClient from carla.sensor import Camera, Image +from carla.sensor import Lidar, LidarMeasurement from carla.settings import CarlaSettings from carla.util import make_connection @@ -45,8 +46,8 @@ class _BasicTestBase(unit_tests.CarlaServerTest): number_of_agents = len(measurements.non_player_agents) logging.debug('received data of %d agents', number_of_agents) logging.debug('received %d images', len(images)) - if len(images) != len(carla_settings._cameras): - raise RuntimeError('received %d images, expected %d' % (len(images), len(carla_settings._cameras))) + if len(sensor_data) != len(carla_settings._sensors): + raise RuntimeError('received %d, expected %d' % (len(sensor_data), len(carla_settings._sensors))) logging.debug('sending control...') control = measurements.player_measurements.autopilot_control if not use_autopilot_control: @@ -80,7 +81,7 @@ class TwoCameras(_BasicTestBase): settings = CarlaSettings() settings.add_sensor(Camera('DefaultCamera')) camera2 = Camera('Camera2') - camera2.set(PostProcessing='Depth', CameraFOV=120) + camera2.set(PostProcessing='Depth', FOV=120) camera2.set_image_size(1924, 1028) settings.add_sensor(camera2) self.run_carla_client(settings, 3, 100) @@ -110,3 +111,10 @@ class LongEpisode(_BasicTestBase): settings = CarlaSettings() settings.add_sensor(Camera('DefaultCamera')) self.run_carla_client(settings, 1, 2000, use_autopilot_control=True) + + +class LidarTest(_BasicTestBase): + def run(self): + settings = CarlaSettings() + settings.add_sensor(Lidar('DefaultLidar')) + self.run_carla_client(settings, 3, 100) diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Settings/CameraDescription.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Settings/CameraDescription.cpp index bb8b38348..6a26b68b8 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Settings/CameraDescription.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Settings/CameraDescription.cpp @@ -17,7 +17,7 @@ void UCameraDescription::Load(const FIniFile &Config, const FString &Section) PostProcessEffect = PostProcessEffect::FromString(PostProcessing); Config.GetInt(*Section, TEXT("ImageSizeX"), ImageSizeX); Config.GetInt(*Section, TEXT("ImageSizeY"), ImageSizeY); - Config.GetFloat(*Section, TEXT("CameraFOV"), FOVAngle); + Config.GetFloat(*Section, TEXT("FOV"), FOVAngle); } void UCameraDescription::Validate()