Page 1 of 1
Forum

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not bring you to the same post, in Dutch, as there is most likely no translated for the post!





Marble-run on Fire
 
Share:
Notifications
Clear all

Marble-run on Fire


(@ledmeup)
New Member
Joined: 3 weeks ago
Posts: 4
Topic starter  

Hans has done a remarkable work with the LED Effects he has posted (Thank you VERY much, Hans! GREAT work!)

The fire effect has kept me busy for quite a while now. As I´m into marble-runs, I had the funny idea to combine runs with all kind of electronic gizmos like led meteor showers and motors and...

When I came across the Fire-effect, I desperatelywanted to include it in the marble-run I´m working on.

(I have scratched the sketch from different sources and adapted a few things for my purpose.)

Here is the idea:

A marble runs through a lightbeam with an LDR.

My Arduino sketch recognises the break of the beam (Sketch works so far :o)

Then it activates the Fire function (Works, too :o)

But: Fire just runs once and then returns to the main code! :o(

But I need Fire to run for about 10 sec or a number of times until it returns to the main code and the LDR can be triggered again by another marble.

In a different post Hans recommended to use a variable.

for(int i=0; i<25; i++) {
Sparkle(0xff, 0xff, 0xff, 0, 1000); //Need to make 25 times
}

But that was for Sparkle and as my Grandma used to say: "A sparkle doesn´t make a fire!".

I have no idea, where to "int" a variable which counts up (or a timer) and keeps Fire running before returning to the main code.

This is my very first post here and if you have any suggestions to improve my appearence here, you are very welcome.

I would appreciate your help so much!

Here is my code:

/* LDR triggered LED Strip with WS2812B and LED effect "Fire" (by Hans)
 *  20.02.2021
 */

#include "FastLED.h"
#define NUM_LEDS 60 
CRGB leds[NUM_LEDS];
#define PIN 6 
const int analogPin = A0;    // pin that the sensor is attached to
const int ledPin1 = A2;       // pin that the green LED is attached to
const int ledPin2 = A1;       // pin that the yellow LED is attached to
const int threshold = 800;   // an arbitrary threshold level that's in the range of the analog input

void setup()
{
  FastLED.addLeds<WS2811, PIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
  
                              // initialize the LED pin as an output:
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
}


void loop() {
 // read the value of the ldr:
  int analogValue = analogRead(analogPin);

                              // if the analog value is high enough, turn on the LED2yellow:
  if (analogValue > threshold) {
    digitalWrite(ledPin2, HIGH);
  } else {
    digitalWrite(ledPin2, LOW);
  }

                              // if the analog value is low enough, turn on the LED1green:
if (analogValue < threshold) {
  digitalWrite(ledPin1, HIGH);
  Fire(55,120,15);  //          ruft die Funktion FIRE auf, wenn LDR unterbrochen
  
} else {
  digitalWrite(ledPin1, LOW);
}                                         //  könnte ich hier die Funktion für FIRE aufrufen?

  delay(1);        // delay in between reads for stability
}



void Fire(int Cooling, int Sparking, int SpeedDelay) {
  static byte heat[NUM_LEDS];
  int cooldown;
  {
  // Step 1.  Cool down every cell a little
  for( int i = 0; i < NUM_LEDS; i++) {
    cooldown = random(0, ((Cooling * 10) / NUM_LEDS) + 2);
    
    if(cooldown>heat[i]) {
      heat[i]=0;
    } else {
      heat[i]=heat[i]-cooldown;
    }
  }
  
  // Step 2.  Heat from each cell drifts 'up' and diffuses a little
  for( int k= NUM_LEDS - 1; k >= 2; k--) {
    heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3;
  }
    
  // Step 3.  Randomly ignite new 'sparks' near the bottom
  if( random(255) < Sparking ) {
    int y = random(7);
    heat[y] = heat[y] + random(160,255);
    //heat[y] = random(160,255);
  }

  // Step 4.  Convert heat to LED colors
  for( int j = 0; j < NUM_LEDS; j++) {
    setPixelHeatColor(j, heat[j] );
  }

  showStrip();
  delay(SpeedDelay);
}
}
void setPixelHeatColor (int Pixel, byte temperature) {
  // Scale 'heat' down from 0-255 to 0-191
  byte t192 = round((temperature/255.0)*191);
 
  // calculate ramp up from
  byte heatramp = t192 & 0x3F; // 0..63
  heatramp <<= 2; // scale up to 0..252
 
  // figure out which third of the spectrum we're in:
  if( t192 > 0x80) {                     // hottest
    setPixel(Pixel, 255, 255, heatramp);
  } else if( t192 > 0x40 ) {             // middle
    setPixel(Pixel, 255, heatramp, 0);
  } else {                               // coolest
    setPixel(Pixel, heatramp, 0, 0);
  }
}

void showStrip() {
 #ifdef ADAFRUIT_NEOPIXEL_H 
   // NeoPixel
   strip.show();
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   FastLED.show();
 #endif
}

void setPixel(int Pixel, byte red, byte green, byte blue) {
 #ifdef ADAFRUIT_NEOPIXEL_H 
   // NeoPixel
   strip.setPixelColor(Pixel, strip.Color(red, green, blue));
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H 
   // FastLED
   leds[Pixel].r = red;
   leds[Pixel].g = green;
   leds[Pixel].b = blue;
 #endif
}

void setAll(byte red, byte green, byte blue) {
  for(int i = 0; i < NUM_LEDS; i++ ) {
    setPixel(i, red, green, blue); 
  }
  showStrip();
}

Thomas


ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 8 years ago
Posts: 1758
 

Interesting "problem" 😊 

I'd probably create a new function, which keeps running the Fire effect for a certain minimal number of seconds.
Something like:

void FireTimed(int Cooling, int Sparking, int SpeedDelay, int Seconds) {
  unsigned long startTime = millis();
  unsigned long runMillis = 1000 * Seconds;
  
  while(millis()-startTime < runMillis) {
    Fire(Cooling, Sparking, SpeedDelay);
  }
}

 

In short;
- Register the time we start this function in startTime.
- Calculate milliseconds from seconds in runMillis.
- While the current time - start time < desired run time we'd like: execute the Fire effect.

So, in your void loop() code, replace "Fire(x,y,z)" with "FireTime(x,y,z,10)" (10 being 10 seconds).

Note: I have not tested this code, but I'm pretty confident this works as expected (if I didn't make any typos).

