FastLED Modified Blend to Target Color - HSV - Flickering between Value changes

Hello,

I am a visual artist, and a total noob at coding. I have a WS2813 strip, with Arudino Uno for the prototype, though I may need a more powerful board for the final large piece.

I am working on a project in which I want to have a controlled fading between specific colors, and after trying out every code I could find from this board and github, and the internet at large, a nice coder helped me to modify this Fade to Color code by @marmilicious:

(His code fades beautifully, but after the one specified color, it goes into random mode.)

My code is pasted below.
If I keep all of the values (V) consistent–like at 200–then the fading across colors looks great. But the problem is that I also want a change in Values–to go from a dim aqua, up through a series of brighter sunset colors, and then back down to a dim dark blue. But if I try and adjust the Value then I get tons of flickering as the values change. Adjusting the Blend Rate does not seem to effect the smoothness. Any ideas on how to fix this?

Thanks for your help!

#include "FastLED.h"
#define DATA_PIN    8
//#define CLK_PIN     13
#define LED_TYPE    WS2813
#define COLOR_ORDER GRB
#define NUM_LEDS    300
#define BRIGHTNESS  200
CRGB leds[NUM_LEDS];

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


//fill in your Hue, Saturation, Value (HSV) colors below. You can add or subtract additional colors as needed
CHSV color1 = CHSV(128,255,100); 
CHSV color2 = CHSV(32,255,200); 
CHSV color3 = CHSV(23,255,225); 
CHSV color4 = CHSV(224,255,225); 
CHSV color5 = CHSV(192,250,200); 
CHSV color6 = CHSV(160,255,100);  

//change number of colors below to reflect how many colors you have listed above
int number_of_colors = 6;
int current_color_index = 0;

//adjust he numbers below to reflect how many colors are listed above
CHSV color_array[6] = {color1, color2, color3, color4, color5, color6 };

//adjust color start CHSV and colorTarget CHSV to match colors above
CHSV colorStart = CHSV(128,255,100);  // starting color
CHSV colorTarget = CHSV(160,255,100);  // target color
CHSV 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.h == colorTarget.h ) {  // 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, SHORTEST_HUES);
    fill_solid( leds, NUM_LEDS, colorCurrent );
//    leds[0] = colorTarget;  // optional - 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);
    k++;
  }

  FastLED.show();  // update the display
}

Have you seen this?

PaulRB:
Have you seen this?

Looks like a similar problem, the HSV value is fluctuating, even when the start and end value are the same. Start and end HSV both have a V of 100 in this case, but V is fluctuating in the calculations.

hue: 128 sat: 255 val: 100
hue: 128 sat: 255 val:  99
hue: 128 sat: 255 val: 100
hue: 128 sat: 255 val:  99
hue: 128 sat: 255 val:  99
hue: 128 sat: 255 val: 100
hue: 128 sat: 255 val:  99
hue: 129 sat: 255 val: 100
hue: 129 sat: 255 val:  99
hue: 129 sat: 255 val:  99
hue: 129 sat: 255 val: 100
hue: 129 sat: 255 val:  99
hue: 129 sat: 255 val: 100
hue: 129 sat: 255 val:  99
hue: 129 sat: 255 val:  99
hue: 130 sat: 255 val: 100
hue: 130 sat: 255 val:  99
hue: 130 sat: 255 val: 100
hue: 130 sat: 255 val:  99
hue: 130 sat: 255 val:  99
hue: 130 sat: 255 val: 100
hue: 130 sat: 255 val:  99
hue: 130 sat: 255 val:  99
hue: 131 sat: 255 val: 100
hue: 131 sat: 255 val:  99
hue: 131 sat: 255 val: 100
hue: 131 sat: 255 val:  99
hue: 131 sat: 255 val:  99
hue: 131 sat: 255 val: 100
hue: 131 sat: 255 val:  99
hue: 131 sat: 255 val: 100
hue: 132 sat: 255 val:  99
hue: 132 sat: 255 val:  99
hue: 132 sat: 255 val: 100
hue: 132 sat: 255 val:  99
hue: 132 sat: 255 val: 100
hue: 132 sat: 255 val:  99
hue: 132 sat: 255 val:  99
hue: 132 sat: 255 val: 100
hue: 133 sat: 255 val:  99
hue: 133 sat: 255 val: 100
hue: 133 sat: 255 val:  99
hue: 133 sat: 255 val:  99
hue: 133 sat: 255 val: 100
hue: 133 sat: 255 val:  99
hue: 133 sat: 255 val:  99
hue: 133 sat: 255 val: 100
hue: 134 sat: 255 val:  99
hue: 134 sat: 255 val: 100
hue: 134 sat: 255 val:  99
hue: 134 sat: 255 val:  99
hue: 134 sat: 255 val: 100
hue: 134 sat: 255 val:  99
hue: 134 sat: 255 val: 100
hue: 134 sat: 255 val:  99
hue: 135 sat: 255 val:  99
hue: 135 sat: 255 val: 100

You can attempt to correcting for the error manually (correction function is at the end of the code):

#include "FastLED.h"
#define DATA_PIN    8
//#define CLK_PIN     13
#define LED_TYPE    WS2813
#define COLOR_ORDER GRB
#define NUM_LEDS    300
#define BRIGHTNESS  200
CRGB leds[NUM_LEDS];

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

//fill in your Hue, Saturation, Value (HSV) colors below. You can add or subtract additional colors as needed
CHSV color1 = CHSV(128, 255, 100);
CHSV color2 = CHSV(32, 255, 200);
CHSV color3 = CHSV(23, 255, 225);
CHSV color4 = CHSV(224, 255, 225);
CHSV color5 = CHSV(192, 250, 200);
CHSV color6 = CHSV(160, 255, 100);

//change number of colors below to reflect how many colors you have listed above
int number_of_colors = 6;
int current_color_index = 0;

//adjust he numbers below to reflect how many colors are listed above
CHSV color_array[6] = {color1, color2, color3, color4, color5, color6 };

//adjust color start CHSV and colorTarget CHSV to match colors above
CHSV colorStart = CHSV(128, 255, 100); // starting color
CHSV colorTarget = CHSV(160, 255, 100); // target color
CHSV colorCurrent = colorStart;

byte previous_val = colorCurrent.val; // previous V from HSV

//---------------------------------------------------------------
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.h == colorTarget.h ) {  // 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, SHORTEST_HUES);
    correctHSV();
    fill_solid( leds, NUM_LEDS, colorCurrent );
    //leds[0] = colorTarget;  // optional - 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);
    k++;
  }

  FastLED.show();  // update the display
}

void correctHSV() {
  if (colorStart.val < colorTarget.val) {  //if val is fading upward
    if (colorCurrent.val < previous_val) { //correct for any decrease in val
      colorCurrent.val = previous_val;
    }
  } else if (colorStart.val > colorTarget.val) { // if val is fading downward
    if (colorCurrent.val > previous_val) { // correct for any increase in val
      colorCurrent.val = previous_val;
    }
  } else { // val remains constant
    colorCurrent.val = colorTarget.val;
  }
  previous_val = colorCurrent.val;
}

The OP said:

But if I try and adjust the Value then I get tons of flickering as the values change.

So it's not a flicker that occurs on what should be a steady Value.

@sharonrlevy, can you post an example of the H, S & Values you see when the flicker occurs, before and after applying david_2018's fix?

@david_2018 - thanks, I will try that and report back

@PaulRB - I had seen that post, I wasn't exactly sure how to make use of it, I thought that meant the code itself was debugged so would make the proper adjustment? Can you please explain how I get that readout of the H, S & V?

how I get that readout of the H, S & V?

Use the Serial.print function call.

sharonrlevy:
I had seen that post, I wasn't exactly sure how to make use of it, I thought that meant the code itself was debugged so would make the proper adjustment?

You mean the GitHub issue? It's not clear if the fix that was made (2 years ago) fixed all the blend() functions or just the RGB one. The issue was raised against the RGB blend function.

sharonrlevy:
Can you please explain how I get that readout of the H, S & V?

I was hoping that david_2018's code included the lines to print the values, but checking again, it doesn't. Perhaps @david_2018 you could share those with the OP?

sharonrlevy:
Can you please explain how I get that readout of the H, S & V?

In you code, colorCurrent.hue, colorCurrent.sat, and colorCurrent.val will give you the values for hue, saturation, and value.

Grumpy_Mike:
Use the Serial.print function call.

I think the OP is asking how to access the h, s & v components. I think it's just colorCurrent.h, colorCurrent.s and colorCurrent.v so just use Serial.print() for each of them.

@david_2018

You can attempt to correcting for the error manually (correction function is at the end of the code):

On code below, I got an error code of:
previous_val = colorCurrent.val;
^
exit status 1
'previous_val' was not declared in this scope

void correctHSV() {
  if (colorStart.val < colorTarget.val) {  //if val is fading upward
    if (colorCurrent.val < previous_val) { //correct for any decrease in val
      colorCurrent.val = previous_val;
    }
  } else if (colorStart.val > colorTarget.val) { // if val is fading downward
    if (colorCurrent.val > previous_val) { // correct for any increase in val
      colorCurrent.val = previous_val;
    }
  } else { // val remains constant
    colorCurrent.val = colorTarget.val;
  }
  previous_val = colorCurrent.val;
}

sharonrlevy:
@david_2018
On code below, I got an error code of:
previous_val = colorCurrent.val;
^
exit status 1
'previous_val' was not declared in this scope

previous_val was declared immediately above void setup () in the code I posted. Don't think I changed anything else.

@david_2018, with code posted as you wrote, I get the error report below, with 'previous_val was not declared in this scope' for each instance. I don't understand code enough to make any adjustments to this on my own  :confused: 




 ^
/Users/Sharon/Documents/Arduino/my sketches/Blend to target color/blendtotargetcolor_SL5/blendtotargetcolor_SL5.ino: In function 'void correctHSV()':
blendtotargetcolor_SL5:84:28: error: 'previous_val' was not declared in this scope
     if (colorCurrent.val < previous_val) { //correct for any decrease in val
                            ^
blendtotargetcolor_SL5:88:28: error: 'previous_val' was not declared in this scope
     if (colorCurrent.val > previous_val) { // correct for any increase in val
                            ^
blendtotargetcolor_SL5:94:3: error: 'previous_val' was not declared in this scope
   previous_val = colorCurrent.val;
   ^
Using library FastLED at version 3.2.5 in folder: /Users/sharon/Documents/Arduino/libraries/FastLED 
exit status 1
'previous_val' was not declared in this scope

sharonrlevy:
@david_2018
On code below, I got an error code of:
previous_val = colorCurrent.val;
^
exit status 1
'previous_val' was not declared in this scope

//adjust color start CHSV and colorTarget CHSV to match colors above
CHSV colorStart = CHSV(128, 255, 100); // starting color
CHSV colorTarget = CHSV(160, 255, 100); // target color
CHSV colorCurrent = colorStart;

byte previous_val = colorCurrent.val; // previous V from HSV  // <<<<<<<< insert this line into your code >>>>>>>>

//---------------------------------------------------------------
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");
}

Thanks @david_2018 that got rid of the error codes.
Unfortunately, that new bit of code didn't seem to change the results on how the LEDs look.

I'm attaching the serial print data from before I added that bit of code (blendtotarget 4) and after (that's the blendtotarget 5 version), if that helps...

Pasting in the code again in its entirety

#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
CHSV colorStart = CHSV(128,90,50);  // starting color
CHSV colorTarget = CHSV(100,100,80);  // target color
CHSV colorCurrent = colorStart;

byte previous_val = colorCurrent.val; // previous V from HSV  // <<<<<<<< insert this line into your code >>>>>>>>

//---------------------------------------------------------------
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.h == colorTarget.h ) {  // 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, SHORTEST_HUES);
    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);
    k++;
  }

  FastLED.show();  // update the display
}

void correctHSV() {
  if (colorStart.val < colorTarget.val) {  //if val is fading upward
    if (colorCurrent.val < previous_val) { //correct for any decrease in val
      colorCurrent.val = previous_val;
    }
  } else if (colorStart.val > colorTarget.val) { // if val is fading downward
    if (colorCurrent.val > previous_val) { // correct for any increase in val
      colorCurrent.val = previous_val;
    }
  } else { // val remains constant
    colorCurrent.val = colorTarget.val;
  }
  previous_val = colorCurrent.val;
}

blendtotarget 4.doc (163 KB)

blendtotarget 5.doc (189 KB)

Just ignore my code, it was only trying to stabilize the value of the HSV, there are fluctuations in the hue and saturation causing a bit of blinking also.

Ah, ok. Does this mean there is nothing to be done to fix it?

No, it doesn't mean that, we still don't know what's causing it. I could not open the .doc files you attached before, my phone won't open them. I was hoping you would just copy & page the printed hsv values between code tags like David_2018 did before. If we can see the numbers behind the flickering, maybe we can understand the cause. If so, we may have to abandon the blend() function provided by FastLED and re-implement it ourselves.

I may have spotted something that could cause the flickering:

void loop()
{
  EVERY_N_MILLISECONDS(blendRate){
    static uint8_t k;
    ...
    ...
    ...
    k++;
  }

  FastLED.show();  // update the display
}

The call to .show() is not inside the EVERY_N_MILLISECONDS section. Its outside that, in loop() itself, so will get called every repetition of loop(), far more frequently than is needed (most of the times, the leds won't have changed, so it just repeats sending the same data).

Move the .show() line to inside the EVERY_N_MILLISECONDS section like this:

void loop()
{
  EVERY_N_MILLISECONDS(blendRate){
    static uint8_t k;
    ...
    ...
    ...
    k++;
    FastLED.show();  // update the display
  }

}

I also tried looking at the hsv values, using serial plotter:


There is a tiny bit of jitter in some of the numbers. I would not have thought it would be noticeable to the eye.

I made these changes to allow me to see the values in serial plotter:

    //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);
    Serial.print(colorCurrent.h); Serial.print(" "); Serial.print(colorCurrent.s); Serial.print(" "); Serial.println(colorCurrent.v);

PaulRB, have a look at this sketch and see if the results look any better. There is still a bit of noticeable flicker when some of the colors change, but that may in part be the dimness of the LEDs, the RGB values are fairly small.

#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  255
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);

const byte number_of_colors = 6;
int current_color_index = 0;

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


//adjust color start CHSV and colorTarget CHSV to match colors above
CHSV colorStart = CHSV(128, 90, 50); // starting color
CHSV colorTarget = CHSV(100, 100, 80); // target color
CHSV colorCurrent = colorStart;

enum directions {increase, decrease, constant};
directions hueDirection, satDirection, valDirection;
bool hueZeroCross;
CHSV colorPrevious;


//---------------------------------------------------------------
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);
  adjustHSVinit();
  Serial.println("Setup done. \n");
}

