RGB LED easy smooth colour transitions


this yet contribution extensive literature surrounds rgb leds , changing colours, in research have not seen method have implemented, here in case can use it.

i wanted build mood lamp type of device, using single rgb led placed in ping pong ball diffuser. needed find algorithm allow me fit code , data in 2k using attiny 2313 chip, prototyped on arduino uno. of code found used random() function, ending on 3k when compiled, due libraries, , many of other methods uncovered did not me.

the rgb colour space can visualised cube (x, y, z) coordinates range (0, 0, 0) or black, (255, 255, 255) or white. more cube defined in 3d space (0,0,0) (1,1,1), scaled 255. vertices of cube define boundaries of colour space, , moving along 3d coordinates 1 point next naturally provide smooth colour transitions.

the algorithm have implemented exploits , traces rgb coordinates 1 corner another, 'plotting' coordinates of line rgb led, displays different colours. in code below path of transitions defined series of vertex numbers each move, can equally implemened selecting next vertex randomly. defining path can allow bias particular area of colour cube (eg, cooler or warmer colours), , path can longer in code below little penalty in memory use.

code: [select]
/*
rgb led - automatic smooth color cycling

marco colli
april 2012

uses properties of rgb colour cube
rgb colour space can viewed cube of colour. if assume cube of dimension 1,
coordinates of vertices cubve range (0,0,0) (1,1,1) (all black white).
transitions between each vertex smooth colour flow , can exploit using
path coordinates led transition effect.
*/
// output pins pwm
#define  r_pin  3  // red led
#define  g_pin  5  // green led
#define  b_pin  6  // blue led

// constants readability better magic numbers
// used adjust limits led, if has lower on threshold
#define  min_rgb_value  10   // no smaller 0.
#define  max_rgb_value  255  // no bigger 255.

// slowing things down need ...
#define  transition_delay  70   // in milliseconds, between individual light changes
#define  wait_delay        500  // in milliseconds, @ end of each traverse
//
// total traversal time ((max_rgb_value - min_rgb_value) * transition_delay) + wait_delay
// eg, ((255-0)*70)+500 = 18350ms = 18.35s

// structure contain 3d coordinate
typedef struct
{
  byte  x, y, z;
} coord;

static coord  v; // current rgb coordinates (colour) being displayed

/*
vertices of cube
     
    c+----------+g
    /|        / |
  b+---------+f |
   | |       |  |    y   
   |d+-------|--+h   ^  7 z
   |/        | /     | /
  a+---------+e      +--->x

*/
const coord vertex[] =
{
//x  y  z      name
  {0, 0, 0}, // or 0
  {0, 1, 0}, // b or 1
  {0, 1, 1}, // c or 2
  {0, 0, 1}, // d or 3
  {1, 0, 0}, // e or 4
  {1, 1, 0}, // f or 5
  {1, 1, 1}, // g or 6
  {1, 0, 1}  // h or 7
};

/*
list of vertex numbers encoded 2 per byte.
hex digits used vertices 0-7 fit nicely (3 bits 000-111) , have same visual
representation decimal, bytes 0x12, 0x34 ... should interpreted vertex 1
v2 v3 v4 (ie, 1 continuous path b c d e).
*/
const byte path[] =
{
  0x01, 0x23, 0x76, 0x54, 0x03, 0x21, 0x56, 0x74,  // trace edges
  0x13, 0x64, 0x16, 0x02, 0x75, 0x24, 0x35, 0x17, 0x25, 0x70,  // diagonals
};

#define  max_path_size  (sizeof(path)/sizeof(path[0]))  // size of array

void setup()
{
  pinmode(r_pin, output);   // sets pins output
  pinmode(g_pin, output); 
  pinmode(b_pin, output);
}

void traverse(int dx, int dy, int dz)
// move along colour line next vertex of cube.
// transition achieved applying 'delta' value coordinate.
// definition coordinates complete transition @ same
// time have 1 loop index.
{
  if ((dx == 0) && (dy == 0) && (dz == 0))   // no point looping if staying in same spot!
    return;
   
  (int = 0; < max_rgb_value-min_rgb_value; i++, v.x += dx, v.y += dy, v.z += dz)
  {
    // set colour in led
    analogwrite(r_pin, v.x);
    analogwrite(g_pin, v.y);
    analogwrite(b_pin, v.z);
   
    delay(transition_delay);  // wait fot transition delay
  }

  delay(wait_delay);          // give rest @ end of traverse
}

void loop()
{
  int    v1, v2=0;    // new vertex , previous one

  // initialise place start first vertex in array
  v.x = (vertex[v2].x ? max_rgb_value : min_rgb_value);
  v.y = (vertex[v2].y ? max_rgb_value : min_rgb_value);
  v.z = (vertex[v2].z ? max_rgb_value : min_rgb_value);

  // loop through path, traversing 1 point next
  (int = 0; < 2*max_path_size; i++)
  {
    // !! loop index double path index nybble index !!
    v1 = v2;
    if (i&1)  // odd number second element , ...
      v2 = path[i>>1] & 0xf;  // ... bottom nybble (index /2) or ...
    else      // ... number first element , ...
      v2 = path[i>>1] >> 4;  // ... top nybble
     
    traverse(vertex[v2].x-vertex[v1].x,
             vertex[v2].y-vertex[v1].y,
             vertex[v2].z-vertex[v1].z);
  }
}

thanks code, seems smoother "on eye"...

i noticed quirk using common anode rgb led (running code on attiny85 btw) - here there visible jumps in between colors. think update code either accept common cathode or common anode rgb leds?

thanks,
christian.


Arduino Forum > Using Arduino > LEDs and Multiplexing > RGB LED easy smooth colour transitions


arduino

Comments

Popular posts from this blog

Thread: PKI Client 5.00 install (for eToken Pro)

ATmega2560-Arduino Pin Mapping

Crossfader Arduino Tutorial