The world’s leading publication for data science, AI, and ML professionals.

Traffic Intersection Simulation using Pygame, Part 3

This series of articles contains a step-by-step guide to develop a traffic intersection simulation from scratch using Pygame.

What features are we adding?

In this article, we will be further adding some more features to the simulation developed in my previous article. The updated simulation will display the count of vehicles that have crossed the intersection for each direction, show the time elapsed since the start of the simulation, enable setting simulation duration, print the signal timers on the terminal every second for analysis, and print some statistics like direction-wise vehicle counts, total vehicles, and simulation time at the end of the simulation. These statistics and timers can then be used in Modelling Problems such as study of inter-arrival times, waiting times, & turnaround times, Data Analysis tasks such as Traffic Data Analysis & Traffic Signal Performance Analysis, and AI applications such as Adaptive Traffic Light Systems & V2V Communication for Smart Traffic Control. The video below shows the final output of the simulation we will be building.

Setting up

We are starting from where we left off in the previous article. Follow the steps in the article to set up the environment and build the simulation, which looks something like this. In this article, we will be modifying the simulation to include the aforementioned additional features. You can find the source code for the simulation along with setup instructions here.

Coding

To code the additional functionalities into our existing simulation, we need to add some new variables, define some new functions, and modify some of the existing functions as well.

Importing required libraries

Only one additional library needs to be imported, which is ‘os’.

import os

Defining variables

We need to define some new variables to implement our desired functionalities.

timeElapsed = 0
simulationTime = 300
timeElapsedCoods = (1100,50)
vehicleCountTexts = ["0", "0", "0", "0"]
vehicleCountCoods = [(480,210),(880,210),(880,550),(480,550)]

The timeElapsed variable stores the value of time elapsed since the beginning of the simulation and is initially set to 0. The simulationTime variable represents the simulation duration in seconds, so a value of 300 means 300/60 i.e. 5 minutes. vehicleCountTexts represent the count of vehicles that have crossed the intersection moving in the direction [right, down, left, up]. timeElapsedCoods and vehicleCountCoods represent the coordinates where timeElapsed and vehicleCountTexts will be rendered on the screen.

There are no changes to be made in the TrafficSignal and Vehicle class.

printStatus() function

This function prints the timer values of all 4 signals every second on the terminal. This function enables us to inspect what is happening behind the scenes in the simulation and analyze the timer values closely.

def printStatus():
    for i in range(0, 4):
        if(signals[i] != None):
            if(i==currentGreen):
                if(currentYellow==0):
                    print(" GREEN TS",i+1,"-> r:",signals[i].red," y:",signals[i].yellow," g:",signals[i].green)
                else:
                    print("YELLOW TS",i+1,"-> r:",signals[i].red," y:",signals[i].yellow," g:",signals[i].green)
            else:
                print("   RED TS",i+1,"-> r:",signals[i].red," y:",signals[i].yellow," g:",signals[i].green)
    print()

The timers are printed on the terminal, as shown in the video below. The format is as follows: SignalColor SignalNumber → r: RedTimer y: YellowTimer g: GreenTimer, where SignalNumber starts from top left and moves to bottom left, clockwise.

repeat() function

As we want to print the timers on the terminal every second, we call the printStatus() function within the while loops of the repeat function(), as shown below.

def repeat():
    global currentGreen, currentYellow, nextGreen
    while(signals[currentGreen].green>0):
        printStatus()
        updateValues()
        time.sleep(1)
    currentYellow = 1   
    for i in range(0,3):
        for vehicle in vehicles[directionNumbers[currentGreen]][i]:
            vehicle.stop=defaultStop[directionNumbers[currentGreen]]
    while(signals[currentGreen].yellow>0):  
        printStatus()
        updateValues()
        time.sleep(1)
    currentYellow = 0  
    minTime = randomGreenSignalTimerRange[0]
    maxTime = randomGreenSignalTimerRange[1]
    if(randomGreenSignalTimer):
        signals[currentGreen].green=random.randint(minTime, maxTime)
    else:
        signals[currentGreen].green = defaultGreen[currentGreen]
    signals[currentGreen].yellow = defaultYellow
    signals[currentGreen].red = defaultRed
    currentGreen = nextGreen 
    nextGreen = (currentGreen+1)%noOfSignals
    signals[nextGreen].red = signals[currentGreen].yellow+signals[currentGreen].green
    repeat()

showStats() function

This function prints the direction-wise vehicle counts as well as cumulative statistics like total vehicles crossing the intersection from all directions and the total time elapsed at the end of the simulation, either when we quit the simulation or when the simulation terminates by itself when timeElapsed is equal to simulationTime.

def showStats():
    totalVehicles = 0
    print('Direction-wise Vehicle Counts')
    for i in range(0,4):
        if(signals[i]!=None):
            print('Direction',i+1,':',vehicles[directionNumbers[i]]['crossed'])
            totalVehicles += vehicles[directionNumbers[i]]['crossed']
    print('Total vehicles passed:',totalVehicles)
    print('Total time:',timeElapsed)
Stats printed on terminal when simulation ends
Stats printed on terminal when simulation ends

simTime() function

This function is responsible for updating the timeElapsed variable every second and terminating the simulation when timeElapsed is equal to simulationTime. As we can see below, showStats() is called before exiting.

def simTime():
    global timeElapsed, simulationTime
    while(True):
        timeElapsed += 1
        time.sleep(1)
        if(timeElapsed==simulationTime):
            showStats()
            os._exit(1)

Main class

We need to make several additions to the Main class. First, we need to create a new thread for the simTime() function, which updates the timeElapsed every second (line 23–25). Second, we need to call showStats() before exiting the simulation (line 32). Third, we need to add code to display the vehicle counts and the time elapsed on the simulation screen (line 55–63). The rest of the Main class remains the same.

Running the code

Time to see the results. Fire up a cmd/terminal and run the command:

$ python simulation.py
Snapshot of final simulation output showing vehicle counts beside each signal & time elapsed at the top right (Image by Author)
Snapshot of final simulation output showing vehicle counts beside each signal & time elapsed at the top right (Image by Author)

And now we have our final simulation! We have added some statistics and analytical features to our simulation – vehicle counts, time elapsed, timers printed on terminal, cumulative statistics at the end of the simulation, and the ability to set simulation end time. These statistics, timers, and logs can be useful in Modelling Problems, Data Analysis tasks, and AI applications. They can also help in effective debugging while customizing the simulation according to your application.

Source code: https://github.com/mihir-m-gandhi/Traffic-Intersection-Simulation-with-Stats


This is the third part in a series of articles:

This simulation was developed as part of a research project titled ‘Smart Control of Traffic Lights using Artificial Intelligence‘. Check out its demonstration video [here](https://ieeexplore.ieee.org/document/9358334). This research work was presented at IEEE International Conference on Recent Advances and Innovations in Engineering (ICRAIE) 2020 and published in IEEE Xplore. Read the paper here.

Special thanks to Darshan Gandhi and Jaineel Shah for proofreading all the articles in this series.

Thanks for reading! I hope this article was helpful. If you have any doubts or need further clarification, feel free to reach out to me on LinkedIn.


Related Articles