Jonathan Warren

Wires Expert GitHub YouTube Blogger LinkedIn

NeoPixel Grid Players

Spring 2020

In my past life, we frequently made custom grids of NeoPixels (individually addressable RGB/RGBW LEDs) to play low-res animations as part of an installation. Think simple chevrons scrolling across a wall when someone touches a button to learn more about a car's speed, pulsing waves when they press a button to learn more about the sound system, etc.

It can be a pain to build an animation and translate it to a microcontroller to play on a grid, and I wanted to find ways to simplify the process in the future. I started pursuing three distinct approaches, which I'll outline here with links to my proof-of-concept code. Unfortunately, I haven't had a need to actually apply this stuff since I built it out, so definitely consider this a work in progress.

Some concepts that apply to every approach include the assumption that every NeoPixel is in a rectangular grid style. This is often not the case, but since those are always entirely custom, approaches like masking pixels, etc. need to be considered on a case-by-case basis. Frequently, grids are wired in what I call a zig-zag pattern - the end of one row is wired to the end of the next row, effectively to reduce wire runs. This means every other row is "backwards". I kept this option broken out in the scripts in case there's a reason to wire the grid differently.

Disclaimer: All of this work was done on a 28x28 pixel board - there's absolutely going to be a balance of hardware processing speed, resolution, and frame rate that will have to be played with to keep this process working in different applications.

Approach 1 - Render and play media directly from a Raspberry Pi

This approach assumes you have an image or video file of the animation already prepared, and a Raspberry Pi connected to a NeoPixel grid. Once configured for your NeoPixel installation, the Python script allows you to render any media file by scaling it down to the grid's resolution and breaking it into individual image files representing each frame. This approach allows you to offload some of the processing required, so you can use older, slower Raspberry Pi boards. I think I used a v3 board for this project.


Approach 2 - Render media on a PC and play from a controller

This approach breaks the above process into a few pieces which can allow for more flexibility. A Processing script runs on a PC to render a media file to a proprietary ANM file I devised, which contains raw frame data adjusted to the configured NeoPixel grid. I designed these files to require the minimum amount of processing possible to drive the NeoPixels. I wasn't able to get Processing to output exactly what I wanted (I'm sure I could if I kept working on it) so for now there's a simple Python script that has to run on the Processing output to convert to ANM format.

My ideal was to be able to load the ANM files onto an SD card and play using a simple Arduino microcontroller. I had some trouble getting it playing smoothly, and since I was just playing around, I haven't yet finished tackling that challenge. To complete the proof of concept, I created a player with Circuit Python that can be used on a Raspberry Pi. I'm interested in seeing how easily I can port this over to the new Raspberry Pi Pico! Stay tuned.


Approach 3 - Render media on a PC and stream to a controller

Mostly a curiosity, I wanted to see if I could directly stream rendered frames to a microcontroller over the standard USB serial connection. The benefit would be that a long/large media file could be used that can be rendered live. A Processing script runs on a PC to render a media file, sending raw frame data adjusted to the configured NeoPixel grid to a controller. The controller firmware is as generic as possible, acting as a simple conversion tool to drive the NeoPixel grid.


I was impressed with the results! The lag you see is more from me pressing Run on the script and then Play on the video so my laptop could show the playing speeds side by side.

Finally, if you enjoy annoying sounds used to avoid copyright infringement, check this out: