I’m sending colors from an Smartphone App to my Arduino.
The color is send as a hex value.
For example I send the hexValue = 0x123456 (1193046 as dec)
Then I light up the LEDs with that value:
leds[i] = 1193046;
Well I want to be able to save this value, so that the LEDs light up like I set it the last time.
Because each memory adress can hold one byte I save this color value as RGB value.
Color “translation” is done by:
red = (hexValue >> 16) & 255; // red
green = (hexValue >> 8) & 255; // green
blue= (hexValue) & 255; // blue
When I now use:
leds[i].setRGB(red, green, blue);
The leds turn to a different value.
Especially the darker colors are even darker when I use RGB color.
Whats going on there and how can I prevent it?
Hi- I suspect you’re seeing something related to plain old integer wrap-around in C, arising from the fact that on AVR Arduino’s default “integer” size is just 16 bits. Often intermediate results get passed through a 16-bit integer and unexpectedly truncated. For example:
unsigned int i = 40000;
unsigned long int sum = i + i;
Serial.println( sum );
You’d expect this code to print 80000, because “i” is big enough to hold “40000”, and “sum” is big enough to hold “80000”. However, if you run this on an AVR Arduino, it prints 14464. This is because the “+” operator on the second line only produces a 16-bit result ((40000 + 40000) % 65536) and then that value is stored into “sum”, and printed.
If you change line 2 (above) to say
unsigned long int sum = (unsigned long)(i) + (unsigned long)(i);
then the code prints the expected result, because now the “+” operator knows that it’s adding two 32-bit values, and not to truncate the result to 16 bits. It’s sort of a pain in the bit.
I think in order to diagnose your specific code a little more deeply, I’d ask for two things. First, could you share a block of your code that’s having the trouble, showing us the data type (“int”, “long unsigned int”, etc) of all the relevant variables?
And second, could you instrument the code to print out the R, G, and B values that you are getting? That might help pinpoint the problem.
As one last item, you can also retrieve the RGB color values from a pixel like this:
uint8_t red, green, blue;
red = leds[i].red;
green = leds[i].green;
blue = leds[i].blue;
So share some code, and some printed-out values of what you’re seeing, and we’ll help get it all working.
The FastLED HSV-to-RGB conversion has a built-in gamma correction of 2.0, which means that the Value scale is not linear. Instead it is adjusted to be closer to visually linear, or to put it another way, it comes out darker.
If you want, you can just perform the brightness effect adjustments in RGB space, or alternatively pre-adjust your HSV values to have a higher V. If you like, I can give you a formula for that.
It would be great if you could give me a formula to bring the HSV to the level of the RGB colors.
The reason I want it that way (an not adjust RGB to HSV) is because I my App to control the LEDs uses HexValues and everything is adjusted to that (values of sliders in the app etc.)
.
But if you also know how to to the other way then I am interessted in it as well (to adjust RGB to the HSV colors).
Earlier you wrote this:
I checked it with the Hex value: 0x123456
translated to decimal: 1193046
translated to RGB: 18, 52, 86
translated to HSV: 149, 201, 86
The first three lines are all literally identical; they’re just different ways of writing down the same numbers:
0x12 (18 decimal) for red,
0x34 (52 decimal) for green, and
0x56 (86 decimal) for blue.
However, the last line that you wrote says that you “translated” the color to HSV. And HSV color space is totally different from RGB color space.
So… how did you do that “translation”? What algorithm did you use? And what HSV color space are you translating into? There are multiple HSV color spaces, see https://github.com/FastLED/FastLED/wiki/FastLED-HSV-Colors for discussion of classic “spectrum” versus “rainbow”.
In order to help you get the right formula you’re looking for, I need to know where you got the “HSV” values to start with. Please let me know if I can help clarify the question, too!
More details: in most applications, “Hue” is represented as a number of ‘degrees’ around a color wheel, 0…359. In FastLED, “Hue” is represented as a number of ‘binary steps’ around the color wheel, ranging from 0…255. So if you’re getting Hue from some outside source, you need to perform a mapping. You can do that by multiplying the Hue360 by 256/360 (0.711111) to get the Hue256. You’ll still be in a spectrum color space, but that’s OK, as you can do this:
The default assignment from a CHSV to a CRGB uses the hwv2rgb_rainbow method, so the hues won’t quite line up.
Again, this all comes back to: where are you getting your HSV values from? What algorithm is doing the translation from/to RGB, and what HSV color space (spectrum or rainbow or ?) is it using?
As for cancelling out the gamma correction… if you want to cancel out the gamma correction of “2.0” that happens automatically inside the HSV to RGB conversion (which is implied here)
Well I know that my first three lines are the same color.
I just wanted to show you that there is no mistake at receiving and using the hex value.
For example I could have made the mistake to store this value as an integer (instead of long).
To be precise in that: With hex value I do mean the RGB hex value. (for me the hex color 0xRRGGBB are directly connected to RGB colorspace - its just another notation.)
To your question about the “translating algorthm”:
I translate the RGB values in the only way that I know and as seen on wikipedia:
There is of course a Hue range from 0° to 359°.
But I converted this to 0-255.
Also the percentage values of the “RGB to HSV color conversion”-calculator are in a range of 0-255.
The check this you can try this calculator linked above and check it with my values given before:
Hex value: 0x123456
translated to decimal: 1193046
translated to RGB: 18, 52, 86
translated to HSV: 149, 201, 86
And now the harder part for me
Well thats right, that FastLED has 2 kinds of HSV color spaces.
In the past I already did some checking in both of theese to figure out which one I prefere. The result was, that “rainbow hsv” looks better in my effects.
I do actually have a lot of different effects which are all “based” (looks better) in the rainbow (adjusted) HSV color space.
For example a rainbow fade through the hue looks much better because of better illustration of red and yellow.
But you know that as this was the reason why you created this rainbow HSV color space.
So as far as I understood, I “just” have to cancel out the gamma correction by recalculate the V-Value like:
newV = sqrt16( oldV * 256);
right?
What is that sqrt16() function exactly?
Is it a square root on 16bit-based CPU?
Because all the Arduinos I own has a 8-bit CPU and I only know about the simple sqrt() function of the ArduinoIDE.
I already tested this on my Arduino Uno (with the color given above 0x123456):
byte val = 86;
double newV = sqrt(oldV * 256); // newV is now 148.38
for (int i = 0 ; i < NUM_LEDS; i++ )
{
leds[i] = CHSV( 149, 201, newV ); // I know the cast is not needed…
}
LEDS.show();
The color is better but there is still a lot of space to:
for (int i = 0 ; i < NUM_LEDS; i++ )
{
leds[i].setRGB(18, 52, 86);
}
LEDS.show();
I’m a bit busy at work today, but I’ll try to move things along in this discussion as I can, bit by bit.
So here’s one thing: “sqrt16” is a FastLED function which takes a 16-bit integer and returns the 8-bit integer square root. It’s several times faster than the Arduino built-in floating point version (and takes up less code space as well). So if you’re going to convert to an integer result anyway (which you are here), instead of
double newV = sqrt(oldV * 256);
you can just say
uint8_t newV = sqrt16( oldV * 256);
and get smaller and faster code.
(uint8_t is the ANSI/ISO equivalent name for Arduino’s “byte” type.)
Both prints me out that newV is 148.
Even if the sqrt16() funktion is faster an takes less space, the result is sadly the same and the color looks the same with sqrt and with sqrt16.
I know it shouldnt be different, as your explaination was only for me to understand that sqrt16() is a great FastLED function.
I just wanted to give you some feedback.
Sorry for the delays, and I will try to help out further. “Life” getting in the way a bit last few days! Still thinking about how best to solve the overall problem. Basically we can’t mix HSV color spaces (traditional spectrum vs FastLED rainbow). RGB is more universally the same.
I continue to keep coming back to the central idea that there are THREE (or four) different color spaces being used here:
the LEDs’ RGB hardware (presumably the same as FastLED RGB, and remote device RGB)
The remote device HSV model, which is probably some kind of a “spectrum” model, and
FastLED HSV color model (or models, actually, since one is a spectrum and one is a rainbow)
And that we can’t just freely convert from one to the other and back. FastLED provides one kind of conversion, but the other conversions are undefined.
I also keep feeling like I wish I had more of the code to understand, or rather, a clearer picture of the data flow. Eg, “Use inputs RGB values on device. DeviceRGB values converted to DeviceHSV by code on the device. DeviceHSV values then sent to Arduino via Bluetooth. (Etc)”
I’ll be around today and can probably take another look, but I have to admit I’m still not sure I’m working on the right part of the problem, and more information would help.