Fastled: fade single leds from color to a target color

Hi all,

I would really like to learn to use the fastled library and have set a goal for a first project. I've been breaking my head over it so far but I think I might have found a possible solution.

It's a pretty long post so thanks for reading in advance :) ... I had to split it up in two post even

First, what do I want to achieve: - I have 20 leds set to a colorset of 2-3 different colors, say red, green, yellow - Every few seconds a number of random leds should fade red to green, green to yellow, yellow to green, within the colorset red/green - Every 30 seconds all leds should fade to colors from a new colorset, say white and blue - Then every few seconds a number of leds should fade from white to blue, blue to white - Repeat

I got this worked out in code and my code does what I want. Except for the fading part. Now the leds just switch to their target color instantly. (see first reply for code)

I found a piece of code by mr. Kriegsman himself that has functions that do the fading trick. (see first reply for code)

I have trouble understanding these and hope someone can help.

Ok, so every led has a current CRGB. The code below seems to check it's current CRGB against the target CRGB. It uses nblendU8TowardU8 to adjust it towards the target by "amount"

// Blend one CRGB color toward another CRGB color by a given amount.
// Blending is linear, and done in the RGB color space.
// This function modifies 'cur' in place.
CRGB fadeTowardColor( CRGB& cur, const CRGB& target, uint8_t amount)
{
  nblendU8TowardU8( cur.red,   target.red,   amount);
  nblendU8TowardU8( cur.green, target.green, amount);
  nblendU8TowardU8( cur.blue,  target.blue,  amount);
  return cur;
}

// Helper function that blends one uint8_t toward another by a given amount
void nblendU8TowardU8( uint8_t& cur, const uint8_t target, uint8_t amount)
{
  if( cur == target) return;
  
  if( cur < target ) {
    uint8_t delta = target - cur;
    delta = scale8_video( delta, amount);
    cur += delta;
  } else {
    uint8_t delta = cur - target;
    delta = scale8_video( delta, amount);
    cur -= delta;
  }
}

So "CRGB fadeTowardColor" accepts : - the current CRGB - the target CRGB - the amount of adjustment

Also "CRGB fadeTowardColor" directly modifies the CRGB value of a single led, in place, at the actual memory location it is stored (right?).

So now for my actual question: How do I pass the CRGB value of one led to "CRGB fadeTowardColor" so that it is directly adjusted toward the target ?

EDIT: Quick answer: just pass leds[ i ] Read replies for more info

My code that works as I want it, except for the fading part:

#include <FastLED.h>
#include <Streaming.h>
#include <Math.h>

// SETTINGS FOR LEDS
#define DATA_PIN    2
//#define CLK_PIN   4
#define LED_TYPE    WS2812
#define COLOR_ORDER GRB
#define NUM_LEDS    26
#define BRIGHTNESS          255

CRGB leds[NUM_LEDS];

// FRAMES PER SECONDS
int intFramesPerSec = 25;

// ARRAYS ==========================================================================

// == Target color
// For each led in the strip a target CRGB color is stored in an array
CRGB arrTargetColor[NUM_LEDS];

// Define some usable/nice colors:
CRGB White = CRGB(240,156,66);
CRGB Red = CRGB(255,0,0);
CRGB Green = CRGB(0,255,0);
CRGB Blue = CRGB(0,0,255);
CRGB Yellow = CRGB(255,110,0);
CRGB Purple = CRGB( 255, 0, 160);
CRGB Lightblue = CRGB( 255, 255, 255);
CRGB Turquiose = CRGB( 0, 255, 255);
CRGB Pink = CRGB( 255, 43, 148);
CRGB Orange = CRGB( 255, 75, 0);

CRGB arrColors[10]=
{
    White,       //0
    Red,         //1
    Green,       //2
    Blue,        //3
    Yellow,      //4
    Purple,      //5
    Lightblue,   //6
    Turquiose,   //7
    Pink,        //8
    Orange       //9
};
// Determine the number of colors in the array
int intLengtharrColors = sizeof(arrColors) / sizeof(arrColors[0]);

