Fastled palette looping help please

Greetings,

I have a loop of 194 WS2812 LEDS and am trying to make a seamless moving rainbow.

I have created a palette that starts and ends with RED and has rainbow colors evenly spread. but I cannot get the transition from 0 - 194 (NUM_LEDS) to correctly blend.

can anyone help me identify my error please?

#include <FastLED.h>

//FASTLED 

#define LEDstripPin 4                          

#define NUM_LEDS 194

#define COLOR_ORDER GRB

#define CHIPSET WS2812B

int paletteIndex = 0; 

CRGB leds[NUM_LEDS];

DEFINE_GRADIENT_PALETTE( Rain_gp ) {

0, 255, 0, 0,       //Red

20, 255, 0, 0,      //Orange

61, 255, 255, 0,    //Yellow

102, 0, 255, 0,     //Green

143, 0, 0, 255,     //Blue

184, 75,0, 130,     //Indego

224, 148,0, 211,    //Violet

255, 200, 0, 0};   //Red 

CRGBPalette16 Rainbow(Rain_gp);

void setup() 

{

 FastLED.addLeds<WS2812B,LEDstripPin , GRB>(leds, NUM_LEDS);

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

 FastLED.show();

 FastLED.setBrightness(255);

}

void loop() 

{

 RainbowStrobe();

}

void RainbowStrobe(){                                                                                                                      // RAINBOW STROBE

 int randomLED = random8(0,NUM_LEDS-1);

fill_palette(leds, NUM_LEDS, paletteIndex,255/NUM_LEDS,Rainbow,255,LINEARBLEND); // 255/NUM_LEDS (led array, number of leds, start index, index delta, palette, brightness, blendtype)

FastLED.show();

EVERY_N_MILLISECONDS(2){

 paletteIndex++;

}

FastLED.setBrightness(255);

FastLED.show();

}

Well for one thing, 0 to 194 is 195 numbers.

thanks but thats not part of my issue. I am handling everything with "NUM_LEDS-1" where required and the fastled fill palette function handles that internally as far as i can see.

here is a simulation showing my issue

Your index delta is calculated in integers ... 255/194 is always equal to 1. I'm pretty sure that's not what you intended.

1 Like

thanks that is a vaild question but i have now declared it as a float and no change.

#include <FastLED.h>

//FASTLED 
#define LEDstripPin 4                          
#define NUM_LEDS 194
#define COLOR_ORDER GRB
#define CHIPSET WS2812B

int paletteIndex = 0; 
float indexDelta = 255/NUM_LEDS; 
CRGB leds[NUM_LEDS];


DEFINE_GRADIENT_PALETTE( Rain_gp ) {
0, 255, 0, 0,       //Red
20, 255, 0, 0,      //Orange
61, 255, 255, 0,    //Yellow
102, 0, 255, 0,     //Green
143, 0, 0, 255,     //Blue
184, 75,0, 130,     //Indego
224, 148,0, 211,    //Violet
255, 200, 0, 0};   //Red 

CRGBPalette16 Rainbow(Rain_gp);

void setup() 
{
  FastLED.addLeds<WS2812B,LEDstripPin , GRB>(leds, NUM_LEDS);

  fill_solid(leds, NUM_LEDS, CRGB( 0, 0, 0));
  FastLED.show();
  FastLED.setBrightness(255);
}


void loop() 
{
  RainbowStrobe();
}

void RainbowStrobe(){                                                                                                                      // RAINBOW STROBE
  int randomLED = random8(0,NUM_LEDS-1);


fill_palette(leds, NUM_LEDS, paletteIndex,indexDelta,Rainbow,255,LINEARBLEND); // 255/NUM_LEDS (led array, number of leds, start index, index delta, palette, brightness, blendtype)
FastLED.show();

EVERY_N_MILLISECONDS(2){
  paletteIndex++;
}
FastLED.setBrightness(255);
FastLED.show();
}

The function takes an integer for the hue increment, so your float is converted to a integer.
Also the function fill_rainbow() takes an integer for the hue increment.

@anon57585045 is right. I think there is no other option then to calculate the color for each led in the sketch, using a float calculation to spread 255 hue over 194 leds.

The next example has split the problem into two parts, the code in the loop() and the code in the function myRainbow(). They can be combined, but I wanted to make a smaller step and make the function first.

