first iteration spawn_npc_sumo

This commit is contained in:
Joel Moriana 2020-04-09 18:45:34 +02:00 committed by bernat
parent 0f92f9e71c
commit 28bc7f9b47
4 changed files with 325 additions and 42 deletions

View File

@ -61,15 +61,23 @@ class SimulationSynchronization(object):
SimulationSynchronization class is responsible for the synchronization of sumo and carla
simulations.
"""
def __init__(self, args):
self.args = args
def __init__(self,
sumo_simulation,
carla_simulation,
tls_manager='none',
sync_vehicle_color=False,
sync_vehicle_lights=False):
self.sumo = SumoSimulation(args)
self.carla = CarlaSimulation(args)
self.sumo = sumo_simulation
self.carla = carla_simulation
if args.tls_manager == 'carla':
self.tls_manager = tls_manager
self.sync_vehicle_color = sync_vehicle_color
self.sync_vehicle_lights = sync_vehicle_lights
if tls_manager == 'carla':
self.sumo.switch_off_traffic_lights()
elif args.tls_manager == 'sumo':
elif tls_manager == 'sumo':
self.carla.switch_off_traffic_lights()
# Mapped actor ids.
@ -94,8 +102,7 @@ class SimulationSynchronization(object):
self.sumo.subscribe(sumo_actor_id)
sumo_actor = self.sumo.get_actor(sumo_actor_id)
carla_blueprint = BridgeHelper.get_carla_blueprint(sumo_actor,
self.args.sync_vehicle_color)
carla_blueprint = BridgeHelper.get_carla_blueprint(sumo_actor, self.sync_vehicle_color)
if carla_blueprint is not None:
carla_transform = BridgeHelper.get_carla_transform(sumo_actor.transform,
sumo_actor.extent)
@ -120,7 +127,7 @@ class SimulationSynchronization(object):
carla_transform = BridgeHelper.get_carla_transform(sumo_actor.transform,
sumo_actor.extent)
if self.args.sync_vehicle_lights:
if self.sync_vehicle_lights:
carla_lights = BridgeHelper.get_carla_lights_state(carla_actor.get_light_state(),
sumo_actor.signals)
else:
@ -129,7 +136,7 @@ class SimulationSynchronization(object):
self.carla.synchronize_vehicle(carla_actor_id, carla_transform, carla_lights)
# Updates traffic lights in carla based on sumo information.
if self.args.tls_manager == 'sumo':
if self.tls_manager == 'sumo':
common_landmarks = self.sumo.traffic_light_ids & self.carla.traffic_light_ids
for landmark_id in common_landmarks:
sumo_tl_state = self.sumo.get_traffic_light_state(landmark_id)
@ -148,8 +155,9 @@ class SimulationSynchronization(object):
carla_actor = self.carla.get_actor(carla_actor_id)
type_id = BridgeHelper.get_sumo_vtype(carla_actor)
color = carla_actor.attributes.get('color', None) if self.sync_vehicle_color else None
if type_id is not None:
sumo_actor_id = self.sumo.spawn_actor(type_id, carla_actor.attributes)
sumo_actor_id = self.sumo.spawn_actor(type_id, color)
if sumo_actor_id != INVALID_ACTOR_ID:
self.carla2sumo_ids[carla_actor_id] = sumo_actor_id
self.sumo.subscribe(sumo_actor_id)
@ -168,7 +176,7 @@ class SimulationSynchronization(object):
sumo_transform = BridgeHelper.get_sumo_transform(carla_actor.get_transform(),
carla_actor.bounding_box.extent)
if self.args.sync_vehicle_lights:
if self.sync_vehicle_lights:
carla_lights = self.carla.get_actor_light_state(carla_actor_id)
if carla_lights is not None:
sumo_lights = BridgeHelper.get_sumo_lights_state(sumo_actor.signals,
@ -181,7 +189,7 @@ class SimulationSynchronization(object):
self.sumo.synchronize_vehicle(sumo_actor_id, sumo_transform, sumo_lights)
# Updates traffic lights in sumo based on carla information.
if self.args.tls_manager == 'carla':
if self.tls_manager == 'carla':
common_landmarks = self.sumo.traffic_light_ids & self.carla.traffic_light_ids
for landmark_id in common_landmarks:
carla_tl_state = self.carla.get_traffic_light_state(landmark_id)
@ -192,7 +200,7 @@ class SimulationSynchronization(object):
def close(self):
"""
Cleans up synchronization.
Cleans synchronization.
"""
# Configuring carla simulation in async mode.
settings = self.carla.world.get_settings()
@ -216,8 +224,15 @@ def synchronization_loop(args):
"""
Entry point for sumo-carla co-simulation.
"""
synchronization = SimulationSynchronization(args)
try:
sumo_simulation = SumoSimulation(args.sumo_host, args.sumo_port, args.step_length,
args.sumo_cfg_file, args.sumo_gui)
carla_simulation = CarlaSimulation(args.carla_host, args.carla_port, args.step_length)
synchronization = SimulationSynchronization(sumo_simulation, carla_simulation,
args.tls_manager, args.sync_vehicle_color,
args.sync_vehicle_lights)
while True:
start = time.time()
@ -232,7 +247,7 @@ def synchronization_loop(args):
logging.info('Cancelled by user.')
finally:
logging.info('Cleaning up synchronization')
logging.info('Cleaning synchronization')
synchronization.close()
@ -263,8 +278,8 @@ if __name__ == '__main__':
type=str,
help='sumo configuration file')
argparser.add_argument('--sumo-gui',
default=True,
help='run the gui version of sumo (default: True)')
action='store_true',
help='run the gui version of sumo')
argparser.add_argument('--step-length',
default=0.05,
type=float,

View File

@ -0,0 +1,277 @@
#!/usr/bin/env python
# Copyright (c) 2019 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>.
"""Spawn Sumo NPCs vehicles into the simulation"""
# ==================================================================================================
# -- imports ---------------------------------------------------------------------------------------
# ==================================================================================================
import argparse
import datetime
import json
import logging
import time
import random
import re
import shutil
import lxml.etree as ET # pylint: disable=wrong-import-position
# ==================================================================================================
# -- 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
# ==================================================================================================
# -- find traci module -----------------------------------------------------------------------------
# ==================================================================================================
if 'SUMO_HOME' in os.environ:
sys.path.append(os.path.join(os.environ['SUMO_HOME'], 'tools'))
else:
sys.exit("please declare environment variable 'SUMO_HOME'")
# ==================================================================================================
# -- carla -----------------------------------------------------------------------------------------
# ==================================================================================================
import carla # pylint: disable=wrong-import-position
import sumolib # pylint: disable=wrong-import-position
import traci # pylint: disable=wrong-import-position
from sumo_integration.carla_simulation import CarlaSimulation # pylint: disable=wrong-import-position
from sumo_integration.sumo_simulation import SumoSimulation # pylint: disable=wrong-import-position
from run_synchronization import SimulationSynchronization # pylint: disable=wrong-import-position
# ==================================================================================================
# -- main ------------------------------------------------------------------------------------------
# ==================================================================================================
def write_sumocfg_xml(town_name, tmp_path, net_file, vtypes_file, viewsettings_file):
"""
Writes sumo configuration xml file.
"""
root = ET.Element('configuration')
input_tag = ET.SubElement(root, 'input')
ET.SubElement(input_tag, 'net-file', {'value': net_file})
ET.SubElement(input_tag, 'route-files', {'value': vtypes_file})
gui_tag = ET.SubElement(root, 'gui_only')
ET.SubElement(gui_tag, 'gui-settings-file', {'value': viewsettings_file})
tree = ET.ElementTree(root)
filename = os.path.join(tmp_path, town_name + '.sumocfg')
tree.write(filename, pretty_print=True, encoding='UTF-8', xml_declaration=True)
return filename
def get_sumo_files(town_name, tmp_path):
"""
Returns sumo configuration file and sumo net.
"""
base_path = os.path.dirname(os.path.realpath(__file__))
net_file = os.path.join(base_path, 'examples', 'net', town_name + '.net.xml')
vtypes_file = os.path.join(base_path, 'examples', 'carlavtypes.rou.xml')
viewsettings_file = os.path.join(base_path, 'examples', 'viewsettings.xml')
cfg_file = write_sumocfg_xml(town_name, tmp_path, net_file, vtypes_file, viewsettings_file)
return cfg_file, net_file
def main(args):
# Creating temporal folder to save configuration file.
tmp_path = 'spawn_npc_sumo-{date:%Y-%m-%d_%H-%M-%S-%f}'.format(date=datetime.datetime.now())
if not os.path.exists(tmp_path):
os.mkdir(tmp_path)
try:
# ----------------
# carla simulation
# ----------------
carla_simulation = CarlaSimulation(args.host, args.port, args.step_length)
world = carla_simulation.client.get_world()
current_map = world.get_map().name
if current_map not in ('Town01', 'Town04', 'Town05'):
raise RuntimeError('This script does not support {} yet.'.format(current_map))
# ---------------
# sumo simulation
# ---------------
cfg_file, net_file = get_sumo_files(current_map, tmp_path)
sumo_net = sumolib.net.readNet(net_file)
sumo_simulation = SumoSimulation(None, None, args.step_length, cfg_file, args.sumo_gui)
# ---------------
# synchronization
# ---------------
synchronization = SimulationSynchronization(sumo_simulation, carla_simulation,
args.tls_manager, args.sync_vehicle_color,
args.sync_vehicle_lights)
# ----------
# Blueprints
# ----------
with open('data/vtypes.json') as f:
vtypes = json.load(f)['carla_blueprints']
blueprints = vtypes.keys()
filterv = re.compile(args.filterv)
blueprints = list(filter(filterv.search, blueprints))
if args.safe:
blueprints = [
x for x in blueprints if vtypes[x]['vClass'] not in ('motorcycle', 'bicycle')
]
blueprints = [x for x in blueprints if not x.endswith('isetta')]
blueprints = [x for x in blueprints if not x.endswith('carlacola')]
blueprints = [x for x in blueprints if not x.endswith('cybertruck')]
blueprints = [x for x in blueprints if not x.endswith('t2')]
if not blueprints:
raise RuntimeError('No blueprints available due to user restrictions.')
if args.number_of_walkers > 0:
logging.warning('Pedestrians are not supported yet. No walkers will be spawned.')
# --------------
# Spawn vehicles
# --------------
# Spawns sumo NPC vehicles.
sumo_edges = sumo_net.getEdges()
for i in range(args.number_of_vehicles):
edge = random.choice(sumo_edges)
type_id = random.choice(blueprints)
traci.route.add('route_{}'.format(i), [edge.getID()])
result = traci.vehicle.add('sumo_{}'.format(i), 'route_{}'.format(i), typeID=type_id)
while True:
start = time.time()
synchronization.tick()
# Updates vehicle routes
for vehicle_id in traci.vehicle.getIDList():
route = traci.vehicle.getRoute(vehicle_id)
index = traci.vehicle.getRouteIndex(vehicle_id)
vclass = traci.vehicle.getVehicleClass(vehicle_id)
if index == (len(route) - 1):
current_edge = sumo_net.getEdge(route[index])
next_edge = random.choice(list(current_edge.getAllowedOutgoing(vclass).keys()))
new_route = [current_edge.getID(), next_edge.getID()]
traci.vehicle.setRoute(vehicle_id, new_route)
end = time.time()
elapsed = end - start
if elapsed < args.step_length:
time.sleep(args.step_length - elapsed)
except KeyboardInterrupt:
logging.info('Cancelled by user.')
finally:
if os.path.exists(tmp_path):
shutil.rmtree(tmp_path)
logging.info('Destroying %d sumo vehicles.', traci.vehicle.getIDCount())
synchronization.close()
if __name__ == '__main__':
argparser = argparse.ArgumentParser(description=__doc__)
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('-n',
'--number-of-vehicles',
metavar='N',
default=10,
type=int,
help='number of vehicles (default: 10)')
argparser.add_argument('-w',
'--number-of-walkers',
metavar='W',
default=0,
type=int,
help='number of walkers (default: 0)')
argparser.add_argument('--safe',
action='store_true',
help='avoid spawning vehicles prone to accidents')
argparser.add_argument('--filterv',
metavar='PATTERN',
default='vehicle.*',
help='vehicles filter (default: "vehicle.*")')
argparser.add_argument('--filterw',
metavar='PATTERN',
default='walker.pedestrian.*',
help='pedestrians filter (default: "walker.pedestrian.*")')
argparser.add_argument('--sumo-gui',
action='store_true',
help='run the gui version of sumo')
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 (default: False)')
argparser.add_argument('--sync-vehicle-color',
action='store_true',
help='synchronize vehicle color (default: False)')
argparser.add_argument('--sync-vehicle-all',
action='store_true',
help='synchronize all vehicle properties (default: False)')
argparser.add_argument('--tls-manager',
type=str,
choices=['none', 'sumo', 'carla'],
help="select traffic light manager (default: none)",
default='none')
argparser.add_argument('--debug', action='store_true', help='enable debug messages')
args = argparser.parse_args()
if args.sync_vehicle_all is True:
args.sync_vehicle_lights = True
args.sync_vehicle_color = True
if args.debug:
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG)
else:
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
main(args)

View File

@ -26,11 +26,7 @@ class CarlaSimulation(object):
"""
CarlaSimulation is responsible for the management of the carla simulation.
"""
def __init__(self, args):
self.args = args
host = args.carla_host
port = args.carla_port
def __init__(self, host, port, step_length):
self.client = carla.Client(host, port)
self.client.set_timeout(2.0)
@ -40,7 +36,7 @@ class CarlaSimulation(object):
# Configuring carla simulation in sync mode.
settings = self.world.get_settings()
settings.synchronous_mode = True
settings.fixed_delta_seconds = args.step_length
settings.fixed_delta_seconds = step_length
self.world.apply_settings(settings)
# The following sets contain updated information for the current frame.
@ -151,7 +147,7 @@ class CarlaSimulation(object):
return False
vehicle.set_transform(transform)
if lights is not None and self.args.sync_vehicle_lights:
if lights is not None:
vehicle.set_light_state(carla.VehicleLightState(lights))
return True

View File

@ -281,24 +281,20 @@ class SumoSimulation(object):
"""
SumoSimulation is responsible for the management of the sumo simulation.
"""
def __init__(self, args):
self.args = args
host = args.sumo_host
port = args.sumo_port
if args.sumo_gui is True:
def __init__(self, host, port, step_length, cfg_file, sumo_gui=False):
if sumo_gui is True:
sumo_binary = sumolib.checkBinary('sumo-gui')
else:
sumo_binary = sumolib.checkBinary('sumo')
if args.sumo_host is None or args.sumo_port is None:
if host is None or port is None:
logging.info('Starting new sumo server...')
if args.sumo_gui is True:
if sumo_gui is True:
logging.info('Remember to press the play button to start the simulation')
traci.start([sumo_binary,
'--configuration-file', args.sumo_cfg_file,
'--step-length', str(args.step_length),
'--configuration-file', cfg_file,
'--step-length', str(step_length),
'--lateral-resolution', '0.25',
'--collision.check-junctions'
])
@ -393,12 +389,12 @@ class SumoSimulation(object):
return SumoActor(type_id, vclass, transform, signals, extent, color)
def spawn_actor(self, type_id, attrs=None):
def spawn_actor(self, type_id, color=None):
"""
Spawns a new actor.
:param type_id: vtype to be spawned.
:param attrs: dictionary with additional attributes for this specific actor.
:param color: color attribute for this specific actor.
:return: actor id if the actor is successfully spawned. Otherwise, INVALID_ACTOR_ID.
"""
actor_id = 'carla' + str(self._sequential_id)
@ -408,10 +404,9 @@ class SumoSimulation(object):
logging.error('Spawn sumo actor failed: %s', error)
return INVALID_ACTOR_ID
if attrs is not None:
if self.args.sync_vehicle_color and 'color' in attrs:
color = attrs['color'].split(',')
traci.vehicle.setColor(actor_id, color)
if color is not None:
color = color.split(',')
traci.vehicle.setColor(actor_id, color)
self._sequential_id += 1
@ -451,7 +446,7 @@ class SumoSimulation(object):
yaw = transform.rotation.yaw
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:
if signals is not None:
traci.vehicle.setSignals(vehicle_id, signals)
return True