Go Down

Topic: fading 6 LEDs independantly starting on random timers (Read 1 time) previous topic - next topic

JesusDoesVegas

Ok, I've tried solving this on my own using the Getting Started with Arduino book, and google (as well as searching this forum), but I've only succeeded in confusing myself even more.

I'm sure this is a pretty easy solve, I'm just a total beginner, and the programming course I took 10 years ago in high school isn't fresh in my memory.

I've got 6 LEDs plugged into my arduino Uno (pins 3, 5, 6, 9, 10, and 11).  My final goal is to have them at (pseudo) random have them fade on and back off independently.  Each LED will have a random wait time before coming back on (between 1 and 5 minutes), and the fade in time should take about 30 seconds to a minute.  This is eventually going in our garden to add a bit of interesting lighting for the plants.  I also plan on adding further functionality down the line, but I'm taking baby steps.

I started out with the premade example for analog fading:

Code: [Select]
int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by

void setup()  {
  // declare pin 9 to be an output:
  pinMode(9, OUTPUT);
}

void loop()  {
  // set the brightness of pin 9:
  analogWrite(9, brightness);   

  // change the brightness for next time through the loop:
  brightness = brightness + fadeAmount;

  // reverse the direction of the fading at the ends of the fade:
  if (brightness == 0 || brightness == 255) {
    fadeAmount = -fadeAmount ;
  }     
  // wait for 30 milliseconds to see the dimming effect   
  delay(30);                           
}


I then figured out how to make them all fade at the same time:

Code: [Select]
int value1 = 0;                            // variable to keep the actual value
int value2 = 0;                                     // I know these aren't used later in the code
int value3 = 0;                                     // I assumed they would be necessary eventually
int value4 = 0;
int value5 = 0;
int value6 = 0;

int ledpin1 = 3;
int ledpin2 = 5;
int ledpin3 = 6;
int ledpin4 = 9;
int ledpin5 = 10;
int ledpin6 = 11;

void setup()  {
  // nothing happens in setup
}

void loop()  {
 
  // FADE IN
  for(value1 = 0 ; value1 <= 255; value1+=5)
{
    analogWrite(ledpin1, value1);           // sets the value (range from 0 to 255)
    analogWrite(ledpin2, value2);           // sets the value (range from 0 to 255)
    analogWrite(ledpin3, value3);           // sets the value (range from 0 to 255)
    analogWrite(ledpin4, value4);           // sets the value (range from 0 to 255)
    analogWrite(ledpin5, value5);           // sets the value (range from 0 to 255)
    analogWrite(ledpin6, value6);           // sets the value (range from 0 to 255)
    delay(300);                            // waits for 30 milli seconds to see the dimming effect
  }
 
  // FADE OUT
  for(value = 255; value >=0; value-=5)   // fade out (from max to min)
  {
    analogWrite(ledpin1, value1);
    analogWrite(ledpin2, value2);
    analogWrite(ledpin3, value3);
    analogWrite(ledpin4, value4);
    analogWrite(ledpin5, value5);
    analogWrite(ledpin6, value6);
    delay(30);
  }
}


I assume I now need to assign a timer for each LED, and before each tick up or down in value, check if the timer has reached 0.  I don't know how to do that.  I tried a different for statement for each LED, but that made them come on one at a time. Is this a situation where I need to set up an array to monitor all 6 at once?  HELP!

j514

#1
Jan 22, 2012, 02:54 am Last Edit: Jan 22, 2012, 03:42 am by j514 Reason: 1
here's an upgrade to your code.  I've left the random delay time for you to put in.
code untested, YMMV

Code: [Select]
int values[] = {0,0,0,0,0,0};
int ledpins[] = {3,5,6,9,10,11};
int direction[] = {1,1,1,1,1,1};
int fadeAmount = 5;    // how many points to fade the LED by

void setup()
{
int i;

 for (i = 0; i<6; i++)
 {
   // set pins as outputs
   pinMode(ledpins[i], OUTPUT);
   // set initial values
   values[i] = random(0, 255);
 }
}

