Help on random led coloring?

What I have found is that using the HSV spectrum really helps when you want to pull random colors. What you will notice from a function that gets any random color out of 16 million is that you end up with white-out colors and the result may be less than what you really want.

Also, you most likely want to control more than one LED and will want more control than just setting a random color. To that end I am working on an LED class and I have put together some randomizing functions. You can set a random color (out of the 16 M) or you can set a random hue from 0 to 255. While the normal hue spectrum is 0 to 360, I convert this to a 0 to 255 spectrum to allow the storage of a full color in one byte (not three) .. when all I care about is the color.

This allows you to control your Saturation and Brightness (Value) and when your color (Hue) changes .. it keeps the same basic brightness / look. Then when you want to keep the same color but just make it more or less bright - you can adjust the Hue and Saturation and the basic color will stay the same.

This is a full demo you can copy / paste into a new project.

Hope this helps.

//- Joseph Francis - Open Source - As Is, etc.

#ifndef RGBCommonLED_H
#define RGBCommonLED_H

#include "WProgram.h"


class RGBCommonLED { 
public:
  RGBCommonLED(int rpin, int gpin, int bpin);
  ~RGBCommonLED();

  //--- methods
  void setRGB(byte r, byte g, byte b);
  void setHSV(byte h, byte s, byte v);
  void setColor(unsigned long v);
  void setHue(byte level);
  void setSat(byte level);
  void setVal(byte level);

  void adjHue(int level);
  void adjSat(int level);
  void adjVal(int level);

  void setRandomColor();
  void setRandomHue();
  void setRandomSat();
  void setRandomVal();

  //--- easy for the chip / code
  void setHSVLevel(int section, byte level);
  void adjHSVLevel(int section, int level);
  void setRandomHSVLevel(int section);
  
  //--- Used to update the led pins (or related vars that update on scan)
  void updateLED();

  //--- Conversion routine that loads the "o"s with a value from 0 to 255 for RGVB
  void HSVToRGB( unsigned int inHue, unsigned int inSaturation, unsigned int inValue,
    unsigned int *oR, unsigned int *oG, unsigned int *oB );

  //--- Conversion routine that loads the "o"s with a value from 0 to 255 for S and V
  //    and load oH with a value from 0 to 360 .. use map(returnval,0,360,0,255) to convert
  void RGBToHSV( unsigned int inRed, unsigned int inGreen, unsigned int inBlue,
    unsigned int *oH, unsigned int *oS, unsigned int *oV );

  //--- When needed - this will update the HSV value by converting from the RGB value
  //   currently set
  void updateHSVFromRGB();

  //--- pins for this led, in order R G B
  int pins[3];
  //--- colors for this led, in order R G B
  int rgb[3];
  //--- colors in HSV format, in order H S V
  int hsv[3];

private:
  //--- used to keep from converting when we dont have to (already did - no change);
  boolean hsvSet;
  void setRGBFromHSV();
  void setHSVFromRGB();
};

#endif


//<<constructor>> 
RGBCommonLED::RGBCommonLED(int rpin, int gpin, int bpin){
  pins[0] = rpin;
  pins[1] = gpin;
  pins[2] = bpin;
  hsvSet = false;
}

//<<destructor>>
RGBCommonLED::~RGBCommonLED(){/*nothing to destruct*/
}

void RGBCommonLED::setColor(unsigned long v)
{
  this->setRGB((v & 255),((v >> 8) & 255),(v >> 16) & 255);
}


void RGBCommonLED::setRGB(byte r, byte g, byte b){
  rgb[0] = r;
  rgb[1] = g;
  rgb[2] = b;
  hsvSet = false;
}

void RGBCommonLED::setHSV(byte h, byte s, byte v){
  hsv[0] = h;
  hsv[1] = s;
  hsv[2] = v;
  this->setRGBFromHSV();
  hsvSet = true;
}


void RGBCommonLED::setHSVLevel(int section, byte level){
  updateHSVFromRGB();
  hsv[section] = level;
  this->setRGBFromHSV();
}

void RGBCommonLED::setHue(byte level){
  this->setHSVLevel(0,level);
}

void RGBCommonLED::setSat(byte level){
  this->setHSVLevel(1,level);
}

void RGBCommonLED::setVal(byte level){
  this->setHSVLevel(2,level);
}

void RGBCommonLED::adjHSVLevel(int section, int level){
  updateHSVFromRGB();
  int th = hsv[section] + level;

  if( th < 0 ){
    th = 255 + th;    
  } 
  else if( th > 255 ) {
    th = 255 - th;    
  }

  th = constrain(th,0,255); //just in case?
  hsv[section] = th;
  this->setRGBFromHSV();
}

void RGBCommonLED::adjHue(int level){
  this->adjHSVLevel(0,level);
}

void RGBCommonLED::adjSat(int level){
  this->adjHSVLevel(1,level);
}

void RGBCommonLED::adjVal(int level){
  this->adjHSVLevel(2,level);
}



