DIY Festival Totem

Check out my glowing totem - perfect for your next festival!

Favorited Favorite 1

It’s festival season, and what better place to show off your creative engineering projects? Festivals are the perfect place to don your interactive, LED-clad outfits and accessories. After checking out some really cute and funny totems online, I decided to make one in my own image: a big, glowing, iridescent crystal totem. A totem in the context of a festival acts as a beacon or a locater for a group of friends and is a perfect object to add some electronics to.



The crystal totem features a clear plastic shaft stuffed with iridescent confetti, which is topped with a large, iridescent, crystal-like structure embedded with WS2812 LEDs.

crystal totem



The microcontroller - a Qduino Mini - can be found at the bottom of the shaft for easy access to the power switch and USB port for charging and reprogramming.

totem qduino



Toward the top of the shaft is a clear, laser-cut acrylic plate held in place using hot glue and wooden dowels. You can find the two potentiometers included in our circuit on this plate.

totem fabrication



Atop the acrylic plate sits an upside-down glass fishbowl, covered in resin-cast crystals and WS2812 LEDs.

totem top

Below is a fritzing digram of the circuit:

Totem Circuit

Having a hard time seeing the circuit? Click on the image for a closer look.

As mentioned, I included two potentiometers in this project. The first, connected to AO, controls the speed of the LED animation. The second, connected to A1, controls the animation currently displaying on the LEDs. My program features 11 distinct modes or animations, including an all-off and all-on mode.

The code for this project can be found below. I am absolutely aware that this is not the most efficiently or elegantly written program, and would love to hear about how you would have approached it in the comments below.

//Melissa Felderman for Sparkfun Electronics 2018 

#include <Adafruit_NeoPixel.h>
#define  A1 
#define speedPot A0
#define PIN 6
#define momBut 3
int numPix = 66;
int speedPotVal;
int modePotVal; 
int mappedSpeed;
int mode = 0;




Adafruit_NeoPixel strip = Adafruit_NeoPixel(numPix, PIN, NEO_GRB + NEO_KHZ800);

int stripOne[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
int stripTwo[] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21};
int stripThree[] = {32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22};
int stripFour[] = {33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43};
int stripFive[] = {54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44};
int stripSix [] = {55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66};

int stripOneNormal[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int stripThreeNormal[] = {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
int stripFiveNormal[] = {44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54};


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  strip.begin();
  strip.show();


}

void loop() {




  speedPotVal = analogRead(speedPot);
  modePotVal = digitalRead(modePot);

  mode = map(modePotVal, 0, 1023, 0, 10);
  mappedSpeed = map(speedPotVal, 0, 1023, 10, 200);
  //
  //  Serial.print(mappedBright);
  //  Serial.print(", ");
  //  Serial.println(mappedSpeed);

  Serial.println(mode);



  switch (mode) {
    case 0:
      for (int i = 0; i < numPix; i++) {
        strip.setPixelColor(i, 0, 0, 0);
      }
      strip.show();
      break;
    case 1:
      oneSixth();
      break;
    case 2:
      alternating();
      break;
    case 3:
      oneDrip();
      break;
    case 4:
      twoDrip();
      break;
    case 5:
      theaterChase(strip.Color(127, 127, 127), 50); // White
      break;
    case 6: 
      oneOpposingDrip();
      break;
    case 7: 
      twoOpposingDrip();
      break;
    case 8: 
     singleChase();
     break;
    case 9:
      allOn(); 
      break;
    case 10:
      allOn();
      break;
  }


}

void theaterChase(uint32_t c, uint8_t wait) {
  for (int j = 0; j < 10; j++) { //do 10 cycles of chasing
    for (int q = 0; q < 3; q++) {
      for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, c);  //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, 0);      //turn every third pixel off
      }
    }
  }
}

void alternating() {
  strip.setBrightness(70);
  for (int i = 0; i < 11; i ++) {
    strip.setPixelColor(stripOne[i], 255, 255, 255);
    strip.setPixelColor(stripThree[i], 255, 255, 255);
    strip.setPixelColor(stripFive[i], 255, 255, 255);

    strip.setPixelColor(stripTwo[i], 0, 0, 0);
    strip.setPixelColor(stripFour[i], 0, 0, 0);
    strip.setPixelColor(stripSix[i], 0, 0, 0);
  }
  strip.show();
  delay(mappedSpeed);
  for (int i = 0; i < 11; i ++) {
    strip.setPixelColor(stripOne[i], 0, 0, 0);
    strip.setPixelColor(stripThree[i], 0, 0, 0);
    strip.setPixelColor(stripFive[i], 0, 0, 0);

    strip.setPixelColor(stripTwo[i], 255, 255, 255);
    strip.setPixelColor(stripFour[i], 255, 255, 255);
    strip.setPixelColor(stripSix[i], 255, 255, 255);
  }
  strip.show();
  delay(mappedSpeed);
}


