Playing with Raspberry Pi: Traffic Lights with a Finite State Machine

Simon Prickett
Jun 5, 2017 · 4 min read

This is the third article in our series where we’re playing with the Low Voltage Labs LED Traffic Lights using Python on the Raspberry Pi. In the first article, we set up a basic traffic light pattern, then enhanced this in the second article to run the lights in either the UK or USA patterns according to the value of an environment variable.

This time, we’ll look at restructuring the code to use a Finite State Machine, so let’s go…

A Finite State Machine (sometimes known as a Finite State Automaton) is a computing model of a theoretical machine which can be in exactly one state at a given time. The machine will have a known (finite) number of states, with each state having one or more transitions to a new state. Modeling traffic lights is a simple example, but one that is often used in teaching materials to introduce the concept to students.

In order to figure out what our states and transitions are, we can draw out a basic state diagram to visualize them:

From the diagram, we can see that the traffic lights have five distinct states, each with a single transition to the next state, and that the state machine enters an infinite loop:

  • INITIALIZING: set up and turn off all the lights
  • RED: turn on the red light only, wait, then transition to REDAMBER if using the UK pattern, or GREEN if using the USA pattern. This is the only state in which we have to make a decision about the next state to transition to
  • REDAMBER: turn on the red and amber lights only, wait, then transition to GREEN
  • GREEN: turn on the green light only, wait, then transition to AMBER
  • AMBER: turn on the amber light only, wait, then transition to RED

To make our code read better, we’ll introduce a couple of convenience classes… the first allows us to name all the states:

class TrafficLightStates:
INITIALIZING = 1
RED = 2
REDAMBER = 3
GREEN = 4
AMBER = 5

And another allows us to give the GPIO pin numbers for each light on the traffic lights more meaningful names:

class TrafficLightLEDs:
RED = 9
AMBER = 10
GREEN = 11

There are many ways we could implement a Finite State Machine, and there are even libraries for Python and many other languages specifically designed to help with this. For example, Transitions is a Finite State Machine framework for Python.

In this case, we have a very simple set of states and transitions, so we can just use an if / elif / elsestatement to build out the Finite State Machine. This wouldn’t scale well for more complex models, but is fine for traffic lights.

First up, we need to keep track of which state the machine is in at any given time… we’ll do that with a variable currentState. At the beginning, this is set to the first state that the machine enters when “booted”:

currentState = TrafficLightStates.INITIALIZING

Then the bulk of our code becomes an infinite loop, in which we:

  • Check the value of currentState
  • Perform actions appropriate for the current state (turn LEDs on and off etc)
  • Set the value of currentStateto whatever the next state in our state diagram is
  • Go around the loop again

If we apply the above rules to each of our states, we end up with:

while True:
if (currentState == TrafficLightStates.INITIALIZING):
if ('TRAFFIC_LIGHT_COUNTRY' in os.environ) and (os.environ['TRAFFIC_LIGHT_COUNTRY'] in ['UK', 'USA']):
pattern = os.environ['TRAFFIC_LIGHT_COUNTRY'].lower()
else:
print('TRAFFIC_LIGHT_COUNTRY should be set to UK or USA')
sys.exit(1)
# Setup Hardware
GPIO.setmode(GPIO.BCM)
GPIO.setup(TrafficLightLEDs.RED, GPIO.OUT)
GPIO.setup(TrafficLightLEDs.AMBER, GPIO.OUT)
GPIO.setup(TrafficLightLEDs.GREEN, GPIO.OUT)
currentState = TrafficLightStates.RED elif (currentState == TrafficLightStates.RED):
GPIO.output(TrafficLightLEDs.RED, True)
GPIO.output(TrafficLightLEDs.AMBER, False)
GPIO.output(TrafficLightLEDs.GREEN, False)
time.sleep(3)
if pattern == 'uk':
currentState = TrafficLightStates.REDAMBER
else:
currentState = TrafficLightStates.GREEN
elif (currentState == TrafficLightStates.REDAMBER):
GPIO.output(TrafficLightLEDs.RED, True)
GPIO.output(TrafficLightLEDs.AMBER, True)
GPIO.output(TrafficLightLEDs.GREEN, False)
time.sleep(1)
currentState = TrafficLightStates.GREEN elif (currentState == TrafficLightStates.GREEN):
GPIO.output(TrafficLightLEDs.RED, False)
GPIO.output(TrafficLightLEDs.AMBER, False)
GPIO.output(TrafficLightLEDs.GREEN, True)
time.sleep(5)

currentState = TrafficLightStates.AMBER
elif (currentState == TrafficLightStates.AMBER):
GPIO.output(TrafficLightLEDs.RED, False)
GPIO.output(TrafficLightLEDs.AMBER, True)
GPIO.output(TrafficLightLEDs.GREEN, False)

if pattern == 'uk':
time.sleep(2)
else:
time.sleep(3)
currentState = TrafficLightStates.RED
else:
print 'Invalid state!'

To make each state self-contained and not dependent on a prior state, we’ve added code to explicitly turn each LED to the required on or off status for each state. This means that should we choose to run the lights in a different order, we just change the code that sets currentState, without changing the actual implementation of a state.

When set to operate using the UK pattern, the lights will cycle as follows:

And with the USA pattern, expect:

Next Steps

In this article, we changed the way that the traffic light code works to incorporate a Finite State Machine. Whilst this is a very simple example, Finite State Machines have a great many uses in programming — you’ll find them used in compiler implementations, game development, and in some of the C language firmware for connected sensors that we’re building at Conectric.

I’d love to hear what you’re up to with the Raspberry Pi — find me on Twitter or via the responses here. If you enjoyed this article, please hit the ❤ and share it far and wide!

Conectric Networks

Conectric Networks eliminates wasted energy consumption…

Simon Prickett

Written by

Software Professional, builder of things with Arduino and Raspberry Pi.

Conectric Networks

Conectric Networks eliminates wasted energy consumption from heating and air conditioning in hotel buildings using our patented occupancy monitoring and HVAC control system.

Simon Prickett

Written by

Software Professional, builder of things with Arduino and Raspberry Pi.

Conectric Networks

Conectric Networks eliminates wasted energy consumption from heating and air conditioning in hotel buildings using our patented occupancy monitoring and HVAC control system.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store