This year at Shambhala, I came to learn of the existence of totems. Far from the carved wood aboriginal sculptures you may be thinking of, totems in the sense of music festivals are signs that people can hold with symbols, text, memes, or other identifying features on top. Their only real practical purpose is to help people find you in a crowd, but nonetheless I was intrigued. That Saturday night, I came up with a plan to build my own totem, one that not only captured the fun creative side of making art, but would also allow me to utilize and further develop my programming skills. Hence the rave totem project was born.

An example of a totem at a festival

Planning

The plan was clear in my head from the get go: I wanted a sign, on a long post, with two LED displays at the top back to back. Think street name signs. The LED displays would be capable of displaying 12 or so characters of scrolling text in a variety of colors. I did want something a little bit more interactive though, the goal being having it programmable by anyone at the festival. This meant it had to have some sort of wireless communication abilities, probably Bluetooth connected to my Android phone. When I recieved a text message, the message body should be validated and sent over bluetooth from my phone to the sign. The sign had to be usuable for several nights off of battery power, so low energy was always a goal as well. As far as compute goes, Arduinos are excellent low powered microcontrollers that were well suited for this project. With some careful programming, an Arduino should be sufficient to power the two displays and a bluetooth module while still being low powered enough to last several nights out on the dance floor.

Structurally, it had to be sturdy. Music festivals are not for the faint of heart: Rain, people, my own dancing, dust particles, and chest-pounding bass vibrations would all be present and trying to destroy my creation. To that end, I required a display case for the LED matrices, an enclosure for the Arduino, as well as a good long pole, 7 foot or so, to tie it all together.

Getting started

With newly found purpose after getting home from Shambs, I got straight to work. I had literally zero experience working with microcontrollers, but I was undaunted. I’m a sysadmin at heart, how hard could it be? I ordered an electronics starter kit off of Amazon, and did some electronics homework to get up to speed in the meantime. Once it arrived I got to work. Well, kind of.

My first electronics project, a battery <-> LED circuit

My method of learning is to ramp up, that is, to start small, and work my way towards the finish line. In light of that, I started with the easiest project of all: Powering an LED with a 9-volt battery. A lot of people may have done this in 7th grade or so as part of learning the science of electricity. Nonetheless, it solidified the concepts of voltage, circuits, breadboards, and generally paved the way for bigger and better things, like my next project. Behold!

Hello, world! My first Arduino project

My second electronics project was slightly more ambitious. I actually got to get in and use the Arduino development environment to program a simple “Hello, world” message with an incrementing counter at the bottom. A potentiometer was used to adjust the resistence to the LED display. At this point, a was feeling pretty confident. As it turns out, Arduinos are pretty simple to get into!

At this point, I had a pretty good idea of what I needed to bring the electronics side this project to the finish line. I started ordering parts:

  • 1 BT-06 Bluetooth module, attached to the Arduino to communicate with my phone
  • 4 32x8 LED matrices, to display the characters
  • 1 Arduino Nano. The electronics starter kit came with an Uno, but it was a bit too large for my liking
  • 1 20100mAh Anker powerbank. I already owned this part fortunately

I also purchased a 3” diameter PVC pipe, some 2” diameter PVC pipe fittings, and began researching acyclic plastics at this point. More on that later.

Don’t let your code be dreams

At this point, all of the necessary hardware had arrived. Now the fun part of the project was at hand: Coding! Arduinos are deceptively easy to get into: you have a setup function, a main loop, and some hardware pins that the program controls. Everything else is just details.

Getting started with the LED matrices. Excuse the poor lighting

I started by learning how to program the LED displays. My initial goal was simply to display some scrolling text on two displays. Connecting the displays together was pretty easy, they’re designed to be daisy chained. There’s software libraries on the internet for these specific displays that make programming them easy. Install the libraries, then simply create a Adafruit_NeoMatrix constructor method to include the a length of 64 pixels. Something like the below handily suited that purpose.

#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>

// LED Matrix setup
int pin = 3; // Set initial pin to 3.
Adafruit_NeoMatrix matrix = new Adafruit_NeoMatrix(64, 8, pin, // Width, height, hardware pin out
  NEO_MATRIX_BOTTOM    + NEO_MATRIX_RIGHT +
  NEO_MATRIX_COLUMNS + NEO_MATRIX_ZIGZAG,
  NEO_GRB            + NEO_KHZ800);
int x = matrix.width();
String message = "Hello, world!"

void setup() {
  matrix.setTextWrap(false);
  matrix.setBrightness(30); // Moderately bright
  matrix.setTextColor(matrix.Color(255, 0, 0)); // Red
}

void loop() {
  matrix.print(text);

  if(--x < -45) { // Reset the scrolling if it gets too far off screen
    x = matrix.width(); 
  }

  matrix.show();
}

Great! I can now display messages on two 32x8 LED displays, daisy chained together to make one display of 64x8. This would be enough for one side of the totem, albiet with some crude scrolling logic. What happens when we go for four 32x8 LED displays?