Please look at the code, how I cleaned up your code. I hope you don't mind for being blunt, but your sketch is a mess.

#include <FastLED.h>

#define DATA_PIN 4                          
#define NUM_LEDS 194

CRGB leds[NUM_LEDS];

int index;

void setup()
{
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
  fill_solid(leds, NUM_LEDS, CRGB( 0, 0, 0));
  FastLED.show();
  FastLED.setBrightness(255);
}

void loop() 
{
  EVERY_N_MILLISECONDS(2)
  {
    myRainbow( index);
    index++;
    if( index >= NUM_LEDS)
    {
      index = 0;
    }
  }
}

// Fill 194 leds with a hue from 0 to 255.
void myRainbow( int startLed)
{
  const float hue_increment = float( 255) / float( NUM_LEDS);

  int j = startLed;
  for( int i=0; i<NUM_LEDS; i++, j++)
  {
    if( j >= NUM_LEDS)        // index rolls beyond the array ?
    {
      j = 0;                  // wrap around
    }
    float thisHue = float( i) * hue_increment;
    leds[j] = CHSV( int(thisHue), 255, 255);
  }
  FastLED.show();
}

The sketch in Wokwi:

Thank you for the help.

Regarding the comment about messy code I do actually mind as that doesn't help at all. Constructive criticism is always welcome because I am here to learn but telling an inexperienced coder that their code is a mess doesn't help at all. There are ways to help people improve without being rude.

I'm sorry for being rude. I will try in a better way:

  • Please use your indents consistant. It is now hard to read.
  • Please use the same style for the '{' and '}'. You can use your own style, but please keep it the same in the whole sketch.
  • Please remove unused code and code that is not needed. The randomLED is not used and setting the brightness is already done in setup() and there are two FastLED.show() in the loop(), only one is needed.
  • You call the fill_pallette() function in the free running part of the loop(), but you only need to set the new colors if some leds needs to be changed.

It really helps if you make your text layout of a sketch look good. Then you can see the structure of the sketch at first glance.

Thank you for the constructive feedback. This is really useful and I do apologize for the 'errors' and will endeavor to improve in future posts.

I don't mean to be rude in reply either but it is frustrating when I am really trying to learn and improve.

In the Arduino IDE is autoformat with Ctrl+T. Also in the menu "Tools".
It will do most of the text formatting for you.

There is a configuration file to set your own style, called "formatter.conf". It is in the same folder as "preferences.txt", which can be found via the Setting windows in the Arduino IDE.

The leds don't have to be updated faster than 50Hz, it will still be okay for the human eye.
So I have slowed down the changing of the leds to a 20ms interval. It should still look good with real leds (I hope).
A direction and a speed is also added.

#include <FastLED.h>

#define DATA_PIN 4                          
#define NUM_LEDS 194

CRGB leds[NUM_LEDS];

int index;
int direction = 1;       // +1 or -1
int speed = 2;           // 1 to 10 or so

void setup()
{
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
  fill_solid(leds, NUM_LEDS, CRGB( 0, 0, 0));
  FastLED.show();
  FastLED.setBrightness(255);
}

void loop() 
{
  EVERY_N_MILLISECONDS(20)   // every 20ms should be enough for human eye
  {
    myRainbow( index);
    index += speed * direction;

    if( index >= NUM_LEDS)
    {
      index -= NUM_LEDS;
    }
    if( index < 0)
    {
      index += NUM_LEDS;
    }
  }

  EVERY_N_SECONDS(3)      // change direction, just for fun
  {
    direction = -direction;
  }
}

// Fill 194 leds with a hue from 0 to 255.
void myRainbow( int startLed)
{
  const float hue_increment = float( 255) / float( NUM_LEDS);

  int j = startLed;
  for( int i=0; i<NUM_LEDS; i++, j++)
  {
    if( j >= NUM_LEDS)        // index rolls beyond the array ?
    {
      j = 0;                  // wrap around
    }
    float thisHue = float( i) * hue_increment;
    leds[j] = CHSV( int(thisHue), 255, 255);
  }
  FastLED.show();
}

And the Wokwi is:

thanks again.

My desired code is more complicated than the example I have posted so I will try and integrate your palette fill method into my code to get my desired outcome.

This is the initial function that I am trying to improve. a beat is detected elsewhere and beattrigger is set to True. this will cause a white strobe to be overlaid on the rainbow palette in a random position.

