Arduino Forum

Forum 2005-2010 (read only) => General => Exhibition => Topic started by: akgraphics on Apr 04, 2008, 07:51 pm

Title: Hue-controllable RGB LED lamp
Post by: akgraphics on Apr 04, 2008, 07:51 pm
My first Arduino project!  :)

I wanted an RGB LED whose colour I could control with just one potentiometer. To do this, I created this workflow:

Read potentiometer > take pot value as a Hue value in a HSB system1 > convert HSB values (with S=1 and B=1) into RGB values > Use arduino pins to PWM RGB output to my RGB LED

The hardest part was converting HSB into RGB - the equations that I worked on from wikipedia are an absolute nightmare to translate into code (at least for me at this stage). I was about to give up when I saw this link, full of ready-made colour conversion functions: http://www.easyrgb.com/math.php?MATH=M21#text21.

The hardware is sitting on a breadboard, with a bit of paper diffusing the LED lamp, so it's not too pretty-looking. Here's my code anyhow:

Code: [Select]
int potpin = 2;              // Switch connected to digital pin 2

int rpin = 9;
int gpin = 10;
int bpin = 11;
float h;
int h_int;
int r=0, g=0, b=0;

int val=0;

void h2rgb(float h, int &R, int &G, int &B);

void setup()                    // run once, when the sketch starts
{
 Serial.begin(9600);           // set up Serial library at 9600 bps
}


void loop()                     // run over and over again
{
 val=analogRead(potpin);    // Read the pin and display the value
 //Serial.println(val);
 h = ((float)val)/1024;
 h_int = (int) 360*h;
 h2rgb(h,r,g,b);
 Serial.print("Potentiometer value: ");
 Serial.print(val);
 Serial.print(" = Hue of ");
 Serial.print(h_int);
 Serial.print("degrees. In RGB this is: ");
 Serial.print(r);
 Serial.print(" ");
 Serial.print(g);
 Serial.print(" ");
 Serial.println(b);

 analogWrite(rpin, r);
 analogWrite(gpin, g);
 analogWrite(bpin, b);
}

void h2rgb(float H, int& R, int& G, int& B) {

 int var_i;
 float S=1, V=1, var_1, var_2, var_3, var_h, var_r, var_g, var_b;

 if ( S == 0 )                       //HSV values = 0 ÷ 1
 {
   R = V * 255;
   G = V * 255;
   B = V * 255;
 }
 else
 {
   var_h = H * 6;
   if ( var_h == 6 ) var_h = 0;      //H must be < 1
   var_i = int( var_h ) ;            //Or ... var_i = floor( var_h )
   var_1 = V * ( 1 - S );
   var_2 = V * ( 1 - S * ( var_h - var_i ) );
   var_3 = V * ( 1 - S * ( 1 - ( var_h - var_i ) ) );

   if      ( var_i == 0 ) {
     var_r = V     ;
     var_g = var_3 ;
     var_b = var_1 ;
   }
   else if ( var_i == 1 ) {
     var_r = var_2 ;
     var_g = V     ;
     var_b = var_1 ;
   }
   else if ( var_i == 2 ) {
     var_r = var_1 ;
     var_g = V     ;
     var_b = var_3 ;
   }
   else if ( var_i == 3 ) {
     var_r = var_1 ;
     var_g = var_2 ;
     var_b = V     ;
   }
   else if ( var_i == 4 ) {
     var_r = var_3 ;
     var_g = var_1 ;
     var_b = V     ;
   }
   else                   {
     var_r = V     ;
     var_g = var_1 ;
     var_b = var_2 ;
   }

   R = (1-var_r) * 255;                  //RGB results = 0 ÷ 255
   G = (1-var_g) * 255;
   B = (1-var_b) * 255;
 }
}

Title: Re: Hue-controllable RGB LED lamp
Post by: akgraphics on Apr 07, 2008, 12:42 am
This evening I've also created another 2 functions for controlling an RGB LED. The first function holds an LED at a certain RGB value for a given time period, using PWM, nothing special there. The second function accepts 2 RGB values, then fades between them over a given time period, with a smooth gradient. One can now program a lighting sequence using the simple colour "holds" and "fades".

