Software

Now we're going to take a look at the code behind our LED trampoline light show!

Copy the following file to your Itsy Bitsy CIRCUITPY drive, and rename it to code.py. Or copy and paste it into your current code.py, replacing its current contents. Save your file, and you're ready to go!

import random
import time

import board
import digitalio
import neopixel

pixel_pin = board.D10  # The pin the NeoPixels are connected to
button_switch_pin = board.D9  # Pin button is attached to
vibration_switch_pin = board.D7  # Pin vibration switch is attached to.
pixel_count = 40  # Number of pixels in your strip
chase_color_duration = 3  # Seconds each color lasts in the color chase mode

pixels = neopixel.NeoPixel(pixel_pin, pixel_count,
                           brightness=.4, auto_write=False)

button_switch = digitalio.DigitalInOut(button_switch_pin)
button_switch.direction = digitalio.Direction.INPUT
button_switch.pull = digitalio.Pull.UP

vibration_switch = digitalio.DigitalInOut(vibration_switch_pin)
vibration_switch.direction = digitalio.Direction.INPUT
vibration_switch.pull = digitalio.Pull.UP

led = digitalio.DigitalInOut(board.D13)
led.direction = digitalio.Direction.OUTPUT

# Colors:
RED = (255, 0, 0)
YELLOW = (255, 150, 0)
ORANGE = (255, 40, 0)
GREEN = (0, 255, 0)
TEAL = (0, 255, 120)
CYAN = (0, 255, 255)
BLUE = (0, 0, 255)
PURPLE = (180, 0, 255)
MAGENTA = (255, 0, 20)
WHITE = (255, 255, 255)
# Sparkle colors:
GOLD = (255, 222, 30)
PINK = (242, 90, 255)
AQUA = (50, 255, 255)
JADE = (0, 255, 40)
AMBER = (255, 100, 0)


def cycle_sequence(seq):
    while True:
        yield from seq


def fade_control():
    brightness_value = iter([r / 15 for r in range(15, -1, -1)])
    while True:
        # pylint: disable=stop-iteration-return
        pixels.brightness = next(brightness_value)
        pixels.show()
        yield


def sparkle_code(color_values):
    (red_value, green_value, blue_value) = color_values
    p = random.randint(0, (pixel_count - 2))
    pixels[p] = (red_value, green_value, blue_value)
    pixels.show()
    pixels[p] = (red_value // 2, green_value // 2, blue_value // 2)
    pixels.show()
    pixels[p + 1] = (red_value // 10, green_value // 10, blue_value // 10)
    pixels.show()


fade = fade_control()

flash_color = cycle_sequence([RED, YELLOW, ORANGE, GREEN, TEAL, CYAN,
                              BLUE, PURPLE, MAGENTA, WHITE])

sparkle_color_list = (MAGENTA, PINK, GOLD, AQUA, JADE, AMBER)
sparkle_color_index = 0

chase_color_list = (RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE)

chase_color_index = 0
chase_color_cycle = chase_color_list[chase_color_index]
offset = 0

chase_last_color = time.monotonic()
chase_next_color = chase_last_color + chase_color_duration

button_state = None

mode = 0
print("Mode:", mode)

initial_time = time.monotonic()

while True:
    try:
        now = time.monotonic()
        if not button_switch.value and button_state is None:
            button_state = "pressed"
        if button_switch.value and button_state == "pressed":
            print("Mode Change")
            led.value = True
            pixels.fill((0, 0, 0))
            mode += 1
            button_state = None
            if mode > 2:
                mode = 0
            print("Mode:,", mode)
        else:
            led.value = False
        if mode == 0:
            try:
                if not vibration_switch.value:
                    print("Flash and fade mode activate!")
                    fade = fade_control()
                    pixels.fill(next(flash_color))
                    pixels.show()
                next(fade)
            except StopIteration:
                pass
        if mode == 1 and not vibration_switch.value:
            print("Sparkle mode activate!")
            pixels.brightness = 1
            sparkle_color_index = (sparkle_color_index + 1) \
                % len(sparkle_color_list)
            sparkle_code(sparkle_color_list[sparkle_color_index])
        if mode == 2 and not vibration_switch.value:
            print("Chase mode activate!")
            pixels.brightness = 1
            for i in range(0, pixel_count):
                c = 0
                if ((offset + i) % 8) < 4:
                    c = chase_color_cycle
                pixels[i] = c
                pixels[(pixel_count - 1) - i] = c
            pixels.show()
            offset += 1
            if now >= chase_next_color:
                chase_color_index = (chase_color_index +
                                     1) % len(chase_color_list)
                chase_color_cycle = chase_color_list[chase_color_index]
                pixels.fill((0, 0, 0))
                chase_last_color = now
                chase_next_color = chase_last_color + chase_color_duration
    except MemoryError:
        pass
The ItsyBitsy has a special pin that has high-level logic output, D5. If you're having problems getting the NeoPixel strip to light up using D10, try swapping the DIN wire to D5 and also update the CircuitPython code!

Setup

The first thing we do after importing the libraries we'll be using is set up the pins so our code knows where to look for the switches and LEDs.

Then we set the pixel_count = 40. This project uses 80 pixels total. However, there were hardware limitations with running 80 pixels. So, we've cut the strip into two, and attached the two strips of 40 to the same pin. Since they're attached to the same pin, the code doesn't know the difference and sends the same data to both strips. That's why the total is set to 40!

We also set the chase_color_duration = 3 which determines how long in seconds each color lasts in the color chase mode. You can change this number if you'd like your colors to last a longer or shorter time.

Next we setup our switches, and the red LED which we will be using as a status light for mode changes.

Next up is a list of color variables. We have a lot of color in this project! Since we reuse the colors multiple times, we've created a variable for each color so we can call it by a name instead of the (R, G, B) color tuple.

Helper Functions

Then we have a few functions that we'll be using. cycle_sequence is a helper function we use with generators. You can learn about how generators work in the Generate Your Colors section of the Hacking Ikea Lamps with CPX guide. In the LED Trampoline project, we're using a generator with our Flash and Fade mode. The fade takes a certain amount of time, and it's possible you could try to jump faster than the fade animation takes. In this case, the generator allows for the fade animation to be interrupted and a new color fade to begin.

We have fade_control which is what handles our flash and fade. Each time we call it, it starts with the brightness at 100 percent and then steps down 15 times to 0. This is how the fade works!

The sparkle_code handles the Sparkle mode. It sets a random pixel to a color and then sets one next to it to a faded version of that color. That is how we achieve a sparkle effect. This continues and once they're all full, will continue to randomly overwrite lit pixels. The sparkle code is super fast! This means that each time you jump, you'll trigger more than one sparkle at a time. It looks amazing!

We set fade = fade_control() so we can later call fade_control using fade.

Next we setup the list of colors we're going to use in Flash and Fade. flash_color uses the cycle_sequence generator to go through the list of colors and start over endlessly. This way you can jump as long as you want on the Flash and Fade mode and the colors keep right on changing!

Color Setup

We set the colors for the Sparkle mode using sparkle_color_list and the six special colors chosen for the Sparkle mode. They're slightly different than the main color list because these colors look especially great with the way the sparkle_code works. You can feel free to change these to any of the other colors or add more if you like!

sparkle_color_index is used to tell the code to start with the first color on the list. Remember, in CircuitPython, counting begins with 0, so 0 represents the first color in the list!

We set the colors for the Color Chase mode using chase_color_list and six of our color variables. You could add to this and change which colors are used if you like!

chase_color_index is the same as the sparkle version - it tells the code to start with the first color on the list.

The next few lines setup the chase color changing. We use time.monotonic() because we'd like to be able to set the amount of time the chase mode is a certain color, but we want the code to continue waiting in case we decide to jump or change modes. time.monotonic() is called non-blocking, meaning the code is not stopped by it. Learn more about non-blocking code in the Passing Time section of the Hacking Ikea Lamps with CPX guide.

We set mode = 0. This tells the code to begin with the first mode. We'll start with Flash and Fade! We print("Mode:", mode) which is "Mode:" and the current mode, which is 0 before we start. So if you are connected to the serial console during testing, you'll see Mode: 0.

To use time.monotonic(), you always set a start time. That's the last thing we do before we start our main loop!

try and except

while True: says to run the code indented beneath it forever.

The first and last thing inside our while True: loop, are try: and except MemoryError: pass. This is due to a very rare situation where the code returns a memory error and stops.

try: says to first try running all of the code indented under the try. If there is an error, the code moves to the except: and completes the code underneath. In this case it will pass which says to just keep right on going and start again with the try.

Since this project is meant to be attached to a trampoline and continue to run while you have fun jumping, we've included this try and except code so if it does run into that problem, it will keep going. This way you can keep on jumping even if the code runs into this problem! Otherwise, you'd have to reset the board. And what's the fun in that!

Main Loop

First, we make it so the button must be pressed and released before the code switches modes. This way you cannot accidentally skip modes by holding down the button too long.

Each time the mode is switched, it turns off the LEDs so you're starting your new mode with a clean slate. It blinks the little red LED, which can't be seen once the project is assembled, but is super handy when you're testing the project while still attached to your computer. Each time the button is pressed and released, it increases the mode by 1. Once that number is greater than 2 (remember we start counting at 0, so 2 is the third mode!) it resets to 0. This way we cycle through each of the three modes and then begin again with the first! Each time it prints the mode to the serial output, which you can see if you're connected while testing the project on your computer.

Flash and Fade Mode

If the mode is 0, we start the Flash and Fade code. Here we have another try and except. This is due to the way that the flash_control generator works. flash_control begins at 100 percent and ends at 0, and would normally simply stop here as it has iterated through all possible values. We want it to keep going so we can jump again, flash again and fade again. So, we've included except StopIteration: pass to keep the Flash and Fade mode moving.

Inside our try, we have if not vibration_switch.value:. The vibration switch defaults to "True" when not triggered, and becomes "False" when triggered. So, if we're looking to do a thing when the switch is triggered, we want to refer to when it is False which is done by using if not. This way, when we jump, we trigger the next set of events to happen. We print that the mode is activated! We call fade, we fill the pixels with the next color from our flash_color list, and we call pixels.show() which tells the pixels to light up with whatever we just set. In this case, it will flash the color and fade to black. Then we call next(fade) which tells the fade_control to start again.

Sparkle Mode

If the mode is 1 and we've triggered the vibration switch, then we start the Sparkle code. We print the mode is activated!

When you change modes in the middle of the Flash and Fade code, the brightness stays at the level it was at the exact moment that you switched modes. This means you could switch modes when the brightness is set to 0. If that happened, you'd get no sparkles at all! That's no good. So, we set pixel.brightness = 1 to set it back to 100%, so you get all the sparkle goodness regardless of where the brightness was when you switched.

The next line tells the sparkle code that sparkle_color_list should cycle through all the colors. And the last line says run the sparkle code repeatedly, cycling through the list of colors as you jump, and to keep doing this until you change modes!

Color Chase Mode

If the mode is 2 and we've triggered the vibration switch, we start the Color Chase code. We print the mode is activated! And, for the same reason as in Sparkle mode, we set the brightness to 100%.

The next bit is the core of the Chase mode. This is the chase code. This tells the strips to light up every 4 LEDs with 4 off between. Then it says, each time the switch is triggered, move the groups of lit LEDs towards the middle. In our case, since we've split our LED strips into 2, the chase will happen in two parts, one on each half, moving towards the middle of that half. They meet and meld in the middle!

The last section is what tells the chase code to change colors. We told it at the beginning to change colors every 3 seconds. So, every time 3 seconds passes, chase mode changes color. It forever cycles through the list of colors we provided during color setup. This happens whether or not you're jumping, because it's entirely based on time!

And that's it!

MicroUSB Dock for Dev Boards

Like the dock in this photo? You can 3D Print and build your own! 

This guide was first published on Apr 11, 2018. It was last updated on Apr 11, 2018. This page (Software) was last updated on Sep 16, 2019.