From 708f3ccfe3dab4a861abee78387142670b870e00 Mon Sep 17 00:00:00 2001 From: Joel Moriana Date: Thu, 5 Mar 2020 16:49:16 +0100 Subject: [PATCH] fixing codacy warnings --- Co-Simulation/Sumo/run_synchronization.py | 164 ++++++++---------- .../Sumo/sumo_integration/bridge_helper.py | 160 ++++++++--------- .../Sumo/sumo_integration/carla_simulation.py | 79 ++++++--- .../Sumo/sumo_integration/constants.py | 10 +- .../Sumo/sumo_integration/sumo_simulation.py | 118 +++++++++---- Co-Simulation/Sumo/util/create_sumo_vtypes.py | 143 +++++++-------- Co-Simulation/Sumo/util/sequential_types.py | 81 ++++----- 7 files changed, 406 insertions(+), 349 deletions(-) diff --git a/Co-Simulation/Sumo/run_synchronization.py b/Co-Simulation/Sumo/run_synchronization.py index b3a4f8c44..583e3cb3e 100644 --- a/Co-Simulation/Sumo/run_synchronization.py +++ b/Co-Simulation/Sumo/run_synchronization.py @@ -10,9 +10,17 @@ Script to integrate CARLA and SUMO simulations """ -# ============================================================================== -# -- find carla module --------------------------------------------------------- -# ============================================================================== +# ================================================================================================== +# -- imports --------------------------------------------------------------------------------------- +# ================================================================================================== + +import argparse +import logging +import time + +# ================================================================================================== +# -- find carla module ----------------------------------------------------------------------------- +# ================================================================================================== import glob import os @@ -26,34 +34,33 @@ try: except IndexError: pass -# ============================================================================== -# -- find traci module --------------------------------------------------------- -# ============================================================================== +# ================================================================================================== +# -- find traci module ----------------------------------------------------------------------------- +# ================================================================================================== if 'SUMO_HOME' in os.environ: - tools = os.path.join(os.environ['SUMO_HOME'], 'tools') - sys.path.append(tools) + sys.path.append(os.path.join(os.environ['SUMO_HOME'], 'tools')) else: sys.exit("please declare environment variable 'SUMO_HOME'") -# ============================================================================== -# -- imports ------------------------------------------------------------------- -# ============================================================================== +# ================================================================================================== +# -- sumo integration importants ------------------------------------------------------------------- +# ================================================================================================== -import argparse -import logging -import time +from sumo_integration.bridge_helper import BridgeHelper # pylint: disable=wrong-import-position +from sumo_integration.carla_simulation import CarlaSimulation # pylint: disable=wrong-import-position +from sumo_integration.constants import INVALID_ACTOR_ID # pylint: disable=wrong-import-position +from sumo_integration.sumo_simulation import SumoSimulation # pylint: disable=wrong-import-position -from sumo_integration.bridge_helper import BridgeHelper -from sumo_integration.carla_simulation import CarlaSimulation -from sumo_integration.constants import * -from sumo_integration.sumo_simulation import SumoSimulation +# ================================================================================================== +# -- simulation synchro ---------------------------------------------------------------------------- +# ================================================================================================== -# ============================================================================== -# -- simulation synchro -------------------------------------------------------- -# ============================================================================== def main(args): + """ + Entry point sumo-carla co-simulation. + """ sumo = SumoSimulation(args) carla = CarlaSimulation(args) @@ -61,8 +68,8 @@ def main(args): sumo2carla_ids = {} # Contains only actors controlled by sumo. carla2sumo_ids = {} # Contains only actors controlled by carla. - BridgeHelper._blueprint_library = carla.world.get_blueprint_library() - BridgeHelper._offset = sumo.get_net_offset() + BridgeHelper.blueprint_library = carla.world.get_blueprint_library() + BridgeHelper.offset = sumo.get_net_offset() try: while True: @@ -81,7 +88,8 @@ def main(args): carla_blueprint = BridgeHelper.get_carla_blueprint(sumo_actor) if carla_blueprint is not None: - carla_transform = BridgeHelper.get_carla_transform(sumo_actor.transform, sumo_actor.extent) + carla_transform = BridgeHelper.get_carla_transform( + sumo_actor.transform, sumo_actor.extent) carla_actor_id = carla.spawn_actor(carla_blueprint, carla_transform) if carla_actor_id != INVALID_ACTOR_ID: @@ -101,9 +109,11 @@ def main(args): sumo_actor = sumo.get_actor(sumo_actor_id) carla_actor = carla.get_actor(carla_actor_id) - carla_transform = BridgeHelper.get_carla_transform(sumo_actor.transform, sumo_actor.extent) + carla_transform = BridgeHelper.get_carla_transform(sumo_actor.transform, + sumo_actor.extent) if args.sync_vehicle_lights: - carla_lights = BridgeHelper.get_carla_lights_state(carla_actor.get_light_state(), sumo_actor.signals) + carla_lights = BridgeHelper.get_carla_lights_state( + carla_actor.get_light_state(), sumo_actor.signals) else: carla_lights = None @@ -138,11 +148,13 @@ def main(args): carla_actor = carla.get_actor(carla_actor_id) sumo_actor = sumo.get_actor(sumo_actor_id) - sumo_transform = BridgeHelper.get_sumo_transform(carla_actor.get_transform(), carla_actor.bounding_box.extent) + sumo_transform = BridgeHelper.get_sumo_transform(carla_actor.get_transform(), + carla_actor.bounding_box.extent) if args.sync_vehicle_lights: carla_lights = carla.get_actor_light_state(carla_actor_id) if carla_lights is not None: - sumo_lights = BridgeHelper.get_sumo_lights_state(sumo_actor.signals, carla_lights) + sumo_lights = BridgeHelper.get_sumo_lights_state( + sumo_actor.signals, carla_lights) else: sumo_lights = None else: @@ -158,9 +170,6 @@ def main(args): except KeyboardInterrupt: logging.info('Cancelled by user.') - except Exception as error: - logging.error('Synchronization failed. {}'.format(error)) - finally: logging.info('Cleaning up synchronization') @@ -180,68 +189,49 @@ def main(args): # Closing sumo client. sumo.close() + if __name__ == '__main__': - argparser = argparse.ArgumentParser( - description=__doc__ - ) - argparser.add_argument( - '--carla-host', - metavar='H', - default='127.0.0.1', - help='IP of the carla host server (default: 127.0.0.1)' - ) - argparser.add_argument( - '--carla-port', - metavar='P', - default=2000, - type=int, - help='TCP port to listen to (default: 2000)' - ) - argparser.add_argument( - '--sumo-host', - metavar='H', - default=None, - help='IP of the sumo host server (default: 127.0.0.1)' - ) - argparser.add_argument( - '--sumo-port', - metavar='P', - default=None, - type=int, - help='TCP port to liston to (default: 8813)' - ) - argparser.add_argument( - '-c', '--sumo-cfg-file', - default=None, - type=str, - help='sumo configuration file' - ) - argparser.add_argument( - '--sumo-gui', - default=True, - help='run the gui version of sumo (default: True)' - ) - argparser.add_argument( - '--step-length', - default=0.05, - type=float, - help='set fixed delta seconds (default: 0.05s)' - ) + argparser = argparse.ArgumentParser(description=__doc__) + argparser.add_argument('--carla-host', + metavar='H', + default='127.0.0.1', + help='IP of the carla host server (default: 127.0.0.1)') + argparser.add_argument('--carla-port', + metavar='P', + default=2000, + type=int, + help='TCP port to listen to (default: 2000)') + argparser.add_argument('--sumo-host', + metavar='H', + default=None, + help='IP of the sumo host server (default: 127.0.0.1)') + argparser.add_argument('--sumo-port', + metavar='P', + default=None, + type=int, + help='TCP port to liston to (default: 8813)') + argparser.add_argument('-c', + '--sumo-cfg-file', + default=None, + type=str, + help='sumo configuration file') + argparser.add_argument('--sumo-gui', + default=True, + help='run the gui version of sumo (default: True)') + argparser.add_argument('--step-length', + default=0.05, + type=float, + help='set fixed delta seconds (default: 0.05s)') argparser.add_argument( '--sync-vehicle-lights', action='store_true', - help='synchronize vehicle lights state between simulations (default: False)' - ) - argparser.add_argument( - '--debug', - action='store_true', - help='enable debug messages' - ) - args = argparser.parse_args() + help='synchronize vehicle lights state between simulations (default: False)') + argparser.add_argument('--debug', action='store_true', help='enable debug messages') + arguments = argparser.parse_args() - if args.debug: + if arguments.debug: logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG) else: logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO) - main(args) \ No newline at end of file + main(arguments) diff --git a/Co-Simulation/Sumo/sumo_integration/bridge_helper.py b/Co-Simulation/Sumo/sumo_integration/bridge_helper.py index 3f75e8b98..836f491cd 100644 --- a/Co-Simulation/Sumo/sumo_integration/bridge_helper.py +++ b/Co-Simulation/Sumo/sumo_integration/bridge_helper.py @@ -6,38 +6,44 @@ # This work is licensed under the terms of the MIT license. # For a copy, see . -# ============================================================================== -# -- imports ------------------------------------------------------------------- -# ============================================================================== +""" This module provides a helper for the co-simulation between sumo and carla .""" + +# ================================================================================================== +# -- imports --------------------------------------------------------------------------------------- +# ================================================================================================== import json import logging import math import random -import carla -import traci +import carla # pylint: disable=import-error +import traci # pylint: disable=import-error from .sumo_simulation import SumoVehSignal -# ============================================================================== -# -- Bridge helper (SUMO <=> CARLA) -------------------------------------------- -# ============================================================================== +# ================================================================================================== +# -- Bridge helper (SUMO <=> CARLA) ---------------------------------------------------------------- +# ================================================================================================== class BridgeHelper(object): + """ + BridgeHelper provides methos to ease the co-simulation between sumo and carla. + """ - _blueprint_library = None - _offset = (0, 0) + blueprint_library = [] + offset = (0, 0) with open('data/vtypes.json') as f: _VTYPES = json.load(f)['carla_blueprints'] @staticmethod def get_carla_transform(in_sumo_transform, extent): - """Returns carla transform based on sumo transform. """ - offset = BridgeHelper._offset + Returns carla transform based on sumo transform. + """ + offset = BridgeHelper.offset in_location = in_sumo_transform.location in_rotation = in_sumo_transform.rotation @@ -45,93 +51,80 @@ class BridgeHelper(object): # (http://sumo.sourceforge.net/userdoc/Purgatory/Vehicle_Values.html#angle) yaw = -1 * in_rotation.yaw + 90 length = 2.0 * extent.x - out_location = ( - in_location.x - math.cos(math.radians(yaw)) * (length / 2.0), - in_location.y - math.sin(math.radians(yaw)) * (length / 2.0), - in_location.z - ) + out_location = (in_location.x - math.cos(math.radians(yaw)) * (length / 2.0), + in_location.y - math.sin(math.radians(yaw)) * (length / 2.0), in_location.z) out_rotation = (in_rotation.pitch, in_rotation.yaw, in_rotation.roll) # Applying offset sumo-carla net. - out_location = ( - out_location[0] - offset[0], - out_location[1] - offset[1], - out_location[2] - ) - out_rotation = out_rotation + out_location = (out_location[0] - offset[0], out_location[1] - offset[1], out_location[2]) # Transform to carla reference system (left-handed system). return carla.Transform( carla.Location(out_location[0], -out_location[1], out_location[2]), - carla.Rotation(out_rotation[0], out_rotation[1] - 90, out_rotation[2]) - ) + carla.Rotation(out_rotation[0], out_rotation[1] - 90, out_rotation[2])) @staticmethod def get_sumo_transform(in_carla_transform, extent): - """Returns sumo transform based on carla transform. """ - offset = BridgeHelper._offset + Returns sumo transform based on carla transform. + """ + offset = BridgeHelper.offset in_location = in_carla_transform.location in_rotation = in_carla_transform.rotation # From center to front-center-bumper (carla reference system). yaw = -1 * in_rotation.yaw length = 2.0 * extent.x - out_location = ( - in_location.x + math.cos(math.radians(yaw)) * (length / 2.0), - in_location.y - math.sin(math.radians(yaw)) * (length / 2.0), - in_location.z - ) + out_location = (in_location.x + math.cos(math.radians(yaw)) * (length / 2.0), + in_location.y - math.sin(math.radians(yaw)) * (length / 2.0), in_location.z) out_rotation = (in_rotation.pitch, in_rotation.yaw, in_rotation.roll) # Applying offset carla-sumo net - out_location = ( - out_location[0] + offset[0], - out_location[1] - offset[1], - out_location[2] - ) - out_rotation = out_rotation + out_location = (out_location[0] + offset[0], out_location[1] - offset[1], out_location[2]) # Transform to sumo reference system. return carla.Transform( carla.Location(out_location[0], -out_location[1], out_location[2]), - carla.Rotation(out_rotation[0], out_rotation[1] + 90, out_rotation[2]) - ) + carla.Rotation(out_rotation[0], out_rotation[1] + 90, out_rotation[2])) @staticmethod def _get_recommended_carla_blueprint(sumo_actor): - """Returns an appropriate blueprint based on the given sumo actor. + """ + Returns an appropriate blueprint based on the given sumo actor. """ vclass = sumo_actor.vclass.value blueprints = [] - for blueprint in BridgeHelper._blueprint_library: + for blueprint in BridgeHelper.blueprint_library: if blueprint.id in BridgeHelper._VTYPES and \ BridgeHelper._VTYPES[blueprint.id]['vClass'] == vclass: blueprints.append(blueprint) - if len(blueprints) == 0: + if not blueprints: return None return random.choice(blueprints) @staticmethod def get_carla_blueprint(sumo_actor): - """Returns an appropriate blueprint based on the received sumo actor. """ - blueprint_library = BridgeHelper._blueprint_library + Returns an appropriate blueprint based on the received sumo actor. + """ + blueprint_library = BridgeHelper.blueprint_library type_id = sumo_actor.type_id if type_id in [bp.id for bp in blueprint_library]: blueprint = blueprint_library.filter(type_id)[0] - logging.debug('[BridgeHelper] sumo vtype {} found in carla blueprints'.format(type_id)) + logging.debug('[BridgeHelper] sumo vtype %s found in carla blueprints', type_id) else: blueprint = BridgeHelper._get_recommended_carla_blueprint(sumo_actor) if blueprint is not None: logging.warning( - 'sumo vtype {} not found in carla blueprints. The following blueprint will be used: {}'.format(type_id, blueprint.id)) + 'sumo vtype %s not found in carla. The following blueprint will be used: %s' + , type_id, blueprint.id) else: - logging.error('sumo vtype {} not supported. No vehicle will be spawned in carla'.format(type_id)) + logging.error( + 'sumo vtype %s not supported. No vehicle will be spawned in carla', type_id) return None if blueprint.has_attribute('color'): @@ -139,26 +132,23 @@ class BridgeHelper(object): blueprint.set_attribute('color', color) if blueprint.has_attribute('driver_id'): - driver_id = random.choice( - blueprint.get_attribute('driver_id').recommended_values) + driver_id = random.choice(blueprint.get_attribute('driver_id').recommended_values) blueprint.set_attribute('driver_id', driver_id) blueprint.set_attribute('role_name', 'sumo_driver') - logging.debug('''[BridgeHelper] sumo vtype {vtype} will be spawned in carla with the following attributes: - \tblueprint: {bp_id:} - \tcolor: {color:}'''.format( - vtype=type_id, - bp_id=blueprint.id, - color=sumo_actor.color if blueprint.has_attribute('color') else (-1, -1, -1) - ) - ) + logging.debug( + '''[BridgeHelper] sumo vtype %s will be spawned in carla with the following attributes: + \tblueprint: %s + \tcolor: %s''', type_id, blueprint.id, + sumo_actor.color if blueprint.has_attribute('color') else (-1, -1, -1)) return blueprint @staticmethod def _create_sumo_vtype(carla_actor): - """Creates an appropriate vtype based on the given carla_actor. + """ + Creates an appropriate vtype based on the given carla_actor. """ type_id = carla_actor.type_id attrs = carla_actor.attributes @@ -186,47 +176,46 @@ class BridgeHelper(object): traci.vehicletype.setWidth(type_id, 2.0 * extent.y) traci.vehicletype.setHeight(type_id, 2.0 * extent.z) - logging.debug('''[BridgeHelper] blueprint{bp_id} not found in sumo vtypes - \tdefault vtype: {dvtype:} - \tvtype: {vtype:} - \tclass: {_class:} - \tshape: {shape:} - \tcolor: {color:} - \tlenght: {lenght:} - \twidth: {width:} - \theight: {height:}'''.format( - bp_id=type_id, - dvtype='DEFAULT_BIKETYPE' if int(attrs['number_of_wheels']) == 2 else 'DEFAULT_VEHTYPE', - vtype=type_id, - _class=traci.vehicletype.getVehicleClass(type_id), - shape=traci.vehicletype.getShapeClass(type_id), - color=traci.vehicletype.getColor(type_id), - lenght=traci.vehicletype.getLength(type_id), - width=traci.vehicletype.getWidth(type_id), - height=traci.vehicletype.getHeight(type_id) - ) - ) + logging.debug( + '''[BridgeHelper] blueprint %s not found in sumo vtypes + \tdefault vtype: %s + \tvtype: %s + \tclass: %s + \tshape: %s + \tcolor: %s + \tlenght: %s + \twidth: %s + \theight: %s''', type_id, + 'DEFAULT_BIKETYPE' if int(attrs['number_of_wheels']) == 2 else 'DEFAULT_VEHTYPE', + type_id, traci.vehicletype.getVehicleClass(type_id), + traci.vehicletype.getShapeClass(type_id), traci.vehicletype.getColor(type_id), + traci.vehicletype.getLength(type_id), traci.vehicletype.getWidth(type_id), + traci.vehicletype.getHeight(type_id)) return type_id @staticmethod def get_sumo_vtype(carla_actor): - """Returns an appropriate vtype based on the type id and attributes. + """ + Returns an appropriate vtype based on the type id and attributes. """ type_id = carla_actor.type_id if not type_id.startswith('vehicle'): - logging.error('[BridgeHelper] Blueprint {} not supported. No vehicle will be spawned in sumo'.format(type_id)) + logging.error( + '[BridgeHelper] Blueprint %s not supported. No vehicle will be spawned in sumo', + type_id) return None if type_id in traci.vehicletype.getIDList(): - logging.debug('[BridgeHelper] blueprint {} found in sumo vtypes'.format(type_id)) + logging.debug('[BridgeHelper] blueprint %s found in sumo vtypes', type_id) return type_id return BridgeHelper._create_sumo_vtype(carla_actor) @staticmethod def get_carla_lights_state(current_carla_lights, sumo_lights): - """Returns carla vehicle light state based on sumo signals. + """ + Returns carla vehicle light state based on sumo signals. """ current_lights = current_carla_lights @@ -280,7 +269,8 @@ class BridgeHelper(object): @staticmethod def get_sumo_lights_state(current_sumo_lights, carla_lights): - """Returns sumo signals based on carla vehicle light state. + """ + Returns sumo signals based on carla vehicle light state. """ current_lights = current_sumo_lights @@ -326,4 +316,4 @@ class BridgeHelper(object): bool(current_lights & SumoVehSignal.BACKDRIVE)): current_lights ^= SumoVehSignal.BACKDRIVE - return current_lights \ No newline at end of file + return current_lights diff --git a/Co-Simulation/Sumo/sumo_integration/carla_simulation.py b/Co-Simulation/Sumo/sumo_integration/carla_simulation.py index 3f1167171..0dfb9900f 100644 --- a/Co-Simulation/Sumo/sumo_integration/carla_simulation.py +++ b/Co-Simulation/Sumo/sumo_integration/carla_simulation.py @@ -6,32 +6,34 @@ # This work is licensed under the terms of the MIT license. # For a copy, see . -# ============================================================================== -# -- imports ------------------------------------------------------------------- -# ============================================================================== +""" This module is responsible for the management of the carla simulation. """ + +# ================================================================================================== +# -- imports --------------------------------------------------------------------------------------- +# ================================================================================================== import logging -import carla -SpawnActor = carla.command.SpawnActor -FutureActor = carla.command.FutureActor -SetSimulatePhysics = carla.command.SetSimulatePhysics +import carla # pylint: disable=import-error -from .constants import * +from .constants import INVALID_ACTOR_ID, SPAWN_OFFSET_Z -# ============================================================================== -# -- carla simulation ---------------------------------------------------------- -# ============================================================================== +# ================================================================================================== +# -- carla simulation ------------------------------------------------------------------------------ +# ================================================================================================== class CarlaSimulation(object): + """ + CarlaSimulation is responsible for the management of the carla simulation. + """ + def __init__(self, args): self.args = args - self.host = args.carla_host - self.port = args.carla_port - self.step_length = args.step_length + host = args.carla_host + port = args.carla_port - self.client = carla.Client(self.host, self.port) + self.client = carla.Client(host, port) self.client.set_timeout(2.0) self.world = self.client.get_world() @@ -40,7 +42,7 @@ class CarlaSimulation(object): # Configuring carla simulation in sync mode. settings = self.world.get_settings() settings.synchronous_mode = True - settings.fixed_delta_seconds = self.step_length + settings.fixed_delta_seconds = args.step_length self.world.apply_settings(settings) # The following sets contain updated information for the current frame. @@ -49,12 +51,20 @@ class CarlaSimulation(object): self.destroyed_actors = set() def get_actor(self, actor_id): + """ + Accessor for carla actor. + """ return self.world.get_actor(actor_id) # This is a workaround to fix synchronization issues when other carla # clients remove an actor in carla without waiting for tick (e.g., # running sumo co-simulation and manual control at the same time) def get_actor_light_state(self, actor_id): + """ + Accessor for carla actor light state. + + If the actor is not alive, returns None. + """ try: actor = self.get_actor(actor_id) return actor.get_light_state() @@ -62,30 +72,46 @@ class CarlaSimulation(object): return None def spawn_actor(self, blueprint, transform): - """Spawns a new actor. + """ + Spawns a new actor. + + :param blueprint: blueprint of the actor to be spawned. + :param transform: transform where the actor will be spawned. + :return: actor id if the actor is successfully spawned. Otherwise, INVALID_ACTOR_ID. """ transform = carla.Transform( transform.location + carla.Location(0, 0, SPAWN_OFFSET_Z), transform.rotation) batch = [ - SpawnActor(blueprint,transform) - .then(SetSimulatePhysics(FutureActor, False)) + carla.command.SpawnActor(blueprint, transform) + .then(carla.command.SetSimulatePhysics(carla.command.FutureActor, False)) ] response = self.client.apply_batch_sync(batch, True)[0] if response.error: - logging.error('Spawn carla actor failed. {}'.format(response.error)) + logging.error('Spawn carla actor failed. %s', response.error) return INVALID_ACTOR_ID - else: - return response.actor_id + + return response.actor_id def destroy_actor(self, actor_id): + """ + Destroys the given actor. + """ actor = self.world.get_actor(actor_id) if actor is not None: return actor.destroy() return False def synchronize_vehicle(self, vehicle_id, transform, lights=None): + """ + Updates vehicle state. + + :param vehicle_id: id of the actor to be updated. + :param transform: new vehicle transform (i.e., position and rotation). + :param lights: new vehicle light state. + :return: True if successfully updated. Otherwise, False. + """ vehicle = self.world.get_actor(vehicle_id) if vehicle is None: return False @@ -93,11 +119,12 @@ class CarlaSimulation(object): vehicle.set_transform(transform) if lights is not None and self.args.sync_vehicle_lights: vehicle.set_light_state(carla.VehicleLightState(lights)) - - def synchronize_walker(self, walker_id, transform): - pass + return True def tick(self): + """ + Tick to carla simulation. + """ self.world.tick() # Update data structures for the current frame. @@ -106,4 +133,4 @@ class CarlaSimulation(object): ]) self.spawned_actors = current_actors.difference(self._active_actors) self.destroyed_actors = self._active_actors.difference(current_actors) - self._active_actors = current_actors \ No newline at end of file + self._active_actors = current_actors diff --git a/Co-Simulation/Sumo/sumo_integration/constants.py b/Co-Simulation/Sumo/sumo_integration/constants.py index 9a5fdc0e1..0f983994c 100644 --- a/Co-Simulation/Sumo/sumo_integration/constants.py +++ b/Co-Simulation/Sumo/sumo_integration/constants.py @@ -6,9 +6,11 @@ # This work is licensed under the terms of the MIT license. # For a copy, see . -# ============================================================================== -# -- constants ----------------------------------------------------------------- -# ============================================================================== +""" This module defines constants used for the sumo-carla co-simulation. """ + +# ================================================================================================== +# -- constants ------------------------------------------------------------------------------------- +# ================================================================================================== INVALID_ACTOR_ID = -1 -SPAWN_OFFSET_Z = 5.0 # meters \ No newline at end of file +SPAWN_OFFSET_Z = 5.0 # meters diff --git a/Co-Simulation/Sumo/sumo_integration/sumo_simulation.py b/Co-Simulation/Sumo/sumo_integration/sumo_simulation.py index 80848079a..1e7f775ef 100644 --- a/Co-Simulation/Sumo/sumo_integration/sumo_simulation.py +++ b/Co-Simulation/Sumo/sumo_integration/sumo_simulation.py @@ -6,28 +6,32 @@ # This work is licensed under the terms of the MIT license. # For a copy, see . -# ============================================================================== -# -- imports ------------------------------------------------------------------- -# ============================================================================== +""" This module is responsible for the management of the sumo simulation. """ + +# ================================================================================================== +# -- imports --------------------------------------------------------------------------------------- +# ================================================================================================== import collections import enum import logging -import carla -import sumolib -import traci +import carla # pylint: disable=import-error +import sumolib # pylint: disable=import-error +import traci # pylint: disable=import-error -from .constants import * +from .constants import INVALID_ACTOR_ID -# ============================================================================== -# -- sumo definitions ---------------------------------------------------------- -# ============================================================================== +# ================================================================================================== +# -- sumo definitions ------------------------------------------------------------------------------ +# ================================================================================================== -# Sumo vehicle signals. # https://sumo.dlr.de/docs/TraCI/Vehicle_Signalling.html class SumoVehSignal(object): + """ + SumoVehSignal contains the different sumo vehicle signals. + """ BLINKER_RIGHT = 1 << 0 BLINKER_LEFT = 1 << 1 BLINKER_EMERGENCY = 1 << 2 @@ -46,6 +50,9 @@ class SumoVehSignal(object): # https://sumo.dlr.de/docs/Definition_of_Vehicles,_Vehicle_Types,_and_Routes.html#abstract_vehicle_class class SumoActorClass(enum.Enum): + """ + SumoActorClass enumerates the different sumo actor classes. + """ IGNORING = "ignoring" PRIVATE = "private" EMERGENCY = "emergency" @@ -84,13 +91,16 @@ SumoActor = collections.namedtuple( class SumoSimulation(object): + """ + SumoSimulation is responsible for the management of the sumo simulation. + """ + def __init__(self, args): self.args = args - self.host = args.sumo_host - self.port = args.sumo_port + host = args.sumo_host + port = args.sumo_port - self.sumo_gui = args.sumo_gui - if self.sumo_gui is True: + if args.sumo_gui is True: sumo_binary = sumolib.checkBinary('sumo-gui') else: sumo_binary = sumolib.checkBinary('sumo') @@ -105,11 +115,11 @@ class SumoSimulation(object): '--collision.check-junctions' ]) - if self.sumo_gui: + if args.sumo_gui: logging.info('Remember to press the play button to start the simulation') else: - logging.info('Connection to sumo server. Host: {} Port: {}'.format(self.host, self.port)) - traci.init(host=self.host, port=self.port) + logging.info('Connection to sumo server. Host: %s Port: %s', host, port) + traci.init(host=host, port=port) # Structures to keep track of the spawned and destroyed vehicles at each time step. self.spawned_actors = set() @@ -123,6 +133,19 @@ class SumoSimulation(object): @staticmethod def subscribe(actor_id): + """ + Subscribe the given actor to the following variables: + + * Type. + * Vehicle class. + * Color. + * Length, Width, Height. + * Position3D (i.e., x, y, z). + * Angle, Slope. + * Speed. + * Lateral speed. + * Signals. + """ traci.vehicle.subscribe(actor_id, [ traci.constants.VAR_TYPE, traci.constants.VAR_VEHICLECLASS, traci.constants.VAR_COLOR, traci.constants.VAR_LENGTH, @@ -134,16 +157,28 @@ class SumoSimulation(object): @staticmethod def unsubscribe(actor_id): + """ + Unsubscribe the given actor from receiving updated information each step. + """ traci.vehicle.unsubscribe(actor_id) def get_net_offset(self): + """ + Accessor for sumo net offset. + """ offset = traci.simulation.convertGeo(0, 0) return (-offset[0], -offset[1]) def get_step_length(self): + """ + Accessor for sumo simulation step length. + """ return traci.simulation.getDeltaT() def get_actor(self, actor_id): + """ + Accessor for sumo actor. + """ results = traci.vehicle.getSubscriptionResults(actor_id) type_id = results[traci.constants.VAR_TYPE] @@ -169,39 +204,57 @@ class SumoSimulation(object): return SumoActor(type_id, vclass, transform, signals, extent, color) - def spawn_actor(self, type_id, attrs={}): - """Spawns a new actor based on given type. + def spawn_actor(self, type_id, attrs=None): + """ + Spawns a new actor. + + :param type_id: vtype to be spawned. + :param attrs: dictionary with additional attributes for this specific actor. + :return: actor id if the actor is successfully spawned. Otherwise, INVALID_ACTOR_ID. """ actor_id = 'carla' + str(self._sequential_id) try: traci.vehicle.add(actor_id, 'carla_route', typeID=type_id) - except Exception as error: - logging.error('Spawn sumo actor failed: {}'.format(error)) + except traci.exceptions.TraCIException as error: + logging.error('Spawn sumo actor failed: %s', error) return INVALID_ACTOR_ID - if 'color' in attrs: - color = attrs['color'].split(',') - traci.vehicle.setColor(actor_id, color) + if attrs is not None: + if 'color' in attrs: + color = attrs['color'].split(',') + traci.vehicle.setColor(actor_id, color) self._sequential_id += 1 return actor_id def destroy_actor(self, actor_id): + """ + Destroys the given actor. + """ traci.vehicle.remove(actor_id) def synchronize_vehicle(self, vehicle_id, transform, signals=None): - x, y = transform.location.x, transform.location.y + """ + Updates vehicle state. + + :param vehicle_id: id of the actor to be updated. + :param transform: new vehicle transform (i.e., position and rotation). + :param signals: new vehicle signals. + :return: True if successfully updated. Otherwise, False. + """ + loc_x, loc_y = transform.location.x, transform.location.y yaw = transform.rotation.yaw - traci.vehicle.moveToXY(vehicle_id, "", 0, x, y, angle=yaw, keepRoute=2) + traci.vehicle.moveToXY(vehicle_id, "", 0, loc_x, loc_y, angle=yaw, keepRoute=2) if signals is not None and self.args.sync_vehicle_lights: traci.vehicle.setSignals(vehicle_id, signals) - - def synchronize_walker(self, walker_id, transform): - pass + return True def tick(self): + """ + Tick to sumo simulation. + """ traci.simulationStep() # Update data structures for the current frame. @@ -209,4 +262,7 @@ class SumoSimulation(object): self.destroyed_actors = set(traci.simulation.getArrivedIDList()) def close(self): - traci.close() \ No newline at end of file + """ + Closes traci client. + """ + traci.close() diff --git a/Co-Simulation/Sumo/util/create_sumo_vtypes.py b/Co-Simulation/Sumo/util/create_sumo_vtypes.py index d1ab6dea6..87e304325 100644 --- a/Co-Simulation/Sumo/util/create_sumo_vtypes.py +++ b/Co-Simulation/Sumo/util/create_sumo_vtypes.py @@ -10,37 +10,38 @@ Script to create sumo vtypes based on carla blueprints. """ -# ============================================================================== -# -- find carla module --------------------------------------------------------- -# ============================================================================== - -import glob -import os -import sys - -try: - sys.path.append(glob.glob('../../../PythonAPI/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 - -# ============================================================================== -# -- imports ------------------------------------------------------------------- -# ============================================================================== - -import carla +# ================================================================================================== +# -- imports --------------------------------------------------------------------------------------- +# ================================================================================================== import argparse +import glob import datetime import json import logging -import lxml.etree as ET +import os +import sys -# ============================================================================== -# -- load specs definition ----------------------------------------------------- -# ============================================================================== +import lxml.etree as ET # pylint: disable=import-error + +# ================================================================================================== +# -- find carla module ----------------------------------------------------------------------------- +# ================================================================================================== + +try: + sys.path.append( + glob.glob('../../../PythonAPI/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 # pylint: disable=import-error, wrong-import-position + + +# ================================================================================================== +# -- load specs definition ------------------------------------------------------------------------- +# ================================================================================================== with open('../data/vtypes.json') as f: SPECS = json.load(f) @@ -49,19 +50,20 @@ with open('../data/vtypes.json') as f: DEFAULT_WHEELED_VEHICLE = SPECS['DEFAULT_WHEELED_VEHICLE'] CARLA_BLUEPRINTS_SPECS = SPECS['carla_blueprints'] -# ============================================================================== -# -- main ---------------------------------------------------------------------- -# ============================================================================== +# ================================================================================================== +# -- main ------------------------------------------------------------------------------------------ +# ================================================================================================== + def write_vtype_xml(filename, vtypes): + """ + Write route xml file. + """ root = ET.Element('routes') - root.addprevious(ET.Comment( - 'generated on {date:%Y-%m-%d %H:%M:%S} by {script:}'.format( - date=datetime.datetime.now(), - script=os.path.basename(__file__)) - ) - ) + root.addprevious( + ET.Comment('generated on {date:%Y-%m-%d %H:%M:%S} by {script:}'.format( + date=datetime.datetime.now(), script=os.path.basename(__file__)))) for vtype in vtypes: ET.SubElement(root, 'vType', vtype) @@ -69,6 +71,7 @@ def write_vtype_xml(filename, vtypes): tree = ET.ElementTree(root) tree.write(filename, pretty_print=True, encoding='UTF-8', xml_declaration=True) + def generate_vtype(vehicle): """Generates sumo vtype specification for a given carla vehicle. @@ -80,23 +83,21 @@ def generate_vtype(vehicle): if type_id not in CARLA_BLUEPRINTS_SPECS: number_of_wheels = int(vehicle.attributes['number_of_wheels']) if number_of_wheels == 2: - logging.warning('type id {id:} not mapped to any sumo vtype. Using default specification for two-wheeled vehicles: {specs:}'.format( - id=type_id, - specs=DEFAULT_2_WHEELED_VEHICLE) - ) + logging.warning( + '''type id %s not mapped to any sumo vtype. + \tUsing default specification for two-wheeled vehicles: %s''', type_id, + DEFAULT_2_WHEELED_VEHICLE) user_specs = DEFAULT_2_WHEELED_VEHICLE else: - logging.warning('type id {id:} not mapped to any sumo vtype. Using default specification for wheeled vehicles: {specs:}'.format( - id=type_id, - specs=DEFAULT_WHEELED_VEHICLE) - ) + logging.warning( + '''type id %s not mapped to any sumo vtype. + \tUsing default specification for wheeled vehicles: %s''', type_id, + DEFAULT_WHEELED_VEHICLE) user_specs = DEFAULT_WHEELED_VEHICLE else: - logging.info('type id {id:} mapped to the following specifications: {specs:}'.format( - id=type_id, - specs=CARLA_BLUEPRINTS_SPECS[type_id]) - ) + logging.info('type id %s mapped to the following specifications: %s', type_id, + CARLA_BLUEPRINTS_SPECS[type_id]) user_specs = CARLA_BLUEPRINTS_SPECS[type_id] specs = { @@ -109,27 +110,32 @@ def generate_vtype(vehicle): specs.update(user_specs) return specs + def main(args): + """ + Main method. + """ client = carla.Client(args.carla_host, args.carla_port) client.set_timeout(2.0) try: world = client.get_world() vehicle_blueprints = world.get_blueprint_library().filter('vehicle.*') - #walker_blueprints = world.get_blueprint_library().filter('walker.pedestrian.*') + #walker_blueprints = world.get_blueprint_library().filter('walker.pedestrian.*') transform = world.get_map().get_spawn_points()[0] vtypes = [] for blueprint in vehicle_blueprints: - logging.info('processing vtype for {}'.format(blueprint.id)) + logging.info('processing vtype for %s', blueprint.id) vehicle = world.spawn_actor(blueprint, transform) vtype = generate_vtype(vehicle) if vtype: vtypes.append(vtype) else: - logging.error('type id {id:} could no be mapped to any vtype'.format(id=vehicle.type_id)) + logging.error( + 'type id %s could no be mapped to any vtype', vehicle.type_id) vehicle.destroy() @@ -138,37 +144,32 @@ def main(args): finally: logging.info('done') + if __name__ == '__main__': # Define arguments that will be received and parsed. - argparser = argparse.ArgumentParser( - description=__doc__) + argparser = argparse.ArgumentParser(description=__doc__) + argparser.add_argument('--carla-host', + metavar='H', + default='127.0.0.1', + help='IP of the host server (default: 127.0.0.1)') + argparser.add_argument('--carla-port', + metavar='P', + default=2000, + type=int, + help='TCP port to listen to (default: 2000)') argparser.add_argument( - '--carla-host', - metavar='H', - default='127.0.0.1', - help='IP of the host server (default: 127.0.0.1)') - argparser.add_argument( - '--carla-port', - metavar='P', - default=2000, - type=int, - help='TCP port to listen to (default: 2000)') - argparser.add_argument( - '--output-file', '-o', + '--output-file', + '-o', metavar='FILE', default='carlavtypes.rou.xml', type=str, help='the generated vtypes will be written to FILE (default: carlavtypes.rou.xml)') - argparser.add_argument( - '--verbose', '-v', - action='store_true', - help='increase output verbosity' - ) - args = argparser.parse_args() + argparser.add_argument('--verbose', '-v', action='store_true', help='increase output verbosity') + arguments = argparser.parse_args() - if args.verbose: + if arguments.verbose: logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO) else: logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.WARNING) - main(args) \ No newline at end of file + main(arguments) diff --git a/Co-Simulation/Sumo/util/sequential_types.py b/Co-Simulation/Sumo/util/sequential_types.py index 62be15882..ef7c8864a 100644 --- a/Co-Simulation/Sumo/util/sequential_types.py +++ b/Co-Simulation/Sumo/util/sequential_types.py @@ -10,29 +10,33 @@ Script to modify automatically vtypes to carla type ids in sumo route files. """ -# ============================================================================== -# -- imports ------------------------------------------------------------------- -# ============================================================================== +# ================================================================================================== +# -- imports --------------------------------------------------------------------------------------- +# ================================================================================================== import argparse import fnmatch import json import logging -import lxml.etree as ET import random -# ============================================================================== -# -- load vtypes --------------------------------------------------------------- -# ============================================================================== +import lxml.etree as ET # pylint: disable=import-error -with open('../data/vtypes.json') as f: +# ================================================================================================== +# -- load vtypes ----------------------------------------------------------------------------------- +# ================================================================================================== + +with open('../data/vtypes.json') as f: VTYPES = json.load(f)['carla_blueprints'].keys() -# ============================================================================== -# -- main ---------------------------------------------------------------------- -# ============================================================================== +# ================================================================================================== +# -- main ------------------------------------------------------------------------------------------ +# ================================================================================================== def main(route_files, vtypes, _random=False): + """ + Main method to automatically modify vtypes to carla type ids in sumo route files. + """ for filename in route_files: tree = ET.parse(filename) root = tree.getroot() @@ -46,47 +50,34 @@ def main(route_files, vtypes, _random=False): new_type = random.choice(vtypes) else: new_type = vtypes[index] - index = (index + 1) if index < (len(vtypes) - 1) else 0 - + index = (index + 1) if index < (len(vtypes) - 1) else 0 + vtype.set('type', new_type) counter += 1 tree = ET.ElementTree(root) tree.write(filename, pretty_print=True, encoding='UTF-8', xml_declaration=True) - logging.info('modified {counter:} vtype(s) in {file:}'.format( - counter=counter, - file=filename - )) + logging.info('modified %d vtype(s) in %s', counter, filename) + if __name__ == '__main__': # Define arguments that will be received and parsed. - argparser = argparse.ArgumentParser( - description=__doc__ - ) - argparser.add_argument( - '--route-files', '-r', - metavar='FILES', - nargs='+', - default=[], - help='sumo route files' - ) - argparser.add_argument( - '--random', - action='store_true', - help='apply vtypes randomly or sequentially' - ) - argparser.add_argument( - '--filterv', - metavar='PATTERN', - default='vehicle.*', - help='vehicles filter (default: "vehicle.*")' - ) - argparser.add_argument( - '--verbose', '-v', - action='store_true', - help='increase output verbosity' - ) + argparser = argparse.ArgumentParser(description=__doc__) + argparser.add_argument('--route-files', + '-r', + metavar='FILES', + nargs='+', + default=[], + help='sumo route files') + argparser.add_argument('--random', + action='store_true', + help='apply vtypes randomly or sequentially') + argparser.add_argument('--filterv', + metavar='PATTERN', + default='vehicle.*', + help='vehicles filter (default: "vehicle.*")') + argparser.add_argument('--verbose', '-v', action='store_true', help='increase output verbosity') args = argparser.parse_args() if args.verbose: @@ -94,5 +85,5 @@ if __name__ == '__main__': else: logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.WARNING) - vtypes = [vtype for vtype in VTYPES if fnmatch.fnmatch(vtype, args.filterv)] - main(args.route_files, vtypes, args.random) \ No newline at end of file + filtered_vtypes = [vtype for vtype in VTYPES if fnmatch.fnmatch(vtype, args.filterv)] + main(args.route_files, filtered_vtypes, args.random)