As you can see I am new to this forum and like to introduce myself, I am a enthousiast electronics and arduino do it selfer. I like to learn and explore the possibilities of components and programming.
What I would like to achieve is a number of breathing leds that have individual random smooth fade IN/OUT cycles.
1 - assign random values for fade sequence
2 - as fade sequence is finnished, assign new random time for specific led
3 - repeat this for all leds individually
I can run the code without problems if I do not try to assign new values after each fading-loop
As soon as I assign new value to the loop that ran out, the leds start flickering and have no smooth transittion anymore.
Please find attached the code I have so far adn feel free to comment .
/* Random breathing leds
*
* RdB december 2017
*/
#include <math.h> // mathematical functions
#include <Entropy.h> // random generator
#define ledNumber 3 // number of leds used
int ledPins[ledNumber] = { 3, 5, 6 }; // assign the PWM pins
int ledBrightness[ledNumber]; // brightness variable
float fadingTime[ledNumber]; // fading time variable
unsigned long currentMillis;
unsigned long previousMillis[ledNumber];
void setup(){
Entropy.Initialize(); // initialize random generator
randomSeed(Entropy.random());
for (int i = 0; i < ledNumber; i++){
fadingTime[i] = 1000 + random(2600); // assign random fading time
previousMillis[i] = 0;
}
}
void loop(){
currentMillis = millis();
for ( int i= 0; i < ledNumber; i++){
breathingLeds(i);
}
}
void breathingLeds(int i){
if (currentMillis - previousMillis[i] <= fadingTime[i]){
ledBrightness[i] = (exp(sin(millis()/fadingTime[i]*PI)) - 0.36787944) * 108.0;
analogWrite(ledPins[i], ledBrightness[i]);
} else {
previousMillis[i] = currentMillis;
fadingTime[i] = 1000 + random(2600); // assign random fading time
}
}
I don't think that is the problem because it is just mapping the sinusoidal value to a brightness. As line 45 is commented out:
previousMillis[i] = currentMillis; // remember time
// fadingTime[i] = 1000 + random(2600); // assign random fading time
}
leds are breathing normally and smooth, but with a fixed fadingTime per led as assigned in the setup loop. What I like to accomplish is that after every fadingTime sequence the led gets a new fadingTime value. So it will fade in and out fast one cycle, and slower or even faster next cycle.
"Debugging" with the serial monitor ( on fadingTime) shows that the led which has completed its fading cycle, gets a new fadingTime assigned, while the others still keep their value. For the calculation of the brightness that means that the brightness will still increase or decrease for these leds as it is just mapping the brightness between a minimum and a maximum of 255.
spa2036:
"Debugging" with the serial monitor ( on fadingTime) shows that the led which has completed its fading cycle, gets a new fadingTime assigned, while the others still keep their value. For the calculation of the brightness that means that the brightness will still increase or decrease for these leds as it is just mapping the brightness between a minimum and a maximum of 255.
Thanks.
any time you find you have similar objects doing similar things, build a class
millis() is total milliseconds since switch-on, so that is not the proportion of 'fadingTime' that has elapsed in this cycle....
I don't think that is the problem because it is just mapping the sinusoidal value to a brightness. As line 45 is commented out:
I agree with TonyWilk. When you suddenly change the denominator, you just changed the period of the sine wave and you're suddenly way out of phase. If you change it to (millis() - previousMillis[ i]) you'll be back in phase.
If you are just trying to get Sean Voisen's single LED example expanded to multiple LED's, here is a simple example that does not have exact times, but eliminates the phase shift problem.
#include <math.h> // mathematical functions
#define ledNumber 3 // number of leds used
int ledPins[ledNumber] = { 3, 5, 6 }; // assign the PWM pins
float fadingInterval[ledNumber]; // fading time variable
int remainingIntervals[ledNumber];
void setup() {
randomSeed(analogRead(0));
for (int i = 0; i < ledNumber; i++) {
fadingInterval[i] = random(1000, 4000); // assign random fading time
remainingIntervals[i] = fadingInterval[i];
}
}
void loop() {
for ( int i = 0; i < ledNumber; i++) {
uint8_t b = (exp(sin(remainingIntervals[i] / fadingInterval[i] * PI)) - 0.36787944) * 108.0;
analogWrite(ledPins[i], b);
if (!--remainingIntervals[i]) {
fadingInterval[i] = random(1000, 4000);
remainingIntervals[i] = fadingInterval[i];
}
}
}
Ok, I see now what TonyWilk was trying to say, was still figuring out his hint .
Next, what BulldogLowell suggested is understood and I had already a look at how classes are created. As I understand is that different instances are created for each led and that every cycle can have its new value.
Jimmus helped me to be back in phase. His solution means the minimum constant has to be recalculated since the brightness never reaches 0 with current constant.
An eye opener from wzaggle, and you are right, exact timings are not essentiel. I have seen various examples of the Sean Voisen's tutorial and others, and I think that this is visually the nicest way to have a breathing led. But same issue here.... I have to recalculate the minimum brightness.
An alternative calculation method which is adjustable and avoids odd 'correction' values would be:
(written out 'longhand' for explanation purposes)
intervalFraction= remainingIntervals[i] / fadingInterval[i]; // range: 0.0 to 1.0
sineVal = sin( intervalFraction * PI ); // range: 0.0 to 1.0 to 0.0
power = 3.0;
powSine = pow( sineVal, power ); // raise to given power, result range is 0.0 to 1.0
brightness= powSine * 255; // exact range of 0 to 255 for brightness
You can alter the power value to get different 'breathing sharpness'.
This is basically the same calculation you need for LED Gamma Correction.
I noticed that with the solutions of Jimmus and wzaggle that the sinewave was upside down / inversed. That was easy to correct with the map function in Arduino.
which gives me a minimum of 3 and a max of 252 brightness. For me it is better the led does not turn off completely.
As for the alternatvie calculation of TonyWilk, I need to take a closer look. Interesting way of calculating, but I am afraid that the visual effect of the fading in and out is non lineair.
The relative brightness of a led is non lineair with the current / duty cycle. That is why I like the sinusoidal waveform as it comes closer to a lineair relative brightness of the led. With a sinus wave it outputs almost 70% of the time at max brightness ( as seen by the eye).
spa2036:
The relative brightness of a led is non lineair with the current / duty cycle. That is why I like the sinusoidal waveform as it comes closer to a lineair relative brightness of the led. With a sinus wave it outputs almost 70% of the time at max brightness ( as seen by the eye).
Exactly... that's what Gamma Correction does.
It corrects the intensity level so that, say, half brightness actually looks half as bright. That involves a power function which is what the exp() function is sort-of providing in the original code.
What the alternative calculation does is take the sine wave and apply gamma correction to it (in a handy way which gives you a nice resulting 0 to 255 value).
I double-checked this and drew a graph of the resulting curves for a few values of 'power' - compare it to the article example linked in post #5.
TonyWilk, I took your example from #8 and put that into a sketch. As your graph is already showing, is that you can really squeeze the curve of the graph to suit the visual effect you need. Compared with the article example in #5 I think you have more possibillities using the POW function.
I have some nice examples and new ideas to experiment some more.