Hi everyone and welcome to episode 2 of FastLED basics. If you're just starting with FastLED,
it's a good idea to check out episode one where you can learn how to set everything
up, how to power your project, and how to light your first strip. In this episode though we'll
be having a look at how FastLED deals with color. The topics we'll cover today are rgb, so
setting and reading colors from your leds. hsv - why do we have a different color system
and what are the advantages of this over rgb? Setting the overall brightness of the display with
FastLED.setBrightness and setting color correction and color temperature as well.
Dealing with color is a fundamental technique in FastLED so hopefully by the end of this
you'll have a much better understanding of how to do it yourself. Let's start with rgb
as this is probably how you dealt with color if you've done any programming in the past.
Our eyes contain three color receptors one for each of red, green, and blue although in reality
the red receptor is more sensitive to yellow and orang colors. Every other color you see
is your brain making it up, by combining information from these three receptors. Mixing
colours of light together works differently to mixing colours of paint. For example with paint
if I was to mix together a green and blue we'd get this sort of dark turquoise.
If I was to mix together red and green for example I'd get a sort of muddy brown.
This is known as subtractive color mixing as we're subtracting the wavelengths that our eyes see.
The resulting color is darker than what we started with. Light behaves differently.
Here I have red, green, and blue light. If I mix red and blue light together I get magenta. Mixing green
and blue I get cyan, and mixing green and red I get yellow. If I mix all three colors together
I get white - and that definitely wouldn't happen if we were using paints.
This is known as additive color mixing as we're adding to the wavelengths that our eyes can see.
By changing the relative amounts of red, green and blue we can make any other color we like
when we're using FastLED we're playing with light of course so we are using additive color
mixing. So how do we do this? In FastLED the CRGB object is a structure that represents a color in
rgb color space and it contains three bytes of data. One byte - that's 0 to 255
representing red, green, and blue. To set an led to a bright yellow color for example, we
could simply do leds[i] so whichever led we're interested in = CRGB(255, 255, 0) because
yellow is produced by having full brightness red full brightness green and no blue in there. We
can also change the red, green, and blue separately we don't have to set them all at once.
For example if we write leds[i].r = 127, we'll just set the red component of that particular led.
If you want to copy the color of an led to another led that's easy to do as well.
For example we could say leds[0] = leds[1] so that will just copy the color that's in
leds one into leds zero. There are many, many more methods available at this link
so I encourage you to have a look at that and see how you can manipulate rgb colors.
Let's use this color picker here to set our entire strip to a particular color so let's go for
this this color here, sort of a bright green. Actually maybe a slightly paler green. And we
can see here that the values are going to be 120 for red 255 for green and 15 for blue. We have
a couple of options here to fill the strip with that particular color. We could use fill_solid like
we did on the last video, but what I'm actually going to do here though is I'm going to do it as a loop.
So start at zero until we get to the number of leds we've got and then i++, and then
we're going to set each led to that greenish color that we picked from the color
picker earlier on. And this is what that looks like. It's not particularly exciting, but you can see that it
does work. Instead of doing that we could actually change these numbers so let's have a little
mess about with some of them. Remember this one is for red, this is for green,
and this one's for blue. As we go along the strip let's change the the values of r, g, and
b so let's do something like i * 20 for r, i * 10 for g and maybe i * 30 for b.
It looks like a bit of a mess and that's because we're just randomly changing the red,
green, and blue values here. It's hard to make anything that looks coherent using just
rgb and so although using rgb is easy enough to do we can very quickly find the limitations of the
rgb model for led strips. Let's say we wanted the led to cycle through various colors all at full
brightness. How would we do that with rgb? Well basically it's a little bit difficult you can see
here. As I move the selector along through the various colors, we've now got green increasing we've got
red decreasing, in a minute we're going to have blue, there we go blue starting to increase and now
green's decreasing again and red's increasing and it all gets pretty complicated to program this.
This is something we want to do quite regularly with led strips,
so what can we do? Well this is where the hsv color model comes in hsv stands for hue,
saturation, and value. You sometimes see hsl which in which the l stands for level
but they're pretty much interchangeable for our purposes. If we move between the colors as we
did before you can see that out of h s and v it's only the hue that's changing. Now normally hue is
measured in degrees and has a range from 0 to 359 degrees. Helpfully it also wraps around on itself so
the 359 changes smoothly back to the hue at zero and this makes producing rainbow effects
really, really, easy we can just keep increasing the hue to change between the various colors.
Let's play a little bit more with this color picker. So moving the selection up and down
changes s the saturation so I'll keep this over on red and watch the s value just here.
When it's at the top here the color is fully saturated - is 100 saturated - and as you move down here the color
becomes less and less saturated. At the bottom there is no color information whatsoever, so we can
say that it has zero percent saturation. Finally, we have a v the value. Another way of thinking of
value is basically brightness so if we change this slider just here we can change the value from 100
all the way down to zero percent and back up again. You can think about this in terms
of it being the brightness of an individual led. To keep things, FastLED uses its own values
from 0 to 255 for each of these parameters. The image shows how the hue value relates
to the color with with red being 0 blue being around 160ish and then we get back to red again
by 255. We can create an hsv color just like we do with CRGB something like this.
leds[i] = CHSV and then we have three bytes of data; hue, saturation, and value. Remember each one of those
is between 0 and 255. If you want to set an led to greenish color that's completely
saturated and half brightness we could do something like this. 80 is the hue that
represents green, 255 is full saturation and 127 is half brightness because remember it's out 255.
--Error here, you cannot use .h, .s, or .v to set those parameters--
There are a large number of methods for talking about color and converting between hsv and rgb and all sorts of other stuff.
If you want to find out a bit more about that which I really recommend you do have a
look at that link. Now we have control over those parameters we can do some more interesting things
with our strip. Set everything up as normal. I've created a variable up here, a uint8_t
called hue and set it equal to zero. Remember, uint8_t is an unsigned
number between 0 and 255 but I'll explain why it's important to use this type
in a second. Then in our loop down here, it fills
all of our leds with a particular hsv color. For the first go through the loop, hue is going
to be 0 which is red, and we're going to set full saturation and full brightness.
Then over time we want to change this hue. You see it says hue++? There's a couple of
things that really important in this function. We haven't really talked about this
function called EVERY_N_MILLISECONDS just yet. This is part of a really useful class of
timing functions that you get in FastLED. There's EVERY_N_MILLISECONDS, _SECONDS, _HOURS
and _MICROSECONDS and the reason this is so incredibly useful is it means we don't have to use
delay. These are non-blocking timing functions so what that means is we can safely use this. I think
in the background it uses timers and interrupts to do this without blocking the the normal program.
So if you want to use timings these are really really good functions to use. What I'm saying
here is every 15 milliseconds I want to increase the hue by one so for the first go through the loop
hue is 0 for all the leds. The second go through, hue will be 1 for all the
leds etc. You can see on the image below there what that's doing to our strip. We're very gently fading
between all the different hues at full saturation and at full brightness. So really, really, helpful!
Now one other thing to think about here with this hue++ - what happens when we get to 255?
We don't want to keep increasing indefinitely right, we can't have 255,
256, 257, 258 ... and that's where this uint8_t comes in.
Say it's 255. If you add 1, it doesn't go to two five six it goes back to zero again and
that's exactly what we want to happen when we're scrolling through the various hues. So that's great,
but so far we're setting all of the leds to the same hue value. What about if we want to set each
led to a slightly different hue value to look like a sort of rainbow pattern traveling along
the strip? Well that's relatively easy to do. We start with hue here, I'm going to add on to that
i*10. That means as we go along the strip the first led will have a hue value of zero
the second led will have a hue value of 10 and the third one will have a hue value of 20.
Now because we're moving the hue every time we go around this loop, we're increasing
the hue by one, that'll make it look like the rainbow pattern is moving along the strip.
Let's change that a bit and let's say we want to make an icy or a cold kind of
pattern using mainly blue colors. We can do that, so what I'm doing is set
up as usual - I have nothing to change there - I'm going to create a new color for led
0 so that's the first led in the strip and we're going to use hsv color. The hue is going to be 160
which is a kind of blue color. For the saturation I'm going to use random8() random8() is a FastLED
random number generator. It's much faster than the random built into the normal arduino
api, so if you can use random8() then use that. It generates a 8 bit number so a
number between 0 and 255 and that's pretty useful because that's what we want for our saturation.
Then for the value which is basically the brightness I'm using random8 again. This time I'm
going to put some arguments in there. I'm going to put 100 and 255 and here random 8 will generate a
random number between 100 and 255. So we're starting off by lighting just that one pixel by itself,
then we're going to copy each led to the next one. So we start at the far end of the strip so we
say for int i = NUM_LEDS - 1, so starting at the far end of the strip, and we'll keep going
until we reach the beginning of the strip. We're going to subtract one from i each time
and then for the led that we're looking at we're going to copy in the color
from the previous led. If we do that for all the leds, basically we've moved every led up
by one or the color of every led up by one. Let's upload that and see what that looks like.
Now you see that's way way too fast. It is doing what we're asking it to do
but it just looks like a bit of a mess because it's just running as fast as it
possibly can. Let's use our EVERY_N_MILLISECONDS functions again so
let's go for say 50. We're going to wrap it in this function.
That's much better, a little bit more relaxing than it was initially, and of course we can
play with that number to speed it up or slow it down. We're using EVERY_N_MILLISECONDS
instead of delay() because this is non-blocking. It means your code can be getting on and doing
other things while it's waiting for those 50 milliseconds to elapse. This is very important
if you're using things like buttons or inputs or even if you want other patterns to keep playing
whilst you're waiting for something else to change. In the hsv color space you can adjust the value
or brightness of each pixel but what if you wanted to change the overall brightness of your strip?
You don't want to have to go through everything you've written and adjust the value for each one.
Instead we can use FastLED.setBrightness() and I've had this at the top of pretty much all
of the scripts that i've used so far. As usual, this function takes a unsigned 8 bit integer
or a value from 0 to 255 with zero being a minimum brightness which is off,
and 255 being full brightness. Let's add a feature to this code where we can
adjust the overall brightness on the fly. There are many ways to do this but I've chosen to use a 10k
potentiometer to control the brightness. The value doesn't matter that much but somewhere between 10k
and 100k is about right. The potentiometer needs to be wired up as shown here with two outside pins
connected to 5V and ground and the middle pin connected to an analog input. I've chosen
A1 here. I've added a new define at the top here so #define pot_pin or potentiometer pin to be A1.
Then we need to add a few lines into our loop. The first thing we need to
do is to read the potentiometer pin then we want to create a variable called brightness
and what we're going to do is we're going to map this potentiometer value.
The value read from the potentiometer is going to be between 0 and 1023 but
FastLED.setBrightness() expects an 8-bit integer in other words a value between 0 and 255.
Now i don't want the brightness here to go all the way up to 255 because it's a little bit too bright
so I'm going to map 0 - 1023 to 0 - 255 instead. Then all we have to do is call
FastLED.setBrightness(brightness) and we should be able to control the brightness of the
strip. I'm using the potentiometer and as you can see as I turn that up and down now the strip is
getting brighter and dimmer. So it's really simple to add overall brightness control to your project.
Let's now have a look at color correction. Although our eyes see our red green and blue,
they're more sensitive to green where the red and green receptors overlap than the other two colors.
You can see the peak on this image just here is about 560-ish nanometers so that's the frequency
that our eyes are most sensitive to. This means that any color you display on the strip can look
a little bit too green. This is the most obvious when the led is set to white and we can alter this
by using FastLEDs setCorrection() function. All strips will be different so the way to use this is
to try the various options and see what works best for you. I've written a quick sketch here what this
does is this applies the three main options one after the other. First we have uncorrected color
then we have typical led strip and then we have typical pixel string. I've also changed the color
of the first pixel here so we can see which one we're displaying each time. Then you want to point
the strip at a white sheet of paper and see which correction if any best represents white light.
Looking at this in my case the uncorrected color looks a little bit too blue, a typical led strip
looks a little bit too purple, and a typical pixel string to me is the closest to a neutral white.
It might not come out so well on the camera. I would add this to the setup function
as shown up here. We can also change the color temperature of the strip. You might have heard
of color temperature when choosing an led light bulb for your house. Confusingly, the higher the
color temperature, the cooler the white light will appear and the lower the color the warmer the
light will appear. Candlelight has a very warm color to it and has a temperature of about 1900 Kelvin
whereas midday sunlight will be closer to 5700 Kelvin. I've written a quick example here to cycle
through the various color temperature corrections I've also used one of those every n functions
again you can see every n seconds to step through one second at a time. It's usually fine not
to add any temperature correction at all but the functions are there if you need to use them and
they would normally be put in the setup function at the top of your sketch. I think that's enough
on color for today, as usual I really hope that was helpful and that maybe you learned something.
In the next video though we'll look at color in a little bit more detail and explore FastLED's
brilliant palette and palette blending functions. If you'd like to know when that comes out, a
subscribe to the channel be very much appreciated. All the best, and I'll see you next time.