Go Down

Topic: Need help with RGB rainbow colors (Read 4067 times) previous topic - next topic

robtillaart

found this one in my experiments section. Code goes 360 degrees through hue space converting it to related RGB values.
links to 2 website included

Code: [Select]

//
//    FILE: RGB2HUE.pde
//  AUTHOR: Rob Tillaart
//    DATE: 2011-09-17
//
// PUPROSE: color-rainbow
//
// http://www.dipzo.com/wordpress/?p=50
// http://www.easyrgb.com/index.php?X=MATH
//

int Rpin=10;
int Gpin=9;
int Bpin=11;

float H,S,L, Rval,Gval,Bval;

void HSL(float H, float S, float L, float& Rval, float& Gval, float& Bval);
float Hue_2_RGB( float v1, float v2, float vH );

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

  pinMode(12, OUTPUT);
}


void loop()
{
  S=1;
  L=.5;
  Rval=0;
  Gval=0;
  Bval=0;
  for (int i = 0; i< 360; i++)
  {
    HSL(i/360.0,S,L,Rval,Gval,Bval);

    //common anode configuration
    //analogWrite(Rpin, 255-Rval);
    //analogWrite(Gpin, 255-Gval);
    //analogWrite(Bpin, 255-Bval);
    //digitalWrite(12,HIGH);

    //common cathode configuration
    analogWrite(Rpin, Rval);
    analogWrite(Gpin, Gval);
    analogWrite(Bpin, Bval);
    digitalWrite(12,LOW);

    //print statements for debug
    Serial.print("position:");
    Serial.print(H);
    Serial.print(" R:");
    Serial.print(Rval);
    Serial.print(" G:");
    Serial.print(Gval);
    Serial.print(" B:");
    Serial.println(Bval);
    delay(100);
  }
}

void HSL(float H, float S, float L, float& Rval, float& Gval, float& Bval)
{
  float var_1;
  float var_2;
  float Hu=H+.33;
  float Hd=H-.33;
  if ( S == 0 )                       //HSL from 0 to 1
  {
    Rval = L * 255;                      //RGB results from 0 to 255
    Gval = L * 255;
    Bval = L * 255;
  }
  else
  {
    if ( L < 0.5 )
      var_2 = L * ( 1 + S );
    else           
      var_2 = ( L + S ) - ( S * L );

    var_1 = 2 * L - var_2;

    Rval = round(255 * Hue_2_RGB( var_1, var_2, Hu ));
    Serial.print("Rval:");
    Serial.println(Hue_2_RGB( var_1, var_2, Hu ));
    Gval = round(255 * Hue_2_RGB( var_1, var_2, H ));
    Bval = round(255 * Hue_2_RGB( var_1, var_2, Hd ));
  }

}
float Hue_2_RGB( float v1, float v2, float vH )             //Function Hue_2_RGB
{
  if ( vH < 0 )
    vH += 1;
  if ( vH > 1 )
    vH -= 1;
  if ( ( 6 * vH ) < 1 )
    return ( v1 + ( v2 - v1 ) * 6 * vH );
  if ( ( 2 * vH ) < 1 )
    return ( v2 );
  if ( ( 3 * vH ) < 2 )
    return ( v1 + ( v2 - v1 ) * (.66-vH) * 6 );
  return ( v1 );
}
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Morris Dovey


Interesting! I just tossed this version into my "play" directory:
Code: [Select]
#define R
#define G      /* Define analog LED pins */
#define B

unsigned char r=~0,g=0,b=0;

void aw(unsigned char p,unsigned char v)
{  analogWrite(p,v);
   delay(50);
}
void setup(void)
{  analogWrite(R,r);
   analogWrite(G,g);
   analogWrite(B,b);
}
void loop(void)
{  do aw(G,++g); while (~g);
   do aw(R,--r); while ( r);
   do aw(B,++b); while (~b);
   do aw(G,--g); while ( g);
   do aw(R,++r); while (~r);
   do aw(B,--b); while ( b);
}
There's always a better way!

TiboJ

They all work fine, but how can I make a color display with the RGB value that I want, for example the color indigo : 111,0,255(red led is less bright, green led is off, blue led is at full brightness) ?
So not automatic color change.

Should I make an array like this?: Red[] = {111,0,255}
And how do I make the array display the color then?

robtillaart


Quote
Should I make an array like this?: Red[] = {111,0,255}
And how do I make the array display the color then?

Yes, define colors as separate arrays
2) define a function something like this, (not tested)

Code: [Select]

byte indigo[] = { 111,0, 255 };
byte red [] = {255, 0, 0 };

void displayColor(byte *color)
{  analogWrite(R, color[0]);
   analogWrite(G, color[1]);
   analogWrite(B, color[2]);
}

then you can call - displayColor(red);
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

TiboJ

That's what I wanted!
With a little modification, it worked.
Thank you!

Now, how can I make a smooth transition between them?

Code: [Select]
byte red [] = { 255, 0, 0 };
byte orange [] = { 255,127,0 };
byte yellow [] = { 255,255,0 };
byte green [] = { 0,255,0 };
byte blue [] = { 0,0,255 };
byte indigo[] = { 111,0,255 };
byte violet[] = { 127,0,255 };

int R = 11;
int G = 10;
int B = 9;

#define DELAY 3000

