• Search in book...
• Toggle Font Controls
© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2022
C. BellBeginning MicroPython with the Raspberry Pi Picohttps://doi.org/10.1007/978-1-4842-8135-2_7

# 7. Project: Pedestrian Crossing

(1)
Warsaw, VA, USA

Now that we’ve had a tutorial of how to design, wire, and implement a MicroPython project, let’s now look at a more advanced project. In this case, we will use some very basic components to learn further how to work with hardware. The hardware of choice for this project will be LEDs, resistors, and a button. A button is the most basic of sensors. That is, when the button is pressed, we can make our MicroPython code respond to that action.

Working with LEDs is perhaps more of a “Hello, World!” style project for hardware because turning LEDs on and off is easy, and except for figuring out what size of current limiting resistor is needed, wiring LEDs is also easy.

However, to make it more interesting and a bit of a challenge, we will be implementing a simulation. More specifically, we will implement a traffic light and a pedestrian walk button. The walk button is a button pedestrians can use to trigger the traffic signal to change and stop traffic so they can cross the street.

Simulation projects can be a lot of fun because we already have an idea of how it should work. For example, unless you’ve lived in a very rural area, you most likely have encountered a traffic signal at an intersection that included walk/don’t walk signs with a button. If you live in the city, you will have encountered these in various configurations. When a pedestrian (or bicyclist) presses the walk button, the traffic lights all cycle to red and the walk sign is illuminated. After some time (30 seconds or so), the walk sign flashes, and then about 15 seconds later, the walk signal cycles to don’t walk and the traffic signals resume their normal cycle.

Note

The word “cycle” refers to a set of states that are linear in action. Thus, cycle refers to the changing of one state to another.

## Overview

In this chapter, we will implement a traffic signal with a pedestrian walk button. This project works with LEDs, which allows us to see the state of our code as it executes. For the traffic light (also called a stoplight), we will use a red, yellow, and green LED to match the same colored lights on the traffic light. We will also use a red and yellow LED to correspond to the don’t walk (red) and walk (yellow) lights.

We will use a pushbutton (also called a momentary button) because it triggers (is on) only when pushed. When released, it is no longer triggered (is off). Trigger is the word used to describe the state of the button where triggered means the connections from one side of the button to another are connected (on). A button that remains triggered (latched) is called a latching button, which typically must be pressed again to turn off.

We will simulate the traffic light and walk signal by first turning on only the green traffic light LED and the red walk LED signal. This is the normal state we will use. When the button is pressed, the traffic light will cycle to yellow for a few seconds and then cycle to red. After a few seconds, the walk signal will cycle to yellow and after a few seconds will begin flashing. After a few more seconds, the walk signal will cycle back to red and the traffic light to green.

Now let’s see what components are needed for this project, and then we will see how to wire everything together.

## Required Components

Table 7-1 lists the components you will need in addition to your Pico and USB cable. Links to vendors are provided should you want to purchase the components. I include both value packages and single unit prices where available.
Table 7-1

Required Components

Component

Qty

Description

Cost

Red LED

2

Pack of 25

\$4.00

Single

\$0.35

www.sparkfun.com/products/9590

Yellow LED

2

Pack of 25

\$4.95

Single

\$0.35

www.sparkfun.com/products/9594

Green LED

1

Pack of 25

\$4.00

Single

\$0.35

www.sparkfun.com/products/9592

220 or 330 Ohm resistors

5

Variety Kit

\$7.95

www.sparkfun.com/products/10969

Pack of 25

\$0.75

Button

1

Momentary button, breadboard friendly (pack)

\$2.50

Single

\$0.50

www.sparkfun.com/products/9190

1

Prototyping board, full-sized

\$5.95

www.sparkfun.com/products/12615

\$5.95

Jumper wires

11

M/M jumper wires, 7" (set of 30)

\$2.25

https://www.sparkfun.com/products/11026

M/M jumper wires, 6" (set of 20)

\$1.95

You can purchase the components separately from Adafruit (adafruit.com), SparkFun (sparkfun.com), or any electronics store that carries electronic components. Costs shown are estimates and do not include any shipping costs.

Some components such as the LEDs and button can be found in a beginning electronics kit like those from the Parts Pal kit from Adafruit that we saw in Chapter 5. Other vendors may have similar kits. Buying basic components like LEDs, buttons, and resistors is much cheaper when bought in a kit.

Similarly, you can pick up a set of resistors of various sizes much cheaper than if you bought a few at a time. In fact, you most likely will find buying a small set of five or ten of each size resistor you will eventually need will be far more expensive than if you purchased a set. The set from SparkFun will provide you all the resistors you need for most projects.

