raspberry pi, technology, iot, python, coding,

Playing with Raspberry Pi and Python: Traffic lights

Simon Prickett Simon Prickett 8 mins read
Playing with Raspberry Pi and Python: Traffic lights

I’ve recently been doing some simple Python programming with the Raspberry Pi and a set of traffic light LEDs that connect to it. In this post I’ll look at setting up a Pi to drive the lights. In future posts, I’ll explore some other programming / devops concepts using the base setup described here.

I subsequently wrote versions of this article describing the same process using the Go programming language (here), Swift (here), Java (here), C (here), Bash scripting (here), Node.js (here) and also Node RED (here). Most recently I looked at this for Arduino, Rust and .NET/C# too.

Let’s go…

Shopping List

To try this out, you will need the following (links here mostly go to Adafruit, UK customers may want to consider Pimoroni as a UK based alternative, Amazon has most if not all of this stuff too):

  • A Raspberry Pi (I’ll use the Pi 3 Model B here, but any model with GPIO pins will work — if you want to use the Pi Zero you’ll need to solder some headers onto it). I’m going to assume you have a Pi 2 or 3 with 40 pins
  • A power supply for your Pi (Raspberry Pi 4 requires a different USB C power supply)
  • Some sort of case is probably a good idea to protect the Pi (but you’ll need to leave the lid off to expose the GPIO pins to connect your lights to)
  • A Micro SD card to install your operating system on (or get one with the OS pre-installed). If you want to install the operating system yourself, you’ll need a Mac, PC, Linux machine with an SD card reader
  • A set of traffic lights from Low Voltage Labs (the two pack is good value)
  • Any USB keyboard to type on the Pi, you might want a mouse too
  • Any HDMI display to show output from the Pi

Attaching the Traffic Lights

The Low Voltage Labs traffic lights connect to the Pi using four pins. One of these needs to be ground, the other three being actual GPIO pins used to control each of the individual LEDs.

Low Voltage Labs Traffic Lights
Low Voltage Labs Traffic Lights.

Before powering up the Pi, attach the traffic lights so that the pins connect to the GPIO pins highlighted in red:

GPIO Pin Diagram
GPIO Pin Diagram.

When you’re done it’s going to look something like this… (an easy way to make sure you have it right is to locate the lights on the left hand row of pins as you look at the Pi with the USB ports to the bottom, then count 8 pins up and attach the lights there).

GPIO pins with lights attached.
GPIO pins with lights attached.
GPIO pins with lights attached.
GPIO pins with lights attached.

Don’t turn the Pi on yet, you’ll need to prepare an operating system image for it first…

Operating System Setup

Install the Raspberry Pi OS which can be downloaded from the official Raspberry Pi site. You can also find an excellent installation guide there should you need help.

Once you’ve got the operating system installed, make sure you can login, and have a working wired or wifi internet connection.

Enjoying this article? Please consider buying me a coffee on Ko-Fi.
Your support helps to fund future projects!

Now you can go ahead and start turning lights on and off!

Programming the Traffic Lights

We’ll use the Python programming language to make the lights work. First, you need to install a couple of extra software packages needed to allow you to download my sample code, and to give Python access to the GPIO pins on the Pi. Enter the following at the command line:

$ sudo apt-get install python-dev python-rpi.gpio git

Answer “Y” when asked if you want to install additional packages.

Now get the code from my GitHub repo:

$ git clone https://github.com/simonprickett/pitrafficlights.git
$ cd pitrafficlights

You should now be able to test the lights:

$ python basicdemo.py

And if they are connected to the correct GPIO pins, they should start to flash on and off in the UK traffic light pattern (red, red + amber, green, amber, red). If you don’t see anything, you might need to make sure that you have the lights connected to the right pins.

Lights installed and working.
Lights installed and working.

How it Works

The code for this is very simple. It starts by importing the RPi.GPIO library, plus time which gives us a timed wait function, signal that allows us to trap the signal sent when the user tries to quit the program and sys so we can send an appropriate exit signal back to the operating system before terminating.

import RPi.GPIO as GPIO
import time
import signal
import sys

Next we put the GPIO library into “BCM” or “Broadcom” mode (so we can refer to pins by the same numbers as are labeled with in GPIO pin diagrams), and sets pins 9 (red LED), 10 (amber LED) and 11 (green LED) to be used as outputs:

# Setup
GPIO.setup(9, GPIO.OUT)
GPIO.setup(10, GPIO.OUT)
GPIO.setup(11, GPIO.OUT)

The main part of the program will run in an infinite loop until the user exits it by stopping Python with Ctrl-C. It’s a good idea to add a handler function that will run whenever this happens, so that we can turn off all the lights prior to exiting (thus ensuring they’ll also be in the state we expect them to start in the next time the program is run):

# Turn off all lights when user ends demo
def allLightsOff(signal, frame):
    GPIO.output(9, False)
    GPIO.output(10, False)
    GPIO.output(11, False)
signal.signal(signal.SIGINT, allLightsOff)

The main body of the code then consists of an infinite while loop that turns on the red light (pin 9), waits, turns on the amber light (pin 10), waits, then cycles through the rest of the traffic light pattern by turning the appropriate LEDs on and off:

# Loop forever
while True: 
    # Red 
    GPIO.output(9, True) 
    # Red and amber 
    GPIO.output(10, True) 
    # Green 
    GPIO.output(9, False) 
    GPIO.output(10, False) 
    GPIO.output(11, True) 
    # Amber 
    GPIO.output(11, False) 
    GPIO.output(10, True) 
    # Amber off (red comes on at top of loop) 
    GPIO.output(10, False)

When Control-C is pressed an interrupt signal signal.SIGINT is sent. This is handled by the allLightsOff function that switches all the lights off, tidies up the GPIO library state and exits cleanly back to the operating system.

Next Steps

In the next post in this series, I’ll look at how to drive the lights in either the UK or USA patterns of operation then we’ll move on to other ways to structure and deploy the code.

I’d love to hear what you’re up to with the Raspberry Pi — get in touch via the Contact page. If you enjoyed this article, please share it far and wide!

Simon Prickett
Written by Simon Prickett
Hugely Experienced Developer Relations Leader.