DIY Festival Totem

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 | comment feed

Leave a Reply

Your email address will not be published. Required fields are marked *