NOTHING. Dang. Not a single pixel on the displays lit up. I had a clue from a Reddit user I was collaborating with that this would happen. As it turns out, Arduinos are woefully low on memory: They have 2KB (2048 bytes) of SRAM. For reference, your average Android phone may contain 4GB of RAM, a mere 2,000,000 time mores. Each pixel takes about 3 bytes of RAM, each byte correlates to a color intensity from 0 to 255 (Red, Blue, and Green). 4 panels * 32 pixels wide * 8 pixels tall = 1024 pixels, 1024 pixels * 3 bytes per LED = 3072 bytes of memory needed, more than my cute little Nano is capable of holding in its tiny brain. So what now?

Behold, low level memory optimization of necessity! My goal wasn’t to have one 1024 pixel display, it was to have two mirrored 512 pixel displays. In addition, my program was pretty inefficient, making use of strings instead of char*, ints instead of shorts, and other such memory hogs. After fixing up those simple variable inefficiencies, I went to tackle the mirrored display problem. There’s a handy setpin() function that allows for updating which pin to send data out on to your LED matrix, which I made use of. Every single loop, update the pin, display the message. Every other loop (Because there’s two displays!), scroll the text one pixel over. Boom! Now we’re only using 1536 bytes of SRAM, leaving me with a whole 512 bytes of RAM to do literally everything else. I made use of object pointers to avoid copying the Adafruit_Neopixel object, it’s an expensive operation to recreate such an object. Using pointers was slightly more efficient, removing the need to copy in the pixel data every loop. Sneaked it in just under the line!

Bluetooth module, why art thou yet so shit

Progress! Next up on the list was communications: How do I talk between my phone and the Arduino to send messages? Enter the BT-06 module (from hell!)

The BT-06 module ended up being the most troublesome part of this whole project, but thinking back I’m actually grateful for the issues it helped shape the end product to be way more polished. In theory, the BT-06 module is pretty simple. There’s 4 pins: a 5v VCC, GND, Rx, and Tx. The VCC and GND are connected to the electrical circuit the Arduino supplies, the Rx pin (Receive) connects to the designated Arduino Tx pin (Transmit) and vise versa. The basic Bluetooth protocol should be familiar to most readers: There’s a pairing process, during which the LED on the BT-06 module blinks, and a connected state, during which the LED is solidly lit. This module is easy to use for serial communication, which is essentially sending bits of data one at a time until you send the whole message. There’s several bluetooth serial apps for Android available on the market for these purposes. The message for BT-06 modules is unhelpfully terminated by a timeout instead of a “\n” newline character for example, but that wasn’t anything I couldn’t work around. Some sample code, out of context and inefficient, is below.

#define BAUD_RATE 9600 // Talk to BT-06 at this baud rate

#include <SoftwareSerial.h>

// Bluetooth Setup
SoftwareSerial bluetooth(9, 10); // RX, TX
String message = ""; // A variable to hold the receieved message

// Bluetooth Setup
SoftwareSerial bluetooth(9, 10); // RX, TX pins

void setup() {
  bluetooth.begin(BAUD_RATE);
}

void loop() {
  if (bluetooth.available()) { // If there's a new message being sent
    while (bluetooth.available()) { // While there is more to be read, keep reading.
      message += (char)bluetooth.read(); // Append the recieved character to the message
    }
    // Do something with the received message here
  }
}

The code was simple enough, the troublesome issue was hardware reliability. Modifying the initial code to accept Bluetooth input was simple enough, but 10% of the time the message wouldn’t be delivered. Worse yet, 30% of the time the message would be received as nothing but mangled garbage. I couldn’t be walking around Shambhala with nonsense ASCII characters being displayed on my sign, nosiree. Thus began the request for reliable data transmission (Shoutout to TCP! I <3 you!)

The first iteration of this BT-06 communicator functionality was making use of a Tasker plugin for BT-06 communication. I would simply listen for incoming texts on my phone, extract the body of the text message, and send that using the Tasker plugin to the BT-06 module. Simple and effective. Well, it would have been if transmission was reliable. Enter my desire to learn Android application development. If I could program my own app that could talk to the Arduino / BT-06 combo (henceforce refered to as “the totem”), I could build my own simple reliable tranmission protocol. I toyed with the idea of doing message checksumming on the Arduino itself, but since I still needed to eliminate the “message-not-received” case, I ultimated decided that simply echoing the message back to the Android application would work.

I’ll be honest, the first five or so attempts at making the app failed miserably. It turns out Bluetooth programming on Android is a bit of a shit show, not to mention having to re-learn Java. Attempt 6 though, that’s where the training wheels came off. I sat down and started writing code just like all the other attempts, however this time is kind of just clicked and workable code came out. Funny how that persistence stuff works, eh?

