Knowledge for the World

The Compact Disc-o: My LED disco ball music festival totem!

I made a programmable LED disco ball totem for bringing to music festivals -- a Compact Disc-o Ball, if you will. :)

What's a totem?
As you may know, you don't get cellular reception at many large music festivals. Also at large music festivals, you're unlikely to find your friends again if you get separated (especially at night). Thus, many people create "totems", which are basically poles with some kind of decoration on it so that you can find your friends in a crowd. The totem is a beacon for your friends -- both new and existing -- to find you and stick together.

So to maximize visibility and awesomeness, I made an LED totem for attending EDC Las Vegas in June -- the largest electronic music festival in the world.

Overview:
I 3D printed the orb and pegs that hold the LED strand and CDs. Then, I used an Adafruit Trinket microcontroller to program a pattern for the LEDs and powered everything using a 4400mAh Lithium-ion battery. I put all the circuitry in a small control box with a switch for durability and made the pole itself from PVC.

This is my build guide!

None

As the prophecy commands, first some completed photos!

Here's a GIF of the disco ball in action (without the totem pole):

And, because GIFs are generally terrible, here's a short video of it in action:

None

And the fully assembled totem pole! The disco ball is about 1.5-2X the size of a basketball

None

The model I used was created by DesignerFred on Thingiverse. Thanks DesignerFred! He told me he'd never actually printed the model before, so I was a bit of a guinea pig on this one.

Printing the orb took about 12 hours, and the 14 pegs needed to hold the CDs took another 12 hours. All in all, it was a day of printing. I used "clear" PLA filament for the print.

With all the support material still attached, it reminds me of the (destroyed) Death Star.

None

I had to print the model with support material so that it didn't collapse on itself while printing (you can't print into thin air, after all). Removing the support material was challenging (and sharp), and I managed to fill the entire bottom of my entire trash can with it.

None

The finished orb! Looks nice.

None

After printing the pegs, I did a test fit using some terrible CDs I had left over from middle and high school. DON'T JUDGE ME.

None

The original model wasn't intended to be illuminated, but I knew I wanted to add some LEDs to make the totem really visible to my friends (and to look awesome).

I wanted to drive each LED individually so that I could program a really cool pattern. So I decided to use a 5V Adafruit Trinket microcontroller to drive a strand of LEDs that are individually addressable (which means that you can tell each LED which color, brightness, etc. to be -- similar to a giant LED billboard).

I ended up using a digital output and digital clock pin from the Trinket, but the Trinket also has analog outputs for PWM. Pulse-Width Modulation (PWM) is an analog output method where the width between pulses in a wave is varied/modulated (hence the name), and the chips in the LEDs can interpret this as data and tell the LEDs when and which color to light up. :)

Using the digital output approach instead, electrical pre-programmed signals are sent directly to and interpreted by each LED's driver.

I've used the Trinket for a lot of projects, it's pretty awesome -- and it's only $6.

None

I needed to power the whole setup using a battery since it's portable; so I grabbed a 4400mAh Lithium-ion battery to power the LEDs and microcontroller. Since most small batteries are 3.7V (don't ask me why), and the microcontroller and LED strip is 5V, a power booster is necessary to boost the 3.7V up to 5V. To do this, I used an Adafruit Power Boost 1000C, which also has a built-in charging circuit. :)

I also brought a few extra batteries just in case: two 2000mAh Lithium-polymer (LiPo) batteries.

None

Here's another shot of how I breadboarded everything for prototyping purposes.

I wrote a simple program to run on the Trinket, based on the Adafruit strandtest program. It's not the cleanest, but I didn't have a lot of time before EDC and it looked really great.

Here's the code I came up with based on the strandtest program (also on Github):

#include "Adafruit_WS2801.h"
///include "SPI.h" // Comment out this line if using Trinket or Gemma
#ifdef __AVR_ATtiny85__
 #include <avr/power.h>
#endif

/*****************************************************************************
Example sketch for driving Adafruit WS2801 pixels!


  Designed specifically to work with the Adafruit RGB Pixels!
  12mm Bullet shape ----> https://www.adafruit.com/products/322
  12mm Flat shape   ----> https://www.adafruit.com/products/738
  36mm Square shape ----> https://www.adafruit.com/products/683

  These pixels use SPI to transmit the color data, and have built in
  high speed PWM drivers for 24 bit color per pixel
  2 pins are required to interface

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution

*****************************************************************************/

// Choose which 2 pins you will use for output.
// Can be any valid output pins.
// The colors of the wires may be totally different so
// BE SURE TO CHECK YOUR PIXELS TO SEE WHICH WIRES TO USE!
uint8_t dataPin  = 1;    // Yellow wire on Adafruit Pixels
uint8_t clockPin = 2;    // Green wire on Adafruit Pixels

