Pages: [1] 2 3   Go Down
Author Topic: Power saving in code for extended battery life.  (Read 4343 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 0
Posts: 91
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

Im not sure if this is the right section of the forum to be posting this in, but its the best fit i could find.

I have mad a "pee-light", it turns on a nice red glow in the hallway when i get up to pee in the middle of the night.

It has a:
  •    darlington photo transistor hooked up to pin A5
  •    "Electronic brick (seeed studios)" PIR hooked up to D11
  •    2x LED's hooked up to D10
It tests for light, if it is dark then it tests for motion, if there is motion then it fades on the LED, if no motion detected for 9 seconds, it fades off LED's.
 
pretty simple, and i have it working exactly as i want it to, with the downside being battery life. I tried it on a 9vold battery and it only lasted 24-36 hours. ive since done some more testing and found out the following:
  • it draws 22mA (both with the PIR off or on)
  • it draws 47mA when LED's are at full brightness (for 9 seconds)

I have read that there are ways to sleep the arduino, but cant really work it out. it could really be off for hours at a time (while its light) but i can only find ways to sleep for 8 seconds.

please can some one suggest ways to improve battery life!??!

here is my code as it stands now. Im sure it looks horrific to all you, im only just starting and have not programmed before (apart from basic HTML 10 years ago!)
anyone has any suggestions on how to make it more neat or efficient that would be much appreciated too. But my main concern is for battery life.


Code:
int lightPin = 5;  // analogue pin for testing ambient light
int lightReading;  // value
int LEDpin = 10;   // Pin for LEDs
int pirPin = 11;   // Pin to read from PIR
int pirVal;        // Returned PIR value
int brightness = 0;    // how bright the LED is
int fadeAmount = 2;    // how many points to fade the LED by
int fadeAmount2 = 4;    // how many points to fade the LED by
int pirOnPin = 4;       // Power to this pin is power to PIR
unsigned long timeon;   // the ms val from millis() when LED is powered on
unsigned long timeoff;  // calculated value time on plus 9 seconds
int lightstate = 0;     // records what state the LED is in

void setup(){
 //Serial.begin(9600);
 pinMode(pirPin, INPUT);
 pinMode(pirOnPin, OUTPUT);
}

void loop(){
  lightReading = analogRead(lightPin);        // read light pin from photo transistor
  //Serial.println(lightReading);
  delay(500);
  if(lightReading > 1000) {                   // if light is greater than 1000, eg dark, turn on PIR and strat reading 
    digitalWrite(pirOnPin, HIGH);
    pirVal = digitalRead(pirPin);
    //Serial.println(pirVal);
      if(pirVal == HIGH){
        //digitalWrite(13, HIGH);              // used in testing to determine when the PIR was triggered
        //delay(50);
        //digitalWrite(13, LOW);
        //Serial.println("fade in");
        if(timeoff < millis()){                // check that the time the LEd are to be faded out is less than millis(). this stops the LED fading, going stright to off and fading back on on constantly
          int i=0;
          //digitalWrite(13, HIGH);
            for(i=0; i < 255; i += fadeAmount2){  // fade LED on
              analogWrite(LEDpin, i);   
              delay(50);
            }
           // Serial.println("full light");
            //analogWrite(LEDpin, 255);
            lightstate = 1;                      // set lighstate to "on", so that lights cant be faded off when they are off already.
          }
          timeon = millis();                     // set the time the LED came on to full power
          timeoff = timeon + 9000;               // set the time the LED will fade off. this will be done each time there is motion detected.

        }
    else{
      if(lightstate == 1){                       // make sure LED is on
          if(timeoff < millis()){                // LED has been on for 9 seconds
            //Serial.println("fade out");
           // digitalWrite(13, LOW);
            int i = 255;
            for(i=255; i > 0; i -= fadeAmount){  // fade off
                analogWrite(LEDpin, i-1);   
                delay(50); 
            }
          //Serial.println("light off");   
          //analogWrite(LEDpin, 0);
          lightstate = 0;                        // LED state is off
          }
      }
}
//Serial.println(timeon);
//Serial.println(timeoff);
//Serial.println(millis());
}
else {
  digitalWrite(pirOnPin, LOW);                   // ambient light has come back up (morning, or hall way light)turn off PIR
if(lightstate == 1){                             // if the LEDs are on, fade off regardless of 9 seconds
   //Serial.println("fade out");
   int i = 255;
   for(i=255; i > 0; i -= fadeAmount){
   analogWrite(LEDpin, i-1);   
   delay(50); 
  }
   //Serial.println("light off");   
   lightstate = 0;                               // reset variables
   timeoff = 0;
}
}
}


Thanks for looking,

Gr0p3r
Logged

California
Offline Offline
Faraday Member
**
Karma: 88
Posts: 3368
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What you could probably do is put it to sleep on an external interrupt and hook the light sensor up to a digital interrupt pin so that when it goes dark, the pin is triggered and Arduino is awoken from sleep.

Another option would be to sleep it using the watchdog timer, and just have it check the light level every 8 seconds, if it's not at what is should be, go back to sleep.
Logged

Orlando, FL
Offline Offline
Full Member
***
Karma: 0
Posts: 147
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'd love to see some example code for putting the unit to sleep using the the watchdog timer and to wake it up every 8 seconds.  I saw the enerlib library but it's very poorly documented.    I'd love to set the watch dog timer to actually go for 15 minutes but it looks like this isn't possible on the atmega chips.  it appears 8 seconds is the longest. 
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 291
Posts: 25847
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The Nightingale code worked for me.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Orlando, FL
Offline Offline
Full Member
***
Karma: 0
Posts: 147
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I've based projects on the nightingale code as well.  I really want to dissect the enerlib library and figure it out.  the enerlib seams to be a lot cleaner way of doing it. 
Logged

Anchorage, AK
Offline Offline
Edison Member
*
Karma: 42
Posts: 1176
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Question...

If you have it sleep for 15 minutes, are you going to stand in the hallway waiting for it to wake up again and check for movement before you walk by?  :-)  It needs to be awake to check its sensors, so sleeping for 8 seconds is about the longest that I imagine would be acceptable anyway.