The only issue is that the rainbow palette doesn't flow evenly around the loop. hence my question and when i tried to simplify my code for my initial question.

void RainbowStrobe() {                                        // RAINBOW STROBE
  int randomLED = random8(0, NUM_LEDS - 1);
  int StrobeWidth = 4; //random8(2,4);
 

  fill_palette(leds, NUM_LEDS, paletteIndex, 255 / NUM_LEDS, Rainbow, ledDisplayBrihtnessValue, LINEARBLEND);
  FastLED.show();

  if ((BassBeatTrigger == true ) || (BeatTrigger == true ) || (TrebleBeatTrigger == true )) {
    leds[randomLED] = CHSV(100, 0, 255);
    for (int i = 1; i <= StrobeWidth; i++) {

      if (randomLED - i < 0) {                                                                            
        leds[(randomLED - i) % NUM_LEDS] = CHSV(100, 0, 255);
      }

      if (randomLED + i >= NUM_LEDS - 1) {
        leds[(randomLED + i) % NUM_LEDS] = CHSV(100, 0, 255);
        leds[randomLED - i] = CHSV(100, 0, 255);

      } else {
        leds[randomLED - i] = CHSV(100, 0, 255);
        leds[randomLED + i] = CHSV(100, 0, 255);

      }
    }

    BassBeatTrigger = false;
    BeatTrigger = false;
    TrebleBeatTrigger = false;
  }
  EVERY_N_MILLISECONDS(2) {
    paletteIndex++;
  }
  FastLED.setBrightness(255);
  FastLED.show();

}

Here is a video of the project i am working on:

the error can be seen (time 0:00 - 0:30 seconds) on the left side where the power cable enters the display. the led strip starts and finishes there and you can see the colours dont blend there.

I think you can set the rainbow, but without FastLED.show() after that, then add the strobe, and then do the FastLED.show().
The next time, just set the rainbow, and the strobe will disappear.

The FastLED library claims that random8() is faster than the Arduino random, but the Arduino random is already fast.

The blending at the start of the strip can be solved with a float calculation. To spread the hue of 255 over 194 leds, I do this:

const float hue_increment = float( 255) / float( NUM_LEDS);
float thisHue = float( i) * hue_increment;
leds[j] = CHSV( int(thisHue), 255, 255);  // The CHSV needs an integer for the hue

Hi, sorry for the delay. I have had to do some work.

I have tried to implement your method for filling the rainbow and in general it works but it only animates for one loop and pauses for 3 seconds then repeats.

The strobing effect is working fine without delay or anything strange..

I cant figure out what is causing the delay in the increment?

#include <FastLED.h>

//FASTLED 
#define LEDstripPin 4                          
const uint16_t NUM_LEDS = 194; 
#define COLOR_ORDER GRB
#define CHIPSET WS2812B

CRGB leds[NUM_LEDS];

bool TrebleBeatTrigger = false;               // boolean for Treble noise detection 
bool BeatTrigger = false;                      // boolean for mid tone noise detection 
bool BassBeatTrigger = false;                  // boolean for Bass noise detection 

CRGBPalette16 currentPalette = Rainbow_gp;

// rainbow stuff
float thisHue = 0;
const float hue_increment = float( 255) / float( NUM_LEDS);
int RainbowIndex;
int direction = 1;       // +1 or -1
int speed = 1;           // 1 to 10 or so
int paletteIndex = 0;

void setup() 
{
  FastLED.addLeds<WS2812B,LEDstripPin , GRB>(leds, NUM_LEDS);

  fill_solid(leds, NUM_LEDS, CRGB( 0, 0, 0));
  FastLED.show();
  FastLED.setBrightness(255);
}


void loop() 
{
  BeatTrigger = true;
  RainbowStrobe();
}

void RainbowStrobe(){                                                                                                                      // RAINBOW STROBE
  int randomLED = random8(0,NUM_LEDS-1);
  int StrobeWidth =4;  //random8(2,4);
  int calc = 0;
  int j = paletteIndex ;
  const float hue_increment = float( 255) / float( NUM_LEDS);


//fill_palette(leds, NUM_LEDS, paletteIndex, 255/NUM_LEDS,Rainbow,ledDisplayBrihtnessValue,LINEARBLEND); 
  for( int i=0; i<NUM_LEDS; i++, j++)
  {
    if( j >= NUM_LEDS)        // index rolls beyond the array ?
    {
      j = 0;                  // wrap around
    }
    float thisHue = float( i) * hue_increment;
    leds[j] = CHSV( int(thisHue), 255, 255);
  }


 RainbowIndex += speed * direction;

    if( RainbowIndex >= NUM_LEDS)
    {
      RainbowIndex -= NUM_LEDS;
    }
    if( RainbowIndex < 0)
    {
      RainbowIndex += NUM_LEDS;
    }

FastLED.show();

if (BeatTrigger == true ){ 
  leds[randomLED] = CHSV(100, 0, 255);
  for(int i = 1; i <= StrobeWidth; i++){

        if (randomLED-i < 0){                                                                                      // i have no idea how to use modulo % in an array 
            leds[(randomLED-i)% NUM_LEDS] = CHSV(100, 0, 255); 
        } 
        
        if(randomLED+i >= NUM_LEDS-1){
          leds[(randomLED+i)%NUM_LEDS] = CHSV(100, 0, 255); 
          leds[randomLED-i] = CHSV(100, 0, 255);

        }else{
          leds[randomLED-i] = CHSV(100, 0, 255);
          leds[randomLED+i] = CHSV(100, 0, 255);
                                                      
        }
      } 
   
  BassBeatTrigger = false;
  BeatTrigger = false;
  TrebleBeatTrigger = false;
}
EVERY_N_MILLISECONDS(2){
  paletteIndex++;
}
FastLED.setBrightness(255);
FastLED.show();
  
}

Ok I think I got it sorted... not elegant but its working for my application so far.

Thank you for the help :slight_smile:

void RainbowStrobe(){                                                                                                                      // RAINBOW STROBE
  int randomLED = random8(0,NUM_LEDS-1);
  int StrobeWidth =4;  //random8(2,4);
  int calc = 0;
  int j = paletteIndex ;
  const float hue_increment = float( 255) / float( NUM_LEDS);


//fill_palette(leds, NUM_LEDS, paletteIndex, 255/NUM_LEDS,Rainbow,ledDisplayBrihtnessValue,LINEARBLEND); 
  for( int i=0; i<NUM_LEDS; i++, RainbowIndex++)
  {
    if( RainbowIndex >= NUM_LEDS)        // index rolls beyond the array ?
    {
      RainbowIndex = 0;                  // wrap around
    }
    float thisHue = float( i) * hue_increment;
    leds[RainbowIndex] = CHSV( int(thisHue), 255, 255);
  }

FastLED.show();

 RainbowIndex += speed * direction;

    if( RainbowIndex >= NUM_LEDS)
    {
      RainbowIndex -= NUM_LEDS;
    }
    if( RainbowIndex < 0)
    {
      RainbowIndex += NUM_LEDS;
    }

EVERY_N_SECONDS(10)      // change direction, just for fun
  {
    direction = -direction;
  }

if ((BassBeatTrigger == true )||(BeatTrigger == true )||(TrebleBeatTrigger == true )){ 
  leds[randomLED] = CHSV(100, 0, 255);
  for(int i = 1; i <= StrobeWidth; i++){

        if (randomLED-i < 0){                                                                                      // i have no idea how to use modulo % in an array 
            leds[(randomLED-i)% NUM_LEDS] = CHSV(100, 0, 255); 
        } 
        
        if(randomLED+i >= NUM_LEDS-1){
          leds[(randomLED+i)%NUM_LEDS] = CHSV(100, 0, 255); 
          leds[randomLED-i] = CHSV(100, 0, 255);

        }else{
          leds[randomLED-i] = CHSV(100, 0, 255);
          leds[randomLED+i] = CHSV(100, 0, 255);
                                                      
        }
      } 
   
  BassBeatTrigger = false;
  BeatTrigger = false;
  TrebleBeatTrigger = false;
}
EVERY_N_MILLISECONDS(2){
  paletteIndex++;
}
FastLED.setBrightness(255);
FastLED.show();
  
}

Try removing the first FastLED.show() in the function RainbowStrobe() and keep the one at the end.
You can remove the FastLED.setBrightness(255) at the end of RainbowStrobe().

you are correct removing them still works. I had it in there because i have other functions that adjust the brightness and wanted a failsafe way to ensure that the rainbow function always stayed bright.

here is a link to the code working on my project. its designed to mount on the wall but is just on the floor for now.

thanks for the help!