// Don't forget to connect the ground wire to Arduino ground,
// and the +5V wire to a +5V supply

// Set the first variable to the NUMBER of pixels. 25 = 25 pixels in a row
Adafruit_WS2801 strip = Adafruit_WS2801(15, dataPin, clockPin);

// Optional: leave off pin numbers to use hardware SPI
// (pinout is then specific to each board and can't be changed)
//Adafruit_WS2801 strip = Adafruit_WS2801(25);

// For 36mm LED pixels: these pixels internally represent color in a
// different format.  Either of the above constructors can accept an
// optional extra parameter: WS2801_RGB is 'conventional' RGB order
// WS2801_GRB is the GRB order required by the 36mm pixels.  Other
// than this parameter, your code does not need to do anything different;
// the library will handle the format change.  Examples:
//Adafruit_WS2801 strip = Adafruit_WS2801(25, dataPin, clockPin, WS2801_GRB);
//Adafruit_WS2801 strip = Adafruit_WS2801(25, WS2801_GRB);

void setup() {
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000L)
  clock_prescale_set(clock_div_1); // Enable 16 MHz on Trinket
#endif

  strip.begin();

  // Update LED contents, to start they are all 'off'
  strip.show();
}


void loop() {
  // base
  colorWipe(Color(255, 0, 0), 50); // red
  rainbow(2);
  colorWipe(Color(0, 255, 0), 50); // green
  rainbowCycle(2);
  colorWipe(Color(0, 0, 255), 50); // blue
  rainbow(2);
  colorWipe(Color(255,0,255), 50); // magenta
  rainbowCycle(2);
  colorWipe(Color(255,140,0), 50); // orange
  rainbow(2);

  // now let's go slow
  colorWipe(Color(255, 0, 0), 100); // red
  colorWipe(Color(255,140,0), 100); // orange
  colorWipe(Color(255,255,0), 100); // yellow
  colorWipe(Color(0, 255, 0), 100); // green
  colorWipe(Color(0, 0, 255), 100); // blue
  colorWipe(Color(255,0,255), 100); // magenta

  // base again..
  colorWipe(Color(255, 0, 0), 50); // red
  rainbow(2);
  colorWipe(Color(0, 255, 0), 50); // green
  rainbowCycle(2);
  colorWipe(Color(0, 0, 255), 50); // blue
  rainbow(2);
  colorWipe(Color(255,0,255), 50); // magenta
  rainbowCycle(2);
  colorWipe(Color(255,140,0), 50); // orange
  rainbow(2);
  
  // now let's go fast!
  colorWipe(Color(255, 0, 0), 10); // red
  colorWipe(Color(255,140,0), 10); // orange
  colorWipe(Color(255,255,0), 10); // yellow
  colorWipe(Color(0, 255, 0), 10); // green
  colorWipe(Color(0, 0, 255), 10); // blue
  colorWipe(Color(255,0,255), 10); // magenta
}

// fill the dots one after the other with said color
// good for testing purposes
void colorWipe(uint32_t c, uint8_t wait) {
  int i;
  
  for (i=0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, c);
      strip.show();
      delay(wait);
  }
}

void rainbow(uint8_t wait) {
  int i, j;
   
  for (j=0; j < 256; j++) {     // 3 cycles of all 256 colors in the wheel
    for (i=0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel( (i + j) % 255));
    }  
    strip.show();   // write all the pixels out
    delay(wait);
  }
}

// Slightly different, this one makes the rainbow wheel equally distributed 
// along the chain
void rainbowCycle(uint8_t wait) {
  int i, j;
  
  for (j=0; j < 256 * 5; j++) {     // 5 cycles of all 25 colors in the wheel
    for (i=0; i < strip.numPixels(); i++) {
      // tricky math! we use each pixel as a fraction of the full 96-color wheel
      // (thats the i / strip.numPixels() part)
      // Then add in j which makes the colors go around per pixel
      // the % 96 is to make the wheel cycle around
      strip.setPixelColor(i, Wheel( ((i * 256 / strip.numPixels()) + j) % 256) );
    }  
    strip.show();   // write all the pixels out
    delay(wait);
  }
}

/* Helper functions */

// Create a 24 bit color value from R,G,B
uint32_t Color(byte r, byte g, byte b)
{
  uint32_t c;
  c = r;
  c <<= 8;
  c |= g;
  c <<= 8;
  c |= b;
  return c;
}

