How to build a traffic light

My seven year old asked me how does a traffic light work. Before explaining too much we put some LEDs and wires together and did a hands-on tutorial. Finally we had a pedestrian crossing with a push button controlled by an app - of course - running dockerized on a Raspberry Pi 3.

Traffic light wiring

The hardware

First we have to build the curcuit. To follow this tutorial you need these parts

The software

The application is written in Python and it is based on the blog post Raspberry PI Traffic Lights by Bob Rathbone. I have added some more LEDs and changed it to our local traffic light scheme. You can find the full source code on GitHub.

Defining the GPIO pins

Initializing the GPIO ports

At the beginning of the app we initialize the GPIO ports and turn off all LEDs. They may turned on from aborting a previous run.

Main loop

The main loop begins with green lights for the cars. In this state the button for the pedestrian crossing is checked.

Pedestrian crossing

After the button has been pressed the next code block just changes the LEDs for the cars to red, green for pedestrians and back again.

That completes the whole app. I could explain how a traffic light works and my daughter could play with it for a while. This could be the whole story, but as I’ve deployed my app with Docker there is another story behind the story.

Dockerize all the things

I want to save my work and make it reproducible for me and others. So beside putting the source code into a GitHub repo I also dockerized the application development and deployment. With the help of Docker and the Docker tools it is very easy to develop from eg. a MacBook.

Even after months and other projects it is easy to spin up that application again as there is a standardized way. There also is no need to backup the SD image and write down what you had to install on your Raspberry Pi.

Developing for RPi from a Mac

As shown in the diagram your Notebook should have the following tools installed.

I don’t get into the details on how to connect your Notebook with the Docker Engine on the Raspberry Pi. This is part of a previous blog post how to use docker-machine for that.

Dockerfile

To build the Docker image we need a Dockerfile. We use a Python base image and install the needed tools and dependencies. Then we add the application source code and define the command to execute.

docker-compose.yml

Docker Compose can be used to simplify running the container. With the docker-compose.yml we can document all the parameters needed to start the container. The file is versioned in Git so we do not forget how to run this container.

Developing the app

When you develop the app or want to modify the source code the Docker image has to be rebuilt with the new code. To do this just run this command

docker-compose build

Running the app

docker-compose up

If you want to stop the app again, just press CTRL+C. You may have to press it twice to kill the app.

Running permanently

You can run the application automatically by adding -d. The docker-compose.yml also sets the restart policy to always, so the container is starting right after booting the Raspberry Pi. This is very useful for such hardware projects which should start automatically after turning on your Pi.

docker-compose up -d

If you want to stop the app again, just use this command

docker-compose kill

Sharing the dockerized app

The advantage of using Docker is to easily share the dockerized app with others. As the developer of an app you just push the Docker image with to the Docker Hub. Others can pull this Docker image from there and run it without to know which tools and dependencies to install.

Developing for RPi from a Mac

Pushing the Docker image

docker images
docker tag dockerrpitrafficlight_trafficlight stefanscherer/rpi-traffic-light
docker push stefanscherer/rpi-traffic-light

The Docker image is send sent to the Docker Hub. My example is available as image stefanscherer/rpi-traffic-light.

Sharing with Others

If someone else wants to build the traffic light and run your application, she has to use this little modified docker-compose.yml to pull the published Docker image instead of building it herself.

version: '2'
services:
  trafficlight:
    image: stefanscherer/rpi-traffic-light
    devices:
      - "/dev/mem:/dev/mem"
    cap_add:
      - SYS_RAWIO
    restart: always

And then run the application with

docker-compose up -d

Or use the docker command with all the parameters

docker run --rm --cap-add SYS_RAWIO --device /dev/mem stefanscherer/rpi-traffic-light

This command pulls the Docker image from the Docker hub if it isn’t available locally on the Raspberry Pi. After that it runs a Docker container with the application.

In this way any app can be published in the same way, regardless the programming language used.

As always use the comments below to give us feedback and share it on Twitter or Facebook.

Stefan @stefscherer

comments powered by Disqus