My problem with the fade code is that I could only seem to make it work when using floating point arithmetic. Attempting to mix up integer math made the PWM go all wrong. So the Arduino is performing a LOT more operations that it really should be doing. This does not affect the timing of the LED colour-changes (to my eyes at least) though I havn't done any rigorous sort of test on that:

Code: [Select]
//i/o pin declarations
int rpin = 9;
int gpin = 10;
int bpin = 11;

//function prototypes
void solid(int r, int g, int b, int t);
void fade(int r1, int g1, int b1, int r2, int g2, int b2, int t);

void setup()                
{
//empty
}

void loop()                    
{
 //colour sequence instructions
 
 //Example sequence one: Rainbow fade over 15 seconds:
 fade(255,0,0,0,255,0,5000); //fade from red to green over 5 seconds
 fade(0,255,0,0,0,255,5000); //fade from green to blue over 5 seconds
 fade(0,0,255,255,0,0,5000); //fade from blue to red over 5 seconds
}

//function holds RGB values for time t milliseconds
void solid(int r, int g, int b, int t)
{

 //map values - arduino is sinking current, not sourcing it
 r = map(r, 0, 255, 255, 0);
 g = map(g, 0, 255, 255, 0);
 b = map(b, 0, 255, 255, 0);

 //output
 analogWrite(rpin,r);
 analogWrite(gpin,g);
 analogWrite(bpin,b);
 
 //hold at this colour set for t ms
 delay(t);

}

//function fades between two RGB values over fade time period t
//maximum value of fade time = 30 seconds before gradient values
//get too small for floating point math to work? replace floats
//with doubles to remedy this?
void fade(int r1, int g1, int b1, int r2, int g2, int b2, int t)
{

 float r_float1, g_float1, b_float1;
 float r_float2, g_float2, b_float2;
 float grad_r, grad_g, grad_b;
 float output_r, output_g, output_b;
 
 //declare integer RGB values as float values
 r_float1 = (float) r1;
 g_float1 = (float) g1;
 b_float1 = (float) b1;
 r_float2 = (float) r2;
 g_float2 = (float) g2;
 b_float2 = (float) b2;
 
 //calculate rates of change of R, G, and B values
 grad_r = (r_float2-r_float1)/t;
 grad_g = (g_float2-g_float1)/t;
 grad_b = (b_float2-b_float1)/t;
 
 //loop round, incrementing time value "i"
 for ( float i=0; i<=t; i++ )
 {
   
   output_r = r_float1 + grad_r*i;
   output_g = g_float1 + grad_g*i;
   output_b = b_float1 + grad_b*i;
   
   //map values - arduino is sinking current, not sourcing it
   output_r = map (output_r,0,255,255,0);
   output_g = map (output_g,0,255,255,0);
   output_b = map (output_b,0,255,255,0);
   
   //output
   analogWrite(rpin, (int)output_r);
   analogWrite(gpin, (int)output_g);
   analogWrite(bpin, (int)output_b);
   
   //hold at this colour set for 1ms
   delay(1);
   
 }
}


Title: Re: Hue-controllable RGB LED lamp
Post by: thebias on Jun 03, 2008, 03:11 am
Could this be done using more than one LED on the output?  Basically I was wondering if this could be scaled up with enough LEDs to add ambient lighting to an entire room.  Nothing too complex as in they could all change at once.  I am guessing you would need some sort of external power supply though as they would draw too much current for just the arduino board.
Title: Re: Hue-controllable RGB LED lamp
Post by: Easty on Jun 16, 2008, 02:46 pm
akgraphics, could you explain this piece of code?

Code: [Select]
//map values - arduino is sinking current, not sourcing it
r = map(r, 0, 255, 255, 0);
g = map(g, 0, 255, 255, 0);
b = map(b, 0, 255, 255, 0);

I'm learning a lot of programming techniques at the moment and it appears you're reversing/inverting the output by mapping it? Is that just to do with how you have your LED's connected to the outputs?

Thanks in advance, Easty.

PS Sorry thebias I can't answer your question (yet) but I'm planning something similar by the sounds of it.
Title: Re: Hue-controllable RGB LED lamp
Post by: tehboii on Jun 16, 2008, 02:48 pm
As you partially guessed, map() takes an amount and the range of values to which it belongs, and remaps it to another range of values. I think the documentation page on it is very clear :

