0

I'm looking into how to smoothly crossfade between colors on an RGB LED with the Arduino and I've found this piece of code for doing it: https://www.arduino.cc/en/Tutorial/ColorCrossfader

I understand all parts of the code except for one thing. The values for red, green and blue are changed incrementally through 1020 steps, because 255*4 = 1020. But WHY 4? There are 3 colors, and 255 * 3 = 765. So why not 765 steps?

3
  • 255 ^ 3 would be nearer the mark, and that's a lot more than 765. Or 1020...
    – Brian Drummond
    Dec 31, 2015 at 11:53
  • @Brian, that would be the number of steps to go through every possible colour combination. That wasn't the program intent. (Paraphrasing:) You define a series of RGB colours - #CC0000, #30DD00, etc. - and get the system to smoothly transition between them. The 1020 steps is intended to give quarter bit resolution on the step interval. Details in my answer.
    – Transistor
    Jan 1, 2016 at 21:51
  • I'm looking a non=blocking cross fader because while it is cycling through the colours slowly the processor is still able to receive serial communications. So far the non-blocking ones are not smooth enough. Feb 22, 2018 at 10:46

2 Answers 2

2

Extract from code:

int wait = 10;      // 10ms internal crossFade delay; increase for slower fades

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
    } 
    DEBUG += 1;
  }
}

The 1020 in the loop determines the time taken to make the crossfade from the current colour to the next - not the total cycle as you seem to think. In the main loop we have

crossFade(red);
crossFade(green);
crossFade(blue);
crossFade(yellow);

And each of these crossfades will take 1024 * wait ms to complete. 'wait' is set to 10 ms so I would expect it to take 10.24 s to complete a fade from one colour to the next.

[Edit]

I think the large number (1020) is just to give a fine resolution in the steps calculation which is all done with integers. (What struck me as odd is that it doesn't use 256 * 4 = 1024.) The larger we make this number the finer the step resolution becomes. With coarse steps the ramp will complete too early.

Let's say we had 255 steps and we wish to go from 134 to 0.

step = 255 / (endValue - prevValue)
step = 255 / (134 - 0 ) = 1.9 which will be rounded down to 1.

This means that the crossfade will be complete in 134 steps instead of 255. i.e., it will finish 47% early.

If we use 1020 steps and we wish to go from 134 to 0.

step = 1020 / (endValue - prevValue)
step = 1020 / (134 - 0 ) = 7.6 which will be rounded down to 7.

This means that the crossfade will be complete in 938 steps instead of 1020. i.e., it will finish 8% early.

7
  • But why is this written in the comments? There seems to be some meaning behind it: * In the real program, the color percentages are converted to * 0-255 values, and there are 1020 steps (255*4).
    – Harald
    Dec 31, 2015 at 12:00
  • See the update.
    – Transistor
    Dec 31, 2015 at 13:12
  • The 1020 is indeed a granularity mistake. First he/she/they/them/it/x say(s) 0 to 255, to then conclude that's 255 levels. Undermines my trust in the efficiency of the remaining maths to be honest, as the total average effective fade error will be lower with the correct 1024 steps for quarter-bit granularity in integer maths. Though the better way is fixed point or integer-remainder maths of course, but "them" often finds that scary?
    – Asmyldof
    Dec 31, 2015 at 13:29
  • I'd say it's fine for the application. I don't know that we'd notice the steps given that they're 1/255 of the full brightness. The Arduino code is intended for a learning audience and in this instance I think simplicity and readability wins over accuracy.
    – Transistor
    Dec 31, 2015 at 13:48
  • "What struck me as odd is that it doesn't use 256 * 4 = 1024" Hee hee. This is classically known as a fence-post error. When you start at (let's say) a value of 00, it only takes 255 steps to get to the maximum value of 256. Dec 31, 2015 at 19:54
0

For my transition between colors I used arrays during the setup to collect the main transitions (bigger jumps between RGB values) then during the loop I used a series of analogWrite() commands essentially splitting the jumps by a 16th, for example starting at 255, 0, 0 the next array value was 223, 0, 0 in the loop it went from 255, 0, 0 to 253, 0, 0 to 251, 0, 0 finally landing the last loop value of 225, 0, 0 before starting the loop over at the next array value of 223, 0, 0. It's important to realize what colors transition into others and what the corresponding RGB values are of that transition.

Tomorrow I'll post my code, it's a bit messy as it was more proof of concept that starting with a distinct plan.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.