In somewhat-pseudo-code, here's what I'd do:

Code:
while (1) {  // Or just in your loop()
  if (it_is_light_out()) {
    // It's light -- sleep for 5 seconds and test again
    snooze(5);
  } else {
    // It's dark -- check for movement
    while (there_is_movement()) {
      light_leds(10);
      delay(250);  // Avoid possibly triggering optical movement sensor based on LED light
    }
   
    // No movement detected -- sleep for 1 second
    snooze(1);
  }
}

You may think that sleeping for a second or 5 isn't much sleep, but consider that (unless someone is there, moving) it's only going to be awake long enough to poll your sensors, then right back to sleep again.  I don't know how long that takes exactly, and it depends on what kind of sensors you're using (purely analog?  1-Wire?  i2c?), but let's take a very conservative guess and say 100ms.  So, for 1/10th of a second every five seconds (2%), your Arduino is running during the day, and 1/10th of a second (10%) every second during the night, vs. 100% as it stands now.  That's assuming 100ms, which is probably waaaaaay beyond how long it'll really take.
Logged

Boston, MA
Offline Offline
Full Member
***
Karma: 0
Posts: 129
Batteries? We don't need no steenking batteries!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Which Arduino board are you using?

Putting the CPU to sleep between activities will save a little power (a few mA), but on many of the official Arduino boards (e.g. Duemilanove, Uno, Mega etc.), onboard features like the power LED and USB interface (powered all the time) are what eat up most of the power. Going to something like a BareBones (USB programming interface is a separate board and only plugged in when needed) will save a lot. Once these big guzzlers are taken care of, battery power savings from sleeping the CPU will be worth your attention :-) A more efficient voltage regulator would help too.