// An array in which each row is a colorset
// eacht row must have the same number of entries
// 12 is chosen so that color sets of 2, 3, 4 and 6 can be used
// while keeping the chance of random selection even
int arrColorsets[3][12] = {
  //{0,3,2,0,3,2,0,3,2,0,3,2},    //0 red white blue
  //{0,1,2,0,1,2,0,1,2,0,1,2},    //1 red green blue
  //{0,3,0,3,0,3,0,3,0,3,0,3},    //2 red white
  {2,1,2,1,2,1,2,1,2,1,2,1},    //3 red green
  //{0,1,4,0,1,4,0,1,4,0,1,4},    //4 red yellow green
  {2,4,2,4,2,4,2,4,2,4,2,4},    //5 yellow green
  {3,6,3,6,3,6,3,6,3,6,3,6}     //6 white lightblue
};

// Determine the number of elements/colorsets
int intNumberOfColorsets = sizeof(arrColorsets) / sizeof(arrColorsets[0]);

int intCurrentColorset = 0;


void setup() {

  Serial.begin(9600);
  
  delay(3000); // 3 second delay for recovery
  
  // tell FastLED about the LED strip configuration
  FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);

  // set master brightness control
  FastLED.setBrightness(BRIGHTNESS);

   // Fill arrTargetColor  with a single target color
  for(int i = 0; i < NUM_LEDS; i++){
    arrTargetColor[i][0] = White.red;  
    arrTargetColor[i][1] = White.green; 
    arrTargetColor[i][2] = White.blue;
  }

  // Set all leds to the current color
  for(int i = 0; i < NUM_LEDS; i++){
    leds[i].setRGB(arrTargetColor[i].red, arrTargetColor[i].green, arrTargetColor[i].blue);
  }
  
  FastLED.show();
  
} // end setup

void loop(){

  FastLED.show();

  // Change the target color of some leds
  EVERY_N_SECONDS(2){
    
      // Change the target color for a few leds
      // since there are only 2-3 colors in a color set, the chance that the new target is the current color is high, therefor all leds will get a new target
     for(int led = 0; led <NUM_LEDS; led++){
      
        //int intTargetLed = random(0, NUM_LEDS);
        
        // generate a random int to select a color from one row in array arrColorsets
        int intGetRandomColorFromSet = random(0,12);

        int intGetColor = arrColorsets[intCurrentColorset][intGetRandomColorFromSet];
        
        arrTargetColor[led].red = arrColors[intGetColor].red;
        arrTargetColor[led].green = arrColors[intGetColor].green;
        arrTargetColor[led].blue = arrColors[intGetColor].blue;
     }
     // set the leds to the targetcolor
     vSetLedColor();
  } 

  EVERY_N_SECONDS(20){
      vChangeColorset();
  }
  
  FastLED.delay(1000/intFramesPerSec);  

}


void vSetLedColor(){

  for(int i = 0; i < NUM_LEDS; i++){
    
    leds[i].setRGB(arrTargetColor[i].red, arrTargetColor[i].green, arrTargetColor[i].blue);
  }
  
} // end vSetLedColor



void vChangeColorset(){
  
  intCurrentColorset = random(0,intNumberOfColorsets); //random() excludes the upper limit so ideal to use as array index :)

  // Fill the array with new target colors
  for(int i = 0; i < NUM_LEDS; i++){

    //Random number that gets a color in one row of arrColorsets
    int intGetRandomColorFromSet = random(0,12);
    // intGetColor is picked out of the current set and used to retreive the color from arrColors
    int intGetColor = arrColorsets[intCurrentColorset][intGetRandomColorFromSet];
    
    arrTargetColor[i][0] = arrColors[intGetColor].red;
    arrTargetColor[i][1] = arrColors[intGetColor].green;
    arrTargetColor[i][2] = arrColors[intGetColor].blue;
  }

}

Complete original code:

#include <FastLED.h>

