So, still struggling with the "two differently timed animations at the same time on

fastled-support
gplus
(Andreas Hopf) #1

So, still struggling with the “two differently timed animations at the same time on the same strip” issue.

There is a sketch/function (1), see below, that very slowly lights an APA102C strip with colours fetched from a palette knifed palette (sunrise, day, sunset). That works well. From Mark Kriegsman’s example, I have a sketch/function (2), see below, that adjustably darkens/brightens an APA102C strip (albeit with preset colours). The question is, how I can use the programmatic concept of (2) to influence what is being written to the entire strip with (1), so as not to break the timing of (1) or (2). It’s, as I understand, not an overlay or a mix, but simply a brightness modulation issue.

(1) with EVERY_N_MILLISECONDS over 10 minutes (later several hours) cycles the whole strip through a palette by writing to leds via fill_solid every interval, and now, with the functionality of (2), I would want to randomly modulate (darken/brighten) what is already in leds, but with a different timing.

  • On a side note, I realised that random(8) is not really random?
  • I saw that FastLED.delay() as currently used in (2) does slow the lava-lamp effect down, with 1000 milliseconds for example, but then the darkening/brightening becomes very “steppy” : (

Any help or hints much appreciated!

(1 - only the function that does the work)

void sky() { // Static variables local to the function, but persist between calls

static const float transitionDuration = 10; // Minutes (10 minutes: one step = 2343.75 milliseconds ~ 2.3 seconds)
static const float interval = ((float)(transitionDuration * 60) / 256) * 1000; // Steps in milliseconds
static byte paletteIndex = 0; // Current gradient palette colour

CRGB colour = ColorFromPalette(activePalette, paletteIndex, maxBrightness, LINEARBLEND); // Or use a built-in palette
fill_solid(leds, ledCount, colour); // Set whole strip to colour fetched from the palette

EVERY_N_MILLISECONDS(interval) { // Timed palette traversal
if (paletteIndex < 240) { // Don’t use 255, see https://github.com/FastLED/FastLED/issues/515#issuecomment-340627525
paletteIndex++;
}
}
}

(2 - working sketch)

#include “FastLED.h”

const byte pinData = 3;
const byte pinClock = 4;

const byte ledCount = 144;
byte maxBrightness = 255; // Can be changed on the fly; 10k potentiometer, etc.

#define DARKEST_COLOUR CRGB(24,32,24)
#define BRIGHTEST_COLOUR CRGB(178,186,178)
#define DARKEN_LED CRGB(7,7,7)
#define BRIGHTEN_LED CRGB(19,19,19)

enum {ledConstant, ledBrightens, ledDarkens}; // A flag for the LED states
byte ledState[ledCount];

struct CRGB leds[ledCount];

void setup() {
LEDS.addLeds<APA102, pinData, pinClock, BGR>(leds, ledCount);
LEDS.setBrightness(maxBrightness);
LEDS.setCorrection(Candle); // Candle too warm, Tungsten40W too cold - in-between correction how?
memset(ledState, ledConstant, sizeof(ledState)); // Set all LEDs to constant state
fill_solid(leds, ledCount, DARKEST_COLOUR);
}

void loop()
{
shimmer();
FastLED.show();
FastLED.delay(50); // Higher number = slower, but introduces “steppiness” : (
}

void shimmer()
{
for ( byte i = 0; i < ledCount; i++) { // Go through the entire strip
if ( ledState[i] == ledConstant) { // If LED is in constant state…
if ( random8() < 3) { // …randomly select it based on a threshold (higher number = busier shimmer)…
ledState[i] = ledBrightens; // …and set it to brightening state
}

} else if ( ledState[i] == ledBrightens ) { // If LED is in brightening state...
  if ( leds[i] >= BRIGHTEST_COLOUR ) { // ...and reached brightest colour...
    ledState[i] = ledDarkens; // ...set it to darkening state
  } else {
    leds[i] += BRIGHTEN_LED; // If not, continue brightening it
  }

} else {
  if ( leds[i] <= DARKEST_COLOUR ) { // If LED reached darkest colour...
    leds[i] = DARKEST_COLOUR; // ...keep it there...
    ledState[i] = ledConstant; // ...and set it to constant state
  } else {
    leds[i] -= DARKEN_LED; // If not, continue darkening it
  }
}

}
}

(Ken White) #2

@Andreas_Hopf - You might want to look at @Mark_Kriegsman 's Marquee Overlay sketch at:

Also, use the search community box on the left side of this page and enter the word: YUM.

These might be of use to you.

(Andreas Hopf) #3

Thanks, I saw the YUM video already a while ago, but did not see something that relates to my issue; the MarqueeOverlay example is frankly way beyond my understanding.

What I want to understand/accomplish is how, while one function (1) periodically updates the leds array with a new colour fetched from a palette (sky), that very same leds array is then operated on by another function (2) that periodically darkens/brightens randomly chosen LEDs (shimmer). Both of these work very well independently, apart from the “steppy” changes, when the change intervals become rather long.

A As per the FastLED wiki CRGB leds[144]; creates the array leds for 144 LEDs

B Then the sky() function writes colour from the palette to every element of that array, and it does that EVERY_N_SECONDS

C Then the shimmer() function randomly darkens/brightens random LEDs from that leds array, and it shall do that EVERY_N_MILLISECONDS @Mark_Kriegsman used delay() though

D Finally FastLED.show(); shows the result

It sounds so very simple…

(Ken White) #4

@Andreas_Hopf - Similar to the Marquee Overlay sketch, you might want to look at the rainbowWithGlitter() function in the DemoReel100 example sketch which does two different animations to the whole strip and does the FastLed.show() after doing the two functions animations in the loop. Both the Marquee Overlay sketch and the rainbowWithGlitter() function use this same basic approach to what you want to accomplish.

I would recommend that you create a function that does the sky() function without FastLed.show() in the function and that you create a function that does the shimmer() function without FastLed.show() in the function. Put both functions in the loop and have a FastLed.show() at the end of the loop.

(Andreas Hopf) #5

Thanks, Ken, for your persistence. Two functions are what I have (it’s tricky to discuss code here in these narrow unformatted columns, I know). I have a function sky(), see code above, and a function shimmer(), see code above. When I insert them in a bare-bones DemoReel100 framework, I get 10 minutes of sky(), followed by 5 seconds of shimmer(), but no “overlay” of the two. The leds array is first written to by sky() and then by shimmer().

Both animations are, as those in the DemoReel100 framework, concatenated; they don’t operate on the leds array at the same time, which is all I need, as I understand it. Like in Arduino C/C++ on other projects, I would need some way to change, randomly, values written to the 144 elements of the leds array by the sky() function.

Maybe if I knew what each leds array element contains, meaning the values/structure of each element, I could find out, how to modify them programmatically?

In @Mark_Kriegsman 's DemoReel100, the glitter does not modify the rainbow’s brightness, it just turns some LEDs of the leds array white (+= CRGB::White). It does not darken/brighten the rainbow at those random locations, if you see what I mean.

There must be some way to modulate an already filled leds array with the shimmer() function (also derived from a @Mark_Kriegsman example) that works just brilliantly on its own.

@Stefan_Petrick has an example where two functions write to two separate leds arrays, which are then blended into a third leds array, a very well-written sketch, easy to understand by a novice. However, he uses FastLED’s built-in leds[i] = blend( leds2[i], leds3[i], 64 ) function, which mixes colours, but cannot brighten/darken them. If there would be an alternative to FastLED blend to darken/brighten, then +Stefan Petrick’s solution would be superb.

(Andreas Hopf) #6

Thinking out loud, setting a single LED is done like this:

leds[i].setRGB( r, g, b);
leds[i] = CHSV( h, s, v);

The sky()_function continuously sets _leds[0] … leds[143] to a colour from a palette. The shimmer() function would then have to randomly decrease/increase randomly selected (r, g, b) or only (v) so as to not alter the colour and also not go over the value of 255 to avoid clipping and losing information, like in a whiteout in Photoshop. Could one somehow code a function, a FastLED library addition:

leds[i].brightenRGB(10); affecting RGB equally
leds[i].darkenRGB(10); affecting RGB equally

or

leds[i].increaseV(10); affecting only V of hs v
leds[i].decreaseV(10); affecting only V of hs v

If that were somehow possible, then one could use @Mark_Kriegsman 's derived shimmer() function to programmatically affect whatever other effect is running on the strip.

Would that be a good way forward?

(Jesus Climent) #7

You could create 2 arrays to maintain temporary LED values: the first function writes in the first array, the second function writes in the second array. A final mixer (or whatever name) analyzes array 1 and 2 and writes into the final LED array that FastLED.show() displays.

(Andreas Hopf) #8

@Jesus_Climent Thanks, yes, that’s what I described above regarding Stefan Petrick’s sketch. The question is how to enhance the existing library with

leds[i].increaseV(10); affecting only V value of hsv
leds[i].decreaseV(10); affecting only V value of hsv

because doing it via

leds[i].brightenRGB(10); affecting RGB equally
leds[i].darkenRGB(10); affecting RGB equally

would change the colour, as I read on other threads.

(Andreas Hopf) #9

@Andreas_Hopf Ok, I just found out via @Jason_Coon that for beginners, the best way is to remain in RGB space and use

leds[i].addToRGB(#);
leds[i].subtractFromRGB(#);

to darken/brighten LEDs that are constantly written to by extrapolation from a palette.