12 Sign redux

A few years ago, I posted about the Seahawks “12” sign that I keep in my window during football season. It was a piece of foam-core board with a strip of Neopixels punched through in the rough shape of a 12.

It is not without its charm, but I needed an upgrade. I have had great luck making fun things out of “RGB LED matrix” panels. These are not built from addressable LEDs like the Neopixel lights in my old 12 sign, but are bare RGB LEDs with just enough circuitry to power and address them. In order to get a persistent image, you have to write to them constantly. Nick Poole did a great write-up on these for Sparkfun.

These panels are usually available from Adafruit or Sparkfun, and they come in a small range of sizes and pitches (pitch is the spacing between the lights). The apple is drawn on a 32×32 6mm pitch panel, about 8″ on a side.

This is the back of a 32×32 4mm pitch panel (5″ x 5″). These panels all have two 16-pin connectors, one input and one output. The primary use case for them is as elements of much larger displays, and they are daisy chainable. You must power each panel individually via the hefty 4-pin connector in the middle. They usually come with a ribbon cable and a power cable (but not a power supply).

I’m driving that Apple logo display with an Arduino Pro Mini. I’m using an Arduino and not a Raspberry Pi because getting a stable image out of these requires consistent timing, and a Pi is just not good at that. I have successfully driven a panel like this from a Pi, but the image was always shaky and flickering. Enter the Adafruit RGB Matrix HAT! This handy little board comes as a kit, which just means that you get to solder the headers on yourself.

The long connector along the back plugs right into the pins on the Pi, the 16-pin connector in the middle is for connecting to the panel, and the screw terminals output 5v. There’s a 2.1mm a barrel connector on the left for 5v in (I recommend a high-amperage supply, at least 2A, preferably more), and there’s a battery slot on the right in case you care about having a persistent real-time clock. In my applications, I don’t need this. The hat will power the Pi, which is nice, and you can use the screw terminals to send power to the panel.

Using these tools, I can build a really neat 12 sign. Driving it with a Raspberry Pi means that I get the full capabilities of a Linux environment to help me decide what to draw. Being able to daisy chain panels lets me build a bigger display. For this project, I chose two 64×32 5mm pitch panels from Adafruit. I have mated them along their long edges, forming an approximately 1′ x 1′ square. I connected them using a 30cm ribbon cable I bought from Amazon.

To join the panels together, I first made a template by laying the panels out how I wanted them and using paper and pencil to make a rubbing of the holes. I used this template to drill out holes in some strips of scrap plastic and then screwed these to the panels (the panels have tapped holes for screw-in feet around their edges). I have a Raspberry Pi + Adafruit’s RGB Matrix HAT connected to the bottom panel and the bottom panel chained up to the top panel. Both panels are powered from the HAT, and the whole thing is powered by an Adafruit 5v 10A supply. I can get this system to pull up to about 40W (8A at 5v) if I turn all the pixels on brightest white. Typical draw is more like 16W.

The software is all python. It takes a rich set of CLI options to define what goes on the panel, and it also exposes an API endpoint and a simple web interface. These are plaintext, unauthenticated endpoints, please do not expose them to the Internet. It defaults to rendering text, but it can also display an image file (I have tested JPG and PNG). Display device options include a single 32×32 panel, a daisy-chained square of 64×32 panels, or an Adafruit Dotstar disc.

One interesting issue I ran into was that I could only convince the Adafruit rgbmatrix library to address the two panels as though they were arranged end-to-end, 128×32 instead of 64×64. I compensate for this by transforming my 64×64 square image to 128×32 at the last minute.

The main executable is “run_sign”, and to run a 64×64 display composed of two 64×32 panels, the call looks like this:

python3 run_sign --decompose --rows 64 --cols 64

The command line arguments represent a subset of the functionality represented by the API.

$ curl localhost:1212/help

Hawks API usage:
  /api/get                Return current settings
  /api/get/presets        Return a list of presets
  /api/set/key/value      Modify a current setting
  /api/do/image           Returns a PNG of the current image

Settings:
  bgcolor                 Background color when rendering 
                           text
  outercolor              Outer color of rendered text
  innercolor              Inner color of rendered text
  font                    Font to use when rendering text
  rows                    Image height
  cols                    Image width
  decompose               Display is a chain of two 64x32 
                           RGB LED matrices arranged to form
                           a big square
  text                    Text to render (if file is "none")
  thickness               Thickness of outercolor border
                           around text
  animation               Options are "waving" or "none"
  amplitude               Amplitude of waving animation
  fps                     FPS of waving animation
  period                  Period of waving animation
  file                    Image file to display (or "none")
  file_path               Directory in which to find files
  margin                  Margin of background color around
                           text
  brightness              Image brighness, full bright = 255
  disc                    Display is a 255-element DotStar
                           disc
  transpose               PIL transpose operations are
                           supported
  rotate                  Rotation in degrees
  mock                    Display is mock rgbmatrix

Calling run_sign with --mock will use mocked implementations of the RGBMatrix and RGBMatrixOptions modules. The mock RGBMatrix will draw the image to your terminal, using two spaces to represent each pixel. This is handy for developing code for an rgbmatrix while not physically near an rgbmatrix. And even when you ARE near your rgbmatrix, you do not have to disturb your sign to test new settings or develop new features.

Calling run_sign with --disc will set the display to an Adafruit Dotstar disc, assumed to be accessible via SPI. These are relatively low-res, but super beautiful.

You can find the code on Github: https://github.com/erickhammersmark/hawks

Leave a comment