Recall from Chapter 5 that LEDs require a current limiting resistor that reduces the current to safe levels for the LED. To determine what size resistor we need, we need to know several things about the LED. This data is available from the manufacturer who provides the data in the form of a data sheet or, in the case of commercially packaged products, lists the data on the package. The data we need includes the maximum voltage, the supply voltage (how many volts are coming to the LED), and the current rating of the LED.

For example, if I have an LED like the ones in the Adafruit Parts Pal, in this case a 5mm red LED, we find on Adafruit's website (www.adafruit.com/products/297) that the LED operates at 1.8–2.2V and 20mA of current. Let's say we want to use this with a 5V supply voltage. We can then take these values and plug them into this formula:
R = (Vcc-Vf)/I
Using more descriptive names for the variable, we get the following:
Resistor = (Volts_supply - Volts_forward) / Desired_current
Plugging our data in, we get this result. Note that we have mA so we must use the correct decimal value (divide by 1000).
Resistor = (5 – 1.8) / 0.020
= 3.2 / 0.020
= 160

Thus, we need a resistor of 160 Ohms. However, there is no resistor with that rating. When this happens, we use the next size up. For example, if you have only 220 or even 330 Ohm resistors, you can use those. The result will be the LEDs will not be as bright, but having a higher resistor is much safer than using one that is too small. Too much current and an LED will burn out.

Now, let’s see how to wire the components together.

## Set Up the Hardware

Before we look at the wiring, let’s review some tips for wiring components. The best way to wire components to your board is to use a breadboard. As we saw in Chapter 5, a breadboard allows us to plug our components in and use jumper wires to make the connections. In this project, we will use one jumper wire for ground from the Pico board to the breadboard power and ground rails (those that run along the top and bottom marked with a red line for power and blue or black for ground) and then jumpers on the breadboard to connect to the button. In fact, we will use the ground rail on one side of the breadboard to plug in one side of the LEDs.

The button works in either position so long as the pins are oriented with two legs on each side of the center trough. If you orient the button with the legs that can reach either side of the trough, it will be oriented correctly. If you get it off by 90 degrees, the button either will not work or will always be triggered. If you have any doubts, use a multimeter to test the continuity of the button connections. You should find the connections open when not pressed and closed when pressed.

The only component that is polarized is the LED (it has a positive and a negative leg). When you look at the LED, you will see one leg (pin) of the LED is longer than the other. This longer side is the positive side. We will plug the LEDs in so that the negative leg is plugged into the ground rail and the positive side is plugged into the main area of the breadboard. We then plug the resistor in to jump over the center trough connecting the resistor to the GPIO pin on the Pico. It doesn’t matter which direction you plug the resistor in – they will work both directions.

Table 7-2 shows the connections needed for this project. Traditionally, we use black for ground (negative) and red for power (positive) at a minimum, but you can use whatever color wires you want. We will start with physical pin 40 and work our way down to the lowest number pin used. As you will see in the drawing, this is working clockwise.
Table 7-2

Connections for the MicroPython Clock

Physical Pin

GPIO Num/Function

Connection

40

VBUS

37

GND

17

GP13

Resistor for red LED (stoplight)

16

GP12

Resistor for yellow LED (stoplight)

15

GP11

Resistor for green LED (stoplight)

12

GP9

Button side A (bottom)

11

GP8

Resistor for red LED (walk light)

10

GP7

Resistor for green LED (walk light)

N/A

Button side B (top)

N/A

All LED negative side

N/A

Resistor

All LED positive side

Wow, that’s a lot of connections! As we saw in Chapter 5, a breadboard allows us to plug our components in and use jumper wires to make the connections. This simplifies wiring the project and allows you to move things around if you need to make more room.

Caution

Never plug or unplug jumper wires when the project is powered on. You risk damaging your board or the components.

Figure 7-1 shows the wiring drawing for the pedestrian crossing project.

Once again, always make sure to double-check your connections before powering the board on. Now, let’s talk about the code we need to write. Don’t power on your board just yet – there is a fair amount of discussion needed before we’re ready to test the project.

## Write the Code

Now it’s time to write the code for our project. The code isn’t overly complicated, but it is a bit longer than the examples thus far. We will see how to write code to simulate the pedestrian crosswalk button and traffic light. We will need to monitor the button and, when pressed, cycle the lights as described earlier. We also need code to initialize the LEDs, setting them to off initially. We can write functions for monitoring the button and cycling the LEDs. We will use an interrupt to tie the function for the button to the hardware so that we can avoid using a polling loop.

### Imports

The imports for the project will require the Pin class from the machine library and the utime library. The following shows the imports for the project:
from machine import Pin
import utime

### Setup

