Projekt Bouřkového mraku

Bouřkový mrak

Vizualizace různých úrovní hlasitosti hudby pomocí LED diod – VRNI, LS 2015/2016

Členové týmu

Jana Ada Kubíčková, Anna Řezníčková, David Vávra

Inspirace projektu

Inspirací projektu byl produkt Richarda Clarksona "Cloud" http://www.richardclarkson.com/shop/cloud, zejména pak jeho cena, která nás přiměla přemýšlet o tom, jak stejný produkt získat s minimální počáteční investicí. Nebyli jsme první, kdo měl podobný záměr, tudíž se nám na stránce makeuseofit.com podařilo dokonce najít i podrobný návod DIY.

Použitý materiál

1x Breadbord 1x UNO R3 SMD + propojovací USB A-B kabel (Ekvivalent Arduino UNO) 1x Mikrofon 9x 5V LED Cca 25x propojovací kabel 1x polystyrenová deska (tloušťka 2 cm) tavná pistole 1x Polyesterová výplň do polštářů 1x drátěné ramínko 1x Powerbanka Použitý software Arduino IDE 1.6.9 ovladače pro Mac OS

Zapojení

Vlastní zdrojový kód

Lighting Cloud Mood Lamp By James Bruce
View the full tutorial and build guide at http://www.makeuseof.com/
Sound sampling code originally by Adafruit Industries.  Distributed under the BSD license.
This paragraph must be included in any redistribution.
  • /
  1. include "FastLED.h"
  2. define NUM_LEDS 9
  3. define LED_MODE WS2812B
  4. define LED_ORDER GRB

// Mode enumeration - if you want to add additional party or colour modes, add them here; you'll need to map some IR codes to them later; // and add the modes into the main switch loop enum Mode { CLOUD, ACID, OFF, ON, RED, GREEN, BLUE, FADE}; Mode mode = CLOUD; Mode lastMode = CLOUD;

// Mic settings, shouldn't need to adjust these.

  1. define MIC_PIN 0 // Microphone is attached to this analog pin
  2. define DC_OFFSET 0 // DC offset in mic signal - if unusure, leave 0
  3. define NOISE 10 // Noise/hum/interference in mic signal
  4. define SAMPLES 10 // Length of buffer for dynamic level adjustment

byte volCount = 0; // Frame counter for storing past volume data int vol[SAMPLES]; // Collection of prior volume samples int n, total = 30; float average = 0;

// used to make basic mood lamp colour fading feature int fade_h; int fade_direction = 1;

// Define the array of leds CRGB leds[NUM_LEDS];

// Makes all the LEDs a single colour, see https://raw.githubusercontent.com/FastLED/FastLED/gh-pages/images/HSV-rainbow-with-desc.jpg for H values void single_colour(int H, int d = 500) {

for (int i = 0; i < NUM_LEDS; i++) {
  leds[i] = CHSV( H, 255, 255);
}
FastLED.show();
//avoid flickr which occurs when FastLED.show() is called - only call if the colour changes
if (lastMode != mode) {
  FastLED.show();
  lastMode = mode;
}
delay(d);

}

void colour_fade() {

//mood mood lamp that cycles through colours
for (int i = 0; i < NUM_LEDS; i++) {
  leds[i] = CHSV( fade_h, 255, 255);
}
if (fade_h > 254) {
  fade_direction = -1; //reverse once we get to 254
}
else if (fade_h < 0) {
  fade_direction = 1;
}
fade_h += fade_direction;
FastLED.show();
delay(100);

}

// utility function to turn all the lights off. void reset() {

for (int i = 0; i < NUM_LEDS; i++) {
  leds[i] = CHSV( 0, 0, 0);
}
FastLED.show();

}

void detect_thunder() {

n   = analogRead(MIC_PIN);                        // Raw reading from mic
n   = abs(n - 512 - DC_OFFSET); // Center on zero
n   = (n <= NOISE) ? 0 : (n - NOISE);             // Remove noise/hum
vol[volCount] = n;                      // Save sample for dynamic leveling
if(++volCount >= SAMPLES) volCount = 0; // Advance/rollover sample counter
total = 0;
for(int i=0; i<SAMPLES; i++) {
  total += vol[i];
}


// If you're having trouble getting the cloud to trigger, uncomment this block to output a ton of debug on current averages.
// Note that this WILL slow down the program and make it less sensitive due to lower sample rate.
for(int t=0; t<SAMPLES; t++) {
  //initial data is zero. to avoid initial burst, we ignore zero and just add the current l
  Serial.print("Sample item ");
  Serial.print(t);
  Serial.print(":");
  Serial.println(vol[t]);
}
Serial.print("total");
Serial.println(total);
Serial.print("divided by sample size of ");
Serial.println(SAMPLES);
Serial.print("average:");
Serial.println(average);
Serial.print("current:");
Serial.println(n);
average = (total/SAMPLES)+2;
if(n>average){
  Serial.println("TRIGGERED");
  reset();
   
  //I've programmed 3 types of lightning. Each cycle, we pick a random one.
  switch(random(1,3)){
     //switch(3){
    case 1:
      thunderburst();
      delay(random(10,500));
      Serial.println("Thunderburst");
      break;
    
    case 2:
      rolling();
      Serial.println("Rolling");
      break;
     
    case 3:
      crack();
      delay(random(50,250));
      Serial.println("Crack");
      break;      
   
  }
}

}