void oneDrip() {
  for (int i = 0; i < 11; i++) {

    strip.setPixelColor (stripOne[i], 255, 255, 255);
    strip.setPixelColor (stripTwo[i], 255, 255, 255);
    strip.setPixelColor (stripThree[i], 255, 255, 255);
    strip.setPixelColor (stripFour[i], 255, 255, 255);
    strip.setPixelColor (stripFive[i], 255, 255, 255);
    strip.setPixelColor (stripSix[i], 255, 255, 255);

    strip.show();
    delay(mappedSpeed);
    strip.setPixelColor (stripOne[i], 0, 0, 0);
    strip.setPixelColor (stripTwo[i], 0, 0, 0);
    strip.setPixelColor (stripThree[i], 0, 0, 0);
    strip.setPixelColor (stripFour[i], 0, 0, 0);
    strip.setPixelColor (stripFive[i], 0, 0, 0);
    strip.setPixelColor (stripSix[i], 0, 0, 0);

  }

}


void twoDrip() {

  for (int i = 0; i < 11; i++) {
    strip.setPixelColor (stripOne[i], 255, 255, 255);
    strip.setPixelColor (stripTwo[i], 255, 255, 255);
    strip.setPixelColor (stripThree[i], 255, 255, 255);
    strip.setPixelColor (stripFour[i], 255, 255, 255);
    strip.setPixelColor (stripFive[i], 255, 255, 255);
    strip.setPixelColor (stripSix[i], 255, 255, 255);

    strip.setPixelColor (stripOne[i + 5], 255, 255, 255);
    strip.setPixelColor (stripTwo[i + 5], 255, 255, 255);
    strip.setPixelColor (stripThree[i + 5], 255, 255, 255);
    strip.setPixelColor (stripFour[i + 5], 255, 255, 255);
    strip.setPixelColor (stripFive[i + 5], 255, 255, 255);
    strip.setPixelColor (stripSix[i + 5], 255, 255, 255);

    strip.show();
    delay(mappedSpeed);
    strip.setPixelColor (stripOne[i], 0, 0, 0);
    strip.setPixelColor (stripTwo[i], 0, 0, 0);
    strip.setPixelColor (stripThree[i], 0, 0, 0);
    strip.setPixelColor (stripFour[i], 0, 0, 0);
    strip.setPixelColor (stripFive[i], 0, 0, 0);
    strip.setPixelColor (stripSix[i], 0, 0, 0);

    strip.setPixelColor (stripOne[i + 5], 0, 0, 0);
    strip.setPixelColor (stripTwo[i + 5], 0, 0, 0);
    strip.setPixelColor (stripThree[i + 5], 0, 0, 0);
    strip.setPixelColor (stripFour[i + 5], 0, 0, 0);
    strip.setPixelColor (stripFive[i + 5], 0, 0, 0);
    strip.setPixelColor (stripSix[i + 5], 0, 0, 0);

  }

}


void oneSixth() {

  for (int i = 0; i < 11; i++) {

    strip.setPixelColor (stripOne[i], 255, 255, 255);
    strip.setPixelColor (stripSix[i], 0, 0, 0);
  }
  strip.show();
  delay(mappedSpeed);
  for (int i = 0; i < 11; i++) {

    strip.setPixelColor (stripOne[i], 0, 0, 0);
    strip.setPixelColor (stripTwo[i], 255, 255, 255);
  }
  strip.show();
  delay(mappedSpeed);
  for (int i = 0; i < 11; i++) {

    strip.setPixelColor (stripTwo[i], 0, 0, 0);
    strip.setPixelColor (stripThree[i], 255, 255, 255);
  }
  strip.show();
  delay(mappedSpeed);
  for (int i = 0; i < 11; i++) {

    strip.setPixelColor (stripThree[i], 0, 0, 0);
    strip.setPixelColor (stripFour[i], 255, 255, 255);
  }
  strip.show();
  delay(mappedSpeed);
  for (int i = 0; i < 11; i++) {

    strip.setPixelColor (stripFour[i], 0, 0, 0);
    strip.setPixelColor (stripFive[i], 255, 255, 255);
  }
  strip.show();
  delay(mappedSpeed);
  for (int i = 0; i < 11; i++) {

    strip.setPixelColor (stripFive[i], 0, 0, 0);
    strip.setPixelColor (stripSix[i], 255, 255, 255);
  }
  strip.show();
  delay(mappedSpeed);
}


void pulse() {
  for (int j = 0; j < 255; j++) {
    for (int i = 0; i < numPix; i++) {
      strip.setPixelColor(i, j, j, j);
    }
    strip.show();
    delay(mappedSpeed/5);
  }
  for (int j = 255; j >= 0; j--) {
    for (int i = 0; i < numPix; i++) {
      strip.setPixelColor(i, j, j, j);
    }
    strip.show();
    delay(mappedSpeed/5);

  }
}

void allOn() {
  for (int i = 0; i < numPix; i++) {
    strip.setPixelColor(i, 150, 150, 150);
  }
  strip.show();
}