//---------------------------------------------------------------
void loop()
{
  EVERY_N_MILLISECONDS(blendRate) {
    static uint8_t k;
    if ( colorCurrent.h == colorTarget.h ) {  // 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);
      adjustHSVinit();

    }


    colorCurrent = blend(colorStart, colorTarget, k, SHORTEST_HUES);
    //adjustHSV();
    fill_solid( leds, NUM_LEDS, adjustHSV(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);
    char buf[60];
    sprintf_P(buf, PSTR("Original H:%3i S:%3i V:%3i    R:%3i G:%3i B:%3i    k:%3i"), colorCurrent.h, colorCurrent.s, colorCurrent.v, leds[1].r, leds[1].g, leds[1].b, k);
    Serial.println(buf);
    CHSV colorTemp = adjustHSV(colorCurrent);
    sprintf_P(buf, PSTR("Adjusted H:%3i S:%3i V:%3i    R:%3i G:%3i B:%3i    k:%3i"), colorTemp.h, colorTemp.s, colorTemp.v, leds[1].r, leds[1].g, leds[1].b, k);
    Serial.println(buf);
    k++;
  }
  FastLED.show();  // update the display
}

void adjustHSVinit() {
  //determine if Saturation will increase, decrease, or remail the same
  colorPrevious = colorCurrent;
  if (colorTarget.s > colorStart.s) {
    satDirection = increase;
  } else if (colorTarget.s < colorStart.s) {
    satDirection = decrease;
  } else {
    satDirection = constant;
  }
  //determine if Value will increase, decrease, or remain the same
  if (colorTarget.v > colorStart.v) {
    valDirection = increase;
  } else if (colorTarget.v < colorStart.v) {
    valDirection = decrease;
  } else {
    valDirection = constant;
  }
  //determine if Hue will increse, decrease, or remain the same
  //  this is a bit more difficult, because Hue will take the shortest path from Start to Target
  //  sometimes crossing from 0>255 or 255>0 to do so
  if (colorTarget.h > colorStart.h) {
    if ((colorTarget.h - colorStart.h) < 128) {
      hueDirection = increase;
      hueZeroCross = false;
    } else {
      hueDirection = decrease;
      hueZeroCross = true;
    }
  } else if (colorTarget.h < colorStart.h) {
    if ((colorStart.h - colorTarget.h) < 128) {
      hueDirection = decrease;
      hueZeroCross = false;
    } else {
      hueDirection = increase;
      hueZeroCross = true;
    }
  } else {
    hueDirection = constant;
  }
}

CHSV adjustHSV(CHSV colorOriginal) {
  CHSV colorCorrected = colorOriginal;

  //the following will only allow the HSV values to change in one direction
  //if the value of any of them temporarily reverts to a previous amount, it is ignored

  //correct value of Hue
  if ((hueDirection == increase) && (colorCorrected.hue < colorPrevious.hue)) {
    //check value to go from 255 to 0 if it is expected to cross 0
    if (!(hueZeroCross && (colorCorrected.hue == 0) && (colorPrevious.hue == 255))) {
      colorCorrected.hue = colorPrevious.hue;
    }
  }
  if ((hueDirection == decrease) && (colorCorrected.hue > colorPrevious.hue)) {
    //allow value to go from 0 to 255 of it is expected to cross 0
    if (!(hueZeroCross && (colorCorrected.hue == 255) && (colorPrevious.hue == 0))) {
      colorCorrected.hue = colorPrevious.hue;
    }
  }
  if ((hueDirection == constant) && (colorCorrected.hue != colorPrevious.hue)) {
    colorCorrected.hue = colorPrevious.hue;
  }
  
  //correct value of Saturation
  if ((satDirection == increase) && (colorCorrected.sat < colorPrevious.sat)) {
    colorCorrected.sat = colorPrevious.sat;
  }
  if ((satDirection == decrease) && (colorCorrected.sat > colorPrevious.sat)) {
    colorCorrected.sat = colorPrevious.sat;
  }
  if ((satDirection == constant) && (colorCorrected.sat != colorPrevious.sat)) {
    colorCorrected.sat = colorPrevious.sat;
  }
  
  //correct value of Value
  if ((valDirection == increase) && (colorCorrected.val < colorPrevious.val)) {
    colorCorrected.val = colorPrevious.val;
  }
  if ((valDirection == decrease) && (colorCorrected.val > colorPrevious.val)) {
    colorCorrected.val = colorPrevious.val;
  }
  if ((valDirection == constant) && (colorCorrected.val != colorPrevious.val)) {
    colorCorrected.val = colorPrevious.val;
  }
  colorPrevious.hue = colorCorrected.hue;
  colorPrevious.sat = colorCorrected.sat;
  colorPrevious.val = colorCorrected.val;
  return colorCorrected;
}