diff --git a/Co-Simulation/Sumo/data/vtypes.json b/Co-Simulation/Sumo/data/vtypes.json
new file mode 100644
index 000000000..750c74245
--- /dev/null
+++ b/Co-Simulation/Sumo/data/vtypes.json
@@ -0,0 +1,94 @@
+{
+ "DEFAULT_2_WHEELED_VEHICLE": {
+ "vClass": "motorcycle"
+ },
+ "DEFAULT_WHEELED_VEHICLE": {
+ "vClass": "passenger"
+ },
+ "carla_blueprints": {
+ "vehicle.audi.a2": {
+ "vClass": "passenger"
+ },
+ "vehicle.audi.tt": {
+ "vClass": "passenger"
+ },
+ "vehicle.bmw.grandtourer": {
+ "vClass": "passenger"
+ },
+ "vehicle.chevrolet.impala": {
+ "vClass": "passenger"
+ },
+ "vehicle.citroen.c3": {
+ "vClass": "passenger"
+ },
+ "vehicle.jeep.wrangler_rubicon": {
+ "vClass": "passenger"
+ },
+ "vehicle.lincoln.mkz2017": {
+ "vClass": "passenger"
+ },
+ "vehicle.mercedes-benz.coupe": {
+ "vClass": "passenger"
+ },
+ "vehicle.mini.cooperst": {
+ "vClass": "passenger"
+ },
+ "vehicle.mustang.mustang": {
+ "vClass": "passenger"
+ },
+ "vehicle.nissan.micra": {
+ "vClass": "passenger"
+ },
+ "vehicle.nissan.patrol": {
+ "vClass": "passenger"
+ },
+ "vehicle.seat.leon": {
+ "vClass": "passenger"
+ },
+ "vehicle.volkswagen.t2": {
+ "vClass": "passenger",
+ "guiShape": "passenger/van"
+ },
+ "vehicle.dodge_charger.police": {
+ "vClass": "authority",
+ "guiShape": "police"
+ },
+ "vehicle.bmw.isetta": {
+ "vClass": "evehicle"
+ },
+ "vehicle.toyota.prius": {
+ "vClass": "evehicle"
+ },
+ "vehicle.tesla.cybertruck": {
+ "vClass": "evehicle"
+ },
+ "vehicle.tesla.model3": {
+ "vClass": "evehicle"
+ },
+ "vehicle.audi.etron": {
+ "vClass": "evehicle"
+ },
+ "vehicle.carlamotors.carlacola": {
+ "vClass": "truck",
+ "guiShape": "truck"
+ },
+ "vehicle.yamaha.yzf": {
+ "vClass": "motorcycle"
+ },
+ "vehicle.harley-davidson.low_rider": {
+ "vClass": "motorcycle"
+ },
+ "vehicle.kawasaki.ninja": {
+ "vClass": "motorcycle"
+ },
+ "vehicle.gazelle.omafiets": {
+ "vClass": "bicycle"
+ },
+ "vehicle.diamondback.century": {
+ "vClass": "bicycle"
+ },
+ "vehicle.bh.crossbike": {
+ "vClass": "bicycle"
+ }
+ }
+}
\ No newline at end of file
diff --git a/Co-Simulation/Sumo/examples/town01/Town01.net.xml b/Co-Simulation/Sumo/examples/town01/Town01.net.xml
new file mode 100644
index 000000000..976457eb9
--- /dev/null
+++ b/Co-Simulation/Sumo/examples/town01/Town01.net.xml
@@ -0,0 +1,691 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Co-Simulation/Sumo/examples/town01/Town01.rou.alt.xml b/Co-Simulation/Sumo/examples/town01/Town01.rou.alt.xml
new file mode 100644
index 000000000..f51047ca2
--- /dev/null
+++ b/Co-Simulation/Sumo/examples/town01/Town01.rou.alt.xml
@@ -0,0 +1,521 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Co-Simulation/Sumo/examples/town01/Town01.rou.xml b/Co-Simulation/Sumo/examples/town01/Town01.rou.xml
new file mode 100644
index 000000000..1ae701dab
--- /dev/null
+++ b/Co-Simulation/Sumo/examples/town01/Town01.rou.xml
@@ -0,0 +1,318 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Co-Simulation/Sumo/examples/town01/Town01.sumocfg b/Co-Simulation/Sumo/examples/town01/Town01.sumocfg
new file mode 100644
index 000000000..26ad574e9
--- /dev/null
+++ b/Co-Simulation/Sumo/examples/town01/Town01.sumocfg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Co-Simulation/Sumo/examples/town01/Town01.xodr b/Co-Simulation/Sumo/examples/town01/Town01.xodr
new file mode 100644
index 000000000..be7adb0e0
--- /dev/null
+++ b/Co-Simulation/Sumo/examples/town01/Town01.xodr
@@ -0,0 +1,7778 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Co-Simulation/Sumo/examples/town01/carlavtypes.rou.xml b/Co-Simulation/Sumo/examples/town01/carlavtypes.rou.xml
new file mode 100644
index 000000000..10c794bcd
--- /dev/null
+++ b/Co-Simulation/Sumo/examples/town01/carlavtypes.rou.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Co-Simulation/Sumo/examples/town01/netconvert_options.sumo b/Co-Simulation/Sumo/examples/town01/netconvert_options.sumo
new file mode 100644
index 000000000..4e8835cd3
--- /dev/null
+++ b/Co-Simulation/Sumo/examples/town01/netconvert_options.sumo
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Co-Simulation/Sumo/examples/town01/trips.trips.xml b/Co-Simulation/Sumo/examples/town01/trips.trips.xml
new file mode 100644
index 000000000..655cb5fcb
--- /dev/null
+++ b/Co-Simulation/Sumo/examples/town01/trips.trips.xml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Co-Simulation/Sumo/examples/town01/viewsettings.xml b/Co-Simulation/Sumo/examples/town01/viewsettings.xml
new file mode 100644
index 000000000..da9dfe672
--- /dev/null
+++ b/Co-Simulation/Sumo/examples/town01/viewsettings.xml
@@ -0,0 +1,774 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Co-Simulation/Sumo/requirements.txt b/Co-Simulation/Sumo/requirements.txt
new file mode 100644
index 000000000..ee1cba5c8
--- /dev/null
+++ b/Co-Simulation/Sumo/requirements.txt
@@ -0,0 +1 @@
+lxml==4.5.0
diff --git a/Co-Simulation/Sumo/run_synchronization.py b/Co-Simulation/Sumo/run_synchronization.py
new file mode 100644
index 000000000..66e9fc9fc
--- /dev/null
+++ b/Co-Simulation/Sumo/run_synchronization.py
@@ -0,0 +1,244 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma de
+# Barcelona (UAB).
+#
+# This work is licensed under the terms of the MIT license.
+# For a copy, see .
+
+"""
+Script to integrate CARLA and SUMO simulations
+"""
+
+# ==============================================================================
+# -- 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:
+ tools = os.path.join(os.environ['SUMO_HOME'], 'tools')
+ sys.path.append(tools)
+else:
+ sys.exit("please declare environment variable 'SUMO_HOME'")
+
+# ==============================================================================
+# -- imports -------------------------------------------------------------------
+# ==============================================================================
+
+import argparse
+import logging
+import time
+
+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 --------------------------------------------------------
+# ==============================================================================
+
+def main(args):
+ sumo = SumoSimulation(args)
+ carla = CarlaSimulation(args)
+
+ # Mapped actor ids.
+ 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()
+
+ try:
+ while True:
+ start = time.time()
+
+ # -----------------
+ # sumo-->carla sync
+ # -----------------
+ sumo.tick()
+
+ # Spawning new sumo actors in carla (i.e, not controlled by carla).
+ sumo_spawned_actors = sumo.spawned_actors - set(carla2sumo_ids.values())
+ for sumo_actor_id in sumo_spawned_actors:
+ SumoSimulation.subscribe(sumo_actor_id)
+ sumo_actor = sumo.get_actor(sumo_actor_id)
+
+ 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_actor_id = carla.spawn_actor(carla_blueprint, carla_transform)
+ if carla_actor_id != INVALID_ACTOR_ID:
+ sumo2carla_ids[sumo_actor_id] = carla_actor_id
+ else:
+ SumoSimulation.unsubscribe(sumo_actor_id)
+
+ # Destroying sumo arrived actors in carla.
+ for sumo_actor_id in sumo.destroyed_actors:
+ if sumo_actor_id in sumo2carla_ids:
+ carla.destroy_actor(sumo2carla_ids.pop(sumo_actor_id))
+
+ # Updating sumo actors in carla.
+ for sumo_actor_id in sumo2carla_ids:
+ carla_actor_id = sumo2carla_ids[sumo_actor_id]
+
+ 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)
+ if args.sync_vehicle_lights:
+ carla_lights = BridgeHelper.get_carla_lights_state(carla_actor.get_light_state(), sumo_actor.signals)
+ else:
+ carla_lights = None
+
+ carla.synchronize_vehicle(carla_actor_id, carla_transform, carla_lights)
+
+ # -----------------
+ # carla-->sumo sync
+ # -----------------
+ carla.tick()
+
+ # Spawning new carla actors (not controlled by sumo)
+ carla_spawned_actors = carla.spawned_actors - set(sumo2carla_ids.values())
+ for carla_actor_id in carla_spawned_actors:
+ carla_actor = carla.get_actor(carla_actor_id)
+
+ type_id = BridgeHelper.get_sumo_vtype(carla_actor)
+ if type_id is not None:
+ sumo_actor_id = sumo.spawn_actor(type_id, carla_actor.attributes)
+ if sumo_actor_id != INVALID_ACTOR_ID:
+ carla2sumo_ids[carla_actor_id] = sumo_actor_id
+ sumo.subscribe(sumo_actor_id)
+
+ # Destroying required carla actors in sumo.
+ for carla_actor_id in carla.destroyed_actors:
+ if carla_actor_id in carla2sumo_ids:
+ sumo.destroy_actor(carla2sumo_ids.pop(carla_actor_id))
+
+ # Updating carla actors in sumo.
+ for carla_actor_id in carla2sumo_ids:
+ sumo_actor_id = carla2sumo_ids[carla_actor_id]
+
+ 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)
+ if args.sync_vehicle_lights:
+ carla_lights = carla_actor.get_light_state()
+ sumo_lights = BridgeHelper.get_sumo_lights_state(sumo_actor.signals, carla_lights)
+ else:
+ sumo_lights = None
+
+ sumo.synchronize_vehicle(sumo_actor_id, sumo_transform, sumo_lights)
+
+ end = time.time()
+ elapsed = end - start
+ if elapsed < args.step_length:
+ time.sleep(args.step_length - elapsed)
+
+ except KeyboardInterrupt:
+ logging.info('Cancelled by user.')
+
+ except Exception as error:
+ logging.error('Synchronization failed. {}'.format(error))
+
+ finally:
+ logging.info('Cleaning up synchronization')
+
+ # Configuring carla simulation in async mode.
+ settings = carla.world.get_settings()
+ settings.synchronous_mode = False
+ settings.fixed_delta_seconds = None
+ carla.world.apply_settings(settings)
+
+ # Destroying synchronized actors.
+ for carla_actor_id in sumo2carla_ids.values():
+ carla.destroy_actor(carla_actor_id)
+
+ for sumo_actor_id in carla2sumo_ids.values():
+ sumo.destroy_actor(sumo_actor_id)
+
+ # 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.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()
+
+ 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)
\ No newline at end of file
diff --git a/Co-Simulation/Sumo/sumo_integration/__init__.py b/Co-Simulation/Sumo/sumo_integration/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/Co-Simulation/Sumo/sumo_integration/bridge_helper.py b/Co-Simulation/Sumo/sumo_integration/bridge_helper.py
new file mode 100644
index 000000000..04e66b71c
--- /dev/null
+++ b/Co-Simulation/Sumo/sumo_integration/bridge_helper.py
@@ -0,0 +1,321 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma de
+# Barcelona (UAB).
+#
+# This work is licensed under the terms of the MIT license.
+# For a copy, see .
+
+# ==============================================================================
+# -- imports -------------------------------------------------------------------
+# ==============================================================================
+
+import json
+import logging
+import math
+import random
+
+import carla
+import traci
+
+from .sumo_simulation import SumoVehSignal
+
+# ==============================================================================
+# -- Bridge helper (SUMO <=> CARLA) --------------------------------------------
+# ==============================================================================
+
+
+class BridgeHelper(object):
+
+ _blueprint_library = None
+ _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
+ in_location = in_sumo_transform.location
+ in_rotation = in_sumo_transform.rotation
+
+ # From front-center-bumper to center (sumo reference system).
+ # (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_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
+
+ # 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]))
+
+ @staticmethod
+ def get_sumo_transform(in_carla_transform, extent):
+ """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_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
+
+ # 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]))
+
+ @staticmethod
+ def _get_recommended_carla_blueprint(sumo_actor):
+ """Returns an appropriate blueprint based on the given sumo actor.
+ """
+ vclass = sumo_actor.vclass.value
+
+ blueprints = []
+ 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:
+ 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
+ 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))
+ 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))
+ else:
+ logging.error('sumo vtype {} not supported. No vehicle will be spawned in carla'.format(type_id))
+ return None
+
+ if blueprint.has_attribute('color'):
+ color = "{},{},{}".format(sumo_actor.color[0], sumo_actor.color[1], sumo_actor.color[2])
+ blueprint.set_attribute('color', color)
+
+ if blueprint.has_attribute('driver_id'):
+ 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)
+ )
+ )
+
+ return blueprint
+
+ @staticmethod
+ def _create_sumo_vtype(carla_actor):
+ """Creates an appropriate vtype based on the given carla_actor.
+ """
+ type_id = carla_actor.type_id
+ attrs = carla_actor.attributes
+ extent = carla_actor.bounding_box.extent
+
+ if int(attrs['number_of_wheels']) == 2:
+ traci.vehicletype.copy('DEFAULT_BIKETYPE', type_id)
+ else:
+ traci.vehicletype.copy('DEFAULT_VEHTYPE', type_id)
+
+ if type_id in BridgeHelper._VTYPES:
+ if 'vClass' in BridgeHelper._VTYPES[type_id]:
+ _class = BridgeHelper._VTYPES[type_id]['vClass']
+ traci.vehicletype.setVehicleClass(type_id, _class)
+
+ if 'guiShape' in BridgeHelper._VTYPES[type_id]:
+ shape = BridgeHelper._VTYPES[type_id]['guiShape']
+ traci.vehicletype.setShapeClass(type_id, shape)
+
+ if 'color' in attrs:
+ color = attrs['color'].split(',')
+ traci.vehicletype.setColor(type_id, color)
+
+ traci.vehicletype.setLength(type_id, 2.0 * extent.x)
+ 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)
+ )
+ )
+
+ return type_id
+
+ @staticmethod
+ def get_sumo_vtype(carla_actor):
+ """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))
+ return None
+
+ if type_id in traci.vehicletype.getIDList():
+ logging.debug('[BridgeHelper] blueprint {} found in sumo vtypes'.format(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.
+ """
+ current_lights = current_carla_lights
+
+ # Blinker right / emergency.
+ if (any([
+ bool(sumo_lights & SumoVehSignal.BLINKER_RIGHT),
+ bool(sumo_lights & SumoVehSignal.BLINKER_EMERGENCY)
+ ]) != bool(current_lights & carla.VehicleLightState.RightBlinker)):
+ current_lights ^= carla.VehicleLightState.RightBlinker
+
+ # Blinker left / emergency.
+ if (any([
+ bool(sumo_lights & SumoVehSignal.BLINKER_LEFT),
+ bool(sumo_lights & SumoVehSignal.BLINKER_EMERGENCY)
+ ]) != bool(current_lights & carla.VehicleLightState.LeftBlinker)):
+ current_lights ^= carla.VehicleLightState.LeftBlinker
+
+ # Break.
+ if (bool(sumo_lights & SumoVehSignal.BRAKELIGHT) !=
+ bool(current_lights & carla.VehicleLightState.Brake)):
+ current_lights ^= carla.VehicleLightState.Brake
+
+ # Front (low beam).
+ if (bool(sumo_lights & SumoVehSignal.FRONTLIGHT) !=
+ bool(current_lights & carla.VehicleLightState.LowBeam)):
+ current_lights ^= carla.VehicleLightState.LowBeam
+
+ # Fog.
+ if (bool(sumo_lights & SumoVehSignal.FOGLIGHT) !=
+ bool(current_lights & carla.VehicleLightState.Fog)):
+ current_lights ^= carla.VehicleLightState.Fog
+
+ # High beam.
+ if (bool(sumo_lights & SumoVehSignal.HIGHBEAM) !=
+ bool(current_lights & carla.VehicleLightState.HighBeam)):
+ current_lights ^= carla.VehicleLightState.HighBeam
+
+ # Backdrive (reverse).
+ if (bool(sumo_lights & SumoVehSignal.BACKDRIVE) !=
+ bool(current_lights & carla.VehicleLightState.Reverse)):
+ current_lights ^= carla.VehicleLightState.Reverse
+
+ # Door open left/right.
+ if (any([
+ bool(sumo_lights & SumoVehSignal.DOOR_OPEN_LEFT),
+ bool(sumo_lights & SumoVehSignal.DOOR_OPEN_RIGHT)
+ ]) != bool(current_lights & carla.VehicleLightState.Position)):
+ current_lights ^= carla.VehicleLightState.Position
+
+ return current_lights
+
+ @staticmethod
+ def get_sumo_lights_state(current_sumo_lights, carla_lights):
+ """Returns sumo signals based on carla vehicle light state.
+ """
+ current_lights = current_sumo_lights
+
+ # Blinker right.
+ if (bool(carla_lights & carla.VehicleLightState.RightBlinker) !=
+ bool(current_lights & SumoVehSignal.BLINKER_RIGHT)):
+ current_lights ^= SumoVehSignal.BLINKER_RIGHT
+
+ # Blinker left.
+ if (bool(carla_lights & carla.VehicleLightState.LeftBlinker) !=
+ bool(current_lights & SumoVehSignal.BLINKER_LEFT)):
+ current_lights ^= SumoVehSignal.BLINKER_LEFT
+
+ # Emergency.
+ if (all([
+ bool(carla_lights & carla.VehicleLightState.RightBlinker),
+ bool(carla_lights & carla.VehicleLightState.LeftBlinker)
+ ]) != (current_lights & SumoVehSignal.BLINKER_EMERGENCY)):
+ current_lights ^= SumoVehSignal.BLINKER_EMERGENCY
+
+ # Break.
+ if (bool(carla_lights & carla.VehicleLightState.Brake) !=
+ bool(current_lights & SumoVehSignal.BRAKELIGHT)):
+ current_lights ^= SumoVehSignal.BRAKELIGHT
+
+ # Front (low beam)
+ if (bool(carla_lights & carla.VehicleLightState.LowBeam) !=
+ bool(current_lights & SumoVehSignal.FRONTLIGHT)):
+ current_lights ^= SumoVehSignal.FRONTLIGHT
+
+ # Fog light.
+ if (bool(carla_lights & carla.VehicleLightState.Fog) !=
+ bool(current_lights & SumoVehSignal.FOGLIGHT)):
+ current_lights ^= SumoVehSignal.FOGLIGHT
+
+ # High beam ligth.
+ if (bool(carla_lights & carla.VehicleLightState.HighBeam) !=
+ bool(current_lights & SumoVehSignal.HIGHBEAM)):
+ current_lights ^= SumoVehSignal.HIGHBEAM
+
+ # Backdrive (reverse)
+ if (bool(carla_lights & carla.VehicleLightState.Reverse) !=
+ bool(current_lights & SumoVehSignal.BACKDRIVE)):
+ current_lights ^= SumoVehSignal.BACKDRIVE
+
+ return current_lights
\ No newline at end of file
diff --git a/Co-Simulation/Sumo/sumo_integration/carla_simulation.py b/Co-Simulation/Sumo/sumo_integration/carla_simulation.py
new file mode 100644
index 000000000..352cba638
--- /dev/null
+++ b/Co-Simulation/Sumo/sumo_integration/carla_simulation.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma de
+# Barcelona (UAB).
+#
+# This work is licensed under the terms of the MIT license.
+# For a copy, see .
+
+# ==============================================================================
+# -- imports -------------------------------------------------------------------
+# ==============================================================================
+
+import logging
+
+import carla
+SpawnActor = carla.command.SpawnActor
+FutureActor = carla.command.FutureActor
+SetSimulatePhysics = carla.command.SetSimulatePhysics
+
+from .constants import *
+
+# ==============================================================================
+# -- carla simulation ----------------------------------------------------------
+# ==============================================================================
+
+
+class CarlaSimulation(object):
+ def __init__(self, args):
+ self.args = args
+ self.host = args.carla_host
+ self.port = args.carla_port
+ self.step_length = args.step_length
+
+ self.client = carla.Client(self.host, self.port)
+ self.client.set_timeout(2.0)
+
+ 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 = self.step_length
+ self.world.apply_settings(settings)
+
+ # The following sets contain updated information for the current frame.
+ self._active_actors = set()
+ self.spawned_actors = set()
+ self.destroyed_actors = set()
+
+ def get_actor(self, actor_id):
+ return self.world.get_actor(actor_id)
+
+ def spawn_actor(self, blueprint, transform):
+ """Spawns a new actor.
+ """
+ transform = carla.Transform(
+ transform.location + carla.Location(0, 0, SPAWN_OFFSET_Z),
+ transform.rotation)
+
+ batch = [
+ SpawnActor(blueprint,transform)
+ .then(SetSimulatePhysics(FutureActor, False))
+ ]
+ response = self.client.apply_batch_sync(batch, True)[0]
+ if response.error:
+ logging.error('Spawn carla actor failed. {}'.format(response.error))
+ return INVALID_ACTOR_ID
+ else:
+ return response.actor_id
+
+ def destroy_actor(self, actor_id):
+ 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):
+ vehicle = self.world.get_actor(vehicle_id)
+ if vehicle is None:
+ return False
+
+ vehicle.set_transform(transform)
+ if lights is not None or self.args.sync_vehicle_lights:
+ vehicle.set_light_state(carla.VehicleLightState(lights))
+
+ def synchronize_walker(self, walker_id, transform):
+ pass
+
+ def tick(self):
+ self.world.tick()
+
+ # Update data structures for the current frame.
+ current_actors = set([
+ vehicle.id for vehicle in self.world.get_actors().filter('vehicle.*')
+ ])
+ 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
diff --git a/Co-Simulation/Sumo/sumo_integration/constants.py b/Co-Simulation/Sumo/sumo_integration/constants.py
new file mode 100644
index 000000000..9a5fdc0e1
--- /dev/null
+++ b/Co-Simulation/Sumo/sumo_integration/constants.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma de
+# Barcelona (UAB).
+#
+# This work is licensed under the terms of the MIT license.
+# For a copy, see .
+
+# ==============================================================================
+# -- constants -----------------------------------------------------------------
+# ==============================================================================
+
+INVALID_ACTOR_ID = -1
+SPAWN_OFFSET_Z = 5.0 # meters
\ No newline at end of file
diff --git a/Co-Simulation/Sumo/sumo_integration/sumo_simulation.py b/Co-Simulation/Sumo/sumo_integration/sumo_simulation.py
new file mode 100644
index 000000000..b4c91ac6e
--- /dev/null
+++ b/Co-Simulation/Sumo/sumo_integration/sumo_simulation.py
@@ -0,0 +1,212 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma de
+# Barcelona (UAB).
+#
+# This work is licensed under the terms of the MIT license.
+# For a copy, see .
+
+# ==============================================================================
+# -- imports -------------------------------------------------------------------
+# ==============================================================================
+
+import collections
+import enum
+import logging
+
+import carla
+import sumolib
+import traci
+
+from .constants import *
+
+# ==============================================================================
+# -- sumo definitions ----------------------------------------------------------
+# ==============================================================================
+
+
+# Sumo vehicle signals.
+# https://sumo.dlr.de/docs/TraCI/Vehicle_Signalling.html
+class SumoVehSignal(object):
+ BLINKER_RIGHT = 1 << 0
+ BLINKER_LEFT = 1 << 1
+ BLINKER_EMERGENCY = 1 << 2
+ BRAKELIGHT = 1 << 3
+ FRONTLIGHT = 1 << 4
+ FOGLIGHT = 1 << 5
+ HIGHBEAM = 1 << 6
+ BACKDRIVE = 1 << 7
+ WIPER = 1 << 8
+ DOOR_OPEN_LEFT = 1 << 9
+ DOOR_OPEN_RIGHT = 1 << 10
+ EMERGENCY_BLUE = 1 << 11
+ EMERGENCY_RED = 1 << 12
+ EMERGENCY_YELLOW = 1 << 13
+
+
+# https://sumo.dlr.de/docs/Definition_of_Vehicles,_Vehicle_Types,_and_Routes.html#abstract_vehicle_class
+class SumoActorClass(enum.Enum):
+ IGNORING = "ignoring"
+ PRIVATE = "private"
+ EMERGENCY = "emergency"
+ AUTHORITY = "authority"
+ ARMY = "army"
+ VIP = "vip"
+ PEDESTRIAN = "pedestrian"
+ PASSENGER = "passenger"
+ HOV = "hov"
+ TAXI = "taxi"
+ BUS = "bus"
+ COACH = "coach"
+ DELIVERY = "delivery"
+ TRUCK = "truck"
+ TRAILER = "trailer"
+ MOTORCYCLE = "motorcycle"
+ MOPED = "moped"
+ BICYCLE = "bicycle"
+ EVEHICLE = "evehicle"
+ TRAM = "tram"
+ RAIL_URBAN = "rail_urban"
+ RAIL = "rail"
+ RAIL_ELECTRIC = "rail_electric"
+ RAIL_FAST = "rail_fast"
+ SHIP = "ship"
+ CUSTOM1 = "custom1"
+ CUSTOM2 = "custom2"
+
+
+SumoActor = collections.namedtuple(
+ 'SumoActor', 'type_id vclass transform signals extent color')
+
+# ==============================================================================
+# -- sumo simulation -----------------------------------------------------------
+# ==============================================================================
+
+
+class SumoSimulation(object):
+ def __init__(self, args):
+ self.args = args
+ self.host = args.sumo_host
+ self.port = args.sumo_port
+
+ self.sumo_gui = args.sumo_gui
+ if self.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:
+ logging.info('Starting new sumo server...')
+ if self.sumo_gui:
+ logging.info('Remember to press the play button in sumo-gui to start the simulation')
+
+ traci.start([
+ sumo_binary,
+ "-c", args.sumo_cfg_file,
+ '--step-length', str(args.step_length),
+ '--lateral-resolution', '0.25'
+ ])
+ else:
+ logging.info('Connection to sumo server. Host: {} Port: {}'.format(self.host, self.port))
+ traci.init(host=self.host, port=self.port)
+
+ # Structures to keep track of the spawned and destroyed vehicles at each time step.
+ self.spawned_actors = set()
+ self.destroyed_actors = set()
+
+ # Creating a random route to be able to spawn carla actors.
+ traci.route.add("carla_route", [traci.edge.getIDList()[0]])
+
+ # Variable to asign an id to new added actors.
+ self._sequential_id = 0
+
+ @staticmethod
+ def subscribe(actor_id):
+ # TODO(joel): Add velocity, acceleration?
+ traci.vehicle.subscribe(actor_id, [
+ traci.constants.VAR_TYPE, traci.constants.VAR_VEHICLECLASS,
+ traci.constants.VAR_COLOR, traci.constants.VAR_LENGTH,
+ traci.constants.VAR_WIDTH, traci.constants.VAR_HEIGHT,
+ traci.constants.VAR_POSITION3D, traci.constants.VAR_ANGLE,
+ traci.constants.VAR_SLOPE, traci.constants.VAR_SPEED,
+ traci.constants.VAR_SPEED_LAT, traci.constants.VAR_SIGNALS
+ ])
+
+ @staticmethod
+ def unsubscribe(actor_id):
+ traci.vehicle.unsubscribe(actor_id)
+
+ # TODO(joel): Review this is correct.
+ def get_net_offset(self):
+ offset = traci.simulation.convertGeo(0, 0)
+ return (-offset[0], -offset[1])
+
+ def get_step_length(self):
+ return traci.simulation.getDeltaT()
+
+ def get_actor(self, actor_id):
+ results = traci.vehicle.getSubscriptionResults(actor_id)
+
+ type_id = results[traci.constants.VAR_TYPE]
+ vclass = SumoActorClass(results[traci.constants.VAR_VEHICLECLASS])
+ color = results[traci.constants.VAR_COLOR]
+
+ length = results[traci.constants.VAR_LENGTH]
+ width = results[traci.constants.VAR_WIDTH]
+ height = results[traci.constants.VAR_HEIGHT]
+
+ location = list(results[traci.constants.VAR_POSITION3D])
+ rotation = [
+ results[traci.constants.VAR_SLOPE],
+ results[traci.constants.VAR_ANGLE], 0.0
+ ]
+ transform = carla.Transform(
+ carla.Location(location[0], location[1], location[2]),
+ carla.Rotation(rotation[0], rotation[1], rotation[2]))
+
+ signals = results[traci.constants.VAR_SIGNALS]
+ extent = carla.Vector3D(length / 2.0, width / 2.0, height / 2.0)
+
+ return SumoActor(type_id, vclass, transform, signals, extent, color)
+
+ def spawn_actor(self, type_id, attrs={}):
+ """Spawns a new actor based on given type.
+ """
+ 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))
+ return INVALID_ACTOR_ID
+
+ 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):
+ traci.vehicle.remove(actor_id)
+
+ def synchronize_vehicle(self, vehicle_id, transform, signals=None):
+ x, y = transform.location.x, transform.location.y
+ yaw = transform.rotation.yaw
+
+ traci.vehicle.moveToXY(vehicle_id, "", 0, x, y, angle=yaw, keepRoute=2)
+ if signals is not None or self.args.sync_vehicle_lights:
+ traci.vehicle.setSignals(vehicle_id, signals)
+
+ def synchronize_walker(self, walker_id, transform):
+ pass
+
+ def tick(self):
+ traci.simulationStep()
+
+ # Update data structures for the current frame.
+ self.spawned_actors = set(traci.simulation.getDepartedIDList())
+ self.destroyed_actors = set(traci.simulation.getArrivedIDList())
+
+ def close(self):
+ traci.close()
\ No newline at end of file
diff --git a/Co-Simulation/Sumo/util/create_sumo_vtypes.py b/Co-Simulation/Sumo/util/create_sumo_vtypes.py
new file mode 100644
index 000000000..d1ab6dea6
--- /dev/null
+++ b/Co-Simulation/Sumo/util/create_sumo_vtypes.py
@@ -0,0 +1,174 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma de
+# Barcelona (UAB).
+#
+# This work is licensed under the terms of the MIT license.
+# For a copy, see .
+
+"""
+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
+
+import argparse
+import datetime
+import json
+import logging
+import lxml.etree as ET
+
+# ==============================================================================
+# -- load specs definition -----------------------------------------------------
+# ==============================================================================
+
+with open('../data/vtypes.json') as f:
+ SPECS = json.load(f)
+
+ DEFAULT_2_WHEELED_VEHICLE = SPECS['DEFAULT_2_WHEELED_VEHICLE']
+ DEFAULT_WHEELED_VEHICLE = SPECS['DEFAULT_WHEELED_VEHICLE']
+ CARLA_BLUEPRINTS_SPECS = SPECS['carla_blueprints']
+
+# ==============================================================================
+# -- main ----------------------------------------------------------------------
+# ==============================================================================
+
+def write_vtype_xml(filename, vtypes):
+ 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__))
+ )
+ )
+
+ for vtype in vtypes:
+ ET.SubElement(root, 'vType', vtype)
+
+ 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.
+
+ :param vehicle: carla actor (carla.Actor)
+ :return: sumo vtype specifications
+ """
+ type_id = vehicle.type_id
+
+ 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)
+ )
+ 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)
+ )
+ 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])
+ )
+ user_specs = CARLA_BLUEPRINTS_SPECS[type_id]
+
+ specs = {
+ 'id': vehicle.type_id,
+ 'length': str(2.0 * vehicle.bounding_box.extent.x),
+ 'width': str(2.0 * vehicle.bounding_box.extent.y),
+ 'height': str(2.0 * vehicle.bounding_box.extent.z)
+ }
+
+ specs.update(user_specs)
+ return specs
+
+def main(args):
+ 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.*')
+
+ transform = world.get_map().get_spawn_points()[0]
+
+ vtypes = []
+ for blueprint in vehicle_blueprints:
+ logging.info('processing vtype for {}'.format(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))
+
+ vehicle.destroy()
+
+ write_vtype_xml(args.output_file, vtypes)
+
+ finally:
+ logging.info('done')
+
+if __name__ == '__main__':
+ # Define arguments that will be received and parsed.
+ 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(
+ '--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()
+
+ if args.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
diff --git a/Co-Simulation/Sumo/util/sequential_types.py b/Co-Simulation/Sumo/util/sequential_types.py
new file mode 100644
index 000000000..62be15882
--- /dev/null
+++ b/Co-Simulation/Sumo/util/sequential_types.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma de
+# Barcelona (UAB).
+#
+# This work is licensed under the terms of the MIT license.
+# For a copy, see .
+
+"""
+Script to modify automatically vtypes to carla type ids in sumo route files.
+"""
+
+# ==============================================================================
+# -- imports -------------------------------------------------------------------
+# ==============================================================================
+
+import argparse
+import fnmatch
+import json
+import logging
+import lxml.etree as ET
+import random
+
+# ==============================================================================
+# -- load vtypes ---------------------------------------------------------------
+# ==============================================================================
+
+with open('../data/vtypes.json') as f:
+ VTYPES = json.load(f)['carla_blueprints'].keys()
+
+# ==============================================================================
+# -- main ----------------------------------------------------------------------
+# ==============================================================================
+
+def main(route_files, vtypes, _random=False):
+ for filename in route_files:
+ tree = ET.parse(filename)
+ root = tree.getroot()
+
+ if not _random:
+ index = 0
+
+ counter = 0
+ for vtype in root.iter('vehicle'):
+ if _random:
+ new_type = random.choice(vtypes)
+ else:
+ new_type = vtypes[index]
+ 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
+ ))
+
+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'
+ )
+ args = argparser.parse_args()
+
+ if args.verbose:
+ logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
+ 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
diff --git a/Co-Simulation/Sumo/util/spawn_sumo_vehicles.py b/Co-Simulation/Sumo/util/spawn_sumo_vehicles.py
new file mode 100644
index 000000000..0651a473e
--- /dev/null
+++ b/Co-Simulation/Sumo/util/spawn_sumo_vehicles.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma de
+# Barcelona (UAB).
+#
+# This work is licensed under the terms of the MIT license.
+# For a copy, see .
+
+"""
+Script to randomly spawn vehicles in sumo.
+"""
+
+# ==============================================================================
+# -- find traci module ---------------------------------------------------------
+# ==============================================================================
+
+import glob
+import os
+import sys
+
+if 'SUMO_HOME' in os.environ:
+ tools = os.path.join(os.environ['SUMO_HOME'], 'tools')
+ sys.path.append(tools)
+else:
+ sys.exit("please declare environment variable 'SUMO_HOME'")
+
+# ==============================================================================
+# -- imports -------------------------------------------------------------------
+# ==============================================================================
+
+import argparse
+import logging
+import random
+
+import sumolib
+import traci
+
+# ==============================================================================
+# -- main ----------------------------------------------------------------------
+# ==============================================================================
+
+def get_random_color():
+ r = random.randrange(256)
+ g = random.randrange(256)
+ b = random.randrange(256)
+ a = 255
+ return (r, g, b, a)
+
+def main(args):
+ try:
+ if args.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:
+ logging.info('Starting new sumo server...')
+ if args.sumo_gui:
+ logging.info('Remember to press the play button in sumo-gui to start the simulation')
+
+ traci.start([
+ sumo_binary,
+ "-c", args.sumo_cfg_file,
+ '--step-length', str(args.step_length),
+ ])
+ else:
+ logging.info('Connection to sumo server. Host: {} Port: {}'.format(args.sumo_host, args.sumo_port))
+ traci.init(host=args.sumo_host, port=args.sumo_port)
+ traci.setOrder(1)
+
+ # Creating a random route to be able to spawn vehicles.
+ traci.route.add("spawn_route", [traci.edge.getIDList()[0]])
+
+ sequential_id = 0
+
+ while True:
+ input('Press a key to spawn a new actor')
+
+ # Remove previously spawned vehicle.
+ if sequential_id > 0:
+ traci.vehicle.remove('spawn_' + str(sequential_id - 1))
+
+ type_id = random.choice(traci.vehicletype.getIDList())
+
+ actor_id = 'spawn_' + str(sequential_id)
+ traci.vehicle.add(actor_id, 'spawn_route', typeID=type_id)
+ traci.vehicle.setColor(actor_id, get_random_color()) # Randomly select color.
+
+ traci.simulationStep()
+ traci.simulationStep()
+ sequential_id += 1
+
+ logging.info('''Spawned new sumo vehicle:
+ \tvtype: {vtype:}
+ \tcolor: {color:}'''.format(
+ vtype=type_id,
+ color=traci.vehicle.getColor(actor_id)
+ )
+ )
+
+ except KeyboardInterrupt:
+ logging.info('Cancelled by user.')
+
+ finally:
+ traci.close()
+
+if __name__ == '__main__':
+ argparser = argparse.ArgumentParser(
+ description=__doc__
+ )
+ 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)'
+ )
+ args = argparser.parse_args()
+
+ logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
+
+ main(args)
\ No newline at end of file