Setup

If you've never used the Circuit Playground Express with CircuitPython before, you'll need to do some setup. Plug in the Circuit Playground Express to your computer via a known good data+power USB cable, and click the little reset button in the center to put it into bootloader mode.

If you have a new flash drive on your computer named CIRCUITPY, all is good.

If the on-board NeoPixels should all turn green and a USB storage drive called CPLAYBOOT shows up, we'll need to load a fresh copy of CircuitPython.

You’ll need to follow the below guide to set up CircuitPython and then come back to continue.

Upload the code

The next step is to put the code onto the Circuit Playground and give it a test! Open a new text file in your text editor of choice, and paste in the code below. Then save the file onto the USB drive under the filename code.py. Please don't rename it, it must be called code.py.

# SPDX-FileCopyrightText: 2019 Archie Roques for Adafruit Industries
#
# SPDX-License-Identifier: MIT

# Code for Circuit Playground Express Rocket Lamp

# A fun lighting project using Circuit Playground Express and NeoPixels

# Written by Archie Roques for Adafruit Industries
# For full instructions see learn.adafruit.com/cpx-rocket-lamp !

# MIT License, see LICENSE for more info.

# import the libraries needed for this project
import time
import random
import board
import neopixel
import digitalio
import audioio
import audiocore

# enables the speaker for audio output
spkrenable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
spkrenable.direction = digitalio.Direction.OUTPUT
spkrenable.value = True

# define the onboard NeoPixel strip, and the externally connected one
pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=.2)
strip = neopixel.NeoPixel(board.A7, 30, brightness=.2)

# turn off the onboard pixels
pixels.fill((0, 0, 0))
pixels.show()

# set the rocket body LEDs to a pretty colour - we chose green!
# Colours are expressed in RGB format
# with each digit going up to 255.
# In this case we've used 0 red, 255 green and 150 blue.
strip.fill((0, 255, 150))
strip.show()

# set up the buttons to trigger the countdown
buttonA = digitalio.DigitalInOut(board.BUTTON_A)
buttonA.direction = digitalio.Direction.INPUT
buttonA.pull = digitalio.Pull.DOWN

buttonB = digitalio.DigitalInOut(board.BUTTON_B)
buttonB.direction = digitalio.Direction.INPUT
buttonB.pull = digitalio.Pull.DOWN

#this function will play the audio file
def play_audio():
    #open the file
    wave_file = open("liftoff.wav", "rb")
    #play the file
    with audiocore.WaveFile(wave_file) as wave:
        with audioio.AudioOut(board.A0) as audio:
            audio.play(wave)
            #wait until audio is done
            while audio.playing:
                pass

# this function lights the CPX NeoPixels up with a blue fire animation
# (really quite hot) for about 1 second
def blue_fire(repeats):
    # fills them with a blue colour to start
    pixels.fill((40, 0, 200))
    pixels.show()
    # each repeat roughly corresponds to a second of running including processing time
    for _ in range(repeats):
        for _ in range(20):
            # pick a random pixel to fill
            j = random.randint(0, 9)
            # makes the pixel either lighter or darker to simulate firey goodness
            if random.random() > 0.5:
                pixels[j] = (40, 80, 250)
            else:
                pixels[j] = (20, 0, 200)
            pixels.show()
            # waits a bit so you can see it
            time.sleep(0.02)
            # returns pixel to original colour
            pixels[j] = (40, 0, 200)
            pixels.show()

# this function lights the CPX NeoPixels up with a white fire animation
# (super very hot) for about 1 second
def white_fire(repeats):
    # fills them with a white colour to start
    pixels.fill((100, 100, 100))
    pixels.show()
    # each repeat roughly corresponds to a second of running including processing time
    for _ in range(repeats):
        for _ in range(20):
            # pick a random pixel to fill
            j = random.randint(0, 9)
            # makes the pixel either lighter or darker to simulate firey goodness
            if random.random() > 0.5:
                pixels[j] = (140, 140, 100)
            else:
                pixels[j] = (100, 100, 140)
            pixels.show()
            # waits a bit so you can see it
            time.sleep(0.01)
            pixels[j] = (100, 100, 100)
            # returns pixel to original colour
            pixels.show()

# this function lights the CPX NeoPixels up with an orange fire animation
# (nice and toasty) for about 1 second
def orange_fire(repeats):
    # fills them with an orangy colour to start
    pixels.fill((200, 50, 0))
    pixels.show()
    # each repeat roughly corresponds to a second of running including processing time
    for _ in range(repeats):
        for _ in range(10):
            # pick a random pixel to fill
            j = random.randint(0, 9)
            # makes the pixel either lighter or darker to simulate firey goodness
            if random.random() > 0.5:
                pixels[j] = (200, 10, 0)
            else:
                pixels[j] = (200, 200, 0)
            pixels.show()
            # waits a bit so you can see it
            time.sleep(0.057)
            # returns pixel to original colour
            pixels[j] = (200, 50, 0)
            pixels.show()

# this function makes the body of the rocket light up in a countdown animation
def countdown(seconds):
    # turns off all the lights
    strip.fill((0, 0, 0))
    strip.show()
    # we pass the amount of seconds into the function at the start so the countdown
    # runs for the right amount of time 15 seconds is the max since we only have 30
    # NeoPixels in our strip, and the countdown runs on both sides. 30/2 = 15 seconds
    for i in range(seconds):
        # lights the top pixels, then the next ones down, etc etc all the way to the bottom
        strip[seconds-(i+1)] = (200, 200, 200)
        strip[30-(seconds-i)] = (200, 200, 200)
        strip.show()
        # we use the white fire animation as a timer since it takes about a second to run
        white_fire(1)
    # when the countdown's done, flash all the pixels and play a sound to celebrate take off!
    play_audio()
    for i in range(3):
        strip.fill((200, 200, 200))
        strip.show()
        time.sleep(0.1)
        strip.fill((0, 0, 0))
        strip.show()
        time.sleep(0.1)
    # return the strip to the original colour
    strip.fill((0, 200, 100))
    strip.show()

# this loop of code runs all the time and controls when all the other functions happen
while True:
    # if button A is pressed
    if buttonA.value:
        #run the ten second countdown procedure
        countdown(10)
    elif buttonB.value:
        # run the blue fire for a bit and then trigger the final countdown
        # this sequence is about a minute long
        blue_fire(45)
        countdown(10)
    # if the button isn't pressed, loop the normal animation sequence of orange fire
    else:
        orange_fire(1)

You’ll also need to download the WAV sound file from the link below, and copy that to the CIRCUITPY USB drive too.

Then eject the drive - the code should automatically run and you should get a nice light show! Press button A and watch the countdown run. Button B should provide a 1-minute long (ish!) timer sequence.

If you want to edit the code, Mu is a good choice for a code editor. Mu is written in Python, and works on all 3 major platforms: MacOS, Windows and Linux (including the Raspberry Pi). It has an awesome CircuitPython mode, and has a built-in serial console, so you can easily see text output from your code too. You can follow the below instructions to install Mu:

Extending the Code

There are all sorts of ideas for extending the code - here are a few possible starting points:

  • Change the delay on the timer
  • Change the sound when the timer finishes
  • Change the colour of the rocket or fire
  • Change the speed of the fire animation
  • Change the countdown animation

Have fun with it! 

This guide was first published on Mar 04, 2019. It was last updated on Mar 27, 2024.

This page (Code) was last updated on Mar 27, 2024.

Text editor powered by tinymce.