void setup(){
 
  pinMode(R, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(B, OUTPUT);
}
void loop(){
  displayColor(red);
  delay(DELAY);
  displayColor(orange);
  delay(DELAY);
  displayColor(yellow);
  delay(DELAY);
  displayColor(green);
  delay(DELAY);
  displayColor(blue);
  delay(DELAY);
  displayColor(indigo);
  delay(DELAY);
  displayColor(violet);
  delay(DELAY);
}

  void displayColor(byte *color)
{  analogWrite(R, color[0]);
   analogWrite(G, color[1]);
   analogWrite(B, color[2]);
}



robtillaart

Quote
Now, how can I make a smooth transition between them?


You need an interpolation function, not trivial as it can have many parameters depending on the way you interpolate.

linear interpolation is easiest (see code below, not tested might contain some bugs)

Code: [Select]

void interpolate( byte *col1, byte *col2, byte *out, int stepnr, int maxsteps)     
{
  for (int i =0; i<3; i++)
  {
    out[i] = col1[i] + stepnr * (col2[i] - col1[i]) / maxsteps);
  }
}

.... usage ...

for (int c=0; c<100; c++)
{
  byte newColor[3];
  interpolate(Red, Green, newColor, c, 100);
  displayColor(newColor);
}

Give it a try
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

TiboJ

Seems to be a bit to difficult for me, because I really don't know where I should place your code into my existing code :)

Should an easy fade out and fade in between each color be easier?

Morris Dovey

Every RBG color consists of a red component, a green component, and a blue component. To output a single color, all that's needed is to output its components. If you want indigo with red = 111, green = 0, and blue = 255 then all that's needed is
Code: [Select]
   analogWrite(redPin,111);
   analogWrite(greenPin,0);
   analogWrite(bluePin,255);


To produce the rainbow cycle you asked about, you'll find it helpful to take a look at a color wheel like the one I've attached below (click on the thumbnail to see full size). Notice that there are 6 (sixty degree) segments in each of which only one of the three components changes while the other two remain constant.

What that means is than if you want to smoothly transition all the way around the wheel, you can do so by setting up a sequence of six loops, each of which changes only one of the three components - as I did in my previous post.   :smiley-mr-green:
There's always a better way!

TiboJ

#23
Mar 10, 2012, 06:37 pm Last Edit: Mar 10, 2012, 06:39 pm by TiboJ Reason: 1
Thanks for the tip! XD

Is it possible to fade out and fade back in to another color between the colors in my code, instead of a delay?
So the colors does not just go out, but fade out, and then fade in to another color.

Morris Dovey

Certainly. All you need to do is choose that "another color" and choose which direction around the color wheel you want to go, then write the sequence(s) to show the intermediate values.
There's always a better way!

Morris Dovey

I might have misunderstood. If you were asking about fading the current color to dark, then gradually bringing up another color, then you might want to try something like this (untested):
Code: [Select]
void write_rgb_components(unsigned char r,unsigned char g,unsigned char b)
{  static unsigned char old_r, old_g, old_b;

   if (r != old_r) analogWrite(R,old_r = r);
   if (g != old_g) analogWrite(G,old_g = g);
   if (b != old_b) analogWrite(B,old_b = b);
   delay(50);
}

void fade_from(unsigned char r,unsigned char g,unsigned char b)
{  unsigned i;
   for (i = 255; i != 0; i--)
      write_rgb_components((i * r) >> 8,(i * g) >> 8,(i * b) >> 8);
   write_rgb_components(0,0,0);
}

void fade_to(unsigned char r,unsigned char g,unsigned char b)
{  unsigned i;
   for (i = 0; i < 256; i++)
      write_rgb_components((i * r) >> 8,(i * g) >> 8,(i * b) >> 8);
   write_rgb_components(r,g,b);
}
There's always a better way!

tiirak

Im not so good at this, but I find bitshift and other things like that hard to understand. I think that everybody is giving good advise, but its a bit over my head. Isn't it easier to make an array in the setup and then use it in the code without any calculations?

Code: [Select]

arrayPos=0;
stepSize=16

// red to magenta
for (x=0; x<255; x+stepSize){
  arrayRGB[arrayPos]=[255,0,x]
  arrayPos++;
}

// magenta to blue
for (x=255; x!=0; x-stepSize){
  arrayRGB[arrayPos]=[x,0,255]
  arrayPos++;
}

// blue to cyan
for (x=0; x<255; x+stepSize){
  arrayRGB[arrayPos]=[0,x,255]
  arrayPos++;
}

// cyan to green
for (x=255; x!=0; x--){
  arrayRGB[arrayPos]=[0,255,x]
  arrayPos++;
}


// green to yellow
for (x=0; x<255; x+stepSize){
  arrayRGB[arrayPos]=[x,255,0]
  arrayPos++;
}

// yellow to red
for (x=255; x!=0; x-stepSize){
  arrayRGB[arrayPos]=[255,x,0]
  arrayPos++;
}

Morris Dovey

@tiirak - we can't assign three values to a single (scalar) array element, but if calculating the values is sufficiently simple, then it may actually cost less to calculate values as needed than to calculate them and store/fetch them from an array.
There's always a better way!

tiirak

Sorry, Im a newbee here. Just tied to write quick and easy to understand. What about this?

Code: [Select]
// red to magenta
for (x=0; x<255; x+stepSize){
  arrayRGB[arrayPos][1]=255;
  arrayRGB[arrayPos][2]=0;
  arrayRGB[arrayPos][3]=x;
  arrayPos++;
}


And isn't it better to take memory (if possible) and not cycles?

Morris Dovey

Hmm - you just used up all available RAM to store 3-byte red values, and then your program crashed.  ]:)

It's up to you to decide if this is the best approach for your particular application. If the application were a simple learning exercise with a goal of transitioning smoothly from one displayed color to another, I would not be much inclined to worry about resources - but rather with my understanding of the interface between the standard hardware, my code, and techniques for producing color.
There's always a better way!

Go Up