Introduction

I’ve always been fascinated by LED screens and seeing beautiful colours mix and merge to create vibrant displays. I also love games, so what better way to combine the two than a giant LED pixel matrix which can play games, display audio levels, really anything you can think of.

It uses a Raspberry Pi to controller strips of digital LEDs mounted inside a pixel grid with a diffuser mounted on top. It requires some basic woodworking skills, soldering, and knowledge of Raspberry Pi.

Project Description

This is a fairly in-depth project build, and as such, the write-up is a bit lengthy, so I’ve broken each section up so you can jump to each stage of the project:

Designing and Printing the Grid

Modelling the baffle

The first step was to create a matrix for separating the pixels. Using non-diffused LEDs is possible for lighting panels, but only with extremely dense LED clusters to create a useable image. I wanted my panel to be big and retro, so some nice chunky pixels were in order. Having the luxury of multiple large format printers available meant that printing them was my first choice. Each pixel (including the pixel frame) is 33mm square, which works nicely with 30 LEDs/m strips. Each part of the frame is 2mm thick, so the pixel ends up only being 31mm in the lit area. Whilst creating mechanical clips for all of the panels would have been possible, I just wanted a simple way to join them and glue/screw together later.

There was no ‘one-size fits all’ tiling pattern available, so I created a couple of different patterns to allow them all to fit together nicely. It also means that someone can take the design and print out more panels to create a bigger matrix if they want.

To make things as easy as possible, I went with a 1m x 0.5m grid, which would allow for 1m strips to make up the rows.

(pictures of models)

Testing for light bleed

After printing a couple of the corner pieces in white, I realised that I should’ve checked for any light bleed between the pixels, so I got testing. It turns out that my baffle model worked well, and almost no light escaped on the top or bottom of the pixels, however, even with a solid 2mm thick wall, the white filament allowed too much light through and you can see a noticeable bleed between the pixels:

Using a black or grey filament eliminated this problem, so I went with grey as I had a bunch of it on hand. I also increased the baffle height to be 20mm instead of 15mm to allow for better dispersion of the light, creating a more even diffusion.

Adding screw tabs

After printing out all the baffles, I realised that I had forgotten to add some anchor points to bolt it into the frame. Not to worry, I just designed and printed some tabs which slotted perfectly between a pixel (on the bottom edge to avoid blocking any light). Some 2-part epoxy and they were rock solid. The entire baffle gets epoxied to the backing frame as well, but having some hardware to help with that mounting is also good.

Constructing the Frame

Using miter joins for frame

Before I assembled the baffle as one whole piece, I wanted to make the frame first so I could ensure a snug fit. Using some 19mm x 42mm pine and some miter joins, I built a simple frame, and then fixed a piece of thick, marine ply to the back. Rather than have all of the wiring exposed on the back panel, I planned to mount a second piece of backing play on top of a small frame to cover the first piece. This can be used to hide any wiring, and also mount the power supplies and board.

Gluing baffle sections together

With my frame completed, I did a second test fit of all the baffle pieces and everything was looking good. After an afternoon and next morning of epoxying the entire baffle together, it became one whole piece which mounted perfectly into the frame with less than 1mm of wiggle room inside the frame. I used Araldite brand epoxy which worked well as it has a 5min set time, but does require 8 hours to fully cure. It is rated at 75KG when fully cured though, so that’s pretty awesome.

Screwing entire baffle into the frame

I used 6x M3 bolts to secure the baffle to the outer frame. This held it in enough to move it around and work on the wiring, without making it to permanent. I ended up removing these once everything was in place as they were no longer required. I then used black silicon and more epoxy to secure everything into place after the wiring was completed.

Adding Backing Panel

The last step to complete the main structure of the display was to add a sheet of 12mm marine grade ply to the back, screwed into the frame, with holes drilled out to run power and data out to the main circuit.

Wiring and Circuitry

Wiring up the LEDs

To make the wiring as neat as possible, I arranged the direction of the grid in a zig-zag pattern starting with 0,0 in a corner. Whilst it makes the code handling a bit trickier, having the wiring as neat as possible was a higher priority, as things can always be modified in code.

Because Dotstar LEDs use SPI, Clock and Data lines are needed and it was the first time I’d wired up that many LEDs in series (15m all up!). After putting in all the SPI wiring, I daisy chained 5V to test the LEDs one by one. The only issue I encountered was a flickering, glitchy behavior on the last few rows of LEDs which I assumed was due to the way I was temporarily running power (it wasn’t, but more on that further on!).

Using multiple power supplies