http://www.arduino.cc/en/Reference/Map
Title: Re: Hue-controllable RGB LED lamp
Post by: Easty on Jun 16, 2008, 02:55 pm
Thanks Theboii, I had had a read of the reference material and seemed to understand it!

I was wondering why akgraphics had used it in his code as in my brief experiments with PWM'ing LEDs last night I didn't have to perform that change. I guess it's circuit specific though...

Cheers, Easty.
Title: Re: Hue-controllable RGB LED lamp
Post by: tehboii on Jun 16, 2008, 05:05 pm
Ok, sorry ^^

Basically, you have to revert the value of an output pin when the pin is connected to the ground of the component. This is called "sinking" instead of "sourcing", which is when you output power to the component.

You often sink current from components instead of sourcing them because the µC can sink more than it can source, since sinking just basically means "connecting to GND"

So, if a component is connected on the gnd side on a pin, and on the cathode side on a power source, you just reverse the values you send : Putting the pin to 0 or LOW will sink 100% of the power (within the limit of the µC capabilities, of course.), putting it to HIGH or PWM255 will prevent electricity to circulate.

I hope I made myself clear... I'm not sure ^_^
Title: Re: Hue-controllable RGB LED lamp
Post by: Easty on Jun 16, 2008, 05:18 pm
Understood 100%!

Interesting about the sink/source comparision... I think I'd better redesign my circuit!

Thanks, Easty.
Title: Re: Hue-controllable RGB LED lamp
Post by: dcb on Jun 16, 2008, 06:13 pm
It is a neat idea, only thing I would suggest is that I might not invite float to the party.

AnalogRead returns 10 bits (0-1023)
You might want to look at the individual bits and assign them to colors directly


say 1 bits for intensity, 3 bits per color

analog read returns 1023 = 1111111111 in binary
intensity,   R,   G,   B
1        , 111, 111, 111

multiply R, G, B by 18 and if intensity is set add 128 to each.  

Edit: while this isn't technically hue, it will give you access to more color combinations and intensities than hue alone would.
Title: Re: Hue-controllable RGB LED lamp
Post by: dcb on Jun 17, 2008, 01:20 am
Here is a non-float, hue only version also.  What is the application?  It sounds like it could be interesting.
Code: [Select]

void setup(){
 Serial.begin(9600);
}

void loop(){
//colors out of phase by 341  (1023/3)
 Serial.println("V,R,G,B");
 for(int v = 0; v < 1024; v++){ //analogRead surrogate
   Serial.print(v);
   Serial.print(",");
   Serial.print(colVal(v+341),DEC);    //red
   Serial.print(",");
   Serial.print(colVal(v),DEC);        //green
   Serial.print(",");
   Serial.println(colVal(v+682),DEC);  //blue
 }
 while(true);
}

//based on green hue function, add phase adjustment for red or blue value
byte colVal(int val){
 int v = val % 1024;
 if(v<=170)
   return (v * 3) / 2;
 if(v<=512)
   return 255;
 if(v<=682)
return 255 - (((v%171) * 3) / 2);
 return 0;
}


Edit:  Just noticed the part about non-floats messing up the pwm functions, that doesn't sound right.
Title: Re: Hue-controllable RGB LED lamp
Post by: makoto on Jul 04, 2008, 07:24 am
akgraphics,

Nice job with that.  Wish I ran across this post earlier.  I actually ended up writing pretty much the same code for the fading, just without the map() and I'm using random values so that it fades from one random color to another.  It's amazing that you thought of pretty much the same exact algorithm.

I ended up adding the map() because my tri-color LED has a common Anode
Title: Re: Hue-controllable RGB LED lamp
Post by: thebias on Jul 17, 2008, 04:19 am
Not sure if this is at all helpful for you too easty but my theory so far is to use a combo of the code you guys have put up here with 3 of these circuits http://www.arduino.cc/playground/uploads/Learning/multiple_leds2.jpg in order to drive the each of 3 colours for each LED.  To start with I would just like to get 3 RGB leds up and running.  I think this should work bearing in mind that I want them to all do the same thing at the same time. If anyone sees any gaping holes in my theory please point it out!

