Hack of the day: LED HSV wheel

I recently worked on an art project called Perceptron, an interactive dance floor (it’s cool, check it out).  The kind folks at Langton Labs hosted our build process for a while, and it was there that I met the lamp of my dreams.

It was a sphere made out of pipette covers, which are a nice milky, translucent plastic, and diffuse light wonderfully.  In the center was an array of RGB LEDs, which would cycle through colors.  There were these gorgeous blues and reds in there that you just don’t see very often: they’re probably beyond what LCD technologies can produce, so it’s a redder red and a bluer blue than you’re used to seeing.

Tonight, while killing time waiting for something, I swung by my neighborhood Radio Shack and picked up an RGB LED.  When I got home, I plugged it into my arduino and got to hacking.  I now have a one-LED version of that lamp, which makes me really happy.  It’s a gorgeous thing to behold, and involves a fun little bit of code and math.  So, of course, I’m going to share it with you.

Color-wheel arduino video

To get the color transitions to be smooth, you can’t just ramp through levels of red, green, and blue: it winds up being a bunch of peaks and valleys.  Instead, you really want to go around the HSV color wheel, changing the hue as you go.  It generates a really smooth transition, which is most pleasant.  Unfortunately, due to how crappily I’m driving the LED, it’s not as smooth as it could be: the arduino has only so much resolution in how finely it can control the level of these LEDs.  This makes for a few little jerky transitions in the blue to red return.

Here’s the code, in full:

// This assumes you're using a RadioShack #276-0028 RGB LED
// 2011-05-12: Note!  The anode is the really long pin.
// You'll need to bend it to get it into Digital8.
//
//          ||  ||  ||  ||
//          ||  ||  ||  ||
//          ||  ||  ||  ||
//          G   B   ||  ||
//                  ||  R
//                   A
//         D11 D10 D08 D09 

int common_anode = 8;
int red_pin = 9;
int blue_pin = 10;
int green_pin = 11;

int red_min = 150;
int red_max = 255;

int blue_min = 185;
int blue_max = 255;

int green_min = 195;
int green_max = 255;

void hsv_to_rgb(float h, float s, float v, unsigned char *rc, unsigned char *gc, unsigned char *bc) {
int h_i = ((int)(h/60)) % 6;

float f = (h/60) - (int)(h/60);

float r,g,b;

float p = v * (1.0 - s);
float q = v * (1.0 - f*s);
float t = (1.0 - (1.0 - f)*s);

switch(h_i) {
case 0:  r = v; g = t; b = p; break;
case 1:  r = q; g = v; b = p; break;
case 2:  r = p; g = v; b = t; break;
case 3:  r = p; g = q; b = v; break;
case 4:  r = t; g = p; b = v; break;
case 5:  r = v; g = p; b = q; break;
}

*rc = red_max - (char)((red_max - red_min)*r);
*gc = green_max - (char)((green_max - green_min)*g);
*bc = blue_max - (char)((blue_max - blue_min)*b);
}

void setup() {
pinMode(common_anode, OUTPUT);
digitalWrite(common_anode, HIGH);

pinMode(red_pin, OUTPUT);
digitalWrite(red_pin, HIGH);

pinMode(green_pin, OUTPUT);
digitalWrite(green_pin, HIGH);

pinMode(blue_pin, OUTPUT);
digitalWrite(blue_pin, HIGH);

Serial.begin(9600);
}

float h = 0.0;
float s = 1.0;
float v = 0.8;

void loop() {

unsigned char r,g,b;

h += 1;
if (h > 360.0)  h -= 360.0;

hsv_to_rgb(h,s,v, &r,&g,&b);
analogWrite(red_pin, r);
analogWrite(green_pin, g);
analogWrite(blue_pin, b);

delay(100);
}

Tags: ,

7 Responses to Hack of the day: LED HSV wheel

  1. Joel Jordan says:

    One of my friends from UIUC milled people’s names into small rectangles of PMMA, then lit them from below with RGB LEDs cycling through hues, driven by a PIC microcontroller with pretty simple firmware. This is pretty easy to duplicate with a laser cutter, and maybe even doable with an Arduino if you can do ~200 Hz PWM with it.

  2. Matt says:

    Newb question here but, I have the same RGB LED from Radio Shack and two of the prongs are longer than the others. Placing it into pins 8-11 results in Green not showing up while cycling through the color wheel. If I adjust the placement of the prongs I can sometimes get green to show up, but not if the pins are placed in firmly. I’m sure the length of the pins is something that was thought out, but I don’t understand the reasoning here.

    More info on this: Two of the pins are equal height, which are placed in pins 8 and 9, the longest is in pin 10 and the second-longest is in pin 11. I assumed the common-anode being the round edge of the LED, was supposed to go into pin 8. What am I doing wrong here? Thanks for your help!

  3. Matt says:

    Oops I figured it out. Got the spec sheet on RadioShack.com and figured out how this all works. In any event, I should have mentioned first off that I really appreciate this code! Off to map values from TouchOSC to this :-)

    • Robert Merritt says:

      I’m lost at the same spot but can’t figure out what you did. what am I doing wrong. And btw/ big thanks for the code!

      • jbm says:

        EDIT: Don’t listen to me. I was cleverer than I remember. Pin 8 doesn’t support PWM on the Arduino, so it has to be the anode.

        The common anode is the longest pin, one of the ones in the middle. The code assumes you’ve bent it such that it goes into the next slot over (Totally obvious, right? Sigh. Sorry about that.) Try replacing the lines at the top of the file with this version:

        // That should fix it.

  4. Cody says:

    Hey, thanks very much for this code. I bought one of these LEDs today and you saved me the trouble of figuring out the code on my own (though it seems kind of fun, but messy).

    But I thought I should mention, the modified code didn’t seem to work, I’m guessing that only pins 9, 10 & 11 are PWM, since that’s what the label on the board says. (So that was a good reason to bend the anode around into 8.)

    (Upon further investigation I see this is specific to my older ATmega8 board.)

    Also, I’m kind of worried about LEDs burning out–the package said 2.6V max on the red, 4V max for the blue and green, and it looks like PWM full on is 5V?

    • jbm says:

      No, actually, 8 still isn’t PWM on the newer boards. I’ll have to change the code back, oi. Apparently I was more clever a few years ago. Thanks for actually testing this, which I clearly didn’t actually do (I’ve lost track of my Radio Shack LED, have a bunch of Chinese ones now…).

      The voltages there aren’t maximums, but are just how much voltage it takes to light the LED. You definitely don’t want to run the LED like this forever, but it shouldn’t be a problem for a quick demo. To do this more correctly, you need resistors on each color’s input, to limit their currents. These resistors are dropping the rest of the voltage, which determines the current flowing through the color, which determines the brightness. I can find (or write) a better explanation if you’re really interested.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>