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.
*/
#include "FastLED.h"
#define NUM_LEDS 9
#define LED_MODE WS2812B
#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.
#define MIC_PIN    0  // Microphone is attached to this analog pin
#define DC_OFFSET  0  // DC offset in mic signal - if unusure, leave 0
#define NOISE     10  // Noise/hum/interference in mic signal
#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