Cheers
Title: Re: Hue-controllable RGB LED lamp
Post by: xandar on Jul 20, 2008, 08:11 am
I've got a question about the 'sinking' technique:
When the source is +5V, and the PWM pin is HIGH, no electricity will flow even if the +5V is capable of higher current than the pin, correct?

Also, how much current can an arduino pin safely sink?  I know the pins can source 40ma, but didnt see a value for sink.

Thanks, and very nice code!
Title: Re: Hue-controllable RGB LED lamp
Post by: Grumpy_Mike on Jul 21, 2008, 05:32 pm
Quote

When the source is +5V, and the PWM pin is HIGH, no electricity will flow even if the +5V is capable of higher current than the pin, correct?


Yes if there is no voltage difference then there is no current flow.

Quote

Also, how much current can an arduino pin safely sink?  I know the pins can source 40ma, but didnt see a value for sink.



You can sink 60mA at 25C and get down to a voltage of 1.5v.

That means sinking current you will not get the full 5v across the load but 5 - 1.5 = 3.5v

Sinking 40mA gets you down to under 1V on the output where as 20mA gets the output voltage down to 0.5v
Title: Re: Hue-controllable RGB LED lamp
Post by: dandy_dan on Apr 24, 2009, 05:53 pm
akgraphics, just wanted to thank you. I have used some of your code in my own project to get a pot to control RGB values. Very useful! :)
Title: Re: Hue-controllable RGB LED lamp
Post by: wileywiggins on Jun 05, 2009, 06:31 pm
I'm trying to do something similar, but instead of a pot, I'm using three Ping))) ultrasonic rangefinders to control fade my LED's. I'm trying to use that map command to get the distance data turned into 0-255 values. Haven't quite got it yet...
Title: Re: Hue-controllable RGB LED lamp
Post by: venkatmvr on Jul 02, 2009, 06:37 pm
Hi,
I have used your code and get the colors to adjust based on a potentiometer input. There is one thing I observed I do not seem to see any blues. I see green, pinks, reds yellow but do not get a good blue. Any ideas why this seems to be the case.
Venkat
Title: Re: Hue-controllable RGB LED lamp
Post by: syrax on Jul 06, 2009, 06:16 pm
excellent algorithm :))) i think is good when read 0 from pot to put all colors off /switch off/ and if the pot value is max 1023 to fire all the leds /white/ this will cover this missing part  ::)
Title: Re: Hue-controllable RGB LED lamp
Post by: LocalgHost on Jul 07, 2009, 09:19 pm
ONe can also do the RGB LED control using a mouse x and y position feed from Processing, I think Its the Firmata libary , It efectively changes the Rduino platform inti a data IO device over serial, This is plent useful for pc based control
Title: Re: Hue-controllable RGB LED lamp
Post by: Oracle on Jul 13, 2009, 02:34 pm
When you output an PWM value between 0 and 255, it's not even remotely similar to the same RGB value.  The problem is that the LED brightness does not climb linearly with the PWM duty cycle.  If you go from 1 to 2, there's a huge jump in brightness while if you go from 100 to 200 there's almost no discernable change.  Quite often just to save power, I'll PWM my LEDs at about 20% duty cycle and it looks almost the same as full brightness.  I've been considering a similar project for a while but because this issue I was looking at only having 10 possible brightness levels for each colour and then using empirical observation to convert those values to PWM levels.


Also, as far as your map function...Why aren't you just using
Code: [Select]

r = 255 - r;
g = 255 - g;
b = 255 - b;
Title: Re: Hue-controllable RGB LED lamp
Post by: lqbert on Jul 22, 2009, 02:06 am
http://www.youtube.com/watch?v=dlu4r_2FVrs

I'm using the TLC5940 PWM LED driver.  No multiplexing... the rows are identical outputs.  This is done with some nested loops and some trig (sine wave conversion).  

I'm sure I could have a potentiometer control 1 or more of the variables used in the loops above to either fade the matrix to a specific color or just take the scrolling part out of it and have the potentiometer just send static values to be used for the color calculation.

