These are chat archives for Makuna/NeoPixelBus

1st
Jun 2016
Maksim Surguy
@msurguy
Jun 01 2016 00:23
Sure, basic example could be seen in NeoPixelFunFadeInOut by using NEO_CENTISECONDS instead of default timing value and using random(20000, 60000) on this line: https://github.com/Makuna/NeoPixelBus/blob/master/examples/NeoPixelFunFadeInOut/NeoPixelFunFadeInOut.ino#L87 , what's interesting is that using same big values in Fade to Black block of code appears to fade to black without stepping while fading from one color to another visibly goes from one color step to another.
Michael Miller
@Makuna
Jun 01 2016 01:13
That piece of code is blending using RGB color space. Generally fine but when doing very slow animations you "might" see stepping. You might want to use HslColor space objects instead. The blend across hue to done with floating point.
HslColor result = HslColor::LinearBlend<NeoHueBlendShortestDistance>(left, right, progress);
But take an example of blending between Blue (0,0,127) to Green (0,127,0). That's a maximum of 127 steps which means about two steps per second when animating over 60 seconds. And due to perceived gamma, (see wiki on gamma correction) some of the low values are often hard to see.
Michael Miller
@Makuna
Jun 01 2016 01:18
@sticilface has done some very slow animating, but I think he also switched to Hsl/Hsb color blending.
Charles
@hallard
Jun 01 2016 10:25
@Makuna
may be a stupid question but what's to best way to create 2 distinct animations (for 2 led on same strip)?
I have 2 leds on board and want to be able to do mainly 2 different animations, both can breathing (not same color) or blinking (not same color), one breathing one blinking and vice-versa and both not at the same speed.
I created with Animation table of 2 element but it does not seem to do the job. because when I call animate in main loop it manage only one "real" animation speed for both.
But may be it's not possible ? Any idea or direction will help me ;-)
Charles
@hallard
Jun 01 2016 10:42
Here is my code declaration
 // The RGB animation state machine 
typedef enum {
  RGB_ANIM_NONE,
  RGB_ANIM_FADE_IN,
  RGB_ANIM_FADE_OUT,
  RGB_ANIM_BLINK_ON,
  RGB_ANIM_BLINK_OFF,
} 
RgbEffectState_e;

#define RGB_LED_COUNT 2

// what is stored for state is specific to the need, in this case, the colors.
// basically what ever you need inside the animation update function
struct MyAnimationState {
  RgbwColor         RgbStartingColor;
  RgbwColor         RgbEndingColor;
  RgbwColor         RgbNoEffectColor;
  RgbEffectState_e  RgbEffectState;  // current effect of RGB LED 
  //uint8_t   IndexPixel;   // general purpose variable used to store pixel index
};

// one entry per pixel to match the animation timing manager
NeoPixelAnimator animations(RGB_LED_COUNT); 
MyAnimationState animationState[RGB_LED_COUNT];
/* ======================================================================
Function: LedRGBBlinkAnimUpdate
Purpose : Blink Anim update for RGB Led
Input   : -
====================================================================== */
void LedRGBBlinkAnimUpdate(const AnimationParam& param)
{
  // this gets called for each animation on every time step
  // progress will start at 0.0 and end at 1.0
  rgb_led.SetPixelColor(param.index, RgbColor(0));

  // 25% on so 75% off
  if (param.progress < 0.25f) {
    rgb_led.SetPixelColor(param.index, animationState[param.index].RgbNoEffectColor);
  }
}

/* ======================================================================
Function: LedRGBFadeAnimUpdate
Purpose : Fade in and out effect for RGB Led
Input   : -
====================================================================== */
void LedRGBFadeAnimUpdate(const AnimationParam& param)
{
  // this gets called for each animation on every time step
  // progress will start at 0.0 and end at 1.0
  // apply a exponential curve to both front and back
  //float progress = NeoEase::CubicInOut(param.progress) ;
  float progress = param.progress ;

  // we use the blend function on the RgbColor to mix
  // color based on the progress given to us in the animation
  RgbwColor updatedColor = RgbwColor::LinearBlend( 
                                      animationState[param.index].RgbStartingColor, 
                                      animationState[param.index].RgbEndingColor, 
                                      progress);
  rgb_led.SetPixelColor(param.index, updatedColor);
}

