LED Dress – Part 3

December 13, 2013 Experiments

Its alllliiiive!  I practiced some more circuit sewing using some snaps and stainless steel thread.  From a tip on Adafruit, the best way to make sure the circuits don’t fall apart is to apply a drop of clear nail polish to each knot that you tie.  Because of the stiffness of the steel thread, knots have tendency to fall apart without this step!

  • Seal the knots with clear nail polish.

I used Kapton tape to insulate the threads in areas where they leave the fabric.

DSC_0283

Here is a quick gif showing how the dress reacts to sound.  Based on the virtual prototype I created previously… I was able to just write a display function to apply the RGB array values to the three strips of NeoPixels.

LEDdressGIF

Here is a short video showing the dress and its sound reaction in a little more depth.

Here is the code showing how I control the lights:

/* LED Dress - Seth Moczydlowski - 12/13/2013
This sketch takes in microphone input and triggers a light pattern based on the ambient sound volume. Running
average values are used to compare the sound levels and change the display color of the LEDs while a threshold
function determines when the "explosion" pattern is enabled
 */
#include <Adafruit_NeoPixel.h>
// Microphone inputs
const int micPin = 10;
const int dcOff = 0;
const int noise = 40;

// Neopixel inputs
const int strand1Pin = 12;
const int strand2Pin = 6;
const int strand3Pin = 9;
Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(8, strand1Pin, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip2 = Adafruit_NeoPixel(4, strand2Pin, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip3 = Adafruit_NeoPixel(4, strand3Pin, NEO_GRB + NEO_KHZ800);

// 4 moving average values that are used to control the light levels
int lvlRaw = 0, lvlSm=0, lvlMd=0, lvlLg=0;

// pseudo-moving average series
const int samples = 20;
// sampleSm stores averages of lvlRaw from the microphone
int sampleSm[samples],
// sampleMd stores averages lvlSm
sampleMd[samples],
// sampleLg stores averages lvlMd
sampleLg[samples];

// keeps track of when averages are taken
int countSm=0,countMd=0;

// array for channel colors of LEDs, this array is used to send to the Processing sketch for
// development, but will also be used to write to the LED displays
int ledDisp[16][3];

// color numbers for the different display elements
int baseColor[3];
int expColor[3];

// sample taking timer
unsigned long timer=0;
int colorDelay = 300;

// explosion timer
unsigned long expTimer;

void setup(){
  //initialize serial for debugging
  //Serial.begin(9600);

  // initialize arrays
  memset(sampleSm, 0, sizeof(sampleSm));
  memset(sampleMd, 0, sizeof(sampleMd));
  memset(sampleLg, 0, sizeof(sampleLg));

  memset(baseColor, 0, sizeof(baseColor));
  memset(expColor, 0, sizeof(expColor)); 

  for (int i=0;i<16;i++){
    for (int j=0;j<3;j++){
      ledDisp[i][j]=0;
    }
  }
  // initialize LED strips
  strip1.begin();
  strip2.begin();
  strip3.begin();
  strip1.show();
  strip2.show();
  strip3.show();

  //initialize timers
  timer=millis();
  expTimer = millis();
}

void loop(){
  uint8_t  i;
  uint16_t minLvl, maxLvl;
  int      n, height;

  // reads mic and dampens the input... taken from Adafruit AmpliTie sketch
  n   = analogRead(micPin);                        // Raw reading from mic 
  n   = abs(n - 512 - dcOff); // Center on zero
  n   = (n <= noise) ? 0 : (n - noise);             // Remove noise/hum
  lvlRaw = ((lvlRaw * 7) + n) >> 3;    // "Dampened" reading (else looks twitchy)
  //Serial.println(lvlRaw);

  // cycle values through sampleSm array, adding newst value to the front
  for (i=samples-1;i>0;i--){
    sampleSm[i]=sampleSm[i-1];
  }
  sampleSm[0] = lvlRaw;
  // update lvlSm 
  lvlSm = getAverage(sampleSm);
  // increment countSm
  countSm++;

  // every (sample #) sampleSm additions, the sampleMd array is augmented
  if (countSm>samples){
    //reset counter
    countSm = 0;
    // cycle values through sampleMd array, adding newst value to the front
    for (i=samples-1;i>0;i--){
      sampleMd[i]=sampleMd[i-1];
    }
    sampleMd[0] = lvlSm;
    //increment counter
    countMd++;
  }
  // update lvlMd number
  lvlMd = getAverage(sampleMd);

  // every (sample #) sampleMd additions, the sampleLg array is augmented
  if (countMd>samples){
    //reset counter
    countMd = 0;
    // cycle values through sampleLg array, adding newst value to the front
    for (i=samples-1;i>0;i--){
      sampleLg[i]=sampleLg[i-1];
    }
    sampleLg[0] = lvlMd;
    // no counter needed
  }
  // update lvlLg number
  lvlLg = getAverage(sampleLg);

// Display running average numbers for debugging
//  Serial.print(lvlRaw);
//  Serial.print(",");
//  Serial.print(lvlSm);
//  Serial.print(",");
//  Serial.print(lvlMd);
//  Serial.print(",");
//  Serial.println(lvlLg);

  //update colors
  updateBaseColor();
  updateExpColor();
  //  initiate explosions
  explosions();

// Debugging functions
  //  printVals();
  //  chase();

  // update LEDs
  updateLEDs();
}

// chase is a test pattern to see if all of the leds are working correctly
int chaseNum = 0;
void chase(){
  ledDisp[chaseNum][0] = 0;
  ledDisp[chaseNum][1] = 0;
  ledDisp[chaseNum][2] = 0;
  chaseNum++;
  if(chaseNum>15)
    chaseNum=0;
  ledDisp[chaseNum][0] = 255;
  ledDisp[chaseNum][1] = 255;
  ledDisp[chaseNum][2] = 255;
}

void printVals(){
  Serial.print(ledDisp[0][0]);
  Serial.print(",");
  Serial.print(ledDisp[0][1]);
  Serial.print(",");
  Serial.print(ledDisp[0][2]);

  for (int i = 1;i<16;i++){
    for (int j = 0;j<3;j++){
      Serial.print(",");
      Serial.print(ledDisp[i][j]);
    }
  }
  Serial.println();
}
// calculates and returns average of the array passed into it
int getAverage(int inArray[]){
  int calc=0;
  for(int i=0;i<sizeof(inArray);i++)
    calc+=inArray[i];

  calc/=sizeof(inArray);
  return calc;
}

// random pattern used for testing
void randColors(){
  if (timer+colorDelay<millis()){
    for (int i = 0; i < 16; i++) {  
      ledDisp[i][0]+=lvlRaw;
      ledDisp[i][1]+=lvlSm;
      ledDisp[i][2]+=lvlMd;
      for (int j=0;j<3;j++){
        if (ledDisp[i][j]>255)
          ledDisp[i][j]-=256;
      }
    }
    timer=millis();
  }
}

int lastExplosion;
int stepsSinceExp;
int expDelay=100;
int expTol = 30;

void explosions(){
  if (expTimer+expDelay<millis()){
    int change = 15;
    //constrains input to randomizing code so nothing goes out of bounds
    for (int i = 0; i < 16; i++) {  
      ledDisp[i][0]=baseColor[0];
      ledDisp[i][1]=baseColor[1];
      ledDisp[i][2]=baseColor[2];
    }
    if (stepsSinceExp>8&&abs(lvlSm-lvlLg)>expTol){
      // sets random explosion point between the 2nd and 7th LEDs
      lastExplosion = int(random(1,6));
      stepsSinceExp=0;
    }

    if (stepsSinceExp==0){
      // when stepsSinceExp is 0, the explosion just happened, so only two LEDs need to light up
      ledDisp[lastExplosion][0]=expColor[0];
      ledDisp[lastExplosion][1]=expColor[1];
      ledDisp[lastExplosion][2]=expColor[2];
      ledDisp[7+8-lastExplosion][0]=expColor[0];
      ledDisp[7+8-lastExplosion][1]=expColor[1];
      ledDisp[7+8-lastExplosion][2]=expColor[2];
    }
    else{
      //position is calculated for the positions above and below the explosion point
      //based on steps since explosion
      int above = lastExplosion-stepsSinceExp;
      int below = lastExplosion+stepsSinceExp;
      if(above>=0){
        // keep display from going out of upper bound
        ledDisp[above][0]=expColor[0];
        ledDisp[above][1]=expColor[1];
        ledDisp[above][2]=expColor[2];
        ledDisp[7+8-above][0]=expColor[0];
        ledDisp[7+8-above][1]=expColor[1];
        ledDisp[7+8-above][2]=expColor[2];
      }
      // keep display from going out of lower bound
      if(below<=7){
        ledDisp[below][0]=expColor[0];
        ledDisp[below][1]=expColor[1];
        ledDisp[below][2]=expColor[2];
        ledDisp[7+8-below][0]=expColor[0];
        ledDisp[7+8-below][1]=expColor[1];
        ledDisp[7+8-below][2]=expColor[2];
      }

    }

    // increases steps since explosion and punches time
    stepsSinceExp++;
    expTimer = millis();
  }
}

void updateBaseColor(){
  // base color fades from red to yellow/green based on the 3rd running average value
  int highNum = 60;
    baseColor[0] = int(map(constrain(lvlLg,0,highNum),0,highNum,255,0));
    baseColor[1] = int(map(constrain(lvlLg,0,highNum),0,highNum,0,75));
    baseColor[2] = 0;

}

void updateExpColor(){
  // Explosion color fades from blue to green also based on the 3rd running average value
  int highNum = 100;
  expColor[0] = 0;
  expColor[1] = int(map(constrain(lvlLg,0,highNum),0,highNum,255,00));
  expColor[2] = int(map(constrain(lvlLg,0,highNum),0,highNum,0,255));

}

void updateLEDs(){
  // when I originally laid out the circuit in the dress... I hadn't completely thought
  // through how I was going to control them... as a result, the order is really screwy
  // this function updates the LEDs with relation to the array I was using for prototyping

  for (int i=0;i<4;i++){
    strip1.setPixelColor(i+4,ledDisp[i][0],ledDisp[i][1],ledDisp[i][2]);
  }

  for(int i=4;i<8;i++){
    strip2.setPixelColor(i-4,ledDisp[i][0],ledDisp[i][1],ledDisp[i][2]);
  }

  for(int i=8;i<12;i++){
    strip3.setPixelColor(11-i,ledDisp[i][0],ledDisp[i][1],ledDisp[i][2]);
  }

  for(int i=12;i<16;i++){
    strip1.setPixelColor(i-12,ledDisp[i][0],ledDisp[i][1],ledDisp[i][2]);
  }
  strip1.show();
  strip2.show();
  strip3.show();
  //delay(30);
}

 

Leave a Reply

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