Something to note about this product is that it requires a fair amount of power. If every LED was lit up at 100% brightness it would draw just over 50 Amps! Fortunately, there are very few cases where you would ever need to draw that much current, however, I used 5 Adafruit 5V 10A power supplies to feed the beast along with some soft limiting in the code, just to allow for maximum fun.

With the Clock and Data lines tested and verified, and all of the LEDs successfully addressed (with the exception of the random glitch behavior), I wired up all 5 power supplies, one for every 3 strips which ensured adequate power for all of the LEDs. The grounds are all connected together, but each 5V line is separated.

Wiring up to Raspberry Pi GPIO

The digital wiring for the Pi is incredibly simple, all I needed to connect was the clock and data lines to the SPI CLK and MOSI pins on the Pi, as well as ground, and I used a spare spot on the power board for a USB port to power the Pi.

Complete rear panel wiring and hanging

With the power supplies mounted, I installed a 6 space power board, ran all of the wires into looms through the panel, and also mounted two hardware strips to run heavy bolts with lock nuts to create a wire hanger for mounting.

Cleaning Up the Grid and Mounting the Diffuser

Mounting paper vellum diffuser

LEDs output bright, focused light, and that’s great for some things, but not for illuminating a giant pixel. To soften the light, I used vellum paper (very similar to tracing paper at art stores) to diffuse each pixel and create a soft, uniform glow. One sheet wasn’t quite enough to get the desired effect, so I used two.

I used some thin, double-sided foam tape on the frame to help mount the vellum paper, before stapling both sheets down around the edge and cutting them down to size.

Mounting acrylic panel

Whilst the vellum paper looked great, it’s fairly easy to tear, and almost impossible to get completely taut so it makes good contact with every part of the grid. So, to create a nice, polished surface, I used a sheet of 4.5mm acrylic, cut down to the size of the frame. I cut out 10 holes for mounting bolts using our new Trotec laser and then used those for guides to drill through the whole frame. I ended up removing the screws I used to mount the backing board to the frame, as they weren’t necessary with the new bolts, and because I had measured the holes for the bolts in the exact same place on the frame (oops!).

The acrylic panel made it look amazing when lit, but the outer edge of the frame wasn’t as clean as I would’ve liked it, so I carefully used some gloss black spray paint to create a nice border.

The only thing I would do differently is to drill the holes for the bolts in the wood before mounting the vellum as when drilling it all together, fine wood chips became lodged in between the layers of vellum. But alas, the construction is finished!

Code

All of the scripts and info required to build your own LED matrix (with some alteration required if you use different dimensions or controllers etc...) can be found on the LED Pixel Panel Github repo.

As I mentioned earlier, there was a strange glitching artifact which occurred towards the end of the signal run. It turned out to be an issue with the line capacitance which played havoc with the high-speed SPI signals, so all that was needed was to decrease the SPI clock speed to 8MHz which is still very fast.

I've posted the scripts for the VU meter and Snake below, however, whilst those scripts will run standalone with the required python modules installed, the project is designed to run on startup, and uses Bluetooth Keyboard inputs to switch between the scripts that are running, which are taken care of by the launcher.sh and handler-script.py files.

Snake

I based my code off a demo written by Paul Brown who published a great demonstration of his snake game which can be played on a Pimoroni Unicorn HAT. After picking through it line by line to understand the mechanics of it, I went to work modifying it to work with an 8Bitdo Bluetooth controller. Pygame actually made it easier than I anticipated as the 8Bitdo controllers have a mode to operate as a standard keyboard.

I tweaked it and added some different event handling and animations, but kept it on the Unicorn HAT form factor. I actually got started on this while I was waiting for my baffle prints to finish, so I didn’t have the full matrix to test it with.

Once I had the basic mechanics working as I wanted them to (I added some end game animations and event handling, plus integrated controller mapping and some other bits and pieces), I modified the code to work with the pixel matrix. It was actually fairly easy as the Unicorn HAT uses WS2812 pixels, which, whilst being functionally different to the APA102 LEDs I used, the library handlers are almost identical (the APA102s are much faster though as they use hardware SPI, not bit-banging protocol).

Spectrum Analyser

This was a fun script to write as it involved learning about some new concepts such as Fourier transforms and other cool maths, however, I left the heavy lifting to the brilliant minds who wrote modules such as ‘numpy’ (number-py). Using a USB microphone, I worked from the basic example shared on the fantastic Rotorton website and then modified it to suit my project.

Build Your Own

As I mentioned at the start, hopefully, I'll have time to create some more games for this panel, however, with the matrix wrapper that I created, anyone can write scripts for it and simply pixels based on a set of cartesian coordinates where 0,0 is the bottom left corner (or you could modify it based on your layout).

I'd love to see a picture if you've made this project or come up with your own remix, so be sure to post some pictures!