I put this project together as a simple Python coding exercise on a Raspberry Pi for 12 - 15 year old students but it can make a good first Raspberry Pi project for anyone wanting to learn about GPIOs.
Initially it was constructed on a solderless breadboard but later I built the model for an open evening and for students coming later. I give only outline instructions for building the model as how you do it will depend on the materials, tools and skills you have available.
When completed, the ultrasonic range finder module detects a "pedestrian" approaching the crossing. If they stay within range for 3 seconds it follows the sequence of a standard British Pelican crossing: the traffic signal goes from green to amber and to red, and then the pedestrian signal changes from wait to cross and a sounder starts to beep. It remains like that for long enough for the pedestrian to cross the road, then the beeper stops, and for a few more seconds the amber and cross signals flash together. The pedestrian signal then returns to wait and the traffic signal to green.
I provide the students with a skeleton Python program which imports the necessary libraries, defines a function for measuring distance with the ultrasonic module, initialises the GPIO pins and tests the LEDs and the beeper. I also provide them with a flow chart which they are then required to implement as Python code.
I suggest that the exercise is done in two parts since the beeping and flashing phase is a little more complicated. In fact, as I show, it can be implemented as a very simple state machine with just one state variables. (The idea of a state machine is an extremely powerful programming concept and a good one to introduce students to.)
Step 1: What You Will Need
First of all, you will need a Raspberry Pi (any model will do equally well) with a power supply and an SDCard set up with Raspian. You will also need a screen, keyboard and mouse, or you can run it "headless" from a PC as I much prefer as it saves fiddling around with cables and the inconvenience of the extra peripherals. There are plenty of instructions online for setting up a Raspberry Pi to run headless.
Whether you build the model or build it on a breadboard you will also need:
- HC-SR04 ultrasonic range finder
- Piezo-electric sounder
- 3 5mm red LEDs
- 3 5mm green LEDs
- 2 5mm amber LEDs
- 1 330Ω resistor
- 1 470Ω resistor
5 220Ω resistors (or a selection between 100Ω and 820Ω in order to equalise the LED brightnesses)
(You can use one less of each colour LED on a breadboard. on the model I have red, amber and green LEDs facing in both traffic directions.)
Step 2: Breadboard Layout
If you decide to go straight for the model, skip this step.
If you are using a breadboard you will need the breadboard itself (a half-size 400 point one will do) and a set of male to male and male to female jumper wires.
Wire up the breadboard exactly as shown.
Note that the piezo sounder must be connected the right way round. The lead shown red in the diagram will be marked with a plus sign.
The LEDs, too, must be connected the right way round. The shorter lead must be adjacent to the resistor. (On the breadboard, you only need 2 red, 2 green and 1 amber LED.)
The ultrasonic range finder can be plugged directly into the breadboard with the transducers facing outwards. (The drawing packaged didn't allow me to show it like that.)
For convenience, the 5 LED series resistors can all be 220Ω or 330Ω - any value in the hundreds of ohms will do, but the brightnesses of the LEDs may differ considerably, depending on the LEDs you use. You can experiment with different values (not less than 100Ω) if you want to equalise their brightnesses. Note, though, that it's important you don't change the values of the other 2 resistors adjacent to the ultrasonic range finder.
Double-check the wiring before applying power to the Raspberry Pi. Better still, triple-check it. A mistake could damage the Pi.
Step 3: Building the Model
If you are going to build the model you will need:
- A 40-way GPIO ribbon cable (or 26-way for the original Pi model A or B),
- A 2x26 way pin header,
- 2 4-way pin header socket strips
- Connecting wire
as well as the materials for the model itself.
I built mine on a piece of shiplap I happened to have left over from repairs to the garden shed but any suitable piece of wood will do. For the traffic light post I used a piece of 6mm carbon fibre tube (left over from kite making) but you could use fibreglass or aluminium tube.
The top of the traffic light is the trickiest to make. I cut a piece of square section wood, cut 3 5mm holes through it one way for the traffic indicators and 2 holes at right angles for the pedestrian lights. I then used a router to make it into a U-section (with the 3 holes on the 2 sides and the 2 holes on the bottom of the U) so that I could fit the LEDs from inside and wire them up before blocking the opening with another piece of wood glued in place. If the wood splits, as is likely, you can glue it together with PVA glue.
You might well prefer to use a piece of square or U-section nylon or acrylic.
Fit the red, amber and green LEDs to the three holes in each side for the traffic indicators, and the red and green pedestrian indicators in the two holes in the bottom of the U-section. The longer leads of all 8 LEDS (which you will have had to shorten) must be soldered together. The other leads of each pair of red, amber and green traffic signals must each be soldered together. These 3 connections, the 2 remaining leads of the pedestrian indicators, and the 8 commoned leads can be connected to the rest of the circuit with a piece of 6-way rainbow ribbon cable fed down the tube used as the post. This ribbon can be fed under the base to the circuit board holding the resistors, the beeper and the ultrasonic range finder as shown.
I firstly painted the top of the board with grey aluminium paint, and then painted the roadway black, leaving a grey border representing the pavement. Finally, I added the road markings by hand with a fine paint brush. The carbon fibre tube for the post was already black but you'll have to paint it if you use some other material. I painted the top black, then added the white stripes to the post.
The post simply slots into a hole in the base so that it can be lifted out and laid flat for storage.
Step 4: The Circuit Board
The photo shows how I mounted the components but you can use whatever method you like if you're comfortable simply following the circuit diagram, perhaps if you construct the model differently.
For the breadboard it doesn't really matter if the LEDs are different brightnesses but the model looks better if they are all similar. You may well find (as I did) that the green LEDs are much brighter than the others, which I corrected by using 100Ω resistors for the red and amber, and 470Ω for the green. You can experiment with different values between 100Ω and 820Ω.
To follow my construction method, from a 64x96mm piece of stripboard (or whatever you have lying around) cut two pieces, one with 15 tracks and 19 holes along the lengths of the tracks (or larger), and the other with 14 tracks and each track 4 holes long. This is big enough for a 26-pin header which you can connect to any model of Raspberry Pi. However, if you know you will never be using an original Pi Model A or B with only 26 GPIO pins you can optionally use a 40-pin header. For this, the larger piece of stripboard must be 22 tracks wide.
On the larger piece, cut 13 tracks as shown by the 3 red bars (or 20 tracks if you're using a 40-pin header). The cut nearest the edge needs to be between two rows of holes so that the pin strip can still be soldered to the copper either side of the cut. The other two cuts are much less critical. For each, use a craft knife and a steel rule to score two cuts then lift the copper between the cuts.
Mount the pin header (on the other side of the board) astride the cut nearest the edge, and solder all the pins.
Solder all the resistors in place and solder the two 4-way pin header sockets to the smaller board as shown. (This will be glued in place later.)
The wiring would be difficult to show in a single diagram so I've split it into three. First, solder all the wires in place shown in blue on the first wiring diagram. On the second diagram, these are shown semi-transparent. Solder in place the wires shown in dark blue on this diagram. The third diagram shows all the wires so far semi-transparent and the remaining wires to be soldered. Before proceeding, check all your wiring.
You have now finished with the copper side of the smaller board and so you can glue it in place onto the larger board. I recommend using a hot-melt glue gun as this will hold it strongly but not so strongly that you can't get it off if something doesn't work.
The last diagram shows where the wires from the Red, Amber, Green, Wait and Cross LEDs must be soldered. The common return connection from all the LEDs is shown in black as Gnd.
The whole circuit board can be blued to the base of the model with hot-melt glue.
Step 5: Putting It Together
If you have an original Raspberry Pi model A or B with 26 GPIO pins you will need a 26 way GPIO ribbon to connect to the model. This won't fit on a Raspberry Pi with 40 GPIO pins, for which you will need a 40 way ribbon. In this case, if you've used a 26 way pin header make sure you connect the Pin 1 end of the ribbon to the pin header, allowing the maximum overhang of the ribbon at the other end of the pin header.
Step 6: Coding It
I shan't describe how to enter, edit and run a Python program on a Raspberry Pi - there are plenty of resources to tell you that.
First of all, download and run the program pelican.py. This tests all the LEDs, the beeper and the ultrasonic range finder, and exits on detection of a range of less than 10cm.
Now examine the code. Don't worry about the def measure() or def measure_average(), but see how the GPIOs are given meaningful names (TRIGGER and ECHO relate to the ultrasonic module), set appropriately as inputs or outputs, set to initial values and then tested.
At the end of this, you will see time.sleep(1) # Replace this with your code!
Download and look at the flowchart. This is in 2 parts. The sequence to follow when the pedestrian can cross is a little more complicated, so to start with, can code the ellipse "Flash and beep for 8 seconds" simply as time.sleep(8).
The secret of coding is to code a little then test a little. When it doesn't work, you then know that the problem must be in the little bit you've just coded.
When you've got that much working, you can code up the second part of the flowchart in place of the time.sleep(8). This works as a "state machine". Time is divided up into 64 states, each lasting 1/8 of a second. The table at the bottom of the flowchart shows which LEDs are to be lit and whether the beeper is to beep in each state, and the flowchart shows how to code that up with a sequence of conditional statements.
The complete worked example is given as the file pelican-ans.py. If you're a teacher, you'll want to hide that away from the kids!
Step 7: Conclusion
The crossing sequence is an example of a very simple state machine. We could have coded the whole project as a state machine. State machines are used for all sorts of things which go through a number of different "states", such as washing machines, vending machines and lifts, and button pushes or sensors will often move them from one state to another, as well as the passage of time. Often, they might move from state A to state B if someone pushes a button, or to state C if a sensor detects something, or to state D if nothing else has happened after a certain length of time. We represented our state machine by a simple table, but more often you'd represent each state by a labelled ellipse, with arrows showing how it moves between state and what stimuli move it from one state to another.