Android apps are usually pretty messy looking, and my amatuerish one is certainly no exception. You can see the repository here, but really the only interesting bit of the repository is this file right here. Looking through it, it contains code for requesting necessary SMS and bluetooth permissions, code for receiving and sending SMS messages, code for connecting to the totem and a few other handy functions (such as validation and retransmission of messages as necessary). Of particular interest is the below snippet of code, which I’m happy to report turns my unreliable BT-06 module into a unreliable-but-fixable BT-06 module

// When receiving a response, check to see if it matches lastMessage. If not, retransmit
        @Override
        public void onMessage(byte[] message) {
            String strMessage = new String(message); // Convert the message
            strMessage = strMessage.replaceAll("[^ -~]", "");
            if (!(strMessage.equals(lastMessage))) {
                logMessage("Received message \"" + strMessage + "\" does not match last sent text \"" + lastMessage + "\", retransmitting...");
                sendMessage(lastMessage);
            } else {
                logMessage("Received matching totem response \"" + strMessage + "\"");
                sendSuccess = true;
            }
        }

I had far too much fun putting together the UI for the app. I could have settled for an uninspired and boring and rickety looking design. That’s not that inspired though, so I went with a fun totem design that indicates the connection to my totem:

The app when it has established a bluetooth connection to the totem

"The app when it's disconnected from the totem"

Putting it all together

I was pretty happy at this point: I had a servicable Android app, a great proof of concept hardware set up, and some memory optimized Arduino code that I was proud of. I still had to put some finishing touches on the Arduino code, it ended up looking like this (Though it’s still subject to change)

#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
#include <SoftwareSerial.h>

#define BAUD_RATE 9600 // Talk to BT-06 at this baud rate

#define LEDPIN1 3
#define LEDPIN2 5
#define LEDREFRESHRATE 0 // Rate at which the screen will update
#define LEDMATRIXWIDTH  64
#define LEDMATRIXHEIGHT 8

#define FONTWIDTH 6

#define MAXMSGLENGTH  32

#define RED 0
#define GREEN 1
#define BLUE  2
#define BRIGHTNESS 16

// Bluetooth Setup
SoftwareSerial bluetooth(9, 10); // RX, TX
char charBuf[MAXMSGLENGTH + 2]; // A buffer to hold the receieved message

// LED Matrix setup
byte pin = LEDPIN1; // Set initial pin to 3.
Adafruit_NeoMatrix* matrix = new Adafruit_NeoMatrix(LEDMATRIXWIDTH, LEDMATRIXHEIGHT, pin,
    NEO_MATRIX_BOTTOM    + NEO_MATRIX_RIGHT +
    NEO_MATRIX_COLUMNS + NEO_MATRIX_ZIGZAG,
    NEO_GRB            + NEO_KHZ800);
short x = matrix->width();
byte color = RED;
short maxDisplacement; // 

void setup() {
  bluetooth.begin(BAUD_RATE);
  matrix->setTextWrap(false);
  matrix->setBrightness(BRIGHTNESS); // Moderately bright
  matrix->setTextColor(matrix->Color(255, 0, 0)); // Red
  matrix->setRotation(2); // Rotate the text 180 degrees
}

void loop() {
  matrix->begin(); // Initialize / Reinitialize, keeping in mind the data PIN changes every loop
  matrix->fillScreen(0);
  matrix->setCursor(x, 0);

  if (bluetooth.available()) { // If there's a new message being sent
    memset(charBuf, 0, sizeof(charBuf)); // Reset the variable that stores the message
    byte i = 0;
    while (bluetooth.available()) { // While there is more to be read, keep reading.
      charBuf[i] += (char)bluetooth.read();
      i++;
    }

    // Send back what was received, to be validated on the other side
    bluetooth.write(strcat(charBuf, "\n"));

    // Update maxDisplacement for improved scrolling (Doesn't reset scroll early / too late)
    maxDisplacement = strlen(charBuf) * FONTWIDTH + matrix->width();
  }

  matrix->print(charBuf);

  // Every loop, swap between digital output pins 3 and 5
  if (pin == LEDPIN1) {
    pin = LEDPIN2;
    if (--x < -maxDisplacement) { // Every other loop, move the cursor. If this is false, it's time to reset the scroll back to the beginning
      x = matrix->width(); // Reset the scrolling if it gets too far off screen

      // Change the color
      if (color == BLUE) {
        color = RED;
      } else {
        color++;
      }
      switch (color) {
        case RED:
          matrix->setTextColor(matrix->Color(255, 0, 0)); // Red
          break;
        case GREEN:
          matrix->setTextColor(matrix->Color(0, 255, 0)); // Green
          break;
        case BLUE:
          matrix->setTextColor(matrix->Color(0, 0, 255)); // Blue
      }
    }
  } else {
    pin = LEDPIN1;
  }

  matrix->setPin(pin); // Perform the actual pin update

  matrix->show();
  delay(LEDREFRESHRATE); // Rate at which the screen will update. Since it's mirrored, it's effectively double this
}

Next steps, constructing the totem. Part two will contain high powered lasers, acrylic plastics, and extremely sketchy looking taped together PVC pipe parts with wires sticking out of them. Will I get arrested? Stay tuned!