Hope this helps 😋 


ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 8 years ago
Posts: 1758
 

Woops, forgot the triggering by other following marbles.

Since the Arduino is not made to multitask, we'd need to check the LDR status in the while loop as well and act accordingly.
Let's first test this new function and then look at how to work with the LDR's.

Since you're using FastLED, we can cleanup your code a little as well - which includes the new function, but is not yet considering following marbles;

/* LDR triggered LED Strip with WS2812B and LED effect "Fire" (by Hans)
 *  20.02.2021
 */

#define FASTLED_INTERNAL // just used to mute the Pragma messages when compiling
#include "FastLED.h"

#define NUM_LEDS 60
CRGB leds[NUM_LEDS];
#define PIN 6
const int analogPin = A0; // pin that the sensor is attached to
const int ledPin1 = A2; // pin that the green LED is attached to
const int ledPin2 = A1; // pin that the yellow LED is attached to
const int threshold = 800; // an arbitrary threshold level that's in the range of the analog input

void setup() {
  FastLED.addLeds < WS2811, PIN, GRB > (leds, NUM_LEDS).setCorrection(TypicalLEDStrip);

  // initialize the LED pin as an output:
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
}

void loop() {
  // read the value of the ldr:
  int analogValue = analogRead(analogPin);

  // if the analog value is high enough, turn on the LED2yellow:
  if (analogValue > threshold) {
    digitalWrite(ledPin2, HIGH);
  } else {
    digitalWrite(ledPin2, LOW);
  }

  // if the analog value is low enough, turn on the LED1green:
  if (analogValue < threshold) {
    digitalWrite(ledPin1, HIGH);
    FireTimed(55, 120, 15, 10); //          ruft die Funktion FIRE auf, wenn LDR unterbrochen

  } else {
    digitalWrite(ledPin1, LOW);
  } //  könnte ich hier die Funktion für FIRE aufrufen?

  delay(1); // delay in between reads for stability
}

void FireTimed(int Cooling, int Sparking, int SpeedDelay, int Seconds) {
  unsigned long startTime = millis();
  unsigned long runMillis = 1000 * Seconds;

  while (millis() - startTime < runMillis) {
    Fire(Cooling, Sparking, SpeedDelay);
  }
}

