A couple of years ago I picked up two plastic skull decorations in the post-halloween sales. Once I got them home, it occurred to me that they could become an interesting project. Adding some lights to their eyes with some fun effects was the plan. It has taken me a while to get time to do this, but I finally pulled all the parts together and modified the basic plastic skull with some LED eyes.
The parts, in addition to the skull of course, are as follows:
- An AdaFruit ItsyBitsy M4 Express (a tiny single board computer)
- Two AdaFruit NeoPixel Jewels for the eyes
- Patch wires
- A 400 pin solderless breadboard from Amazon (one of a box of 6)
The circuit is very simple:
Power comes from the USB, which also acts as the data connection to the computer for programming the board.
As mentioned in an earlier post, this board comes pre-installed with Circuit Python, which makes it very simple to code up the effects we needed for this relatively simple project. We only need a single output pin from the board to drive the data line for the LEDs. They connect to each other to form a chain of 14 pixels. Each pixel has 16 million colors to choose from, expressed in standard RGB values.
Each eye has 7 pixels. Pixel 0 is the center one, the 1 through 6 are around it. Since we chained them together, Pixels 0 and 7 are the centers of our eyes and 1-6 and 8-13 are the rings. The plan for the eyes is to have a two LED chaser ring in first in orange, then purple and finally green, interspersed with random flickering red from all 7 LEDs.
Using the Jupyter Notebook connected to Circuit Python made it simple to test colors and effects. Then, when it was complete, I turned it into a simple Python script which is copied to the ItsyBitsy (which looks like a USB drive to the host computer). Name the file code.py and when the board sees it, it will run it.
Setting up the Board
Setup for our simple circuit is easy. Make sure the NeoPixel Python library is copied in to the libs folder and then this will get the board setup:
import time import board import neopixel import random OFF = (0, 0, 0) RED = (255, 0, 0) GREEN = (0, 255, 0) PURPLE = (180, 0, 255) ORANGE = (255, 75, 0) pixels = neopixel.NeoPixel(board.A1, 14, brightness=0.3, auto_write=False) pixels.fill(OFF) pixels.show()
This also sets up some variables for the colors we’re going to be using.
The sequence starts with LEDs 1 and 2 on each eye lit and then loops around extinguishing the first and then lighting the next. The initial setup is handled by this code:
def setupChase(colour): pixels.fill(OFF) pixels = colour pixels = colour pixels = colour pixels = colour pixels.show()
The actual chaser by this:
def chase(colour, loops=2): for loop in range(loops): for x in range(1,7): time.sleep(0.1) # Turn x off, x+2 on (wrapping) pixels[x] = OFF pixels[x+7] = OFF if x <=4: nxt = x+2 else: nxt = x-4 # 5 => 1, 6 => 2 pixels[nxt] = colour pixels[nxt+7] = colour pixels.show()
The red flashing is meant to be flickery, so there is a random element to the timing. The code for this is as follows:
def redFlash(limit=1.0): t = 0.0 mx = limit / 8.0 while (True): pixels.fill(RED) pixels.show() delay = (random.random() * mx) t += delay time.sleep(delay) pixels.fill(OFF) pixels.show() delay = (random.random() * mx) time.sleep(delay) t += delay if t > limit: break;
Putting It All Together
For testing, I ran this in a loop that just went a few times. Once ready for standalone use though this sits in a while true loop as we want it to just run forever.
col = 0 colours = [ ORANGE, PURPLE, GREEN ] while True: setupChase(colours[col]) chase(colours[col], loops=5) redFlash() col = (col + 1) % len(colours)