The setup code for this project will need to initialize the button and LED instances and then turn off all the LEDs (as a precaution) and turn on the green stoplight LED and the red walk signal LED. Listing 7-1 shows the code for setup and initialization.
# Setup the button and LEDs
stoplight_red = Pin(13, Pin.OUT)
stoplight_yellow = Pin(12, Pin.OUT)
stoplight_green = Pin(11, Pin.OUT)
button = Pin(9, Pin.IN, Pin.PULL_DOWN)
pedestrian_red = Pin(8, Pin.OUT)
pedestrian_green = Pin(7, Pin.OUT)
# Setup lists for the LEDs
stoplight = [stoplight_red, stoplight_yellow, stoplight_green]
pedestrian_signal = [pedestrian_red, pedestrian_green]
# Turn off the LEDs
for led in stoplight:
led.off()
for led in pedestrian_signal:
led.off()
# Start with green stoplight and red pedestrian_signal
stoplight[2].on()
pedestrian_signal[0].on()
Listing 7-1

Setup and Initialization of the Button and LEDs

One thing to notice is how the button is initialized. This is a Pin object instance that is set up as an input (read), and the pull-up resistors are turned on. This allows the board to detect when the button is pressed because the value of the pin will be a positive value when the connection is made (the button is pressed).

Notice also I create a list that contains the LEDs for the stoplight and walk signal (named pedestrian_signal in the code). This is mostly for demonstration so you can see how to manage lists of class objects. As you can see, it makes it easier to call the same function for all the objects in the list using a loop. Take note of this technique as you will need it from time to time in other projects.

### Functions

There are two functions needed for this part of the project. First, we need a function to cycle through the lights. Second, we need a function to monitor the button press. Let’s look at the cycle light function.

We will name the cycle light function cycle_lights(). Recall we need to control how the lights change state. We do this with a specific cycle as described earlier. To recap, we call this function when we want to simulate changing the stoplight when the walk request button is pressed. Thus, this function will be called from the code for the button. Listing 7-2 shows the code for the cycle_lights() button. As you will see, the code is rather straightforward. The only tricky part may be the loop used to flash the yellow walk LED. Be sure to read through it so that you understand how it works.
# We need a method to cycle the stoplight and pedestrian_signal
#
# We toggle from green to yellow for 2 seconds
# then red for 20 seconds.
def cycle_lights():
# Go yellow.
stoplight[2].off()
stoplight[1].on()
# Wait 2 seconds
utime.sleep(2)
# Go red and turn on walk light
stoplight[1].off()
stoplight[0].on()
utime.sleep_ms(500)  # Give the pedestrian a chance to see it
pedestrian_signal[0].off()
pedestrian_signal[1].on()
# After 10 seconds, start blinking the walk light
utime.sleep(1)
for i in range(0,10):
pedestrian_signal[1].off()
utime.sleep_ms(500)
pedestrian_signal[1].on()
utime.sleep_ms(500)
# Stop=green, walk=red
pedestrian_signal[1].off()
pedestrian_signal[0].on()
utime.sleep_ms(500)  # Give the pedestrian a chance to see it
stoplight[0].off()
stoplight[2].on()
Listing 7-2

The cycle_lights() Function

We will name the button function button_pressed(). This function is used as a callback for the button press interrupt. Technically, we tell MicroPython to associate this method with the pin interrupt, but we will see that in a moment. However, there is another element to this function that requires explanation.

When we use a component like a button and the user (you) presses the button, the contacts in the button do not go from an off state to an on state instantaneously. There is a very small period where the value read is erratic. Thus, we cannot simply say “when the pin goes high” because the value read on the pin may “bounce” from low to high (or high to low) rapidly. This is called bouncing. We can overcome this artificially with code (as well as other techniques) – called debouncing.

In this case, we can check the value of the pin (button) over time and only “trigger” the button press if and only if the value remains stable during that time. The code for debouncing the pin is shown in Listing 7-3. Notice in the loop we wait for a value of 50. This is 50 milliseconds. If the trigger is long enough, we call the cycle_lights() function.
# Create callback for the button
def button_pressed(line):
cur_value = button.value()
active = 0
while (active < 50):
if button.value() != cur_value:
active += 1
else:
active = 0
utime.sleep_ms(1)
print("")
if active:
cycle_lights()
else:
print("False press")
Listing 7-3

The button_pressed() Function

Tip

For more information about debouncing and the techniques available to avoid it, see www.eng.utah.edu/~cs5780/debouncing.pdf.