void Fire(int Cooling, int Sparking, int SpeedDelay) {
  static byte heat[NUM_LEDS];
  int cooldown; {
    // Step 1.  Cool down every cell a little
    for (int i = 0; i < NUM_LEDS; i++) {
      cooldown = random(0, ((Cooling * 10) / NUM_LEDS) + 2);

      if (cooldown > heat[i]) {
        heat[i] = 0;
      } else {
        heat[i] = heat[i] - cooldown;
      }
    }

    // Step 2.  Heat from each cell drifts 'up' and diffuses a little
    for (int k = NUM_LEDS - 1; k >= 2; k--) {
      heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3;
    }

    // Step 3.  Randomly ignite new 'sparks' near the bottom
    if (random(255) < Sparking) {
      int y = random(7);
      heat[y] = heat[y] + random(160, 255);
      //heat[y] = random(160,255);
    }

    // Step 4.  Convert heat to LED colors
    for (int j = 0; j < NUM_LEDS; j++) {
      setPixelHeatColor(j, heat[j]);
    }

    FastLED.show();
    delay(SpeedDelay);
  }
}

void setPixelHeatColor(int Pixel, byte temperature) {
  // Scale 'heat' down from 0-255 to 0-191
  byte t192 = round((temperature / 255.0) * 191);

  // calculate ramp up from
  byte heatramp = t192 & 0x3F; // 0..63
  heatramp <<= 2; // scale up to 0..252

  // figure out which third of the spectrum we're in:
  if (t192 > 0x80) { // hottest
    leds[Pixel] = CRGB(255, 255, heatramp);
  } else if (t192 > 0x40) { // middle
    leds[Pixel] = CRGB(255, heatramp, 0);
  } else { // coolest
    leds[Pixel] = CRGB(heatramp, 0, 0);
  }
}

ReplyQuote
(@ledmeup)
New Member
Joined: 3 weeks ago
Posts: 4
Topic starter  

Hi Hans!

You are the man!!! I wasn´t expecting an answer that soon. Thank you VERY much!

I just checked the sketch out:

It compiles without errors and runs perfectly after triggering the LDR.

The LDR can be triggered again after the 10 secs and it starts fine again. I´m very impressed!

There is just one small issue:

After the 10secs the Strip gets kind of stuck with some LEDs emitting white at the bottom and a few reds somewhere in the strip.

Maybe it´s neccessary to put all LEDs to low (or black) when the time has elapsed?

Your grateful

Thomas

Thomas


ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 8 years ago
Posts: 1758
 

Hi Thomas!

You're very welcome 😊 

To make the LEDs black after the 10 seconds, you can use

fill_solid( leds, NUM_LEDS, CRGB(0,0,0));

Like so:

void FireTimed(int Cooling, int Sparking, int SpeedDelay, int Seconds) {
  unsigned long startTime = millis();
  unsigned long runMillis = 1000 * Seconds;

  while (millis() - startTime < runMillis) {
    Fire(Cooling, Sparking, SpeedDelay);
  }
  
  fill_solid( leds, NUM_LEDS, CRGB(0,0,0));
}

 

This will set the entire strip to black (off).

Hope this fixes that little residue 😊 


ReplyQuote



(@ledmeup)
New Member
Joined: 3 weeks ago
Posts: 4
Topic starter  

@hans

Dear Hans!

Again: Thanks for your help!

I have put the codeline in the void FireTimed... exactly at the place you suggested. But the strip still gets stuck.

I double checked if I did it like you suggested.

 

Thomas


ReplyQuote
(@ledmeup)
New Member
Joined: 3 weeks ago
Posts: 4
Topic starter  

Hi Hans!

There's a big HEUREKA!!!

This line was just missing:

FastLED.show();

Now the sketch runs perfectly and I'm so glad!

Thanks to your help. Without you I would never have made it.

 

Thomas


ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 8 years ago
Posts: 1758
 

Awesome!!!! 👍 😎 

Glad to hear it works as you wanted to! Nice!

And ... you're most welcome! Being able to help someone like this just makes my day 😊 


ReplyQuote

Like what you see and you'd like to help out? 

The best way to help is of course by assisting others with their questions here in the forum, but you can also help us out in other ways:

- Do your shopping at Amazon, it will not cost you anything extra but may generate a small commission for us,
- send a cup of coffee through PayPal ($5, $10, $20, or custom amount),
- become a Patreon,
- donate BitCoin (BTC), or BitCoinCash (BCH).

Share: