Go Down

Topic: FastLED Modified Blend to Target Color - HSV - Flickering between Value changes (Read 893 times) previous topic - next topic

PaulRB

Try this version. I changed the code so that the blend happens in RGB colourspace.
Code: [Select]
#include "FastLED.h"
#define DATA_PIN    7
//#define CLK_PIN     13
#define LED_TYPE    WS2813
#define COLOR_ORDER GRB
#define NUM_LEDS    60
//#define BRIGHTNESS  100
CRGB leds[NUM_LEDS];

uint8_t blendRate = 50;  // How fast to blend.  Higher is slower.  [milliseconds]

CHSV color1 = CHSV(128, 90, 50);
CHSV color2 = CHSV(64, 50, 80);
CHSV color3 = CHSV(32, 200, 190);
CHSV color4 = CHSV(192, 200, 190);
CHSV color5 = CHSV(160, 90, 190);
CHSV color6 = CHSV(100, 100, 80);

int number_of_colors = 6;
int current_color_index = 0;

CHSV color_array[6] = {color1, color2, color3, color4, color5, color6};


//adjust color start CHSV and colorTarget CHSV to match colors above
CRGB colorStart = color1; // starting color
CRGB colorTarget = color2; // target color
CRGB colorCurrent = colorStart;

//---------------------------------------------------------------
void setup() {
  Serial.begin(115200);  // Allows serial monitor output (check baud rate)
  delay(3000); // 3 second delay for recovery
  //FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  //FastLED.setBrightness(BRIGHTNESS);
  Serial.println("Setup done. \n");
}


//---------------------------------------------------------------
void loop()
{
  EVERY_N_MILLISECONDS(blendRate) {
    static uint8_t k;
    if ( colorCurrent == colorTarget ) {  // Check if target has been reached
      colorStart = colorCurrent;
      colorTarget = color_array[current_color_index];  // new target to transition toward
      current_color_index += 1;
      if (current_color_index == number_of_colors) {
        current_color_index = 0;
      }
      k = 0;  // reset k value
      //Serial.print("New colorTarget:\t\t\t"); Serial.println(colorTarget.h);
    }

    colorCurrent = blend(colorStart, colorTarget, k);
    fill_solid( leds, NUM_LEDS, colorCurrent );
    //leds[0] = colorTarget;  // set first pixel to always show target color
    //Serial.print("colorCurrent:\t"); Serial.print(colorCurrent.h); Serial.print("\t");
    //Serial.print("colorTarget:\t"); Serial.print(colorTarget.h);
    //Serial.print("\tk: "); Serial.println(k);
    //CRGB colorCurrentRGB = colorCurrent;
    //Serial.print(colorCurrentRGB.r); Serial.print(" "); Serial.print(colorCurrentRGB.g); Serial.print(" "); Serial.println(colorCurrentRGB.b);
    k++;
    FastLED.show();  // update the display
  }

}

david_2018

I'm becoming convinced that Mike is right, the integer maths that FastLED is using to blend colours and to convert between colourspaces is the problem here. There is some jitter in the HSV values, so even if the conversion to RGB was perfect, there would still be some flicker. But it might be acceptably small, is hard to guess.

The math in FastLED appears to mostly be done with 8-bit integers, with a primary objective being speed, so that something like blend can be applied to large numbers of LEDs quickly.  The flicker is most noticeable at low brightness, particularly when more than one color changes level simultaneously.  With hue, saturation, and value all varying, there are times when the value for a particular RGB color will go up, down, then up again.

Grumpy_Mike

Quote
I changed the code so that the blend happens in RGB colourspace.
You get a whole different set of colours depending on which colour space you do the blend in. I wrote different space blending examples in my Raspberry Pi for dummies edition 3 book.

It is traversing a different colour space that makes the blends so interesting. Not just RGB and HSV but there are other colour spaces as well. All produce different colours and they all blend seamlessly.

PaulRB

Realise that, Mike, but thought the OP might be happy with the RGB blending, especially if it fixes the flickering problem.

sharonrlevy

@PaulRb, I do think that RGB version is slightly more fluid in the value transitions. Not miraculously different, but minutely. In both your RGB conversion version and the last version from @david_2018 there is no flickering; they both have a little bit of lurching between the value changes, but the RGB one might have slightly less. 

@Grumpy_Mike thanks, I just don't know how to fix this as I'm really not a coder. Any suggestions are extremely welcome.

I guess it might be work letting the developer know about the issue and see what happens.

I definitely feel so much better about where this is at, and I can't thank you all enough!

PaulRB

Quote
a little bit of lurching between the value changes
I wonder if that could be the 8-bits-per-colour resolution of all addressable strips. Only 256 intensity levels are available in each of the red, green and blue channels. Because the eye is not linear, a difference level of 1 is not noticeable for levels over about 100, but for low levels, it can be very noticeable indeed. For example level 2 is obviously twice as bright as level 1!

I seem to remember FastLED has a "temporal dithering" feature which might help. I've never used it, but here's a link.

PaulRB

Non-addressable RGB strips don't have the 8-bit limitation. Maybe that would be a better option for your project, given that you are setting all LEDs to the same colour, you don't need addressable LEDs.

With non-addressable strips, the driver circuits that control the intensity levels in the red, green and blue channels are external to the strip, you have to build our buy them. The most basic driver circuit consists of 3 MOSFETs connected to 3 Arduino PWM pins. By default, Arduino PWM pins are also 8-bit resolution, so that would be no better than what you have now. But if you used an external PWM chip, or maybe an Arduino with a faster more powerful chip, such as an Arduino Zero, Teensy 3.x or similar, you could achieve 10 or 12 bit resultion, which would mean 4 or 16 times as many intensity levels.

sharonrlevy

@PaulRB - sorry for the delayed response.
That's an interesting idea. I chose the addressable strips because I'd thought to do more complicated things witht hem, until I realized how complicated the "simple" things are!
If I changed strip type would I still use the same code, or would I need to make adjustments (aside from the strip type, pin, etc)


Grumpy_Mike

Quote
If I changed strip type would I still use the same code
No.

Quote
would I need to make adjustments
It would have to be completely rewritten depending on the type of strip you got. Strips that do not contain addressable LEDs do not need a library at all.

sharonrlevy

thanks @Grumpy_Mike. I'll try and make what I have work, otherwise I'll be back on this board with a whole new set of questions!

Go Up