//Input a value 0 to 255 to get a color value.
//The colours are a transition r - g -b - back to r
uint32_t Wheel(byte WheelPos)
{
  if (WheelPos < 85) {
   return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
   WheelPos -= 85;
   return Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170; 
   return Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

None

I grabbed a cheap project enclosure from Radioshack when it was closing (you can get them on Amazon too). This will hold the power switch, power booster, and microcontroller. I also wanted it to hold the battery originally, but the enclosure was too small, so I ended up Velcroing the battery on instead (more on that later).

None

After I was happy that everything was working, it was time to solder up my control box. I added a 4-wire quick-release JST connector so I could disconnect the control box easily. This was necessary since I was going to package this thing up and fly to the music festival with it.

None

Here's the completed photo of the control box. The battery didn't fit inside the box so I used some Velcro to secure it. It worked really well and this approach made it easier to change batteries on the go.

None

I also had a few Lithium-polymer (LiPo) batteries lying around that I was able to use.

Did I mention I brought this on a plane without hassle? I thought for sure it would look sketchy.

None

Using a power booster to increase 3.7V to 5V decreases its overall capacity -- after all, you're drawing more power. Since my battery capacity (measured in mAh, or milliamp-hours) has now decreased, I wanted to be sure I'd bring enough batteries. So I had to use.. a spreadsheet. Dunn-dunn-dunnnn...

I uploaded the spreadsheet here if you're into that sort of thing or want to build something similar.

100% power consumption assumes that all LEDs are lit up white at 100% brightness (which isn't really the case per the program I wrote), so the combined batteries lasted more like 12 hours.

None

So, the guy who made this model didn't intend for it to be used with LEDs in the first place, and the housing on the LEDs was just barely too large to fit through each hole. Also, you can't drill the hole out to make it larger since drilling PLA plastic makes it melt and ruins it immediately (found through testing).

So I had to cut each set of LED wires, run an extension set of 4 wires through the hole, and then solder them. I ended up using 14 LEDs for the 14 holes, which is 8 wires per LED (4 in and 4 out).

This totaled 112 individually soldered wires, making it by far the most time-consuming part of the project. On the bright side, I'm now a pro at joining wires via soldering! :) I also shrink-wrapped each wire for good measure.

I used the NASA approach for joining wires so I could get some practice with that method (it's the best IMHO):

None

It was important to leave a length of wire on each "arm" so it could protrude properly out of the end of each peg, where the CD resides. I left a bit of slack on each just to be safe.

None

All soldered up! I also added a 15th LED to the center of the orb to light it up as well, in addition to the 14 LED arms.

None

I attached all of the pegs and ran a test pattern. It's really starting to come together!

My plan was to run the totem like this for a day, and then add the CDs on the following day. Because I think it looks pretty neat both with and without the CDs.

None

Next, I added all my terrible CDs and did another test.

None

And a shot in the dark.

None

I really wish I had more photos of the PVC pipe (totem pole) that held the disco ball, but I kind of rushed through that part. It was made of 3 different 4' segments of PVC pipe. One segment slid into the second, and the third segment attached via a PVC coupling. So when fully assembled, the totem pole was 12' tall!

I painted the poleblue, drilled holes in it, and ran bolts through the holes to provide mounting points for the disco ball and control box. Unfortunately, I don't have a lot of pics of assembling the totem pole itself, but I do have some pics of the totem in action at EDC. Like this one.

None

And this one, testing the totem on the shuttle bus on the way to EDC!

None

I had the idea to add some loops to the totem so that my friend Genevieve could attach her LED hula hoop to it. This would make the totem stand out more, and also she wouldn't have to carry her hoop around all night. So I 3D printed a few hoop loops and attached them to the totem pole using stainless steel hose clamps. I added a bit of Velcro to each one for extra security.

None

Here's a picture of the totem in action with hoop deployed -- this was the day when I left the CDs off the totem. You can see a few of the pegs hanging off -- apparently, reinstalling the pegs repeatedly when I was building it and packing it for the plane ride weakened the connective portion of the peg, so some of them didn't stay on that great through hours of constant movement.

This was only an issue because of how much I was beating on it and how many times I took it apart. For the second day, I swapped these out with some fresh backup pegs I printed and I was good to go.

None

Bonus blurry photo of Genevieve hooping!

None

And one more bonus EDC photo I took! If you look very carefully in the bottom left, you can see the totem hoop (I was on my way to change the battery in the disco ball for my buddies, so it's not lit up!)

None

The final resting place for my disco ball -- to save on airline baggage fees, I ditched the pole in Vegas and only brought the disco ball back.

It's now hanging in my office, above my 3D printer. This was super handy for Hurricane Irma -- it lit up the entire room when we were out of power. :) I'm planning a different totem for the next music festival (probably a backpack-mounted one so I can keep my hands free).

Anyways, I hope you enjoyed my build! If you want to build your own and need any help, or have any questions/ideas, be sure to post in the comments section below.