Once you've finished setting up your RP2040 Prop-Maker Feather with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download as a zipped folder.
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries # # SPDX-License-Identifier: MIT import time import board import audiocore import audiobusio import audiomixer import pwmio from digitalio import DigitalInOut, Direction, Pull import neopixel from adafruit_ticks import ticks_ms, ticks_add, ticks_diff from adafruit_led_animation.animation.pulse import Pulse from adafruit_led_animation.animation.rainbow import Rainbow from adafruit_led_animation.color import RED from adafruit_motor import servo import adafruit_lis3dh time.sleep(2) # enable external power pin # provides power to the external components external_power = DigitalInOut(board.EXTERNAL_POWER) external_power.direction = Direction.OUTPUT external_power.value = True # i2s playback wave_file = open("wand-mix-sfx.wav", "rb") wave = audiocore.WaveFile(wave_file) audio = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA) mixer = audiomixer.Mixer(voice_count=1, sample_rate=22050, channel_count=1, bits_per_sample=16, samples_signed=True) audio.play(mixer) mixer.voice[0].play(wave, loop=True) mixer.voice[0].level = 0 # servo control pwm = pwmio.PWMOut(board.EXTERNAL_SERVO, frequency=50) prop_servo = servo.ContinuousServo(pwm) servo_move = False # external button switch = DigitalInOut(board.EXTERNAL_BUTTON) switch.direction = Direction.INPUT switch.pull = Pull.UP switch_state = False # external neopixels num_pixels = 24 pixels = neopixel.NeoPixel(board.EXTERNAL_NEOPIXELS, num_pixels) pixels.brightness = 0.3 rainbow = Rainbow(pixels, speed=0.05, period=2) pulse = Pulse(pixels, speed=0.1, color=RED, period=3) i2c = board.I2C() int1 = DigitalInOut(board.ACCELEROMETER_INTERRUPT) lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c, int1=int1) lis3dh.range = adafruit_lis3dh.RANGE_2_G clock = ticks_ms() prop_time = 3000 while True: if not servo_move: pulse.animate() mixer.voice[0].level = 0.0 prop_servo.throttle = 0.0 else: prop_servo.throttle = 0.5 rainbow.animate() mixer.voice[0].level = 0.5 if ticks_diff(ticks_ms(), clock) >= prop_time: servo_move = False if lis3dh.shake(shake_threshold=20) or not switch.value and switch_state is False: servo_move = True clock = ticks_ms() clock = ticks_add(clock, prop_time) switch_state = True if switch.value and switch_state is True: switch_state = False
Upload the Code and Libraries to the RP2040 Prop-Maker Feather
After downloading the Project Bundle, plug your RP2040 Prop-Maker Feather into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the RP2040 Prop-Maker Feather's CIRCUITPY drive.
- lib folder
- code.py
- wand-mix-sfx.wav
Your RP2040 Prop-Maker Feather CIRCUITPY drive should look like this after copying the lib folder, the code.py file and wand-mix-sfx.wav audio file.
How the CircuitPython Code Works
The code begins by enabled the EXTERNAL_POWER
pin. This pin enables power to all of the external component pins, which includes the servo header, external NeoPixel pin, external button pin and speaker output.
# enable external power pin # provides power to the external components external_power = DigitalInOut(board.EXTERNAL_POWER) external_power.direction = Direction.OUTPUT external_power.value = True
Audio Setup
Next is I2S audio setup. The wand-mix-sfx.wav audio file is passed to a Mixer
object. The Mixer
is setup to play the sound effect in a loop, but with the volume initially at 0
. Later on in the code loop, the volume will be adjusted so that you can hear the audio. This is one technique you can use to incorporate playing and pausing audio in a non-blocking way in your code.
# i2s playback wave_file = open("wand-mix-sfx.wav", "rb") wave = audiocore.WaveFile(wave_file) audio = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA) mixer = audiomixer.Mixer(voice_count=1, sample_rate=22050, channel_count=1, bits_per_sample=16, samples_signed=True) audio.play(mixer) mixer.voice[0].play(wave, loop=True) mixer.voice[0].level = 0
Servo and Button
A continuous servo and button are setup next using the servo header and the external button pin.
# servo control pwm = pwmio.PWMOut(board.EXTERNAL_SERVO, frequency=50) prop_servo = servo.ContinuousServo(pwm) servo_move = False # external button switch = DigitalInOut(board.EXTERNAL_BUTTON) switch.direction = Direction.INPUT switch.pull = Pull.UP switch_state = False
NeoPixels and Animations
The NeoPixel ring is setup on the external NeoPixel pin. The NeoPixels are using the Rainbow
and Pulse
animations from the LED animations library.
# external neopixels num_pixels = 24 pixels = neopixel.NeoPixel(board.EXTERNAL_NEOPIXELS, num_pixels) pixels.brightness = 0.3 rainbow = Rainbow(pixels, speed=0.05, period=2) pulse = Pulse(pixels, speed=0.1, color=RED, period=3)
Accelerometer
Last but not least, the onboard LIS3DH is initialized over I2C. In the loop, the LIS3DH will be able to affect the prop by detecting shake
.
i2c = board.I2C() int1 = DigitalInOut(board.ACCELEROMETER_INTERRUPT) lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c, int1=int1) lis3dh.range = adafruit_lis3dh.RANGE_2_G
The Loop
In the loop the servo_move
state determines what all of the components are doing. If servo_move
is False
, then the NeoPixels pulse red, the speaker is silent and the servo does not move.
if not servo_move: pulse.animate() mixer.voice[0].level = 0.0 prop_servo.throttle = 0.0
If the LIS3DH detects a shake
or the external button is pressed, then servo_move
is set to True
.
if lis3dh.shake(shake_threshold=20) or not switch.value and switch_state is False: servo_move = True clock = ticks_ms() clock = ticks_add(clock, prop_time) switch_state = True if switch.value and switch_state is True: switch_state = False
When servo_move
is True
, the NeoPixels show the rainbow animation, the servo spins and the speaker output is set to 0.5
with the Mixer
object. ticks
is used to keep time in a non-blocking way. After three seconds have passed, then servo_move
is set back to False
.
else: prop_servo.throttle = 0.5 rainbow.animate() mixer.voice[0].level = 0.5 if ticks_diff(ticks_ms(), clock) >= prop_time: servo_move = False
Text editor powered by tinymce.