I am working on a low-power Arduino board called Mosquino (basically done, just a few software tweaks needed here and there) that integrates several 'easy' low-power tricks - no power LED, USB stuff unpowered when cable disconnected, low-leakage regulator, and a realtime clock to get the best use of the CPU deep sleep mode. Together this gets the sleep power consumption down to a few uA.

A handful of other things - I don't know whether or not the PIR module you are using has "smarts" builtin to detect motion (and so might need to be powered all the time to work). If not - if it draws less than about 20mA you may be able to power it directly from an I/O pin, sample it periodically (every second or two) and cut the power to it between measurements. Same for an ambient light sensor - assuming the sun does not rise or set too quickly ;-) you might only have to check this once per few minutes before deciding to use the PIR or not, and sleep in between. You can use one of the libraries using the watchdog timer trick mentioned above (rocketscream's Lightweight Low Power Arduino Library is another). But, if you don't mind Yet Another Chip, an external realtime clock (where you can set an alarm for any time in the future) will let you save more power by turning off the watchdog timer too (about 20uA difference in my tests).
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 91
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well, so many good ideas.

i would think that it could check for light and if there is light then sleep for 15 mins. that will be fine, once it is dark then change the sleep time to 5 seconds. then put in a bit to say dont sleep for 5 minutes after motion detected (for the return trip smiley-wink ).

the watchdog idea would be good too (sleep all day and wake at night)
What you could probably do is put it to sleep on an external interrupt and hook the light sensor up to a digital interrupt pin so that when it goes dark, the pin is triggered and Arduino is awoken from sleep.
, but how would that work with a phototrasistor?? it outputs an analogue value, as far as im aware, how can you use that as a digital trigger? example code?

Drmn4ea:

ive made my own board using the atmega. im using an 7805 as a voltage regulator. is that good enough? there is no power led or any other superflous hardware (i think.) i have read about using the internal clock so as to do away with the crystal, that would be something to consider if i could find a nice easy step by step guide where i dont need to buy any extra programmers and dont have the option to brick my chip.

ive attached pictures. the PIR is powered off a digital pin (pirOnPin) and is only activated when a light threshold is reached.
see my code:
Code:
  if(lightReading > 1000) {                   // if light is greater than 1000, eg dark, turn on PIR and strat reading 
    digitalWrite(pirOnPin, HIGH);
    pirVal = digitalRead(pirPin);
The LED was only used in testing to notify me when the PIR went HIGH. there is stuff all information about my PIR and the datasheet is useless.
This is it: http://www.robotshop.com/seeedstudio-electronic-brick-pir-motion-sensor-2.html


* PeeLight1.jpeg (1925.61 KB, 2592x1936 - viewed 44 times.)

* PeeLight2.jpeg (1641.31 KB, 2592x1936 - viewed 32 times.)
Logged

California
Offline Offline
Faraday Member
**
Karma: 88
Posts: 3368
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

, but how would that work with a phototrasistor?? it outputs an analogue value, as far as im aware, how can you use that as a digital trigger? example code?

An analog value is just a voltage. digitalRead is also reading a voltage, it just "translates" that voltage to either a 0 or a 1. If the voltage at the digital pin gets low enough, digitalRead will start reading it as 0, so you would need to setup a voltage division circuit with the proper resistor values so that it falls below that voltage when you want it to turn on. I think there is a "floating" voltage level (2-3v?) where the digitalRead wouldn't be accurate, so you may have to use an additional device to account for that if the light change is fairly gradual.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 91
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i see, do you have a link to an example of the watchdog wakeup trigger? ill have to have a play around and see if i can get that to work. i have a feeling that the light cange is going to be too gradual and it will hit that "floating point" you described and confuse it. what is the device that will switch 0-4v to 0 and 4-5v to 5?
Logged

California
Offline Offline
Faraday Member
**
Karma: 88
Posts: 3368
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/

My first thought would be a zener diode for blocking lower voltages.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 91
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh awesome, i just googled zenner diode, and going from the pictures, i think i may have some of them already, i didnt know what they were smiley-grin

if i can use the nightingale code and get the battery life to 3 years, that would be unbelievable!

anyone know if the 7805 voltage regulator is low-leak like Drmn4ea was suggesting?
also the Nightingale sketch doesnt have a voltage regulator. do i even need one??
will there be an harm in running straight off the battery? i was planning on using a 9v down to 5v through 7805, but if i can run off 4x1.2v AA...
i have found that the PIR i have will give continuous false positives if it is given less than 4v
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 224
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Some suggestions:

1. The power consumption of the chip is approximately A * f + B where f is the clock frequency and A and B are constants. At high clock frequencies, the A * f term dominates. So use a much lower clock frequency to save power. Preferably, use the internal 128KHz RC oscillator, which requires programming the fuses. If you don't want to program the fuses, you can still get a substantial power reduction by writing to the clock prescaler register, which allows the clock frequency to be divided by up to 256.

2. To detect the light level, you can use the analog comparator function of the atmega328p. See the datasheet. This will be more reliable than using a digital input, and gives you two options:

a) Wake up every 8 seconds on the watchdog and read the comparator. This is much quicker than doing an analogRead. So if it is light you can have the processor go back to sleep immediately, having consumed hardly any power.

