|
|
| Traffic Controller Collection for SUMO Traffic Simulatons |
sumoITScontrol is an open-source Python framework that provides a standardized collection of established traffic controllers for the SUMO simulator for signal control and freeway ramp metering algorithms. It enables reproducible, variance-aware benchmarking of intelligent traffic control methods through consistent implementations and rigorous evaluation practices.
Table of Contents
Highlights
| Covered Controllers | ||
| Intersection Management | Ramp Metering | |
|
|
|
| |
|
|
|
==> Link to Documentation Page <==
Installation
The python package sumoITScontrol can be installed using pip:
pip install sumoITScontrol
Usage
You can use sumoITScontrol as a Python library to easily integrate ITS controllers into your SUMO simulations. For this, you need to include only one line of code into your main loop when using SUMO with TraCI. Certain preparation, such as defining sensors and traffic lights, or control parameters, is necessary additionally. The usage is exemplified at the example of ALINEA controler and ramp metering. For further details, please see the section on Case Study Demonstrations.
Step 1: Define Sensors and Traffic Lights
You need to provide a control context such as a RampMeter or RampMeterCoordinationGroup in the context of ramp metering, and Intersection or IntersectionGroup in the context of signalised intersection management.
The context informs sumoITScontrol about relevant sensors (e2_5, e2_4, e2_0) and traffic lights (J0).
ramp_meter = RampMeter(
tl_id="J0",
mainline_sensors=["e2_5", "e2_4"],
queue_sensors=["e2_0"],
)
Step 2: Define Control Parameters
You need to provide a controller and relevant parameters to connect the controller to the control context such as ALINEA, HERO, or METALINE in the context of ramp metering, and MaxPressure_Fix, MaxPressure_Flex or ScootScats in the context of singalised intersection management.
controller = ALINEA(
params={
"target_occupancy": 10,
"K_P": 30,
"K_I": 0,
"cycle_duration": 60,
"measurement_period": int(
60 / 0.5
), # int(cycle_duration / simulation.time_step)
"min_rate": 5,
"max_rate": 100,
},
ramp_meter=ramp_meter,
)
Step 3: Add One Line to Main Loop
Any SUMO simulation that is executed with TraCI somehow has the structure of starting traci, inside a loop calling traci.simulationStep() for the duration of the simulation, and then closing traci.
Anything you have to do (for most controllers) is to simply add one line of code inside your loop, as outlined below.
Please Note: For the controller ScootScats, you might need to add one line to the initialization (after traci.start() but before traci.simulationStep()). For further details, please see the section on Case Study Demonstrations.
# Start Sumo
traci.start(SUMO_CMD)
# Initialize
# Execute Simulation
for simulation_timestep in range(0, SIMULATION_DURATION):
# run one step
traci.simulationStep()
# retrieve time
current_time = traci.simulation.getCurrentTime()
# execute control
controller.execute_control(current_time) # <-- !!! ADD THIS LINE !!!
# Stop Sumo
traci.close()
Case Study Demonstrations
Demo Python scripts and SUMO simulations for each implemented controller can be found in the folder .\sumoITScontrol\demos\*.py and .\sumoITScontrol\demos\demo_simulation_models\.
The Python scripts open sumo-gui for the simulation, and afterwards render figures with control-relevant statistics as reported in the paper.
There are three case studies:
- Control in the context of ramp metering
- Control in the context of signalised intersection management
- Calibration / Fine-tuning of control parameters
Ramp Metering
Relevant demos include:
python demo_ALINEA.py
python demo_HERO.py
python demo_METALINE.py
Signalised Intersection Management
Relevant demos include:
python demo_MAX_FIX.py
python demo_MAX_FLEX.py
python demo_SCOSCA.py
Calibration / Fine-Tuning of Control Parameters
Relevant demos include:
python demo_optimisation.py
which calls the python script demo_optimisation_execute_script.py.
Documentation
This documentation lists specific details to control context objects and traffic control algorithms for ramp metering and signalised intersection management.
Control Context Objects
RampMetering
This is the example of RampMetering object specification. The sensors can be E2 sensors or E1 sensors.
ramp_meter = RampMeter(
tl_id="J0",
mainline_sensors=["e2_5", "e2_4"],
queue_sensors=["e2_0"],
)
RampMeteringCoordinationGroup
This is the example of RampMeterCoordinationGroup object specification. The sensors can be E2 sensors or E1 sensors.
ramp_meter_group = RampMeterCoordinationGroup(
ramp_meters_ordered=[
RampMeter(
tl_id="J12",
mainline_sensors=["e1_13", "e1_14"],
queue_sensors=["e2_1", "e2_2"],
smoothening_factor=0.1,
saturation_flow_veh_per_sec=0.5,
),
RampMeter(
tl_id="J11",
mainline_sensors=["e1_2", "e1_3"],
queue_sensors=["e2_3"],
smoothening_factor=0.1,
saturation_flow_veh_per_sec=0.5,
),
RampMeter(
tl_id="J0",
mainline_sensors=["e2_5", "e2_4"],
queue_sensors=["e2_0"],
smoothening_factor=0.1,
saturation_flow_veh_per_sec=0.5,
),
],
ramp_meter_ids=["J12", "J11", "J0"],
)
Intersection
This is the example of Intersection object specification.
You can either provide a list of sensors (E2 sensors) or a list of lanes (links) to measure traffic states (queue lengths, degree of saturation).
If both are provided, sensors are taken first.
Provision of green_states and yellow_states is only necessary for SCOOT/SCATS.
intersection2 = Intersection(
tl_id="intersection2",
phases=[0, 2, 4],
# links = {0:["183049933#0_1", "-38361908#1_1"],
# 2:["-38361908#1_1", "-38361908#1_2"],
# 4:["-25973410#1_1", "758088375#0_1", "758088375#0_2"]},
sensors={
0: ["e2_183049933#0_1", "e2_-38361908#1_1"],
2: ["e2_-38361908#1_1", "e2_-38361908#1_2"],
4: ["e2_-25973410#1", "e2_758088375#0_1", "e2_758088375#0_2"],
},
green_states=["GGrrrGrr", "GGGrrrrr", "rrrGGrGG"],
yellow_states=["yyrrryrr", "yyyrrrrr", "rrryyryy"],
)
IntersectionGroup
This is the example of IntersectionGroup object specification. You can either provide a list of sensors (E2 sensors) or a list of lanes (links) to measure traffic states (queue lengths, degree of saturation). If both are provided, sensors are taken first.
intersection1 = Intersection(
tl_id="intersection1",
...
)
intersection2 = Intersection(
tl_id="intersection2",
...
)
intersection3 = Intersection(
tl_id="intersection3",
...
)
intersection4 = Intersection(
tl_id="intersection4",
...
)
intersection5 = Intersection(
tl_id="intersection5",
...
)
districts = {
"front": ["intersection1", "intersection2"],
"middle": ["intersection3", "intersection4"],
"back": ["intersection5"],
}
critical_district_order = {
"front": [
"intersection1",
"intersection2",
"intersection3",
"intersection4",
"intersection5",
],
"middle": [
"intersection3",
"intersection2",
"intersection4",
"intersection1",
"intersection5",
],
"back": [
"intersection5",
"intersection4",
"intersection3",
"intersection2",
"intersection1",
],
}
connection_between_intersections = {
"intersection1": ["183049934_1", "183049933#0_1", "1164287131#0_1"], # To Int 2
"intersection2": ["38361908#1_1", "E3_1"], # To Int 3
"intersection3": [
"E1_1",
"758088377#1_1",
"758088377#2_1",
"22889927#0_1",
], # To Int 4
"intersection4": [
"22889927#2_1",
"22889927#3_1",
"22889927#4_1",
"387296014#0_1",
"387296014#1_1",
"696225646#1_1",
"696225646#2_1",
"696225646#3_1",
"130569446_1",
"E5_1",
"E6_1",
], # To Int 5
}
intersection_group = IntersectionGroup(
intersections=[
intersection1,
intersection2,
intersection3,
intersection4,
intersection5,
],
districts=districts,
critical_district_order=critical_district_order,
connection_between_intersections=connection_between_intersections,
)
Ramp Metering
ALINEA
This is the example of ALINEA object specification.
controller = ALINEA(
params={
"target_occupancy": 10,
"K_P": 30,
"K_I": 0,
"cycle_duration": 60,
"measurement_period": int(
60 / 0.5
), # int(cycle_duration / simulation.time_step)
"min_rate": 5,
"max_rate": 100,
},
ramp_meter=ramp_meter,
)
HERO
This is the example of HERO object specification.
controller = HERO(
params={
"hero_cycle_duration": 60, # similar to ALINEA cycle duration
"queue_activation_threshold_m": 15.0, # master queue trigger
"queue_release_threshold_m": 2.5, # dissolve cluster
"min_queue_setpoint_m": 5.0, # for slaves
"anticipation_factor": 1.0, # factor to obtain nonconservative prediction of demand to come in next control period
"avg_vehicle_spacing": 7.5, # average vehicle spacing to convert meters to vehicles and vice versa, from queue length measurements
},
coordination_group=ramp_meter_group,
alinea_controllers={
"J12": alinea_controller1,
"J11": alinea_controller2,
"J0": alinea_controller3,
},
)
METALINE
This is the example of METALINE object specification.
controller = METALINE(
params={
"cycle_duration": 60, # control cycle
"measurement_period": int(
60 / 0.5
), # int(cycle_duration / simulation.time_step)
"min_rate": 5,
"max_rate": 100,
},
coordination_group=ramp_meter_group,
target_occupancies=[10, 10, 10],
# Interaction gain matrix (3x3)
K_P=np.array(
[
[30, -5, 0], # ramp 1 influenced negatively by ramp 2
[-3, 25, -2], # ramp 2 influenced by neighbors
[0, -4, 20],
]
),
# Optional integral gain matrix
K_I=np.zeros(shape=(3, 3)),
)
Signalised Intersection Management
Max-Pressure (Fixed-Cycle)
This is the example of MaxPressure_Fix object specification.
controller = MaxPressure_Fix(
params={
"T_L": 3, # Yellow Time
"G_T_MIN": 5, # Min Greentime (used for Max. Pressure)
"G_T_MAX": 50, # Max Greentime (used for Max. Pressure)
"measurement_period": int(1 / 0.25), # int(1 / simulation.time_step)
"cycle_duration": 120,
},
intersection=intersection1
)
Max-Pressure (Flexible-Cycle)
This is the example of MaxPressure_Flex object specification.
controller = MaxPressure_Flex(
params={
"T_A": 5, # Recheck-Pressure Time (used for Max.Pressure)
"T_L": 3, # Yellow Time
"G_T_MIN": 5, # Min Greentime (used for Max. Pressure)
"G_T_MAX": 50, # Max Greentime (used for Max. Pressure)
"measurement_period": int(1 / 0.25), # int(1 / simulation.time_step)
"cycle_duration": 120,
},
intersection=intersection1
)
SCOOT/SCATS
This is the example of ScootScats object specification.
controller = ScootScats(
scosca_params = {
"adaptation_cycle": 30,
"adaptation_green": 10,
"green_thresh": 2,
"adaptation_offset": 1,
"offset_thresh": 0.5,
"min_cycle_length": 50,
"max_cycle_length": 180,
"ds_upper_val": 0.925,
"ds_lower_val": 0.875,
"measurement_period": int(1 / 0.25), # 1 / simulation_step_size
"travel_time_adjustments": {
"intersection1": ["183049934_1", 2],
"intersection3": ["E1_1", 3],
"intersection4": ["22889927#3_1", 9],
},
"intersection_offset_rules": {
"intersection2": {
"base_offset_from": None,
"travel_time_from": "intersection2",
},
"intersection4": {
"base_offset_from": None,
"travel_time_from": "intersection3",
},
"intersection1": {
"base_offset_from": "intersection2",
"travel_time_from": "intersection1",
},
"intersection3": {
"base_offset_from": "intersection4",
"travel_time_from": "intersection4",
},
"default": {
"base_offset_from": "intersection4",
"travel_time_from": "intersection4",
},
},
},
intersection_group=intersection_group1,
initial_greentimes={
"intersection1": [30, 30, 21],
"intersection2": [30, 30, 21],
"intersection3": [30, 30, 21],
"intersection4": [40, 30],
"intersection5": [30, 30, 21],
},
initial_cycle_length=120,
)
Citations
Please cite our paper if you find sumoITScontrol useful:
@inproceedings{riehl2026sumoITScontrol,
title={sumoITScontrol: Traffic Controller Collection for SUMO Traffic Simulations},
author={Riehl, Kevin and Kouvelas, Anastasios and Makridis, Michail A.},
booktitle={SUMO Conference Proceedings},
year={2026}
}
Metadata
Release files for sumoITScontrol 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| sumoitscontrol-0.1.0.tar.gz | 35.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sumoitscontrol-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 70.4 kB
Release files / sumoitscontrol-0.1.0.tar.gz
| Download URL | sumoitscontrol-0.1.0.tar.gz |
|---|---|
| Size | 35.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2d79ffd29883b696373715809039bce5c87534f6b6a0b17fdd2359da3e757a01
|
|
BLAKE2b-256 checksum How to use checksums |
02f49fa9d34eb3233675108ed30fdd2d532f62d5a65a486a5de3628d0fff956d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.25
|
Release files / sumoitscontrol-0.1.0-py3-none-any.whl
| Download URL | sumoitscontrol-0.1.0-py3-none-any.whl |
|---|---|
| Size | 35.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2d6a0eaf839ed631264dfab967c8b94889bf8b58ac54f15e42632d8eca51570a
|
|
BLAKE2b-256 checksum How to use checksums |
99e7241f7d9bf00d49fd41e2682aaf675b6d7dbacb7010d14de483672e987eb3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.25
|
Security for sumoITScontrol 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.