Adventures with Electronics is a father and son project to learn how to connect up and code 37 different electronic sensors using a Raspberry Pi Pico.

After setting up the software and firmware needed to write python code on a Raspberry Pi Pico, this is the third project in our adventure in electronics. It uses an push button sensor as a reaction timer game with a Lego compatible servo connected to a trap door that could send a minifig plunging down into a shark infested piranha pool.

The pico explorer screen says “Get ready” for a random amount of time. As soon as the screen goes red, you have to press the button as soon as you can. If you’re fast enough, the minifig lives to play another round. If you’re too slow (or too fast and try to cheat) the servo opens the trapdoor and the minifigure slides down to meet a sticky end.

About the sensor

The push button breakout has three pins.

Push button sensor
Pin numberNameDescription
1SSignal (connect to GPIO port)
2VCCPower supply (3.3v or 5v)*
3Ground (0v)*

* Whilst the breakout board labels the + and – pins as shown in the table above, I had more success when swapping the power and ground round as shown in the schematic below and the video above. When the push button is pressed, a connection is made between pins 1 and 3. The middle pin is connected to a resistor that can be a pull up or pull down resistor depending on whether you connect up the switch as shown in the table above or in the schematic below.

The circuit

Reaction timer breadboard circuit with raspberry pi pico, switch and servo

The servo is connected to a Lego trap door as shown below:

The servo we should have used is a GeekServo Lego Compatible servo but we don’t have one of those yet. That would allow us to control the exact angle of the trap door. Instead, we used a continuous rotation servo which runs more like a motor, continuously rotating as the name would suggest. Using a servo rather than a motor means we don’t have to use a h bridge motor driver to protect the pico as you would for a motor but the continuous rotation means that the only way of opening or closing the trap door is to make the servo on for a set amount of time and hope that it rotates fully. The Lego model restricts the trapdoor from opening or closing too much so the timings set in code should be plenty of time to allow for this.

The code

Reaction timer on a raspberry pi pico with a push button and servo to open or close a Lego trapdoor

When the program starts it says “Get ready” for a random amount of time (between 1 and 3 seconds) then the edge of the screen goes red to indicate that you need to press the button. If you press the button too soon (before the screen goes red) or too late (or not at all) then the servo opens the trapdoor and the Lego minifig falls to its watery doom.


"""
Adventures in Electronics
* Firmware:
 - CircuitPython v9.2.1
* Hardware:
 - Raspberry pi pico in pico explorer board
 - Servo
     Pin1 (Orange	=> GP1)
     Pin2 (Red		=> 3v3)
     Pin3 (Brown	=> GND)
 - Push switch (note inverse polarity)
     Pin1 (GND 		=> 3v3)
     Pin2 (VCC		=> GND)
     Pin3 (S		=> GP0)
     
* Description:
 Reaction timer trap door of doom:
 Pico explorer board will display "Get ready" for a random amount of time
 As soon as the screen goes red, you have to press the button. If you're too slow the servo will
 open a Lego trapdoor
"""
import picoexplorer
import time
import random
import board
import pwmio
from digitalio import DigitalInOut, Direction, Pull
from adafruit_motor import servo

TIME_TOO_SLOW = 2
TIME_MAX_WAIT = 5

# Set up button
btn = DigitalInOut(board.GP0)
btn.direction = Direction.INPUT
btn.pull = Pull.UP


# Set up servo
pwm = pwmio.PWMOut(board.GP1, duty_cycle=2 ** 15, frequency=50)
trapdoor_servo = servo.Servo(pwm)

# Open Lego servo trapdoor of doom
def open_trapdoor():
    trapdoor_servo.angle = 0
    time.sleep(1)
    trapdoor_servo.angle = 90

# Make sure trapdoor is closed
def close_trapdoor():
    trapdoor_servo.angle = 180
    time.sleep(2)
    trapdoor_servo.angle = 90
    
picoexplorer.init()
close_trapdoor()
while True:
    picoexplorer.set_line(3, "Get ready")
    picoexplorer.set_line(4, "")

    # random delay before pressing button
    delay = random.randint(10,30) / 10
    start_time = time.monotonic()
    duration = 0
    
    # make sure button isn't pressed too soon
    while duration < delay:
        time.sleep(0.05)
        duration = time.monotonic() - start_time
        if btn.value:
            picoexplorer.set_line(4, "Cheat!")
            open_trapdoor()
            
    # Go!
    picoexplorer.set_color(picoexplorer.COLORS_BACKGROUND_OUTER, 0xFF0000)
    picoexplorer.set_line(3, "Press button!")
    
    # Time how long it takes to press button
    start_time = time.monotonic()
    while not btn.value:
        time.sleep(0.05)
        duration = time.monotonic() - start_time
        
        # don't wait for too long
        if duration > TIME_MAX_WAIT:
            break

    # display time
    picoexplorer.set_color(picoexplorer.COLORS_BACKGROUND_OUTER, 0x000000)
    picoexplorer.set_line(3, "Time: {:.2f}s".format(duration))

    # open the trapdoor if they take too long
    if duration > TIME_TOO_SLOW:
        picoexplorer.set_line(4, "Too slow!")
        open_trapdoor()
        close_trapdoor()
    
    # if button is pressed soon enough, keep the trapdoor closed for another try
    else:
        picoexplorer.set_line(4, "Well done!")
    time.sleep(2)

Link to code (including the picoexplorer module and other required libraries) here.

There’s also some micropython code just to read from the sensor here.