RGB LED issues

Am working on my first project using the Arduino (or anything related), and have been running into a couple problems with the programming. But here is a quick description of what I'd like to do:

Want to have 4 RGB LEDs hooked up to a pot, where the pot determines the speed at which the LEDs cycle through pre-set colours.

Basically, am having trouble figuring out how to programme the LEDs to cylce through the colours I've set at random. I've been trying to piece together bits of code from here and there I think will work, not sure if you need it all but here it is so far (haven't started with the input stuff yet):

int potpin = 2;
// Output
int redPin = 9; // Red LED, connected to digital pin 9
int grnPin = 10; // Green LED, connected to digital pin 10
int bluPin = 11; // Blue LED, connected to digital pin 11

// Color arrays
int darkGrey[3] = {
18, 31, 31 };
int midnightBlue[3] = {
10, 10, 44 };
int darkBlue[3] = {
28, 24, 55 };
int steelBlue[3] = {
27, 51, 71 };
int cadBlue[3] = {
37, 62, 63 };
int darkOlive[3] = {
33, 42, 18 };
int seaGreen[3] = {
18, 55, 34 };
int aqua[3] = {
27, 55, 46 };
int chart[3] = {
27, 55, 0 };
int golden[3] = {
86, 65, 13 };
int peru[3] = {
80, 52, 25 };
int darkOrange[3] = {
100, 55, 0 };
int choc[3] = {
100, 50, 14 };
int indianRed[3] = {
80, 36, 36 };
int fire[3] = {
70, 13, 13 };
int sadBrwn[3] = {
55, 27, 8 };
int darkORed[3] = {
55, 15, 0 };
int rosyBrwn[3] = {
73, 56, 56 };
int orchid[3] = {
55, 28, 54 };
int medGrey[3] = {
37, 28, 55 };
int thistle[3] = {
80, 71, 80 };
int dimWhite[3] = {
30, 30, 30 };
// etc.

// Set initial color
int redVal = dimWhite[0];
int grnVal = dimWhite[1];
int bluVal = dimWhite[2];

int wait = 10; // 10ms internal crossFade delay; increase for slower fades
int hold = 10; // Optional hold when a color is complete, before the next crossFade
int DEBUG = 1; // DEBUG counter; if set to 1, will write values back via serial
int loopCount = 60; // How often should DEBUG report?
int repeat = 0; // How many times should we loop before stopping? (0 for no stop)
int j = 0; // Loop counter for repeat

// Initialize color variables
int prevR = redVal;
int prevG = grnVal;
int prevB = bluVal;

// Set up the LED outputs
void setup()
{
pinMode(redPin, OUTPUT); // sets the pins as output
pinMode(grnPin, OUTPUT);
pinMode(bluPin, OUTPUT);

if (DEBUG) { // If we want to see values for debugging...
Serial.begin(9600); // ...set up the serial ouput
}
}

// Main program: list the order of crossfades
void loop()
{
crossFade(red);
crossFade(green);
crossFade(blue);
crossFade(yellow);

if (repeat) { // Do we loop a finite number of times?
j += 1;
if (j >= repeat) { // Are we there yet?
exit(j); // If so, stop.
}
}
}

int calculateStep(int prevValue, int endValue) {
int step = endValue - prevValue; // What's the overall gap?
if (step) { // If its non-zero,
step = 1020/step; // divide by 1020
}
return step;
}

int calculateVal(int step, int val, int i) {

if ((step) && i % step == 0) { // If step is non-zero and its time to change a value,
if (step > 0) { // increment the value if step is positive...
val += 1;
}
else if (step < 0) { // ...or decrement it if step is negative
val -= 1;
}
}
// Defensive driving: make sure val stays in the range 0-255
if (val > 255) {
val = 255;
}
else if (val < 0) {
val = 0;
}
return val;
}

void crossFade(int color[3]) {
// Convert to 0-255
int R = (color[0] * 255) / 100;
int G = (color[1] * 255) / 100;
int B = (color[2] * 255) / 100;

int stepR = calculateStep(prevR, R);
int stepG = calculateStep(prevG, G);
int stepB = calculateStep(prevB, B);

for (int i = 0; i <= 1020; i++) {
redVal = calculateVal(stepR, redVal, i);
grnVal = calculateVal(stepG, grnVal, i);
bluVal = calculateVal(stepB, bluVal, i);

analogWrite(redPin, redVal); // Write current values to LED pins
analogWrite(grnPin, grnVal);
analogWrite(bluPin, bluVal);

delay(wait); // Pause for 'wait' milliseconds before resuming the loop

if (DEBUG) { // If we want serial output, print it at the
if (i == 0 or i % loopCount == 0) { // beginning, and every loopCount times
Serial.print("Loop/RGB: #");
Serial.print(i);
Serial.print(" | ");
Serial.print(redVal);
Serial.print(" / ");
Serial.print(grnVal);
Serial.print(" / ");
Serial.println(bluVal);
}
DEBUG += 1;
}
}
// Update current values for next loop
prevR = redVal;
prevG = grnVal;
prevB = bluVal;
delay(hold); // Pause for optional 'wait' milliseconds before resuming the loop
}

Thanks in advance!

Update:

Could it be an array issue? Was suggested that I create a multidimensional array where one value could act as a index, so the colours now look like:

int darkGrey[20][3] = {
{18, 31, 31},{18, 31, 31}
};
int midnightBlue[19][3] = {
{10, 10, 44},{10, 10, 44}
};
int darkBlue[18][3] = {
{28, 24, 55},{28, 24, 55}
};
int steelBlue[17][3] = {
{27, 51, 71},{27, 51, 71}
};

but I'm still very confused about the syntax...

If you just want to cycle through all colors, not fade from one specific to anoter specific color try to see this code:

http://todbot.com/arduino/sketches/RGBMoodLight/

It is muc smaller and simpler than yours.

All you need to add is a delay that can be controlled with your pot, but that should be a piece of cake

int steelBlue[17][3] = {
{27, 51, 71},{27, 51, 71}
};

but I'm still very confused about the syntax...

What you have defined here is a two dimensional int array called steelBlue having 17 rows and three columns.

You need to define your array as:-
int colour[20][3] = { 1,2,3,4,5 ............}
Using this you loose the name of the colour.
You can restore this link by defining colours to numbers with :-
#define steelBlue 17
#define R 0

then you would use it like
analogWrite(redPin,colour[steelBlue][R] );
or replace the steelBlue with an index

Your array of 3 colors seems fine to me... your mod is not fine.

It would be nice if you explained what's going wrong!

But here is something:

int calculateStep(int prevValue, int endValue) {
int step = endValue - prevValue; // What's the overall gap?
if (step) { // If its non-zero,
step = 1020/step; // divide by 1020
}
return step;
}

By doing an integral division step will be rounded down and the result is you will not get to your color.
To get there either convert it all to float so the fractions are not lost (or at least less is lost). Or to do it perfectly, and very quickly in integers use the fundamental insight in Bresenham's line drawing algorithm (google it).

Basically, for just one color:

  1. Start a counter.
  2. for each iteration, add (end-start) to the counter.
  3. If the counter goes below 0 or above 1020 (i.e. the # steps), ADD or SUBTRACT 1020 respectively, and tick your color down/up by 1.

Why it works:
Adding end-start to a counter and then comparing it to 1020 is just like doing (i % step ==0)
Except that when you hit the condition, the remainder is preserved since you add/subtract.
This remainder is a cumulative error that will eventually advance your color just a little sooner than if it did not exist.

Think of it as division deconstructed :-). Way back in 2nd grade when you learned what division really WAS this is what they did.

This is an extremely powerful algorithm for embedded programming where floating point is too expensive; its generally applicable any time you want to move X times in Y steps.

Ok, so I have that division bit in there, driving the crossFade function.

It goes fine but seems to stop after the third fade, why I have no idea.
I messed around with the value to divide by (i.e. 550 instead of 1020 to see if that changed the speed of fading), but do you know of a better way?

What it looks like now:

// Output
int redPin = 9; // Red LED, connected to digital pin 9
int red2Pin = 3;
int grnPin = 5; // Green LED, connected to digital pin 10
int grn2Pin = 10;
int bluPin = 6; // Blue LED, connected to digital pin 11
int blu2Pin = 11;

// Color arrays
int darkGrey[]={18, 31, 31};
int midnightBlue[]={10, 10, 44};
int darkBlue[]={28, 24, 55};
int steelBlue[]={27, 51, 71};
int cadBlue[]={37, 62, 63};
int darkOlive[]={33, 42, 18};
int seaGreen[]={18, 55, 34};
int aqua[]={27, 55, 46};
int chart[]={27, 55, 0};
int golden[]={86, 65, 13};
int peru[]={80, 52, 25};
int darkOrange[]={100, 55, 0};
int choc[]={100, 50, 14};
int indianRed[]={80, 36, 36};
int fire[]={70, 13, 13};
int sadBrwn[]={55, 27, 8};
int darkORed[]={55, 15, 0};
int rosyBrwn[]={73, 56, 56};
int orchid[]={55, 28, 54};
int medGrey[]={37, 28, 55};
int thistle[]={80, 71, 80};
int dimWhite[]={30, 30, 30};
int black[]={0, 0, 0};
// etc.

// Set initial color
int redVal = black[0];
int grnVal = black[1];
int bluVal = black[2];

int wait = 0; // 10ms internal crossFade delay; increase for slower fades
int hold = 0; // Optional hold when a color is complete, before the next crossFade
int repeat = 0; // How many times should we loop before stopping? (0 for no stop)
int j = 0; // Loop counter for repeat

// Initialize color variables
int prevR = redVal;
int prevG = grnVal;
int prevB = bluVal;

// Set up the LED outputs
void setup()
{for (int i=0; i<6;i ++){
pinMode(redPin, OUTPUT); // sets the pins as output
pinMode(red2Pin, OUTPUT);
pinMode(grnPin, OUTPUT);
pinMode(grn2Pin, OUTPUT);
pinMode(blu2Pin, OUTPUT);
pinMode(bluPin, OUTPUT);

// if (DEBUG) { // If we want to see values for debugging...
// Serial.begin(9600); // ...set up the serial ouput
}
}

// Main program: list the order of crossfades
void loop() {
crossFade(darkOrange);
crossFade(darkGrey);
crossFade(thistle);
crossFade(indianRed);
crossFade(midnightBlue);
crossFade(medGrey);
crossFade(peru);
crossFade(choc);
crossFade(darkBlue);
crossFade(golden);
crossFade(orchid);
crossFade(steelBlue);
crossFade(rosyBrwn);
crossFade(cadBlue);
crossFade(darkORed);
crossFade(darkOlive);
crossFade(sadBrwn);
crossFade(seaGreen);
crossFade(fire);
crossFade(aqua);
crossFade(chart);

//if (repeat) { // Do we loop a finite number of times?
// j += 1;
// if (j >= repeat) { // Are we there yet?
// exit(j); // If so, stop.
// }
//}
}

/* BELOW THIS LINE IS THE MATH -- YOU SHOULDN'T NEED TO CHANGE THIS FOR THE BASICS
*

  • The program works like this:
  • Imagine a crossfade that moves the red LED from 0-10,
  • the green from 0-5, and the blue from 10 to 7, in
  • ten steps.
  • We'd want to count the 10 steps and increase or
  • decrease color values in evenly stepped increments.
  • Imagine a + indicates raising a value by 1, and a -
  • equals lowering it. Our 10 step fade would look like:
  • 1 2 3 4 5 6 7 8 9 10
  • R + + + + + + + + + +
  • G + + + + +
  • B - - -
  • The red rises from 0 to 10 in ten steps, the green from
  • 0-5 in 5 steps, and the blue falls from 10 to 7 in three steps.
  • In the real program, the color percentages are converted to
  • 0-255 values, and there are 1020 steps (255*4).
  • To figure out how big a step there should be between one up- or
  • down-tick of one of the LED values, we call calculateStep(),
  • which calculates the absolute gap between the start and end values,
  • and then divides that gap by 1020 to determine the size of the step
  • between adjustments in the value.
    */

int calculateStep(int prevValue, int endValue) {
int step = endValue - prevValue; // What's the overall gap?
if (step) { // If its non-zero,
step = 550/step; // divide by 1020
}
return step;
}

/* The next function is calculateVal. When the loop value, i,

  • reaches the step size appropriate for one of the
  • colors, it increases or decreases the value of that color by 1.
  • (R, G, and B are each calculated separately.)
    */

int calculateVal(int step, int val, int i) {

if ((step) && i % step == 0) { // If step is non-zero and its time to change a value,
if (step > 0) { // increment the value if step is positive...
val += 1;
}
else if (step < 0) { // ...or decrement it if step is negative
val -= 1;
}
}
// Defensive driving: make sure val stays in the range 0-255
if (val > 255) {
val = 255;
}
else if (val < 0) {
val = 0;
}
return val;
}

/* crossFade() converts the percentage colors to a

  • 0-255 range, then loops 1020 times, checking to see if
  • the value needs to be updated each time, then writing
  • the color values to the correct pins.
    */

void crossFade(int color[3]) {
// Convert to 0-255
int R = (color[0] * 255) / 100;
int G = (color[1] * 255) / 100;
int B = (color[2] * 255) / 100;

int stepR = calculateStep(prevR, R);
int stepG = calculateStep(prevG, G);
int stepB = calculateStep(prevB, B);

for (int i = 0; i <= 550; i++) {
redVal = calculateVal(stepR, redVal, i);
grnVal = calculateVal(stepG, grnVal, i);
bluVal = calculateVal(stepB, bluVal, i);

analogWrite(redPin, redVal); // Write current values to LED pins
analogWrite(grnPin, grnVal);
analogWrite(bluPin, bluVal);
analogWrite(grn2Pin, grnVal);
analogWrite(red2Pin, redVal);
analogWrite(blu2Pin, bluVal);

delay(10); // Pause for 'wait' milliseconds before resuming the loop

}
}

My scrolling finger hurts.

My scrolling finger hurts.

mine too...

PrevR G B are not being set to the current color in this new one... but I'm not sure why that would cause the fade to stop. Can you blink pin 13 LED in crossfade, and have it go solid between crossfades() to determine whether the sketch freezes or if it keeps going but is just not having an effect on the RGB led?