void RGBCommonLED::RGBToHSV( unsigned int inRed, unsigned int inGreen, unsigned int inBlue,
unsigned int *oH, unsigned int *oS, unsigned int *oV )
{
  //struct Color_HSV HSV; //structure to return
  double vals[3]; //thue = temporary var (linked to hue)
  unsigned char maxc=0, minc=0; //red=0, green=1, blue=2
  double hue, sat, val;

  vals[0]=inRed;
  vals[1]=inGreen;
  vals[2]=inBlue;
  //red is set as maximum and minimum
  if(vals[1]>vals[maxc]) maxc=1; //if green is greater, make green the max.
  if(vals[2]>vals[maxc]) maxc=2; //if blue is greater, make blue the max
  if(vals[1]<vals[minc]) minc=1; //if green is less, make green the min.
  if(vals[2]<vals[minc]) minc=2; //if blue is less, make blue the min.
  val = vals[maxc]; //set the HSV.val to the maximum component value (this is a final value)
  if(vals[maxc]==0) //if maximum component is 0, color must be black
    sat = hue = 0; //so set values to 0 manually to avoid div by 0 errors
  else
  { //otherwise, calculate the values
    sat=255*(1-(vals[minc]/vals[maxc])); //compressed equation - original: HSV.sat=((vals[maxc]-vals[minc])/vals[maxc])*255;
    hue = 60 * ((maxc*2) + (vals[(maxc+1)%3] - vals[(maxc+2)%3])/(vals[maxc] - vals[minc])); //this cannot be simplified - and i havn't got time to explain it
  }
  if(hue < 0) hue += 360; //corrector for hues in -60 to 0 range
  *oH = hue; //map(hue,0,360,0,255);
  *oS = sat;
  *oV = val;
}

void RGBCommonLED::HSVToRGB( unsigned int inHue, unsigned int inSaturation, unsigned int inValue,
unsigned int *oR, unsigned int *oG, unsigned int *oB )
{
  if( inSaturation == 0 )
  {
    // achromatic (grey)
    *oR = *oG = *oB = inValue;
  }
  else
  {
    unsigned int scaledHue = (inHue * 6);
    unsigned int sector = scaledHue >> 8; // sector 0 to 5 around the color wheel
    unsigned int offsetInSector = scaledHue - (sector << 8);      // position within the sector
    unsigned int p = (inValue * ( 255 - inSaturation )) >> 8;
    unsigned int q = (inValue * ( 255 - ((inSaturation * offsetInSector) >> 8) )) >> 8;
    unsigned int t = (inValue * ( 255 - ((inSaturation * ( 255 - offsetInSector )) >> 8) )) >> 8;

    switch( sector ) {
    case 0:
      *oR = inValue;
      *oG = t;
      *oB = p;
      break;
    case 1:
      *oR = q;
      *oG = inValue;
      *oB = p;
      break;
    case 2:
      *oR = p;
      *oG = inValue;
      *oB = t;
      break;
    case 3:
      *oR = p;
      *oG = q;
      *oB = inValue;
      break;
    case 4:
      *oR = t;
      *oG = p;
      *oB = inValue;
      break;
    default:            // case 5:
      *oR = inValue;
      *oG = p;
      *oB = q;
      break;
    }
  }
} 

void RGBCommonLED::setRandomColor(){
  this->setColor((unsigned long)random(0x01000000));
}

void RGBCommonLED::setRandomHue(){
  this->setRandomHSVLevel(0);
}
void RGBCommonLED::setRandomSat(){
  this->setRandomHSVLevel(1);
}
void RGBCommonLED::setRandomVal(){
  this->setRandomHSVLevel(2);
}

void RGBCommonLED::setRandomHSVLevel(int section){
  this->setHSVLevel(section, (unsigned int)random(0x0100));
}


void RGBCommonLED::updateHSVFromRGB(){
  //   if (hsvSet)
  //     return;
  this->setHSVFromRGB();   
  hsvSet = true;
}


void RGBCommonLED::updateLED(){
  analogWrite(this->pins[0], rgb[0]);
  analogWrite(this->pins[1], rgb[1]);
  analogWrite(this->pins[2], rgb[2]);
}


void RGBCommonLED::setRGBFromHSV(){
  unsigned int h = hsv[0];
  unsigned int s = hsv[1];
  unsigned int v = hsv[2];
  unsigned int r = 0;
  unsigned int g = 0;
  unsigned int b = 0;
  HSVToRGB(h,s,v,&r,&g,&b);
  this->setRGB(r,g,b);
}

void RGBCommonLED::setHSVFromRGB(){
  unsigned int r = rgb[0];
  unsigned int g = rgb[1];
  unsigned int b = rgb[2];
  unsigned int h;
  unsigned int s;
  unsigned int v;

  this->RGBToHSV(r,g,b,&h,&s,&v);
  hsv[0] = map(h,0,360,0,255);
  hsv[1] = s;
  hsv[2] = v;
  hsvSet = true;
}

RGBCommonLED led1(10,11,9);

void setup()
{
  Serial.begin(9600);
  randomSeed(analogRead(0));
  testRGB();
}

void testRGB(){
  led1.setRGB(255,0,0);
  led1.updateLED();
  delay(500);
  led1.setRGB(0,255,0);
  led1.updateLED();
  delay(500);
  led1.setRGB(0,0,255);
  led1.updateLED();
  delay(2000);
  return;

}

void loop()
{  
  led1.setRandomHue();
  led1.setSat(255);
  led1.setVal(255);
  led1.updateLED();
  delay(1000);
  led1.setRandomColor();
  led1.updateLED();
  delay(1000);
  return;

}