Advertisement
otoc

simple rain and lightning simulation using FastLED

Nov 1st, 2015
602
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.11 KB | None | 0 0
  1. #include <FastLED.h>
  2.  
  3. // This simulates a light rain with some lightning.
  4. // You still need to add some wind to get a thunderstorm.
  5. // using a lot of 3rd party code (almost all)
  6. // For a demo see here: https://www.youtube.com/watch?v=7VH_mzjnUwE
  7. //   Thomas Runge (tom@truwo.de)
  8.  
  9. #define DATA_PIN      9
  10. #define LED_PIN       13
  11. #define LED_TYPE      WS2811
  12. #define COLOR_ORDER   GRB
  13. #define M_WIDTH       8
  14. #define M_HEIGHT      8
  15. #define NUM_LEDS      (M_WIDTH*M_HEIGHT)
  16. #define BRIGHTNESS    180
  17. #define NUM_DROPLETS  (2*M_WIDTH)
  18.  
  19. CRGB leds_plus_safety_pixel[ NUM_LEDS + 1 ];
  20. CRGB* leds(leds_plus_safety_pixel + 1);
  21.  
  22. uint16_t XY(uint8_t x, uint8_t y) {
  23.   uint16_t i;
  24.  
  25.   if(y & 0x01) {
  26.     // Even rows run backwards
  27.     i = (y * M_WIDTH) + x;
  28.   } else {
  29.     // Odd rows run forwards
  30.     uint8_t reverseX = (M_WIDTH - 1) - x;
  31.     i = (y * M_WIDTH) + reverseX;
  32.   }
  33.  
  34.   return i;
  35. }
  36.  
  37. uint16_t XYsafe(uint8_t x, uint8_t y) {
  38.   if(x >= M_WIDTH) {
  39.     return -1;
  40.   }
  41.   if(y >= M_HEIGHT) {
  42.     return -1;
  43.   }
  44.   return XY(x,y);
  45. }
  46.  
  47. // Original by: Daniel Wilson, 2014
  48. // Modified by: Andrew Tuline 2015
  49. // found: https://github.com/atuline/FastLED-Demos/blob/master/lightnings/lightnings.ino
  50. // modified to run almost non blocking by Thomas Runge
  51. void lightning(uint8_t firstled, uint8_t num_leds, uint8_t flashchance) {
  52.   static const uint8_t FLASHES = 8;
  53.   static unsigned long flashNext;
  54.   static uint8_t flashCounter = 0, flashMax = 0;
  55.   static uint8_t ledlen, ledstart;
  56.  
  57.   // (re)init data
  58.   if (flashCounter == flashMax) {
  59.     ledlen = random8(3, num_leds-3); // length of flash, at least 3 LEDs
  60.     ledstart = firstled+random8(num_leds-ledlen); // start of flash
  61.     flashNext = millis()+1000*random8(flashchance); // random start of flash sequence
  62.     flashCounter = 0;
  63.     flashMax = random8(3, FLASHES);
  64.   }
  65.  
  66.   // show next flash, if it's time has come
  67.   if (millis() >= flashNext) {
  68.     uint8_t dimmer;
  69.  
  70.     if(flashCounter == 0) {
  71.       // the brightness of the leader is scaled down by a factor of 5
  72.       dimmer = 5;
  73.     } else {
  74.       // return strokes are brighter than the leader
  75.       dimmer = random8(1, 3);
  76.     }
  77.  
  78.     // Show a section of LED's
  79.     fill_solid(leds+ledstart, ledlen, CHSV(255, 0, 255/dimmer));
  80.  
  81.     // each flash only lasts 4-10 milliseconds
  82.     FastLED.delay(random8(4, 10));
  83.  
  84.     // Clear the section of LED's
  85.     fill_solid(leds+ledstart, ledlen, CRGB::Black);
  86.     FastLED.show();
  87.  
  88.     flashNext = millis()+50+random8(100);
  89.     if (flashCounter == 0) {
  90.       flashNext += 150;
  91.     }
  92.     flashCounter++;
  93.   }
  94. }
  95.  
  96.  
  97. // algorithm by "danny"
  98. // found here: http://rurandom.org/justintime/index.php?title=WS2811_%22Water_torture%22
  99. // or here: https://github.com/DannyHavenith/ws2811/blob/master/src/water_torture.hpp
  100. // ported to FastLED by Thomas Runge
  101. /// This class maintains the state and calculates the animations to render a falling water droplet
  102. /// Objects of this class can have three states:
  103. ///    - inactive: this object does nothing
  104. ///    - swelling: the droplet is at the top of the led strip and swells in intensity
  105. ///    - falling: the droplet falls downwards and accelerates
  106. ///    - bouncing: the droplet has bounced of the ground. A smaller, less intensive droplet bounces up
  107. ///      while a part of the drop remains on the ground.
  108. /// After going through the swelling, falling and bouncing phases, the droplet automatically returns to the
  109. /// inactive state.
  110. class Droplet {
  111.   public:
  112.     Droplet()
  113.     : column(0), color(CRGB::Black), gravity(5),
  114.       position(0), speed(0), state(inactive)
  115.     {}
  116.  
  117.     void init(uint16_t column) {
  118.       this->column = column;
  119.       reinit();
  120.     }
  121.  
  122.     void reinit() {
  123.       this->position = 0;
  124.       this->speed = 0;
  125.       this->color = CHSV(144+random8(32), 255, BRIGHTNESS);
  126.       this->start = millis()+1000*random8(5);
  127.       state = swelling;
  128.     }
  129.  
  130.     /// perform one step and draw.
  131.     void step(CRGB *leds) {
  132.       if (millis() >= start) {
  133.         step();
  134.         draw(leds);
  135.       }
  136.     }
  137.  
  138.   private:
  139.     /// calculate the next step in the animation for this droplet
  140.     void step() {
  141.       if (state == falling || state == bouncing) {
  142.         position += speed;
  143.         speed += gravity;
  144.    
  145.         // if we hit the bottom...
  146.         const uint16_t maxpos16 = (M_HEIGHT-1) << 8;
  147.         if (position > maxpos16) {
  148.           if (state == bouncing) {
  149.             // this is the second collision,
  150.             // deactivate.
  151.             state = inactive;
  152.             reinit();
  153.           } else {
  154.             // reverse direction and dampen the speed
  155.             position = maxpos16 - (position - maxpos16);
  156.             speed = -speed/4;
  157.             color.nscale8_video(collision_scaling);
  158.             state = bouncing;
  159.           }
  160.         }
  161.       } else if (state == swelling) {
  162.         ++position;
  163.         if (color.blue <= 10 || color.blue - position <= 10) {
  164.           state = falling;
  165.           position = 0;
  166.         }
  167.       }
  168.     }
  169.  
  170.     /// Draw the droplet on the led string
  171.     /// This will "smear" the light of this droplet between two leds. The closer
  172.     /// the droplets position is to that of a particular led, the brighter that
  173.     /// led will be
  174.     void draw(CRGB *leds) {
  175.       if (state == falling || state == bouncing) {
  176.         uint8_t position8 = position >> 8;
  177.         uint8_t remainder = position; // get the lower bits
  178.    
  179.         CRGB tc = color;
  180.         if (position8 < M_HEIGHT) {
  181.           uint8_t lidx = XYsafe(column, M_HEIGHT-1-position8);
  182.           leds[lidx] += tc.nscale8_video(256 - remainder);
  183.           if (remainder && position8+1 < M_HEIGHT) {
  184.             lidx = XYsafe(column, M_HEIGHT-1-position8+1);
  185.             tc = color;
  186.             leds[lidx] += tc.nscale8_video(remainder);
  187.           }
  188.         }
  189.    
  190.         if (state == bouncing) {
  191.           uint8_t lidx = XYsafe(column, 0);
  192.           leds[lidx] = color;
  193.         }
  194.       } else if (state == swelling) {
  195.         CRGB tc = color;
  196.         uint8_t lidx = XYsafe(column, M_HEIGHT-1);
  197.         leds[lidx] = tc.nscale8_video(position);
  198.       }
  199.     }
  200.  
  201.     // how much of a color is left when colliding with the floor, value
  202.     // between 0 and 256 where 256 means no loss.
  203.     static const uint16_t collision_scaling = 40;
  204.     uint16_t column;
  205.     CRGB color;
  206.     uint16_t gravity;
  207.     uint16_t position;
  208.     int16_t  speed;
  209.     enum stateval {
  210.       inactive,
  211.       swelling,
  212.       falling,
  213.       bouncing
  214.     };
  215.  
  216.     stateval state;
  217.     unsigned long start;
  218. };
  219.  
  220. Droplet droplets[NUM_DROPLETS];
  221.  
  222. void setup() {
  223.   randomSeed(analogRead(0));
  224.   random16_set_seed(1579);
  225.   random16_add_entropy(analogRead(0));
  226.  
  227.   FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalSMD5050);
  228.   FastLED.setBrightness(BRIGHTNESS);
  229.  
  230.   for (uint8_t idx = 0; idx < NUM_DROPLETS; ++idx) {
  231.     droplets[idx].init(idx % M_WIDTH);
  232.   }
  233. }
  234.  
  235. void loop() {
  236.   lightning(NUM_LEDS-M_WIDTH, M_WIDTH, 10);
  237.  
  238.   fill_solid(leds, NUM_LEDS, CRGB::Black);
  239.   for (uint8_t idx = 0; idx < NUM_DROPLETS; ++idx) {
  240.     droplets[idx].step(leds);
  241.   }
  242.  
  243.   FastLED.delay(15);
  244. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement