Coding in CircuitPython for Crickit and Circuit Playground Express
Crickit and Circuit Playground Express (CPX) are a great combo for robotics projects. And when paired with CircuitPython, it's very straightforward to write your own code and iterate quickly during testing.
Setup the CPX and Crickit
The Circuit Playground Express (CPX) paired with the Crickit is a powerful, yet simple to use combination for building animatronics! To get started, you'll want to set up the CPX for use with CircuitPython by following this guide. When you're ready, and can upload code to the board return here.
To use the Crickit with the CPX, follow the steps listed here to install the special build of CircuitPython (name will begin with 'adafruit-circuitpython-circuitplaygroundexpress-crickit...').
To use with CircuitPython, you need to first install a few libraries, into the lib folder on your CIRCUITPY drive. Then you need to update code.py with the example script.
Thankfully, we can do this in one go. In the example below, click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, open the directory Tightrope_Unicycle_Bot/ and then click on the directory that matches the version of CircuitPython you're using and copy the contents of that directory to your CIRCUITPY drive.
Your CIRCUITPY drive should now look similar to the following image:

# SPDX-FileCopyrightText: 2018 John Park for Adafruit Industries # # SPDX-License-Identifier: MIT import time import board import neopixel import audioio import audiocore import adafruit_crickit print("Adabot Tightrope Unicyclist!") RED = (16, 0, 0) GREEN = (0, 16, 0) BLACK = (0, 0, 0) pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness = 0.2) pixels.fill(BLACK) # Create a motor on Crickit Motor 1 port motor = adafruit_crickit.crickit.dc_motor_1 ############### User variables run_time = 6 speed = 0.65 ############### Music cpx_audio = audioio.AudioOut(board.A0) # speaker out on Crickit def play_file(wavfile): with open(wavfile, "rb") as f: wav = audiocore.WaveFile(f) cpx_audio.play(wav) while cpx_audio.playing: pass wav_file_name = "circus.wav" play_file(wav_file_name) while True: # set NeoPixels green in direction of movement for i in range(5): pixels[i] = GREEN for i in range(5): pixels[i+5] = BLACK motor.throttle = speed # full speed forward time.sleep(run_time) # motor will run for this amount of time # set NeoPixels red when stopped pixels.fill(RED) motor.throttle = 0 # stop the motor # set NeoPixels green in direction of movement for i in range(5): pixels[i] = BLACK for i in range(5): pixels[i+5] = GREEN motor.throttle = -1 * speed # full speed backward time.sleep(run_time) # motor will run for this amount of time pixels.fill(RED) motor.throttle = 0 # stopped
Audio File
We'll have the bot play some circus music when it starts up. Download the file here and copy it to the root level of your CPX CIRCUITPY drive that shows up when it's plugged into your computer.
The CC licensed circus theme music came from Freesound.
Here are the different sections of the code, and how they work.
Library Imports
First, we'll import a few libraries. We'll import time
so we can use the sleep command.
We also import the board
library, which gives us convenient definitions for objects on the CPX that we can call.
Then, we'll import neopixel
, audioio
and audiocore
. That way we can blink lights (neopixels) and make some music!
Finally, the good stuff - from the adafruit_crickit
library we import crickit
, this is the library that lets us talk to the Crickit robotics board and make stuff move!
import time import board import neopixel import audioio import audiocore from adafruit_crickit import crickit
NeoPixel Prep
We'll define variables to represent the color values we'll use for the NeoPixels to indicate forward, backward, and stopped states.
Then, we'll set up the NeoPixel object and set them to black (off).
RED = (16, 0, 0) GREEN = (0, 16, 0) BLACK = (0, 0, 0) pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness = 0.2) pixels.fill(BLACK)
Motor Prep
The next thing to do is to instantiate the motor output, we'll be using the Motor 1 port (The two pins are labeled on the Crickit as Motor and then the "1" pair) To make things easier to type we'll call the motor, simply motor
!
# Create a motor on Crickit Motor 1 port motor = crickit.dc_motor_1
User Variables
Depending on your tightrope's length, you may want to unicycle for greater or lesser amounts of time in each direction. You may also want to direct Adabot to go faster or slower.
These two variables -- run_time
and speed
-- are used to define the run time in each direction in seconds, and the amount of power to send to the motor from '0' to '1'. (Technically, this goes down to '-1' for reverse, but we'll handle that with a bit of math later.)
############### User variables run_time = 6 speed = 0.65
Music, Maestro
This next section is used to create an audio output object named cpx_audio
, and then to define a process called play_file()
we can call upon to play back audio files in the .wav format.
############### Music cpx_audio = audioio.AudioOut(board.A0) # speaker out on Crickit def play_file(wavfile): with open(wavfile, "rb") as f: wav = audiocore.WaveFile(f) cpx_audio.play(wav) while cpx_audio.playing: pass
We saved a file to the CPX named 'circus.wav' so we'll cast a variable for that, and then run the play_file()
command to have it play once during startup of the robot.
wav_file_name = "circus.wav" play_file(wav_file_name)
Main Loop
With the setup complete, now we get into the bulk of the program, which runs over and over. This is everything that follows the while True:
line.
The main loop does just a few things over and over:
- Light the five NeoPixels on the left of the board green
- Run the motor forward for a set amount of time
- Light all NeoPixels red
- Stop the motor
- Light the five NeoPixels on the right of the board green
- Run the motor backward for a set amount of time
- Light all NeoPixels red
- Stop the motor
- Repeat
This is the code that does those steps:
NeoPixels Forward
This runs through the first five NeoPixels in the for
loop and sets them to green, then runs through the second five and sets them black, or off.
# set NeoPixels green in direction of movement for i in range(5): pixels[i] = GREEN for i in range(5): pixels[i+5] = BLACK
Motor Forward
This section uses the motor.throttle
command and sets it to the speed
we previously defined, for the run_time
in seconds.
motor.throttle = speed # full speed forward time.sleep(run_time) # motor will run for this amount of time
# set NeoPixels red when stopped pixels.fill(RED) motor.throttle = 0 # stop the motor
Then, we essentially repeat these steps for the reverse direction. Note, the use of motor.throttle = -1 * speed
as a way to reverse motor direction.
# set NeoPixels red when stopped pixels.fill(RED) motor.throttle = 0 # stop the motor # set NeoPixels green in direction of movement for i in range(5): pixels[i] = BLACK for i in range(5): pixels[i+5] = GREEN motor.throttle = -1 * speed # full speed backward time.sleep(run_time) # motor will run for this amount of time pixels.fill(RED) motor.throttle = 0 # stopped
Once you start to run your unicyclist on the tightrope you can come back and revisit the code to change the behavior.
- What if you want to pause between directions and play the song again?
- How about varying the speed to ease into and out of the top speed?
- Since the same things happen in each direction, can you optimize the code to reduce the repetitive code blocks?
Page last edited January 14, 2025
Text editor powered by tinymce.