sumo net automatically generated

This commit is contained in:
Joel Moriana 2020-04-10 17:50:33 +02:00 committed by bernat
parent 4ec9723df3
commit 02330cd84d
6 changed files with 129 additions and 111 deletions

View File

@ -87,6 +87,12 @@ class SimulationSynchronization(object):
BridgeHelper.blueprint_library = self.carla.world.get_blueprint_library()
BridgeHelper.offset = self.sumo.get_net_offset()
# Configuring carla simulation in sync mode.
settings = self.carla.world.get_settings()
settings.synchronous_mode = True
settings.fixed_delta_seconds = self.carla.step_length
self.carla.world.apply_settings(settings)
def tick(self):
"""
Tick to simulation synchronization
@ -225,8 +231,8 @@ def synchronization_loop(args):
Entry point for sumo-carla co-simulation.
"""
try:
sumo_simulation = SumoSimulation(args.sumo_host, args.sumo_port, args.step_length,
args.sumo_cfg_file, args.sumo_gui)
sumo_simulation = SumoSimulation(args.sumo_cfg_file, args.step_length, args.sumo_host,
args.sumo_port, args.sumo_gui)
carla_simulation = CarlaSimulation(args.carla_host, args.carla_port, args.step_length)
synchronization = SimulationSynchronization(sumo_simulation, carla_simulation,
@ -254,6 +260,7 @@ def synchronization_loop(args):
if __name__ == '__main__':
argparser = argparse.ArgumentParser(description=__doc__)
argparser.add_argument('sumo_cfg_file', type=str, help='sumo configuration file')
argparser.add_argument('--carla-host',
metavar='H',
default='127.0.0.1',
@ -272,14 +279,7 @@ if __name__ == '__main__':
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',
action='store_true',
help='run the gui version of sumo')
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,

View File

@ -12,13 +12,13 @@
# ==================================================================================================
import argparse
import datetime
import json
import logging
import time
import random
import re
import shutil
import tempfile
import time
import lxml.etree as ET # pylint: disable=wrong-import-position
@ -59,16 +59,17 @@ from sumo_integration.sumo_simulation import SumoSimulation # pylint: disable=w
from run_synchronization import SimulationSynchronization # pylint: disable=wrong-import-position
from util.netconvert_carla import netconvert_carla
# ==================================================================================================
# -- main ------------------------------------------------------------------------------------------
# ==================================================================================================
def write_sumocfg_xml(town_name, tmp_path, net_file, vtypes_file, viewsettings_file):
def write_sumocfg_xml(cfg_file, net_file, vtypes_file, viewsettings_file):
"""
Writes sumo configuration xml file.
"""
root = ET.Element('configuration')
input_tag = ET.SubElement(root, 'input')
@ -79,58 +80,51 @@ def write_sumocfg_xml(town_name, tmp_path, net_file, vtypes_file, viewsettings_f
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
tree.write(cfg_file, pretty_print=True, encoding='UTF-8', xml_declaration=True)
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)
# Temporal folder to save intermediate files.
tmpdir = tempfile.mkdtemp()
# ----------------
# carla simulation
# ----------------
carla_simulation = CarlaSimulation(args.host, args.port, args.step_length)
world = carla_simulation.client.get_world()
current_map = carla_simulation.client.get_world().get_map()
xodr_file = os.path.join(tmpdir, current_map.name + '.xodr')
current_map.save_to_disk(xodr_file)
# ---------------
# sumo simulation
# ---------------
net_file = os.path.join(tmpdir, current_map.name + '.net.xml')
netconvert_carla(xodr_file, net_file, guess_tls=True)
basedir = os.path.dirname(os.path.realpath(__file__))
cfg_file = os.path.join(tmpdir, current_map.name + '.sumocfg')
vtypes_file = os.path.join(basedir, 'examples', 'carlavtypes.rou.xml')
viewsettings_file = os.path.join(basedir, 'examples', 'viewsettings.xml')
write_sumocfg_xml(cfg_file, net_file, vtypes_file, viewsettings_file)
sumo_net = sumolib.net.readNet(net_file)
sumo_simulation = SumoSimulation(cfg_file,
args.step_length,
host=None,
port=None,
sumo_gui=args.sumo_gui)
# ---------------
# synchronization
# ---------------
synchronization = SimulationSynchronization(sumo_simulation, carla_simulation, args.tls_manager,
args.sync_vehicle_color, args.sync_vehicle_lights)
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
# ----------
@ -183,10 +177,12 @@ def main(args):
if index == (len(route) - 1):
current_edge = sumo_net.getEdge(route[index])
next_edge = random.choice(list(current_edge.getAllowedOutgoing(vclass).keys()))
available_edges = list(current_edge.getAllowedOutgoing(vclass).keys())
if available_edges:
next_edge = random.choice(available_edges)
new_route = [current_edge.getID(), next_edge.getID()]
traci.vehicle.setRoute(vehicle_id, new_route)
new_route = [current_edge.getID(), next_edge.getID()]
traci.vehicle.setRoute(vehicle_id, new_route)
end = time.time()
elapsed = end - start
@ -197,10 +193,9 @@ def main(args):
logging.info('Cancelled by user.')
finally:
if os.path.exists(tmp_path):
shutil.rmtree(tmp_path)
if os.path.exists(tmpdir):
shutil.rmtree(tmpdir)
logging.info('Destroying %d sumo vehicles.', traci.vehicle.getIDCount())
synchronization.close()
@ -239,9 +234,7 @@ if __name__ == '__main__':
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('--sumo-gui', action='store_true', help='run the gui version of sumo')
argparser.add_argument('--step-length',
default=0.05,
type=float,
@ -272,4 +265,4 @@ if __name__ == '__main__':
else:
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
main(args)
main(args)

View File

@ -32,12 +32,7 @@ class CarlaSimulation(object):
self.world = self.client.get_world()
self.blueprint_library = self.world.get_blueprint_library()
# Configuring carla simulation in sync mode.
settings = self.world.get_settings()
settings.synchronous_mode = True
settings.fixed_delta_seconds = step_length
self.world.apply_settings(settings)
self.step_length = step_length
# The following sets contain updated information for the current frame.
self._active_actors = set()

View File

@ -14,6 +14,7 @@
import collections
import enum
import logging
import os
import carla # pylint: disable=import-error
import sumolib # pylint: disable=import-error
@ -21,6 +22,8 @@ import traci # pylint: disable=import-error
from .constants import INVALID_ACTOR_ID
import lxml.etree as ET # pylint: disable=import-error
# ==================================================================================================
# -- sumo definitions ------------------------------------------------------------------------------
# ==================================================================================================
@ -99,7 +102,7 @@ class SumoActorClass(enum.Enum):
SumoActor = collections.namedtuple('SumoActor', 'type_id vclass transform signals extent color')
# ==================================================================================================
# -- sumo simulation -------------------------------------------------------------------------------
# -- sumo traffic lights ---------------------------------------------------------------------------
# ==================================================================================================
@ -277,11 +280,35 @@ class SumoTLManager(object):
self._current_phase[tl_id] = current_phase
# ==================================================================================================
# -- sumo simulation -------------------------------------------------------------------------------
# ==================================================================================================
def _get_sumo_net(cfg_file):
"""
Returns sumo net.
This method reads the sumo configuration file and retrieve the sumo net filename to create the
net.
"""
cfg_file = os.path.join(os.getcwd(), cfg_file)
tree = ET.parse(cfg_file)
tag = tree.find('//net-file')
if tag is None:
return None
net_file = os.path.join(os.path.dirname(cfg_file), tag.get('value'))
logging.debug('Reading net file: %s', net_file)
sumo_net = traci.sumolib.net.readNet(net_file)
return sumo_net
class SumoSimulation(object):
"""
SumoSimulation is responsible for the management of the sumo simulation.
"""
def __init__(self, host, port, step_length, cfg_file, sumo_gui=False):
def __init__(self, cfg_file, step_length, host=None, port=None, sumo_gui=False):
if sumo_gui is True:
sumo_binary = sumolib.checkBinary('sumo-gui')
else:
@ -303,6 +330,9 @@ class SumoSimulation(object):
logging.info('Connection to sumo server. Host: %s Port: %s', host, port)
traci.init(host=host, port=port)
# Retrieving net from configuration file.
self.net = _get_sumo_net(cfg_file)
# Creating a random route to be able to spawn carla actors.
traci.route.add("carla_route", [traci.edge.getIDList()[0]])
@ -349,20 +379,11 @@ class SumoSimulation(object):
"""
traci.vehicle.unsubscribe(actor_id)
@staticmethod
def get_net_offset():
def get_net_offset(self):
"""
Accessor for sumo net offset.
"""
offset = traci.simulation.convertGeo(0, 0)
return (-offset[0], -offset[1])
@staticmethod
def get_step_length():
"""
Accessor for sumo simulation step length.
"""
return traci.simulation.getDeltaT()
return self.net.getLocationOffset()
@staticmethod
def get_actor(actor_id):

View File

View File

@ -17,10 +17,10 @@ the net and inserts, manually, the traffic light landmarks retrieved from the op
import argparse
import bisect
import collections
import datetime
import logging
import shutil
import subprocess
import tempfile
import lxml.etree as ET # pylint: disable=import-error
@ -362,29 +362,30 @@ class SumoTrafficLight(object):
# ==================================================================================================
def netconvert_carla(args, tmp_path):
def _netconvert_carla_impl(xodr_file, output, tmpdir, guess_tls=False):
"""
Generates sumo net.
Implements netconvert carla.
"""
# ----------
# netconvert
# ----------
tmp_file = os.path.splitext(os.path.basename(args.xodr_file))[0]
tmp_sumo_net = os.path.join(tmp_path, tmp_file + '.net.xml')
basename = os.path.splitext(os.path.basename(xodr_file))[0]
tmp_sumo_net = os.path.join(tmpdir, basename + '.net.xml')
try:
basedir = os.path.dirname(os.path.realpath(__file__))
result = subprocess.call(['netconvert',
'--opendrive', args.xodr_file,
'--opendrive', xodr_file,
'--output-file', tmp_sumo_net,
'--geometry.min-radius.fix',
'--geometry.remove',
'--opendrive.curve-resolution', '1',
'--opendrive.import-all-lanes',
'--type-files', 'data/opendrive_netconvert.typ.xml',
'--type-files', os.path.join(basedir, 'data/opendrive_netconvert.typ.xml'),
# Necessary to link odr and sumo ids.
'--output.original-names',
# Discard loading traffic lights as them will be inserted manually afterwards.
'--tls.discard-loaded', 'true'
'--tls.discard-loaded', 'true',
])
except subprocess.CalledProcessError:
raise RuntimeError('There was an error when executing netconvert.')
@ -401,7 +402,7 @@ def netconvert_carla(args, tmp_path):
# ---------
# Carla map
# ---------
with open(args.xodr_file, 'r') as f:
with open(xodr_file, 'r') as f:
carla_map = carla.Map('netconvert', str(f.read()))
# ---------
@ -437,7 +438,7 @@ def netconvert_carla(args, tmp_path):
tls[tlid] = SumoTrafficLight(tlid)
tl = tls[tlid]
if args.guess_tls:
if guess_tls:
for from_edge, from_lane in sumo_topology.get_incoming(road_id, lane_id):
successors = sumo_topology.get_successors(from_edge, from_lane)
for to_edge, to_lane in successors:
@ -503,25 +504,33 @@ def netconvert_carla(args, tmp_path):
connection.from_road, connection.to_road, connection.from_lane,
connection.to_lane))
tree.write(args.output, pretty_print=True, encoding='UTF-8', xml_declaration=True)
tree.write(output, pretty_print=True, encoding='UTF-8', xml_declaration=True)
def netconvert_carla(xodr_file, output, guess_tls=False):
"""
Generates sumo net.
:param xodr_file: opendrive file (*.xodr)
:param output: output file (*.net.xml)
:param guess_tls: guess traffic lights at intersections.
:returns: path to the generated sumo net.
"""
try:
tmpdir = tempfile.mkdtemp()
_netconvert_carla_impl(xodr_file, output, tmpdir, guess_tls)
finally:
if os.path.exists(tmpdir):
shutil.rmtree(tmpdir)
if __name__ == '__main__':
argparser = argparse.ArgumentParser(description=__doc__)
argparser.add_argument('xodr_file', help='open drive file (*.xodr')
argparser.add_argument('xodr_file', help='opendrive file (*.xodr')
argparser.add_argument('--output', '-o', type=str, help='output file (*.net.xml)')
argparser.add_argument('--guess-tls',
action='store_true',
help='guess traffic lights at intersections (default: False)')
args = argparser.parse_args()
try:
tmp_path = 'tmp-{date:%Y-%m-%d_%H-%M-%S-%f}'.format(date=datetime.datetime.now())
if not os.path.exists(tmp_path):
os.mkdir(tmp_path)
netconvert_carla(args, tmp_path)
finally:
if os.path.exists(tmp_path):
shutil.rmtree(tmp_path)
netconvert_carla(args.xodr_file, args.output, args.guess_tls)