void loop()
{
int i;

 for (i=0; i<6; i++)
 {
  // set led values
  analogWrite(ledpins[i], values[i]);

  // change the brightness for next time through the loop:
  values[i] = values[i] + (fadeAmount * direction[i]);

  // reverse the direction of the fading at the ends of the fade:
  if (values[i] == 0 || values[i] == 255)
  {
    direction[i] = -direction[i];
  }    
 }

 // wait for 30 milliseconds to see the dimming effect    
 delay(30);                            
}


edit: i accidentally, twice!
a][+ ascii express, 110/300 novation cat, xmodem

JesusDoesVegas

#2
Jan 22, 2012, 04:10 am Last Edit: Jan 22, 2012, 04:28 am by JesusDoesVegas Reason: 1
Thanks for pushing me in the right direction! This got me a lot closer than I was before.

I am trying to add a timer to each LED that is assigned a random value (right now between 1 and 10 seconds).

The if statement should do three things...
first - check to see if the timer is greater than zero, and if so subtract 1.
second - check to see if timer is equal to 0 and the value of the lights is greater than zero, and if so run through the fade sequence.
third - check to see if the timer and the value of the lights both equal zero, and if so assign new random values to the timer and the value of the lights.

Code: [Select]
int values[] = {
  1,1,1,1,1,1};
int ledpins[] = {
  3,5,6,9,10,11};
int direction[] = {
  1,1,1,1,1,1};
int fadeAmount = 5;    // how many points to fade the LED by
int timer[] = {
  0,0,0,0,0,0};

void setup()
{
int i;

  for (i = 0; i<6; i++)
  {
    // set pins as outputs
    pinMode(ledpins[i], OUTPUT);
    // set initial values
    timer[i] = random(10, 100);
  }
}

void loop()
{

  int i;

if (timer[i] > 0) {
    timer[i] = timer[i] - 1;
  } else if (timer[i] == 0, values[i] > 0) {
  for (i=0; i<6; i++)
  {
    // set led values
    analogWrite(ledpins[i], values[i]);

    // change the brightness for next time through the loop:
    values[i] = values[i] + (fadeAmount * direction[i]);

    // reverse the direction of the fading at the ends of the fade:
    if (values[i] == 0 || values[i] == 255)
    {
      direction[i] = -direction[i];
      timer[i] = random(10, 100);
    }
  }
  }
  // wait for 30 milliseconds to see the dimming effect   
  delay(100);                           
}


right now all its doing is waiting the 1 to 10 seconds, and then the lights all begin flashing without pause.  I think my problem is in my understanding of how the arduino reads the code.  When using an array like i am now (with instead of numbering the iterations) can I treat the code as if all 6 LEDs are being processed at the same time?  Is my timer actually independent for every LED?  Currently it seems like they aren't since all the lights come on at once.

EDIT - updated my code a bit in an attempt to break out of the for loop and reset the timer... still not right.

lloyddean

#3
Jan 22, 2012, 04:11 am Last Edit: Jan 22, 2012, 07:35 am by lloyddean Reason: 1
One possibility (compiles, but otherwise untested)-

Code: [Select]

#define HAS_TIME_PASSED(VAR_FUTURE_)    (((long)(millis() - VAR_FUTURE_)) >= 0)

typedef unsigned long       millis_t;

struct light_t
{
   uint8_t     _pin;
   uint8_t     _brightness;
   uint8_t     _dStep;
   millis_t    _millisNextUpdate;
};

const uint8_t   pinLED1         =  3;
const uint8_t   pinLED2         =  5;
const uint8_t   pinLED3         =  6;
const uint8_t   pinLED4         =  9;
const uint8_t   pinLED5         = 10;
const uint8_t   pinLED6         = 11;

const millis_t  TIME_DELTA_MAX  = 2000UL;

const uint8_t   STEP_SIZE       = 5;

light_t     lights[] =
{
     { pinLED1, 0, STEP_SIZE, 0 }
   , { pinLED2, 0, STEP_SIZE, 0 }
   , { pinLED3, 0, STEP_SIZE, 0 }
   , { pinLED4, 0, STEP_SIZE, 0 }
   , { pinLED5, 0, STEP_SIZE, 0 }
   , { pinLED6, 0, STEP_SIZE, 0 }
};

const int       LIGHT_COUNT     = (sizeof(lights) / sizeof(lights[0]));

void loop()
{
   for ( int i = LIGHT_COUNT; i--; )
   {
       analogWrite(lights[i]._pin, lights[i]._brightness);    

       if ( HAS_TIME_PASSED(lights[i]._millisNextUpdate) )
       {
           lights[i]._brightness += lights[i]._dStep;
           if ( lights[i]._brightness == 0 || lights[i]._brightness == 255 )
           {
               lights[i]._dStep = -lights[i]._dStep;
           }    

           lights[i]._millisNextUpdate += (millis_t)(rand() % TIME_DELTA_MAX);
       }
   }
}

void setup()
{
   // REMEMBER TO SEED RANDOM with 'srand'
   for ( int i = LIGHT_COUNT; i--; )
   {
       pinMode(lights[i]._pin, OUTPUT);
       
       lights[i]._millisNextUpdate = (millis_t)(rand() % TIME_DELTA_MAX);
   }
}


EDIT: Fixed next update time

JesusDoesVegas

#4
Jan 22, 2012, 04:20 am Last Edit: Jan 22, 2012, 04:32 am by JesusDoesVegas Reason: 1
lloyddean - you've solved my "all lights come on at the same time" problem.  Tested your code, all lights pop on independently in about a 3 second range, then they all flash rapidly until i reset the arduino.  I don't understand a lot of what you're doing here, so I'll have to do a bit of poking around to figure it out.

edit - I just noticed every time I reset the arduino, the lights come on in the same order (by pins) 5, 11, 6, 9, 3, 10.  Weird.

lloyddean

#5
Jan 22, 2012, 04:32 am Last Edit: Jan 22, 2012, 04:35 am by lloyddean Reason: 1

lloyddean - you've solved my "all lights come on at the same time" problem.  Tested your code, all lights pop on independently in about a 3 second range, then they all flash rapidly until i reset the arduino.  I don't understand a lot of what you're doing here, so I'll have to do a bit of poking around to figure it out.

edit - I just noticed every time I reset the arduino, the lights come on in the same order (by pins) 5, 11, 6, 9, 3, 10.  Weird.


That was my intent - to give you a starting framework to work with.  And differently than everybody else as something to study.

EDIT:  Check the comment "REMEMBER TO SEED RANDOM with 'srand' " in 'setup'
"

j514

#6
Jan 22, 2012, 05:52 am Last Edit: Jan 22, 2012, 05:55 am by j514 Reason: 1
Quote
When using an array like i am now (with instead of numbering the iterations) can I treat the code as if all 6 LEDs are being processed at the same time?  Is my timer actually independent for every LED?  Currently it seems like they aren't since all the lights come on at once.


The instance of each led is a dimension in the array, eg: ledpins[0] and ledpins[1] are two different leds in your group.  Your timer is independent for every led as well.

Next steps to last code posted:

Code: [Select]
// these should be put into a struct for simplicity
int values[] =    {1,1,1,1,1,1};
int ledpins[] =   {3,5,6,9,10,11};
int direction[] = {1,1,1,1,1,1};
long timer[] =    {0,0,0,0,0,0};

int fadeAmount = 5;    // how many points to fade the LED by

void setup()
{
int i;

 for (i = 0; i<6; i++)
 {
   // set pins as outputs
   pinMode(ledpins[i], OUTPUT);

   // set initial timer (now plus 1-10 seconds)
   timer[i] = millis() + (random(1, 10) * 1000);
 }
}

void loop()
{
int i;

 for (i=0; i<6; i++)
 {
    if (millis() - timer[i] > 0)
    {
      // timer has expired

      // set led values
      analogWrite(ledpins[i], values[i]);

      // change the brightness for next time through the loop:
      values[i] = values[i] + (fadeAmount * direction[i]);

      // reverse the direction of the fading at the ends of the fade:
      if (values[i] == 0 || values[i] == 255)
      {
        direction[i] = -direction[i];
        timer[i] = random(10, 100);        
      }
    }
  // wait for 100 milliseconds to see the dimming effect    
  delay(100);                            
 }
}


From here this code needs two things.  A way to set the next timer, and some checking to make sure millis() doesn't get reset below your timer values.

edit: accidentallied a word
a][+ ascii express, 110/300 novation cat, xmodem

lloyddean

JesusDoesVegas  - Fixed a bug in the setting the next update time in the above framework example.

KirAsh4

I posted a code snippet in this thread http://arduino.cc/forum/index.php/topic,85763.0.html that does what you're wanting to do, in a way.  It randomly fades a number of LEDs on and off, at different speeds as well.

JesusDoesVegas

#9
Jan 22, 2012, 08:07 am Last Edit: Jan 22, 2012, 08:45 am by JesusDoesVegas Reason: 1
Code: [Select]
// these should be put into a struct for simplicity
int values[] =    {
 0,0,0,0,0,0};
int ledpins[] =   {
 3,5,6,9,10,11};
int direction[] = {
 1,1,1,1,1,1};
long timer[] =    {
 0,0,0,0,0,0};

int fadeAmount = 5;    // how many points to fade the LED by

void setup()
{
 int i;

 for (i = 0; i<6; i++)
 {
   // set pins as outputs
   pinMode(ledpins[i], OUTPUT);

   // set initial timer (now plus 1-10 seconds)
   timer[i] = millis() + (random(10, 20) * 1000);
 }
}

void loop()
{
 int i;

 for (i=0; i<6; i++)
 {
   if (millis() > timer[i])
   {
     if (direction[i] = 1)
     {
       values[i] = values[i] + (fadeAmount);
       analogWrite(ledpins[i], values[i]);
       delay(10);

       if (values[i] >= 255)
       {
         direction[i] = -direction[i];        
       }

       {
         values[i] = values[i] - (fadeAmount);
         analogWrite(ledpins[i], values[i]);
         delay(10);

         if (values[i] <= 0)
         {
           direction[i] = -direction[i];
           timer[i] = millis() + (random(10, 20) * 1000);    
         }
       }
     }
   }
 }
}


I'm getting closer.  You guys are great for helping me out.  I re-did some things because down the road I'm going to want a bit more control over the brightness as they fade in and out, but that's still not working right.  Good news is I've got my timers working.  When I run the code above the lights only blip on for moment before going back out, but they do all seem to be on random timers between 10 and 20 seconds.  I've gone from knowing nothing at all to that in a day... I'm going to go take a break.  It's been a pretty good nerdy Saturday.

EDIT - KirAsh4 - I'll take a look.  Thank you.
        lloyddean - I think I may have addressed what you're talking about in the new code.  Not sure.  The timer wasn't working at all before, I realized that when I set it to 30 seconds and the lights all came on immediately anyway.

EDIT AGAIN - KirAsh4... it does exactly what I'm looking for.  I sort of feel like I wasted a lot of time today, but I learned a lot (thanks to you guys) so its not a total loss.

My next step is to rig up a speaker and some sort of sound producer to each LED station, and assign each a note in a chord, so when they light up, the volume fades in.  The idea is to make the garden sing to you.  I'll also be adding a mute button, as well as a way to dim all of the lights at once... but that's for another time.  You guys are great.

KirAsh4

I apologize for coming late into this thread - been busy working on some other projects and I purposely stayed away from the boards so I don't get sucked into other stuff. :)

But, I'm glad the code snippet works for you.  You should not feel like you've wasted your time though, there are so many ways of skinning the cat.  What you were doing and what others were suggesting will work just as well.  I was in the same boat not too long ago when I was looking to do something very similar and I came across that snippet.  I too spend days, if not weeks, trying to find a better solution than what I was doing.

Now, you have a choice of picks, use one or the other.

Go Up