/* ======================================================================
Function: LedRGBAnimate
Purpose : Manage RGBLed Animations
Input   : parameter (here animation time in ms)
====================================================================== */
void LedRGBAnimate(uint16_t param)
{
  if ( animations.IsAnimating() ) {
    // the normal loop just needs these two to run the active animations
    animations.UpdateAnimations();
    rgb_led.Show();

  } else {
    // Loop trough animations
    for (uint8_t i=0 ; i<RGB_LED_COUNT; i++) {
      RgbEffectState_e effect = animationState[i].RgbEffectState;

      // We start animation with current led color
      animationState[i].RgbStartingColor = rgb_led.GetPixelColor(i);

      // Node default fade in
      if ( effect==RGB_ANIM_NONE )
        animationState[i].RgbEffectState=RGB_ANIM_FADE_IN ;

      // Fade in 
      if ( effect==RGB_ANIM_FADE_IN ) {
        animationState[i].RgbEndingColor = animationState[i].RgbNoEffectColor; // selected color
        animationState[i].RgbEffectState=RGB_ANIM_FADE_OUT; // Next
        animations.StartAnimation(i, param, LedRGBFadeAnimUpdate);

      // Fade out
      } else if ( effect==RGB_ANIM_FADE_OUT ) {
        animationState[i].RgbEndingColor = RgbColor(0); // off
        animationState[i].RgbEffectState=RGB_ANIM_FADE_IN; // Next
        animations.StartAnimation(i, param, LedRGBFadeAnimUpdate);

      // Blink ON
      } else if ( effect==RGB_ANIM_BLINK_ON ) {
        animationState[i].RgbEffectState=RGB_ANIM_BLINK_OFF; // Next
        animations.StartAnimation(i, param, LedRGBBlinkAnimUpdate);

      // Blink OFF
      } else if ( effect==RGB_ANIM_BLINK_OFF ) {
        animationState[i].RgbEffectState=RGB_ANIM_BLINK_ON; // Next
        animations.StartAnimation(i, param, LedRGBBlinkAnimUpdate);
      }
    }
  }
}
/* ======================================================================
Function: LedRGBON
Purpose : Set RGB LED strip color, but does not lit it
Input   : Hue of LED (0..360)
          led number (from 1 to 2), if 0 then all leds
          if led should be lit immediatly
====================================================================== */
void LedRGBON (uint16_t hue, uint16_t led, bool doitnow)
{
  uint8_t start = 0;
  uint8_t end   = RGB_LED_COUNT-1; // Start at 0

  // Convert to neoPixel API values
  // H (is color from 0..360) should be between 0.0 and 1.0
  // S is saturation keep it to 1
  // L is brightness should be between 0.0 and 0.5
  // rgb_luminosity is between 0 and 100 (percent)
  RgbColor target = HslColor( hue / 360.0f, 1.0f, 0.005f * rgb_luminosity);

  // just one LED ?
  // Strip start 0 not 1
  if (led) {
    led --;
    start = led ;
    end   = led ;
  } 

  for (uint8_t i=start ; i<=end; i++) {
    animationState[i].RgbNoEffectColor = target;
    // do it now ?
    if (doitnow) {
      // Stop animation
      animations.StopAnimation(i);
      animationState[i].RgbEndingColor  = RgbColor(0);
      rgb_led.SetPixelColor(i, target);
      rgb_led.Show();  
    }
  }
}

/* ======================================================================
Function: LedRGBOFF 
Purpose : light off the RGB LED strip
Input   : Led number starting at 1, if 0=>all leds
====================================================================== */
void LedRGBOFF(uint16_t led)
{
  uint8_t start = 0;
  uint8_t end   = RGB_LED_COUNT-1; // Start at 0

  // just one LED ?
  if (led) {
    start = led ;
    end   = led ;
  }

  // stop animation, reset params
  for (uint8_t i=start ; i<=end; i++) {
    animations.StopAnimation(i);
    animationState[i].RgbStartingColor = RgbColor(0);
    animationState[i].RgbEndingColor   = RgbColor(0);
    animationState[i].RgbNoEffectColor = RgbColor(0);
    animationState[i].RgbEffectState   = RGB_ANIM_NONE;

    // clear the led strip
    rgb_led.SetPixelColor(i, RgbColor(0));
    rgb_led.Show();  
  }
}

Then when I'm doing as follow all is fine

void setup(void) {
  // Set Breathing color Led #1
  animationState[0].RgbEffectState=RGB_ANIM_FADE_IN;
  LedRGBON(COLOR_YELLOW, 1); 

  // Set blinking color led #2
  animationState[1].RgbEffectState=RGB_ANIM_BLINK_ON;
  LedRGBON(COLOR_GREEN , 2); 
}

void loop (void) {
  LedRGBAnimate(1000);
}

But when I'm trying to change animation speed for each led as follow

void setup(void) {
  // Set Breathing color Led #1
  animationState[0].RgbEffectState=RGB_ANIM_FADE_IN;
  LedRGBON(COLOR_YELLOW, 1); 

  // Set blinking color led #2
  animationState[1].RgbEffectState=RGB_ANIM_BLINK_ON;
  LedRGBON(COLOR_GREEN , 2); 
}

void loop (void) {
  LedRGBAnimate(1000, 1);
  LedRGBAnimate( 500, 2);
}

Seems animation timing is wrong and broken, but again I'm not sure if what I've done is correct

Is it possible to call something like this ?

animations.UpdateAnimations(0);
animations.UpdateAnimations(1);
Michael Miller
@Makuna
Jun 01 2016 15:24
@hallard It is supported and even one of the samples demonstrates this; so there is something being done incorrectly.
When you call UpdateAnimations, it will check every "running" animations and apply change.
In your code above, you call LedRGBAnimate(1000, 1); but this function only takes one param?
Michael Miller
@Makuna
Jun 01 2016 15:34
@hallard the way you structured your animation setup/update is problematic. When all animations complete, then inside LedRGBAnimation() you reset them, but you call this function twice in a row in the loop. So what happens is "randomly" one of these two calls notices the lack of animations and then restarts them, but then the other will then think animations are running and not do anything.
@hallard I suspect you also changed LedRGBAnimation() to not loop across all animations?
Remove the code in the LedRGBAnimation() that checks and updates the animations and put it in the loop like this...
void loop () {
  if ( animations.IsAnimating() ) {
    // the normal loop just needs these two to run the active animations
    animations.UpdateAnimations();
    rgb_led.Show();

  } else {
   LedRGBAnimate(1000, 1);
   LedRGBAnimate( 500, 2);
  }
}
Charles
@hallard
Jun 01 2016 17:10
@Makuna
thanks, as soon I've got some minutes I'll try ;-)