Finally, we need to set up the button to call the button_pressed() function when the board detects the interrupt. The following sets the callback function using the interrupt setting for the button pin:
# Create an interrupt for the button
button.irq(trigger=Pin.IRQ_RISING, handler=button_pressed)
Now we’re all set to test the code. Go ahead and open a new file named pedestrian_crossing.py and enter the preceding code. Listing 7-4 shows the complete code for the project.
#
# Beginning MicroPython
#
# Chapter 07 – Pedestrian Crossing
#
# This example implements a Pedestrian Crossing Simulator
# controlling LEDs and button as input
#
# Dr. Charles Bell
#
# Import libraries
from machine import Pin
import utime
# Setup the button and LEDs
stoplight_red = Pin(13, Pin.OUT)
stoplight_yellow = Pin(12, Pin.OUT)
stoplight_green = Pin(11, Pin.OUT)
button = Pin(9, Pin.IN, Pin.PULL_DOWN)
pedestrian_red = Pin(8, Pin.OUT)
pedestrian_green = Pin(7, Pin.OUT)
# Setup lists for the LEDs
stoplight = [stoplight_red, stoplight_yellow, stoplight_green]
pedestrian_signal = [pedestrian_red, pedestrian_green]
# Turn off the LEDs
for led in stoplight:
led.off()
for led in pedestrian_signal:
led.off()
# Start with green stoplight and red pedestrian_signal
stoplight[2].on()
pedestrian_signal[0].on()
# We need a method to cycle the stoplight and pedestrian_signal
#
# We toggle from green to yellow for 2 seconds
# then red for 20 seconds.
def cycle_lights():
# Go yellow.
stoplight[2].off()
stoplight[1].on()
# Wait 2 seconds
utime.sleep(2)
# Go red and turn on walk light
stoplight[1].off()
stoplight[0].on()
utime.sleep_ms(500)  # Give the pedestrian a chance to see it
pedestrian_signal[0].off()
pedestrian_signal[1].on()
# After 10 seconds, start blinking the walk light
utime.sleep(1)
for i in range(0,10):
pedestrian_signal[1].off()
utime.sleep_ms(500)
pedestrian_signal[1].on()
utime.sleep_ms(500)
# Stop=green, walk=red
pedestrian_signal[1].off()
pedestrian_signal[0].on()
utime.sleep_ms(500)  # Give the pedestrian a chance to see it
stoplight[0].off()
stoplight[2].on()
# Create callback for the button
def button_pressed(line):
cur_value = button.value()
active = 0
while (active < 50):
if button.value() != cur_value:
active += 1
else:
active = 0
utime.sleep_ms(1)
print("")
if active:
cycle_lights()
else:
print("False press")
# Create an interrupt for the button
button.irq(trigger=Pin.IRQ_RISING, handler=button_pressed)
Listing 7-4

Pedestrian Crossing Simulation Code

OK, now we’re ready to execute the project.

## Execute

We are finally at the point where we can copy all the files to our board and execute the project code. Once again, be sure to check all hardware connections before connecting the Pico to your PC. Then, copy the code files to your Pico and execute the script. You can create a directory on your Pico to place the code if you’d like to keep things tidy. For example, you can create a directory named project2 and place the files there as shown in Figure 7-2.

Once you’ve downloaded the file (pedestrian_crossing.py) to your Pico, simply click the Run button and watch your code run! If everything is connected correctly, and the code is correct, you will see the green LED for the stoplight illuminated and the red LED for the pedestrian cross walk illuminated.

You can then press the button and watch the stoplight change from green to yellow and then red. The cross walk will then change from red to green and start flashing. When the timer expires, the cross walk will change from green to red and the stoplight from red to green. If something doesn’t work, go back and check your code.

### Taking It Further

This project shows excellent prospects for reusing the techniques in other projects. This is especially true since we have now learned how to use analog devices (LEDs). You should now consider taking time to explore some embellishments. Here are a few you may want to consider. Some are easy and some may be a challenge or require more research and more complex coding:
• Use NeoPixels (www.adafruit.com/category/168) instead of LEDs. These are RGB LEDs, so you need only two – one for the stoplight and one for the walk light. See https://github.com/JanBednarik/micropython-ws2812 for more information and examples.

• Use OLED from the last project in place of the LEDs for the walk sign to show “WALK” or “DON’T WALK.”

• Add another stoplight to complete the simulation for a pedestrian crossing.

• Add three more stoplights and extend the simulation to include controlling stoplights in two directions. By this point, you will have a lot of wires in your breadboard, so you may need to use a second breadboard to keep all of the wiring tidy.

• Once you have four stoplights working, add a second pedestrian crossing for the other intersection.

Of course, if you want to press on to the next project, you’re welcome to do so, but take some time to explore these potential embellishments – it will be a good practice.

## Summary

Working with discrete electronic components can be a lot of fun. Just making the circuit work is a real thrill when you’re just starting out with electronics. Now that we know a lot more about controlling our Pico and hardware connected to the GPIO, we can see how powerful having an easy-to-program language like MicroPython at our disposal is to make things easy.

In this chapter, we implemented a simulation of a pedestrian crossing button and stoplight. We used a series of LEDs to represent the stoplight and walk signal. We also added a hardware button to simulate pressing the real walk. If you liked this project, you would enjoy the next two projects even more.

In the next chapter, we will explore our first sensor project1 to read values and then archive the data and display it on an OLED.

• No Comment
..................Content has been hidden....................