Conserving Power with Arduino/GSM

Hello,

I am working on a project that measures a level in a tank in the middle of nowhere and communicates the level to a server. I am using an ultrasonic level device (HC-SR04), battery power (2 AA), and a GPRS (SIM 900) signaling device. Unfortunately the battery drains pretty quickly and I would like to have it last as long as I can. I have worked with sleep functions to conserve power but I find that it only limits power to my UNO and not the GSM. Also a solar panel is not really a viable option due to the lack of sunlight in the tank's location.

I think I know a good solution I just need some validation and some help from you guys to figure it out.

Since I only need about 1 reading per day I am thinking I need an external piece of hardware with a timer that turns on power to the Arduino UNO and GSM for about 10 minutes (or until a signal is confirmed) and then shuts it off for 24 hours. In my research I've found that a DC power booster combined with a PIC controller may be the best way. Does anyone have any experience with this or have any recommendations and some good hardware?

We have solved this issue by using the Seeedstudio Stalker board with a GPRSbee (http://www.gprsbee.com).

The GPRSbee can be shut on/off in software so we use it to only upload data once per hour. The upload doesn't take more dan 30 seconds so the power usage for upload it really minimal

Furthermore we conserve the power usage by using the deep sleep mode of the Atmega (SLEEP_MODE_PWR_DOWN). We then wake it periodically by an interrupt from teh Real Time Clock taht the Stalker board has.

Our whole setup runs on a 1.5W solar panel and a 1000 mAh LiPo battery.

Thanks for the reply, it seems like this solution will work. I had a couple of clarifying questions.

1.) How do you stay in sleep mode for an hour? Is there a way to do this without cycling through a for loop?

2.) Is there any way to use another battery other than the LiPo?

3.) How long can you go with a fully charged battery with no solar panel hook up?

Thank you in advance for your help and if you have any example code I can use, that would be great!

You can use the various sleep modes of the Arduino. Best would be the SLEEP_MODE_PWR_DOWN. This would however require an external event to wake up the Arduino. In the Stalker Board

http://www.seeedstudio.com/depot/seeeduino-stalker-v2-p-727.html?cPath=6_7

this can be done using the Real Time Clock it has on board. This clock trigger an interrupt to wake the microcontroller, after whcih you can do the upload and go back to sleep.

With the GPRSbee you will have to use a LiPo battery. You could accomplish the same with an Arduino + GPRS shield and another type of battery, but it will be less power efficient.

If you would use for instance a 2000mAh LiPo battery and do hourly uploads (for just a few seconds at a time) you should be able run it for a few weeks before it needs a recharge.

Thank you, that helps a lot.

Everything works with my seeduino Stalker board but I can’t seem to wake up from an Interrupt. I have soldered the bottom of the stalker board (INT to PD2) but the library I have found does not seem to trigger the wakeup signal I need.

Here is the .h file:

#ifndef STALKER_POWER
#define STALKER_POWER

#include <Arduino.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <DS3231.h>

class Power
{
  public:
    Power();
    void initSleepMode();
    
    /**
     * Sleep for <tt>seconds</tt> seconds for <tt>RTC.now()</tt>.
     */
    void sleepFor(int seconds);
    /**
     * Sleep every <tt>seconds</tt> seconds since last wake up.
     * This is most likely the methods you'll use if you need to wake up precisely every <tt>seconds</tt> seconds.
     */
    void sleepEvery(int seconds);
    /**
     * Sleep until the specified <tt>date</tt> DateTime.
     */
   void sleepUntil(DateTime date);
  private:
   DS3231 RTC;
   DateTime lastWakeup;
};

//The following code is taken from sleep.h as Arduino Software v22 (avrgcc), in w32 does not have the latest sleep.h file
#define sleep_bod_disable() \
{ \
  uint8_t tempreg; \
  __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \
                       "ori %[tempreg], %[bods_bodse]" "\n\t" \
                       "out %[mcucr], %[tempreg]" "\n\t" \
                       "andi %[tempreg], %[not_bodse]" "\n\t" \
                       "out %[mcucr], %[tempreg]" \
                       : [tempreg] "=&d" (tempreg) \
                       : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \
                         [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \
                         [not_bodse] "i" (~_BV(BODSE))); \
}


#endif

And here is the .cpp file:

#include <Power.h>

Power::Power()
{
}

// Interrupt service routine for external interrupt on INT0 pin conntected to DS3231 /INT
void INT0_ISR()
{
  //Keep this as short as possible. Possibly avoid using function calls
  detachInterrupt(0);
}

void Power::initSleepMode()
{
  // Initialize INT0 pin for accepting interrupts
  PORTD |= 0x04; 
  DDRD &=~ 0x04;
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  
  RTC.begin();
  lastWakeup = RTC.now();
}

void Power::sleepFor(int seconds)
{
  sleepUntil(DateTime(RTC.now().get() + seconds));
}

void Power::sleepEvery(int seconds)
{
  sleepUntil(DateTime(lastWakeup.get() + seconds));
}

void Power::sleepUntil(DateTime wakeupTime)
{
  RTC.clearINTStatus(); //This function call is  a must to bring /INT pin HIGH after an interrupt.
  RTC.enableInterrupts(wakeupTime.hour(), wakeupTime.minute(), wakeupTime.second());    // set the interrupt at (h,m,s)
  attachInterrupt(0, INT0_ISR, LOW);  //Enable INT0 interrupt (as ISR disables interrupt). This strategy is required to handle LEVEL triggered interrupt
  
  // Power Down routines
  cli(); 
  sleep_enable();      // Set sleep enable bit
  sleep_bod_disable(); // Disable brown out detection during sleep. Saves more power
  sei();
        
  //Serial.println("\nSleeping");
  delay(10);           // This delay is required to allow print to complete
  // Shut down all peripherals like ADC before sleep. Refer Atmega328 manual
  power_all_disable(); // This shuts down ADC, TWI, SPI, Timers and USART
  sleep_cpu();         // Sleep the CPU as per the mode set earlier(power down)  
  sleep_disable();     // Wakes up sleep and clears enable bit. Before this ISR would have executed
  power_all_enable();  // This shuts enables ADC, TWI, SPI, Timers and USART
  
  lastWakeup = RTC.now();
  
  delay(10);           // This delay is required to allow CPU to stabilize
}

I am trying to use a command “power.sleepFor(5);” so that the board sleeps for 5 seconds and then wakes up. The board sleeps but never wakes up. Has anyone had any luck using the RTC on a stalker board to wake it up from an interrupt?

I run today in the same issue. Think we have to modify the hardware and make a solder bridge:

http://www.seeedstudio.com/wiki/Seeeduino_Stalker_v2.3#DS3231_Interrupts

This example is a demonstration of interrupt detection from DS3231 INT output. This feature is useful for data-logger functionality where the MCU is put to sleep mode when not in use and DS3231 INT wakes up the CPU periodically. This extends battery power. The complete operation is documented in the code.

  • Solder PD2 and INT pins of INT jumper. This connects the DS3231 interrupt out pin to ATmega328 INT0 pin.