void acid_cloud() {

// a modification of the rolling lightning which adds random colour. trippy.
//iterate through every LED
for (int i = 0; i < NUM_LEDS; i++) {
  if (random(0, 100) > 90) {
    leds[i] = CHSV( random(0, 255), 255, 255);
  }
  else {
    leds[i] = CHSV(0, 0, 0);
  }
}
FastLED.show();
delay(random(5, 100));
reset();
//}

}

void rolling() {

// a simple method where we go through every LED with 1/10 chance
// of being turned on, up to 10 times, with a random delay wbetween each time
for (int r = 0; r < random(2, 10); r++) {
  //iterate through every LED
  for (int i = 0; i < NUM_LEDS; i++) {
    if (random(0, 100) > 90) {
      leds[i] = CHSV( 0, 0, 255);
    }
    else {
      //dont need reset as we're blacking out other LEDs her
      leds[i] = CHSV(0, 0, 0);
    }
  }
  FastLED.show();
  delay(random(5, 100));
  reset();
}

}

void crack() {

//turn everything white briefly
for (int i = 0; i < NUM_LEDS; i++) {
  leds[i] = CHSV( 0, 0, 255);
}
FastLED.show();
delay(random(10, 100));
reset();

}

void thunderburst() {

// this thunder works by lighting two random lengths
// of the strand from 10-20 pixels.
int rs1 = random(0, NUM_LEDS / 2);
int rl1 = random(10, 20);
int rs2 = random(rs1 + rl1, NUM_LEDS);
int rl2 = random(10, 20);
//repeat this chosen strands a few times, adds a bit of realism
for (int r = 0; r < random(3, 6); r++) {
  for (int i = 0; i < rl1; i++) {
    leds[i + rs1] = CHSV( 0, 0, 255);
  }
  if (rs2 + rl2 < NUM_LEDS) {
    for (int i = 0; i < rl2; i++) {
      leds[i + rs2] = CHSV( 0, 0, 255);
    }
  }
  FastLED.show();
  //stay illuminated for a set time
  delay(random(10, 50));
  reset();
  delay(random(10, 50));
}

}

// basically just a debug mode to show off the lightning in all its glory, no sound reactivity. void constant_lightning() {

switch (random(1, 5)) {
  case 1:
    Serial.println("Thunderburst");
    thunderburst();
    delay(random(10, 500));
    break;
  case 2:
    Serial.println("Rolling");
    rolling();
    break;
  case 3:
    Serial.println("Crack");
    crack();
    delay(random(50, 250));
    break;
  case 4:
    acid_cloud();
    Serial.println("Acid");
    delay(random(50, 250));
    break;
}

}

void setup() {

// this line sets the LED strip type - refer fastLED documeantion for more details https://github.com/FastLED/FastLED
FastLED.addLeds<LED_MODE, 3, LED_ORDER>(&leds[0], 3);
FastLED.addLeds<LED_MODE, 5, LED_ORDER>(&leds[3], 2);
FastLED.addLeds<LED_MODE, 6, LED_ORDER>(&leds[5], 2);
FastLED.addLeds<LED_MODE, 9, LED_ORDER>(&leds[7], 1);
FastLED.addLeds<LED_MODE, 10, LED_ORDER>(&leds[8], 1);
// starts the audio samples array at volume 15.
memset(vol, 15, sizeof(vol));
Serial.begin(115200);

}

void test_lights() {

for (int i = 0; i < NUM_LEDS; i++) {
  leds[i] = CRGB(255, 127, 127);
  FastLED.show();
  delay(500);
  leds[i] = CHSV( 0, 0, 0);
  FastLED.show();
}

}

void loop() {

//constant_lightning();
detect_thunder();
reset();
//{
  /*int r = random(10000);
  if (r < 5) {
    Serial.println("random trigger");
    rolling();
  }*/
//}
/*
  // Maps mode names to code functions.
  switch(mode){
  case CLOUD: detect_thunder();reset();break;
  case ACID: acid_cloud();reset();break;
  case OFF:reset();break;
  case ON: constant_lightning();reset();break;
  case RED: single_colour(0);break;
  case BLUE: single_colour(160);break;
  case GREEN: single_colour(96);break;
  case FADE: colour_fade();break;
  default: detect_thunder(); reset();break;
  }
*/

}

Popis vývoje a konečná verze vlastního produktu

Pro vstupy, které následně generují vzorec blikání, jsme využili mikrofon. Ten zachytí zvuk z prostředí a na základě jeho hlasitosti (v principu rozlišuje tři úrovně hlasitosti - “blesk”, “hrom” a “hřmění”) rozbliká LED. LED diody i mikrofon jsou skrz breadboard vedeny do “arduina”, které je naprogramováno výše zmíněným kódem. Veškeré prvky jsou umístěny v polystyrenové kostře obalené polyesterovou náplné do polštářů tak, aby vypadala jako mrak. Napájení je zajištěno power bankou, takže zařízení je soběstačné a mobilní.

Zhodnocení

Práce na projektu i výsledný výstup předčil naše očekávání. V průběhu práce na projektu jsme museli čelit několika přkážkám - původně zamýšlené LED diody nešly použít kvůli vysokým energetickým nárokům, nikdo z našeho týmu neuměl efektivně pájet, mrak nedělal to, co jsme chtěli, aby dělal. I přes tato dílčí příkoří se však podařilo uspěšně sestrojit mrak, který reaguje na zvuky (bouřky) tak, že budí dojem skutečného bouřkového mraku. Do budoucna bychom chtěli projekt nadále rozšiřovat - zejména přidat bluetooth ovládání a reproduktor.

Fotodokumentace

Videogalerie

https://www.facebook.com/UnicornsAreReal/videos/10209519726973865/?l=3361546968519763848