Partly trying to have something fun to demo and get juices flowing for the kids in the new STEM Explorer Post 314 we’re trying to start up, I thought I’d try to make a smoothly randomly color changing RGB LED while they were experiencing the joys of their first ‘hello world’ blinking LEDs. We’re bringing them up on Parallax BOE Bots (courtesy of the electronics lab at TCD) which run on Basic Stamp 2s, so it seemed appropriate to drive my LED with the same controller. PWM in Pbasic 2.5 is a little cruder than on Arduino, but should be sufficient.
There’s an RGB LED kicking around in my Arduino box I’d made up a while ago with resistors and breadboard-friendly leads waiting for a chance to play, so that was the obvious target hardware. I’d drilled out a roundish translucent white button and hot melted the 5mm LED in it for a nice diffuser. I think I’d chosen the resistors trying for sort of equal brightness for each of the LEDs, though apparently I didn’t do a great job: blue is noticeably dimmer than the others. I had to read the cryptic connection note I’d attached a few times before it made sense.
Another requirement was that it should stay about the same overall brightness all the time. OK – how to compute the 3 brightness values? How about 3 random numbers (let’s normalize to 0-1 for each)? No, with some of each color every time, I’d never hit pure R, G, or B, and my vision certainly included those colors. How about dividing each by 3? No, still no pure colors. And overall brightness changes, too. Hmm – harder than I’d expected. I didn’t get it to do anything but blink on the BS2’s that first night.
OK, how about a ‘color wheel’ approach? R,G, B at 0º, 120º, 240º and pick a random ‘hue’ number 0-359? The pure colors are certainly possible that way. I could apportion brightness between the two colors bounding the random value chosen. But that doesn’t nearly cover all the possibilities: if I chose say 60º, half way between R and G, there would be no B at all. So what are all those excluded colors? If I have half R half G and start to add some B (adjusting R, G values down to keep constant brightness), it gets closer to white. So the simple color wheel gives me only fully saturated colors. Those are certainly pretty, and maybe a good simple starting point. If I miss the more pastel shades I could add another random variable that controls how much of the missing primary is included.
It slowly dawned on me that while my (hardware-based) blinders kept me thinking RGB, what I’ve described is essentially the HSL color space. It’s always amusing to discover that you’ve reinvented some standard thing 🙂 .
That approach should work pretty well. I get nice saturated colors (all of them, not just pure R, G, B), and I can skew the distribution of saturation values to favor high saturation, while still hitting white occasionally. And if I miss having brightness variations, I could scale each R,G,B value with an additional single random brightness multiplier. If implemented, the distribution of brightness values would certainly be skewed toward high brightness.
A quick try on an Arduino (since I don’t have a BS2) using analogWrite() PWM scaled 0-255 was a bad fail. Took a while before the face-palm moment when I remembered it was a common anode LED, so bright was 0, not 255. It got much better when I added a couple of “255 -“s in appropriate places. But that was when I noticed how much dimmer B was than the other colors. Fine – I’ll #define a max brightness for each, with B 255 and the others suitably derated. Oops – yeah, it’s maximum brightness, but minimum PWM value. I’m not an OO kind of guy, but it started to look like a really good idea to encapsulate all this brightness-value-inversion-with-per-color-scaling crap in a custom set-brightness function for each color, with a nice normalized 0-1 input value. That abstraction would allow for swapping in a common-cathode LED, as well as allowing me to concentrate on the aesthetic side of how to skew the saturation and brightness values to make it look ‘just right’. Whatever that means.
More when I actually have some working code instead of just hot air.