Title: Re: Hue-controllable RGB LED lamp
Post by: DeFex on Aug 23, 2009, 04:16 am
I would also like to thank you i have used the fade function to test RGB leds in my first little project. it picks random amounts for RGB and fades between them at also a random speed, its like a full color candle :)

eventually what i want to make is a lamp which changes color according to barometric pressure, average ambient noise level, temperature, and other environmental inputs. so this would be perfect.

I just got the arduino for a particular musical instrument project (but im having way too much fun with it)
Title: Re: Hue-controllable RGB LED lamp
Post by: rr on Sep 23, 2009, 10:27 am
Hey Peoples,

I Have implemented this code in a project and it works great. I am using a 10k pot and it gives me all the range of color I need.

I wanted to use a flex sensor (variable resistor) to control hue. However when I plugged it into the circuit it doesn't give me the same range I am only getting about half. I know that it is because the flex sensor has a different range of ohms. The flex sensor has a range of about 11k - 40k ohms. Since the flex sensor only has 2 pins I am using a 10K resistor in between on of the pins and ground. I have tried fooling around with some numbers in the code, but not with any luck. I know there are some ways to connect supplemental resistors in parallel to change values, but I am a bit confused.

Is there a way to do what I want with the flex sensor I have and is it a hardware problem or a program problem?

Any help would be greatly appreciated...

Thanks
rr



Title: Re: Hue-controllable RGB LED lamp
Post by: raron on Sep 29, 2009, 03:41 pm
I thought up a different value -> RGB formula a couple of years ago when I dabbled a little in Milkdrop. While it isn't perfect, it worked pretty well imho. (I needed it for a lightbeam that splits up into different colors, for a "Dark Side of the Moon" animation: http://raron.deviantart.com/art/Dark-Side-of-the-Moon-54658436) Here, yellow is the worst represented color (although it is present - barely.)

This is what I came up with:
R = 0.5 + 0.5 * cos((value+0.125) * 2 * PI)
G = 0.5 + 0.5 * cos((value+0.375) * 2 * PI)
B = 0.5 + 0.5 * cos (value * PI)

Where value is from 0 to 1, as is the returned RGB values in this case.

As stated, not perfect (could be more tweaking fixes it, but I kind of liked the formulas too  ::) ), it doesn't give quite clean colors.

I had to test it on my arduino with a common-anode RGB LED of course. Unfortunately it didn't turn up too well. Here, it is  the green which is the worst, and also the yellow... so yeah not perfect at all. I just wanted my say in the matter :D Although the original HSV formula is much better (I presume, I haven't tested it yet but I'm pretty sure it is).

Anyway, this sums up my RGB test sketch:
Code: [Select]

const int ledRed = 9;
const int ledGreen = 10;
const int ledBlue = 11;

double redLevel;
double greenLevel;
double blueLevel;


void setup()
{
pinMode(ledRed, OUTPUT);
pinMode(ledGreen, OUTPUT);
pinMode(ledBlue, OUTPUT);
}

void loop()
{
   int value = analogRead(analogPin);
   double RGBslider = (double)value/1024.0;
   
   redLevel   = 128.0 * ( 1 + cos( 2 * PI * (RGBslider + 0.125)));
   greenLevel = 128.0 * ( 1 + cos( 2 * PI * (RGBslider + 0.375)));
   blueLevel  = 128.0 * ( 1 + cos( PI * RGBslider));
   
   if (redLevel > 255) redLevel = 255;
   if (redLevel < 0) redLevel = 0;
   if (greenLevel > 255) greenLevel = 255;
   if (greenLevel < 0) greenLevel = 0;
   if (blueLevel > 255) blueLevel = 255;
   if (blueLevel < 0) blueLevel = 0;
   
   analogWrite(ledRed, 255 - ((byte)redLevel)); // negating the output for common anode (sinking)
   analogWrite(ledGreen, 255 - ((byte)greenLevel));
   analogWrite(ledBlue, 255 - ((byte)blueLevel));
}