// fadeTowardColor example code.
//
// Sample code that includes a function for fading one RGB color toward a target RGB color
// Also includes a function for fading a whole array of pixels toward a given color
//
// Both of these functions _modify_ the existing color, in place.
//
// All fades are done in RGB color space.
//
// Mark Kriegsman
// December 2016


#define NUM_LEDS 50
#define LED_PIN 3
#define LED_TYPE WS2811
#define COLOR_ORDER GRB

CRGB leds[NUM_LEDS];

void setup() {
  delay(3000); // sanity delay
  FastLED.addLeds<LED_TYPE,LED_PIN,COLOR_ORDER>(leds,NUM_LEDS);
}




// Helper function that blends one uint8_t toward another by a given amount
void nblendU8TowardU8( uint8_t& cur, const uint8_t target, uint8_t amount)
{
  if( cur == target) return;
  
  if( cur < target ) {
    uint8_t delta = target - cur;
    delta = scale8_video( delta, amount);
    cur += delta;
  } else {
    uint8_t delta = cur - target;
    delta = scale8_video( delta, amount);
    cur -= delta;
  }
}

// Blend one CRGB color toward another CRGB color by a given amount.
// Blending is linear, and done in the RGB color space.
// This function modifies 'cur' in place.
CRGB fadeTowardColor( CRGB& cur, const CRGB& target, uint8_t amount)
{
  nblendU8TowardU8( cur.red,   target.red,   amount);
  nblendU8TowardU8( cur.green, target.green, amount);
  nblendU8TowardU8( cur.blue,  target.blue,  amount);
  return cur;
}

// Fade an entire array of CRGBs toward a given background color by a given amount
// This function modifies the pixel array in place.
void fadeTowardColor( CRGB* L, uint16_t N, const CRGB& bgColor, uint8_t fadeAmount)
{
  for( uint16_t i = 0; i < N; i++) {
    fadeTowardColor( L[i], bgColor, fadeAmount);
  }
}


void loop() 
{
  CRGB bgColor( 0, 15, 2); // pine green ?
  
  // fade all existing pixels toward bgColor by "5" (out of 255)
  fadeTowardColor( leds, NUM_LEDS, bgColor, 5);

  // periodically set random pixel to a random color, to show the fading
  EVERY_N_MILLISECONDS( 300 ) {
    uint16_t pos = random16( NUM_LEDS);
    CRGB color = CHSV( random8(), 255, 255);
    leds[ pos ] = color;
  }

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

Before you go too far down this road, you should consider the HSV color model for color-to-color transitions.

FastLED supports HSV.

Well, I'm already too far down this road :) I would like this to work for now, I could realy use a "wow this works" feeling.

But yes, I am reading up on the HSV model. I try to learn as I go along, also if that means choosing the wrong path initially.

Whoohoo, I got it working just like I wanted it to !

|500x285

So now for my actual question: How do I pass the CRGB value of one led to "CRGB fadeTowardColor" so that it is directly adjusted toward the target ?

"CRGB fadeTowardColor" takes : - the current CRGB which is actually just "leds[ i ]" from the decalred CRGB leds[NUM_LEDS]; - the targe CRGB, from arrTargetColor - a change value 0-255 ``` for(int i = 0; i ``` ``` *// Blend one CRGB color toward another CRGB color by a given amount. // Blending is linear, and done in the RGB color space. // This function modifies 'cur' in place. CRGB fadeTowardColor( CRGB& cur, const CRGB& target, uint8_t amount) {   nblendU8TowardU8( cur.red,  target.red,  amount);   nblendU8TowardU8( cur.green, target.green, amount);   nblendU8TowardU8( cur.blue,  target.blue,  amount);   return cur; }

// Helper function that blends one uint8_t toward another by a given amount void nblendU8TowardU8( uint8_t& cur, const uint8_t target, uint8_t amount) {   if( cur == target) return;     if( cur < target ) {     uint8_t delta = target - cur;     delta = scale8_video( delta, amount);     cur += delta;   } else {     uint8_t delta = cur - target;     delta = scale8_video( delta, amount);     cur -= delta;   } }* ```