b) Use the analog comparator interrupt to wake the process up from deep sleep when it gets dark.

3. How much current does the PIR detector draw? You could power it down during daylight.

4. The standard 7805 has a quiescent current of about 5mA, so far too high for your application. You need something like LM2396-5.0 instead (9uA typical quiescent current when the load current is <100uA).

The capacity of a 9v battery is around 565mAH for alkaline and 1.2Ah for lithium. So you'll need to get the average current consumption (including PIR) down to 45uA for a lithium 9v battery to last 3 years.
« Last Edit: May 03, 2012, 06:57:43 am by dc42 » Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Offline Offline
Jr. Member
**
Karma: 0
Posts: 91
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hi dc42,
thanks for your very informative reply. i think it going to take me a while to digest all of that, there are a few things i dont understand and will have to google. like the "analog comparator function".
Quote
Preferably, use the internal 128KHz RC oscillator, which requires programming the fuses. If you don't want to program the fuses, you can still get a substantial power reduction by writing to the clock prescaler register, which allows the clock frequency to be divided by up to 256.
can either of these be done with the standard arduino board?

Quote
3. How much current does the PIR detector draw? You could power it down during daylight.
ive just done some testing with my multimeter as the datasheet is good for nothing.
it draws .055mA - .075mA while testing
it draws 1.11mA when its sending the HIGH signal.
its power is currently connected to an arduino pin and is only "powered up" by a HIGH to that pin (only when the light is dark)

Quote
So you'll need to get the average current consumption (including PIR) down to 45uA for a lithium 9v battery to last 3 years.
i never expected to be able to get 3 years life. i just saying that because thats what nightingale got. I would be happy with 6-12 months .

ARRCH:
ive found some diode, but am having trouble with them. 4 types, the markings are hard to read but from what i can make out these are what i have:
1N4534A
1N4138AF
1N94 could be 1N9_4_?
4148T could be T4148 or 8T141 etc (its in a loop)
Yellow Brown White ( this one is marked with bands, brown could also be dark purple or black, hard to tell)

I have tied googling all these but to not much avail. do any of these sound like what you are talking about?
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 91
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The standard 7805 has a quiescent current of about 5mA, so far too high for your application. You need something like LM2396-5.0 instead
i cant find one of them how about a TDA3664? or know where i can get a LM2396-5.0 in australia without paying $60 postage from america  smiley-eek
http://www.ebay.com.au/itm/NEW-IC-TDA3664-N1-TDA3664-NXP-VOLTAGE-REGULATOR-/250814457643?pt=LH_DefaultDomain_0&hash=item3a65b4e72b
i can actually get these.
Logged

Pages: [1] 2 3   Go Up
Jump to: