IntersectionControl

Project Structure

Overview

The design of the project is aimed at enabling the comparison of various intersection control algorithms across various environments.

Examples of algorithms include Query-based centralised intersection control, decentralised reinforcement learning and decentralised negotiation-based approaches. Examples of environments include SUMO, CARLA or a scale-model road environment like Duckietown.

Algorithm and Environment Interaction

In order to achieve this, the project separates an intersection control experiment into two components: the algorithm, and the environment: the algorithm determines the behaviour of the vehicles at each point in time, and interacts with the environment to get the information (speed, position etc) necessary to determine that behaviour, before using the environment to execute it.

The algorithm interacts with the environment through a uniform interface defined in intersection_control.core.environment. This means that in theory, the same algorithm could be tested in a number of different environments - this could, for example, provide insights into the algorithm’s resilience and stability.

Similarly, the algorithms implement a uniform interface (all of their behaviour is determined by implementing a step() function), and so a number of algorithms could be run on the same environment in the same traffic conditions, and their performance compared.

Directory/Package Structure

The intersection_control package is split into 4 sub-packages:

intersection_control.core provides the interfaces described here. Specifically, it defines the APIs for environment, algorithm, communication and performance_indication.

The 3 other packages contain concrete implementations of these interfaces:

  1. intersection_control.algorithms provides concrete implementations of the Algorithm API - namely Query-based intersection control

  2. intersection_control.environments provides concrete implementations of the Environment API - namely a SumoEnvironment

  3. intersection_control.communication provides concrete implementations of the Communication API - namely a DistanceBasedUnit

IntersectionControl
├── docs  # Documentation images and files
├── intersection_control  # The main source code package
│   ├── core  # Defines all interfaces and defines the component structure
│   │   ├── environment  # Provides an interface for any environment to implement
│   │   │   ├── environment.py  # Defines the base Environment class
│   │   │   ├── intersectiont_handler.py  # Defines the base IntersectionHandler class 
│   │   │   └── vehicle_handler.py  # Defines the base VehicleHandler class
│   │   ├── algorithm
│   │   │   ├── vehicle.py  # Defines the base Vehicle class
│   │   │   └── intersection_manager.py  # Defines the base IntersectionManager class
│   │   ├── communication.py  # Provides an interface for communication - V2V or V2I is possible. Specifically, defines the base MessagingUnit class
│   │   └── performance_indication.py  # Defines the base PerformanceIndicator class (Not yet implemented)
│   ├── algorithms  # A collection of intersection control algorithm implementations (for now only QBIM). These are implementations of core.Vehicle and core.IntersectionManager
│   ├── environments  # A collection of environment implementations (for now only SUMO). These are implementations of core.Environment
│   └── communication  # A collection of communication implementations (for now only DistanceBasedUnit). These are implementations of core.MessagingUnit
├── test  # unit tests for various components
└── misc  # Miscellaneous stand-alone scripts and experiments

Environment

The Environment API is defined in intersection_control.core.environment and consists of three components:

Environment API Structure

The main Environment class is what any intersection control algorithm will interact with, and will provide methods for retrieving general information about the environment, such as the current time, any new vehicles which have arrived in the environment etc. It also provides a step() method, which should advance the state of the environment by a time step. In a simulated environment, this will consist of advancing the simulation state, and in a physical environment this could consist of time.sleep()-ing for a few milliseconds.

Additionally, the Environment class provides access to both a VehicleHandler and IntersectionHandler object (through its intersections and vehicles properties) which provide more specialised behaviour for retrieving and modifying the state of vehicles and intersections respectively.

Implementing your own environment

Creating a new environment to test intersection control algorithms in would involve subclassing these three components and providing their implementations. One such implementation which is provided by the library is intersection_control.environments.SumoEnvironment. Some more information about implementing your own environment can be found in the Implementing an intersection environment section

Algorithm

The Algorithm API is defined in intersection_control.core.algorithm and consists of the Vehicle and IntersectionManager components:

Algorithm API Structure

As shown in the diagram, both the Vehicle and IntersectionManager hold a reference to the environment and are able to interact with it in order to retrieve or modify the state of the environment.

The base Vehicle class already implements some trivial methods, such as get_speed() simply by calling the corresponding method on the environment object with the corresponding vehicle_id:

def get_speed(self) -> float:
    return self.environment.vehicles.get_speed(self.vehicle_id)

The base IntersectionManager class also implements a set of similarly trivial methods which call into the environment. These are simply convenience methods which make algorithm implementations clearer:

# i.e.
self.get_speed()
# instead of:
self.environment.get_speed(self.vehicle_id)

Communication

As well as information from the environment, intersection control algorithms have at their disposal a means of both V2V (vehicle-to-vehicle) and V2I (vehicle-to-infrastructure - in this case IntersectionManager) communication. This is achieved through the Communication API which consists of Messages and MessagingUnits:

Communication API

In order to keep it as general and as simple as possible, the Message class only has two attributes: sender and contents. Here, contents is a python dict, which is extremely general and could be used to implement any sort of messaging protocol.

Messages are exchanged by MessagingUnits using the four methods in the above diagram.

This communication API was designed to be general enough to implement any type of communication mechanisms and protocols. For example, the implementation of a MessagingUnit could be backed by a powerful network simulator such as Omnet++.

A reasonably simple concrete implementation of a distance-based MessagingUnit (where the discoverability of other communication units is based on distance) can be found in intersection_control.communication.DistanceBasedUnit.

Vehicles and IntersectionManagers can then make use of MessagingUnits to communicate:

# In Vehicle class
def __init__(self, vehicle_id: str, environment: Environment):
    # ...
    self.messaging_unit = DistanceBasedUnit(self.get_id(), 50, self.get_position)
    # ...


def step(self):
    # ...
    # Broadcast current speed to all other units in range
    self.messaging_unit.broadcast(Message(self.messaging_unit.address, {
        "speed": self.get_speed(),
        # ...
    }))

Implementing your own algorithm

Implementing an intersection control algorithm then consists of providing an implementation for Vehicle.step() and IntersectionManager.step(), which you can assume will be called repeatedly after a small delta. One such implementation which is provided by the library is intersection_control.algorithms.qb_im - which is a query-based intersection control approach inspired by the well-known paper by Dresner and Stone: A Multiagent Approach to Autonomous Intersection Management. For more information on implementing your own intersection control algorithm, refer to the documentation section Implementing an intersection control algorithm