Once you've finished setting up your Circuit Playground Express 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: 2022 Liz Clark for Adafruit Industries # # SPDX-License-Identifier: MIT import time import board import pwmio import neopixel from adafruit_motor import servo from adafruit_led_animation.animation.comet import Comet from adafruit_led_animation.sequence import AnimationSequence from adafruit_led_animation.color import PURPLE # create 2 PWM instances for the servos left_pwm = pwmio.PWMOut(board.A3, duty_cycle=2 ** 15, frequency=50) right_pwm = pwmio.PWMOut(board.A6, duty_cycle=2 ** 15, frequency=50) # left wing servo left_servo = servo.Servo(left_pwm) # right wing servo right_servo = servo.Servo(right_pwm) # use onboard neopixels on CPX pixel_pin = board.NEOPIXEL # number of onboard neopixels num_pixels = 10 # neopixels object pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.05, auto_write=False) # comet animation comet = Comet(pixels, speed=0.01, color=PURPLE, tail_length=10, bounce=True) # create animation sequence animations = AnimationSequence(comet) # beginning angles for each wing left_angle = 100 right_angle = 30 # minimum range for the servos min_range = 30 # maximum range for the servos max_range = 100 # the change in degrees for the servos degree_change = 10 # it's not recommended to go faster than 0.05 speed = 0.05 while True: # run comet animation while servos move animations.animate() # left angle decreases by 10 left_angle = left_angle - degree_change # once it's less than 30 degrees, reset to 100 if left_angle < min_range: left_angle = max_range # right angle increases by 10 right_angle = right_angle + degree_change # once it's greater than 100, reset to 30 if right_angle > max_range: right_angle = min_range # move left wing left_servo.angle = left_angle # move right wing right_servo.angle = right_angle # delay time.sleep(0.05)
Upload the Code and Libraries to the Circuit Playground Express
After downloading the Project Bundle, plug your Circuit Playground Express 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 Circuit Playground Express' CIRCUITPY drive.
- lib folder
- code.py
Your Circuit Playground Express CIRCUITPY drive should look like this after copying the lib folder and the code.py file.

The code begins by setting up two pins for the servo motors to have PWM out. Then left_servo
and right_servo
are created as servo objects.
# create 2 PWM instances for the servos left_pwm = pwmio.PWMOut(board.A3, duty_cycle=2 ** 15, frequency=50) right_pwm = pwmio.PWMOut(board.A6, duty_cycle=2 ** 15, frequency=50) # left wing servo left_servo = servo.Servo(left_pwm) # right wing servo right_servo = servo.Servo(right_pwm)
The onboard NeoPixels are used for this project. The pin to access them is board.NEOPIXEL
. Then, pixels
is setup as the NeoPixel object.
# use onboard neopixels on CPX pixel_pin = board.NEOPIXEL # number of onboard neopixels num_pixels = 10 # neopixels object pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.05, auto_write=False)
The Comet
animation is setup and added to the AnimationSequence()
. If you want to change the color for the animation, you would change the color
property.
# comet animation comet = Comet(pixels, speed=0.01, color=PURPLE, tail_length=10, bounce=True) # create animation sequence animations = AnimationSequence(comet)
There are a few variables for the servo motor angles that are defined before the loop. You can change these values to customize the look of your bat's wing flapping.
min_range
and max_range
define the angle range of the wings. Change these values if you want to increase or decrease the range of the motor angles between 0
and 180
. degree_change
is the rate of movement for the motors. If you increase this value, the motors will move more abruptly; decrease the value and the motors will move more incrementally. speed
is the delay amount in the loop and as a result, determines how fast the servo motors move.
# beginning angles for each wing left_angle = 100 right_angle = 30 # minimum range for the servos min_range = 30 # maximum range for the servos max_range = 100 # the change in degrees for the servos degree_change = 10 # it's not recommended to go faster than 0.05 speed = 0.05
In the loop, animations.animate()
allows the comet NeoPixel animation to run as long as the code is running.
# run comet animation while servos move animations.animate()
The servos move like mirror images of each other to imitate a wing flapping motion. As a result, the angle of the servo on the left increases while the angle of the servo on the right decreases.
The left_angle
value decreases by the value of degree_change
. Once its value is less than min_range
, its reset to max_range
.
# left angle decreases by 10 left_angle = left_angle - degree_change # once it's less than 30 degrees, reset to 100 if left_angle < min_range: left_angle = max_range
The right_angle
value increases by the value of degree_change
. Once its value is greater than max_range
, its reset to min_range
.
# right angle increases by 10 right_angle = right_angle + degree_change # once it's greater than 100, reset to 30 if right_angle > max_range: right_angle = min_range
The servos move by changing the value of their angle
property.
# move left wing left_servo.angle = left_angle # move right wing right_servo.angle = right_angle # delay time.sleep(speed)
Page last edited January 21, 2025
Text editor powered by tinymce.