void singleChase() {
  for (int i = 0; i < numPix; i++){
    strip.setPixelColor(i, 255, 255, 255);
    strip.setPixelColor(i+1, 255, 255, 255);
   strip.setPixelColor(i+2, 255, 255, 255);
   strip.show();
   delay(mappedSpeed); 
    strip.setPixelColor(i, 0, 0, 0);
    strip.setPixelColor(i+1, 0, 0, 0);
   strip.setPixelColor(i+2, 0, 0, 0);

  }
}

void oneOpposingDrip() {
  for (int i = 0; i < 11; i++) {


      strip.setPixelColor (stripOneNormal[i], 255, 255, 255);
      strip.setPixelColor (stripTwo[i], 255, 255, 255);
      strip.setPixelColor (stripThreeNormal[i], 255, 255, 255);
      strip.setPixelColor (stripFour[i], 255, 255, 255);
      strip.setPixelColor (stripFiveNormal[i], 255, 255, 255);
      strip.setPixelColor (stripSix[i], 255, 255, 255);

      strip.show();
      delay(mappedSpeed);
      strip.setPixelColor (stripOneNormal[i], 0, 0, 0);
      strip.setPixelColor (stripTwo[i], 0, 0, 0);
      strip.setPixelColor (stripThreeNormal[i], 0, 0, 0);
      strip.setPixelColor (stripFour[i], 0, 0, 0);
      strip.setPixelColor (stripFiveNormal[i], 0, 0, 0);
      strip.setPixelColor (stripSix[i], 0, 0, 0);

    }
  }





void twoOpposingDrip() {

  for (int i = 0; i < 11; i++) {

    strip.setPixelColor (stripOneNormal[i], 255, 255, 255);
    strip.setPixelColor (stripTwo[i], 255, 255, 255);
    strip.setPixelColor (stripThreeNormal[i], 255, 255, 255);
    strip.setPixelColor (stripFour[i], 255, 255, 255);
    strip.setPixelColor (stripFiveNormal[i], 255, 255, 255);
    strip.setPixelColor (stripSix[i], 255, 255, 255);

    strip.setPixelColor (stripOneNormal[i + 5], 255, 255, 255);
    strip.setPixelColor (stripTwo[i + 5], 255, 255, 255);
    strip.setPixelColor (stripThreeNormal[i + 5], 255, 255, 255);
    strip.setPixelColor (stripFour[i + 5], 255, 255, 255);
    strip.setPixelColor (stripFiveNormal[i + 5], 255, 255, 255);
    strip.setPixelColor (stripSix[i + 5], 255, 255, 255);

    strip.show();
    delay(mappedSpeed);
    strip.setPixelColor (stripOneNormal[i], 0, 0, 0);
    strip.setPixelColor (stripTwo[i], 0, 0, 0);
    strip.setPixelColor (stripThreeNormal[i], 0, 0, 0);
    strip.setPixelColor (stripFour[i], 0, 0, 0);
    strip.setPixelColor (stripFiveNormal[i], 0, 0, 0);
    strip.setPixelColor (stripSix[i], 0, 0, 0);

    strip.setPixelColor (stripOneNormal[i + 5], 0, 0, 0);
    strip.setPixelColor (stripTwo[i + 5], 0, 0, 0);
    strip.setPixelColor (stripThreeNormal[i + 5], 0, 0, 0);
    strip.setPixelColor (stripFour[i + 5], 0, 0, 0);
    strip.setPixelColor (stripFiveNormal[i + 5], 0, 0, 0);
    strip.setPixelColor (stripSix[i + 5], 0, 0, 0);

  }

}

Every build leads to much discovery. In the case of my crystal totem, I found as I fabricated my totem that it was quickly getting far too heavy to realistically be held for several hours of dancing. In the next iteration, I would likely cast much smaller crystals and look for a lighter fishbowl - perhaps something in plastic. I might also increase the number of LED strips to 12 to give it some more light, and add a microphone to include a sound-reactive mode.

What would your festival totem look like? Let us know your thoughts in the comments below!


Comments 2 comments

  • Neat project, Feldi! I do have a suggestion, though, based on my “flashy badge” (sort of a “Hello, my name is…” that flashes it in Morse code) and my “flashy Santa hat”: The programmable LEDs can be dazzlingly bright in low light levels, but if you want to be seen in full sun light you need to have them running at full tilt – you need some way to respond to ambient light. In my projects I’ve used an analog light sensor to do the adjustments “automagically”, though since you already have a couple of pots, and plenty of space for them, adding a third pot to do it manually would work. BTW, I would expect that at least some festivals would have “light effects” of their own (I’ve never been to one, and given my physical handicaps, it’s not that likely I will ever get to one), so if you do go the “automated” route you might want to include some sort of “averaging” on the readings so it doesn’t respond (much) to flashes of light from outside your totem. (If you want some more detailed suggestions on how to do the “averaging”, feel free to ask me!)

  • Using glass? For shame! Glass at festivals is dangerous, because accidents happen. You should have used an acrylic/plastic/something bowl, or cobbled something together, NOT glass.

    How’d you do the resin “crystals”?

Related Posts

Recent Posts

Tags


All Tags