Code with CircuitPython
CircuitPython Setup
For this project you need to ensure your version of CircuitPython is at least 3.0. Adafruit recommends the latest version available by clicking the green button below. Download the file to your Downloads folder, Desktop, etc. (a place you'll remember for the next step).
To load the downloaded file, plug in the HalloWing over USB to your computer and then double-click the reset button on the HalloWing. This will put it into bootloader mode, allowing you to change the firmware. You'll see a USB drive appear on your computer called HALLOWBOOT.
Drag the .uf2 file you downloaded onto the HALLOWBOOT drive. Once it copies over, it will automatically restart, show up as a drive named CIRCUITPY and you will be ready to load a CircuitPython program.
Adafruit really likes using the Mu editor to edit the CircuitPython code. See this guide on loading and using Mu.
Libraries
You'll also need to add a code library for this project. Follow this guide on adding libraries. The only one you'll need is the adafruit_motor folder from the Circuit Python bundle in the lib folder, so just drag it from your downloaded, unzipped lib folder onto the HalloWing's lib folder.
Code Outline
Here's the basic flow of our trap:
- Startup
- Rotate the servo arm to the set position
- Watch for the PIR sensor to be triggered
- Play hissing sound over the speaker
- Rotate the servo to drop the creepy bug
- Wait for the screaming to subside
- Rotate the servo back to the set position
- Wait for the user to press the reset cap touch tooth button
- Begin waiting for the PIR sensor to be tripped again
User Feedback
In order to help you (or your lab assistant Igor) in setting the trap, we'll use the LCD TFT screen on the HalloWing to provide status messages and prompts.
Here are the screens we'll use:
The simplest way to us the HalloWing screen currently is as an image player to show pre-generated bitmap graphics. Download this .zip file and then uncompress it. Plug in you HalloWing and then drag the four .bmp files onto the root level of your HalloWing's CIRCUITPY USB drive.
Audio Playback
We'll use two methods of audio playback with the audio.play() -- for beeping we'll use the tone playback of a sine wave sample, and for hissing we'll use the audiocore.WaveFile() playback method.
Download this wave file and drag it onto your HalloWing's CIRCUITPY drive at the root level.
# SPDX-FileCopyrightText: 2018 John Edgar Park for Adafruit Industries
#
# SPDX-License-Identifier: MIT
# HalloWing Jump Scare Trap
# use PIR sensor, speaker, and servo
import time
import array
import math
import board
import displayio
import pwmio
from adafruit_motor import servo
import digitalio
import touchio
import audioio
import audiocore
# Setup LED and PIR pins
LED_PIN = board.LED # Pin number for the board's built in LED.
PIR_PIN = board.SENSE # Pin port connected to PIR sensor output wire.
# Setup digital input for PIR sensor:
pir = digitalio.DigitalInOut(PIR_PIN)
pir.direction = digitalio.Direction.INPUT
# Setup digital output for LED:
led = digitalio.DigitalInOut(LED_PIN)
led.direction = digitalio.Direction.OUTPUT
# Setup servo
# servo = pwmio.PWMOut(board.D4, frequency=50)
pwm = pwmio.PWMOut(board.D4)
servo = servo.Servo(pwm)
# Setup cap touch button
ready_button = touchio.TouchIn(board.TOUCH1)
def servo_ready():
servo.angle = 0
def servo_release():
servo.angle = 90
# Set servo to ready position
servo_ready()
# Function for playing wav file, releasing servo
def play_wave():
wave_file = open("hiss01.wav", "rb") # open a wav file
wave = audiocore.WaveFile(wave_file)
audio.play(wave) # play the wave file
led.value = True
servo_release()
print('Motion detected!')
while audio.playing: # turn on LED, turn servo
pass
wave_file.close() # close the wav file
# Setup audio out pin
audio = audioio.AudioOut(board.A0)
# tone player setup for status beeps
tone_volume = 0.1 # Increase this to increase the volume of the tone.
frequency_hz = 880 # Set this to the Hz of the tone you want to generate.
length = 8000 // frequency_hz
sine_wave = array.array("H", [0] * length)
for i in range(length):
sine_wave[i] = int((1 + math.sin(math.pi * 2 * i / length)) * tone_volume * (2 ** 15 - 1))
sine_wave_sample = audiocore.RawSample(sine_wave)
# Function for beeping, usage: 'beep(3)' will beep 3x
def beep(count):
for _ in range(count):
audio.play(sine_wave_sample, loop=True)
time.sleep(0.1)
audio.stop()
time.sleep(0.05)
# Function for counting down, usage: 'countdown(5)'
def countdown(count):
for k in range(count):
print(count - k)
led.value = True
time.sleep(0.1)
led.value = False
time.sleep(1)
# function for blinking, usage: 'blink(5, 0.2)'
def blink(count, speed):
for _ in range(count):
led.value = True
time.sleep(speed)
led.value = False
time.sleep(speed)
# display setup
backlight = pwmio.PWMOut(board.TFT_BACKLIGHT)
splash = displayio.Group()
board.DISPLAY.root_group = splash
max_brightness = 2 ** 15
backlight.duty_cycle = 0
# Image list
images = ["trap_sprung.bmp", "reset_trap.bmp", "please_standby.bmp",
"trap_set.bmp"]
# Function for displaying images on HalloWing TFT screen
def show_image(filename):
odb = displayio.OnDiskBitmap(filename)
face = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader)
backlight.duty_cycle = 0
splash.append(face)
board.DISPLAY.refresh(target_frames_per_second=60)
backlight.duty_cycle = max_brightness
beep(1) # startup beep
show_image(images[2]) # waiting display
print('Stabilizing')
countdown(3)
print('Ready')
blink(3, 0.2)
beep(3) # ready beeps
triggered = False
ready = True
show_image(images[3]) # ready display
while True:
# Check PIR sensor
pir_value = pir.value
# Check touch button
ready = ready_button.value
if pir_value and triggered is not True:
# PIR is detecting movement!
play_wave()
splash.pop()
show_image(images[0])
print('Triggered')
countdown(8)
blink(3, 0.2)
beep(1)
print('Please reset')
led.value = False
triggered = True
servo_ready()
splash.pop()
show_image(images[1])
if ready: # touch sensor has been pressed
beep(1)
splash.pop()
show_image(images[2])
countdown(8)
print('Ready.')
blink(3, 0.2)
beep(3)
splash.pop()
show_image(images[3])
triggered = False
Next we'll test out the code and deploy the trap!
Page last edited January 21, 2025
Text editor powered by tinymce.



