jandelgado / jled

Non-blocking LED controlling library for Arduino and friends.
MIT License
331 stars 55 forks source link

jled to control RGB? #108

Closed RossAWaddell closed 1 year ago

RossAWaddell commented 1 year ago

I'd like to use jled to control a 5mm RGB LED (common anode or cathode) due to the superior fading algorithm. What I'd like to do is:

  1. Fade up to a set colour (cadmium orange [rgb(255, 97, 3)])
  2. After a set period of 5sec, cross fade to another set colour (royal blue [rgb(65, 105, 225)])

Is that possible with the library as it involves 3 PWM pins in coordination when cross fading?

jandelgado commented 1 year ago

Yes, that should be possible. The simplest approach would be to fade in RGB colorspace, with something like (untested):

// fade from (0,0,0) to (255,97,3) in 1s and wait 5s afterwards
JLed leds[]  = { 
    JLed(1).Fade(0, 255, 1000).DelayAfter(5000),
    JLed(2).Fade(0, 97, 1000).DelayAfter(5000),
    JLed(3).Fade(0, 3, 1000).DelayAfter(5000)
};
auto rgbLED = JLedSequence(JLedSequence::eMode::PARALLEL, leds);

void loop() {
    static auto stage = 0;
    if (!rgbLED.Update() && stage == 0) {  
       // fade to (65,105,255) after first configuration is reached
       leds[0].Fade(255, 65, 1000);
       leds[1].Fade(97, 105, 1000);
       leds[2].Fade(3, 255, 1000);
       rgbLED.Reset();
       stage++;
   }
}

The fade method is pretty new, make sure to update JLed.

However I'm not sure if this looks as expected (i.e. fade from off/black to initial color) and if its not better to do color calculations in HSV or HSL space.

The Problem sounds interesting, I will do some research in the next days.

RossAWaddell commented 1 year ago

The challenge with a smooth RGB cross fade is the steps from one colour value to another to time it so each of the three LEDs reach their end value at (roughly) the same time. The code above looks a bit abrupt to me:

#include <jled.h>         // https://github.com/jandelgado/jled

// fade from (0,0,0) to (255,97,3) in 1s and wait 5s afterwards
JLed leds[]  = { 
    JLed(9).Fade(0, 255, 1000).DelayAfter(5000),
    JLed(10).Fade(0, 97, 1000).DelayAfter(5000),
    JLed(11).Fade(0, 3, 1000).DelayAfter(5000)
};
auto rgbLED = JLedSequence(JLedSequence::eMode::PARALLEL, leds);

void setup()
{

}

void loop() {
    static auto stage = 0;
    if (!rgbLED.Update() && stage == 0) {  
       // fade to (65,105,255) after first configuration is reached
       leds[0].Fade(255, 65, 1000);
       leds[1].Fade(97, 105, 1000);
       leds[2].Fade(3, 255, 1000);
       rgbLED.Reset();
       stage++;
   }
}

https://youtu.be/EJsRLk3jrzg

I found this description of cross fading and the Arduino code looks good, but it uses blocking calls (DELAY) which is no good for my purposes as the final sketch will need to control other LEDs separate from this RGB:

* 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.
*/

I'm not sure your library can do this without a big feature change.

RossAWaddell commented 1 year ago

I worked up a non-blocking cross-fade but it's not as smooth a fade as your library. Still gotta try out your code.

https://pastebin.com/5xCMrNeA

RossAWaddell commented 1 year ago

Actually, your code looks pretty good. I added a DelayBefore() to each pin as ultimately there will be other things that need to occur before this sequence.

#include <jled.h>         // https://github.com/jandelgado/jled

// fade from (0,0,0) to (255,97,3) in 1s and wait 5s afterwards
JLed leds[]  = { 
    JLed(9).Fade(255-0, 255-255, 3000).DelayBefore(2000).DelayAfter(4000),
    JLed(10).Fade(255-0, 255-97, 3000).DelayBefore(2000).DelayAfter(4000),
    JLed(11).Fade(255-0, 255-3, 3000).DelayBefore(2000).DelayAfter(4000)
};
auto rgbLED = JLedSequence(JLedSequence::eMode::PARALLEL, leds);

void setup() {

}

void loop() {

    static auto stage = 0;

    if (!rgbLED.Update() && stage == 0) {  
       // fade to (65,105,255) after first configuration is reached
       leds[0].Fade(255-255, 255-65, 1000);
       leds[1].Fade(255-97, 255-105, 1000);
       leds[2].Fade(255-3, 255-255, 1000);
       rgbLED.Reset();
       stage++;
   }

}

https://flic.kr/p/2oaPDCa

I still need to think about overall brightness - not sure if MaxBrightness() will work when there are 3 separate LED elements all at different PWMs.

jandelgado commented 1 year ago

Sounds great. In parallel I'm working on an example using a HAL for RGB LED's, but I'll need some time. Will keep you updated.

Welsyntoffie commented 1 year ago

This is my usage of crossfade and usage of this library https://github.com/Welsyntoffie/csgo-gsi-python-to-arduino/tree/develop/arduino/CSGO_lighting_controller

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 5 days