Many years ago, I thought it’d be a fun idea to have an RGB panel that would display game sprites on demand, connected to the internet, so people could display a sprite on demand. Just a sort of fun thing to have on my desk. One evening last week, I decided that I wanted to make this thing happen, so I put together some simple software for the panel. Before too long, the software matured into a fun program for my coworkers – Ghost Message
I bought this 16×32 RGB LED panel from Adafruit several years ago. It turned out to require a fair amount of work to get displaying, and I lost interest after unsuccessful attempts. One very difficult part of the problem was wiring. The panel requires a dozen or so pins for clock, latch, three address pins, and two sets of R,G, and B channels. A bit after struggling with Arduino wiring, I had a Nootroopic Backpack manufactured by OSHpark. This reduced the problems to software. In the Nootropic demo, you can see several Pacman ghosts go back and forth. I found this delightful, and set off to replicate it. As I couldn’t find the code for the demo, I reviewed a couple of tutorials and forums on drawing sprites with the libraries for Arduino. You draw graphics on a matrix like this by telling the matrix which LEDs should be on, and which should be off. The easiest way (in my opinion) is to describe it in 8-bit bytes – that is, you layout which dots you want on or off with 0’s or 1’s. Because the ghost that I was making is 14-dots-wide, I needed to have two bytes for each line. When the graphics library read the bytes, it would ignore the last two bits. The code looks like this:
const unsigned char PROGMEM ghost[] =
{
B00000111, B10000000,
B00011111, B11100000,
B00111111, B11110000,
B01111111, B11111000,
B01111111, B11111000,
B01111111, B11111000,
B01111111, B11111000,
B11111111, B11111100,
B11111111, B11111100,
B11111111, B11111100,
B11111111, B11111100,
B11111111, B11111100,
};
If you squint, you can kind of see a ghost shape. That’s what the microcontroller will use to determine where to turn on the LEDs. The output on the display looks like this:
I added some eyes, pupils, and what I refer to in code as the skirt, and I had a good looking Pacman ghost:
After getting the ghost on the display, I decided that I needed some reason for the ghost to be there. Initially it was going to have something to do with the bowl of candy that I keep on my desk. After some thought I decided I liked the idea of someone being able to type a message into a webpage, and then the ghost would go ‘fetch’ that message and bring it back.
Getting a message to the Arduino on the backpack was relatively easy. I just had to add in a serial receiver. The trick was getting a message from someone on a webpage. I threw together a quick NodeJS webserver that had a field and a submit button – soon I was in business:
The server and page was simple enough. The server received POST requests from the page, and would send the message over serial to the board. Basically, people could go to this page, send a message, and it’d be displayed This existed all within my work’s network, so I felt relatively comfortable that nothing truly awful was going to end up on it.
Immediately though, I saw a problem: You had no idea what was on the board, which meant that, while it was interesting for me, people were setting messages and not really getting any feedback other than “Message Delivered”. I wanted everyone to be able see the messages being sent by everyone else. For this, I implemented another networking mechanism: WebSockets.
WebSockets let you maintain a bi-directional connection between the client and the server, and you send data back to the client at any time. For my purposes, I had the added benefit of being able to “broadcast” to all the connected clients, meaning I could send messages sent by one person to everyone else. I had successfully re-invented the chat room.
For fun I added the ability to change the color of the ghost by clicking on it. I’m still working on making the color of the ghost change on the LED Matrix. Getting the colors right while not blinding my neighbors turns out to be a bit hard.
Most recently, I’ve updated the website to animated messages coming in from the right-hand side, in a similar vein as they do on the matrix. Next up is rebuilding the code for the panel – Because it’s been built progressively, with no plan, I’m switching it over to a state machine so I can have lots of options for actions to perform based on state.
As always, I’m interested in your thoughts and comments. If you’d like to see the code, it’s available on Github.