Title: Re: Hue-controllable RGB LED lamp
Post by: raron on Oct 10, 2009, 04:14 pm
Well RGB LED's are fun, so I've been playing with one of those lately. I got one sitting on a breadboard at the moment, lighting up a crystal above it. It looks quite nice cycling colors in various modes, and will be a little desklamp thingy soon :)

Anyway, now I've tried OP's algorithm, which of course worked much better then my previous one (though mine is more of a rainbow spectrum, or at least it was supposed to be, and this one is a color wheel starting and ending in red).

But I also wanted to adjust  the light/dark-ness of it. However I could simply not get the HSL -> RGB algorithm to work, from this page: http://www.easyrgb.com/index.php?X=MATH&H=19#text19

So I modifyed the HSV -> RGB function instead, making it into a sort of HSVL -> RGB function. Though V is not an argument, it is made dependent of the float variable "L".  I just added a little snippet for lightness (the L float variable, from 0 to 1).

So when the argument L=0.5, the colors are fully saturated, like before. Less than 0.5 and they are darker, above and they are linearly more white until L=1 = white.

Of course, for the color to be as white as possible, one would have to balance the current limiting resistors to the R,G and B portion of the LED.

Anyway, if anyone is interested this is the (slightly) modified function.
Code: [Select]
void hsvl2rgb(float H, float L, int& R, int& G, int& B)
{
 int var_i;
 float S=1, V, lightness, var_1, var_2, var_3, var_h, var_r, var_g, var_b;

 V = L * 2;                         // For the "darkness" of the LED
 if ( V > 1 ) V = 1;

 if ( S == 0 )                      //HSV values = 0 ÷ 1
 {
   R = V * 255;
   G = V * 255;
   B = V * 255;
 }
 else
 {
   var_h = H * 6;
   if ( var_h == 6 ) var_h = 0;  //H must be < 1
   var_i = int( var_h ) ;            //Or ... var_i = floor( var_h )
   var_1 = V * ( 1 - S );
   var_2 = V * ( 1 - S * ( var_h - var_i ) );
   var_3 = V * ( 1 - S * ( 1 - ( var_h - var_i ) ) );

   if ( var_i == 0 ) {
     var_r = V     ;
     var_g = var_3 ;
     var_b = var_1 ;
   }
   else if ( var_i == 1 ) {
     var_r = var_2 ;
     var_g = V     ;
     var_b = var_1 ;
   }
   else if ( var_i == 2 ) {
     var_r = var_1 ;
     var_g = V     ;
     var_b = var_3 ;
   }
   else if ( var_i == 3 ) {
     var_r = var_1 ;
     var_g = var_2 ;
     var_b = V     ;
   }
   else if ( var_i == 4 ) {
     var_r = var_3 ;
     var_g = var_1 ;
     var_b = V     ;
   }
   else {
     var_r = V     ;
     var_g = var_1 ;
     var_b = var_2 ;
   }

   if ( L > 0.5 )         // Adjusting the Lightness (whiteness)
   {
     lightness = ( L - 0.5 ) / 0.5;
     var_r += ( lightness * ( 1 - var_r ) );
     var_g += ( lightness * ( 1 - var_g ) );
     var_b += ( lightness * ( 1 - var_b ) );
   }

   R = (1-var_r) * 255;     // RGB results = 0 ÷ 255. Reversed for common anode RGB LED's
   G = (1-var_g) * 255;
   B = (1-var_b) * 255;
 }
}
Title: Re: Hue-controllable RGB LED lamp
Post by: Jkm3141 on Feb 25, 2010, 02:23 pm
I too must thank the original thread creator, and all the contributors of this thread as It greatly helped in my first arduino 'project', which has a HSV loop and various other RGB LED controls controlled through serial and a python front end.

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1267104041/0
Title: Re: Hue-controllable RGB LED lamp
Post by: PostOfficeBuddy on Jul 20, 2010, 10:56 am
Thanks to all the contributors in this thread for helping me get a quick prototype RGB control circuit up and running. When it's late at night and you're working on hardware the last thing you want to do is reinvent the wheel in code!
Title: Re: Hue-controllable RGB LED lamp
Post by: Cybot_Rules on Sep 04, 2010, 11:45 am
Hi,
just wanted to say thanks, im using this code to run a RGB backlight to a lcd thats howing my computer stats :D