Testing the Eflite 120mAh battery with a minimal jeenode

I want to build some small wireless sensor nodes that run off small LiPo batteries and use small solar cells to charge the battery. I found some small LiPo batteries that are used for RC Helicopters (see here.) I need to test how this battery holds up over time. BTW, this battery has protection circuitry — not all eflite batteries have it. I consider this a necessity since these will be remote and cannot be watched while charging. The charging circuitry also has safety cut-offs for over/under voltage but given the potentially explosive nature of LiPo batteries, I think you can’t be too careful. Anyways, onto the fun.

So, I put together a small Jeenode setup with a single DS18S20 temp chip, 1 blue LED and a voltage divider circuit to measure the battery voltage. The jeenode is setup to:

  1. wake-up
  2. turn on LED
  3. read temp
  4. read voltage
  5. send to receiver via RF12B
  6. wait for ACK
  7. resend if necc, if got ACK then,
  8. go to sleep for ~1 minute

Pretty simple.

Here is the code:

#include <Ports.h>
#include <RF12.h>
#include <OneWire.h>

#define DEBUG      1

// ACK stuff
#define RETRY_LIMIT     9   // maximum number of times to retry
#define ACK_TIME        10  // number of milliseconds to wait for an ack

#define NODE_ID         9  // my Node ID
OneWire ds1(4);

#if DEBUG
// LED Setup
Port led (2);
#endif

OneWire ds(4);

typedef struct {
 int temp1;
 int lipo_mV;
 int retries;
 int failed_packets;
}
Payload_temp;
Payload_temp m;  // m = measurement

ISR(WDT_vect) {
 Sleepy::watchdogEvent();
}  // interrupt handler for watchdog

static int readDS18S20() {
 ds1.reset();
 ds1.skip();
 ds1.write(0x4E); // write to scratchpad
 ds1.write(0);
 ds1.write(0);
 ds1.write(0x1F); // 12-bits is enough, measurement takes 750 msec
 ds1.reset();                               // Reset device
 ds1.skip();
 ds1.write(CONVERT,1);                      // Issue Convert command
 delay(1000);                             // maybe 750ms is enough, maybe not
 ds1.reset();                    // Reset device
 ds1.skip();
 ds1.write(READSCRATCH);                   // Read Scratchpad
 byte data[12];
 for (uint8_t j = 0; j < 9; j++) {               // we need 9 bytes
 data[j] = ds1.read();
 }
 ds1.reset();

 if(OneWire::crc8(data,8) != data[8]) {
#if DEBUG
 Serial.println(" crc?");
#endif
 return 0;
 }
 int16_t raw = ((int16_t)data[1] << 8) | data[0];
 float celsius = ((float)(raw >> 1) - 0.25 +((float)(data[7] - data[6]) / (float)data[7]));
 return int(((celsius*1.8)+32)*100);
}

//------------------------------------------------------------------------------
// SETUP
//------------------------------------------------------------------------------
void setup () {
#if DEBUG
 Serial.begin(57600);
 Serial.println("\n[120mAh Test]");
 led.mode(OUTPUT);               // setup DIO pin as output
 led.mode2(INPUT);              // setup AIO pin as output
 led.digiWrite(HIGH);                // turn on BLUE led
#endif 
 m.temp1 = 0;
 rf12_initialize(NODE_ID, RF12_915MHZ, 212);  //nodeID //freqBand //netGroup
 //rf12_config();

}

//------------------------------------------------------------------------------
// LOOP
//------------------------------------------------------------------------------
void loop () {
 m.retries = 0;
 byte i;

#if DEBUG
 led.digiWrite(1);               // turn on GREEN led
#endif
 m.temp1 = readDS18S20();
 m.lipo_mV = (map(led.anaRead(),0,1023,0,3300))/0.68;

 rf12_sleep(RF12_WAKEUP);  // turn on radio
 for (i = 0; i < RETRY_LIMIT; ++i) {
 m.retries = (int)i;
 while(!rf12_canSend())
 rf12_recvDone();
 rf12_sendStart(RF12_HDR_ACK,&m,sizeof m);
 rf12_sendWait(0);
 byte acked = wait_for_ACK(); // from roomNode.pde
 //rf12_recvDone();

#if DEBUG
 Serial.print("Sending Attempt #");
 Serial.print(m.retries);
 Serial.print("  Failed Packets: ");
 Serial.print(m.failed_packets);
 Serial.print("  Temp: ");
 Serial.print(m.temp1);
 Serial.print("  Lipo mV: ");
 Serial.println(m.lipo_mV);
 delay(2);
#endif

 if(acked) {
 m.failed_packets = 0;
 # if DEBUG
 Serial.print(" --> Got ACK  Failed Packets: ");
 Serial.println(m.failed_packets);
 delay(2);
 #endif
 break;
 }
 }

 if(i >= RETRY_LIMIT) {
 ++m.failed_packets;
 #if DEBUG
 Serial.print("Incrementing Failed Packets  -- Failed Packets: ");
 Serial.println(m.failed_packets);
 delay(2);
 #endif
 }

#if DEBUG
 Serial.println("\n\n");
 led.digiWrite(0);               // turn off led 
#endif

 rf12_sleep(RF12_SLEEP);  // turn off radio
 Sleepy::loseSomeTime(60000);  // power down AVR for ~ 1 minute // 2000 for getting the temps etc...
}

//------------------------------------------------------------------------------
// wait a few milliseconds for proper ACK to me, return true if indeed received
// see http://talk.jeelabs.net/topic/811#post-4712
static byte wait_for_ACK() {
 MilliTimer ackTimer;
 while (!ackTimer.poll(ACK_TIME)) {
 if (rf12_recvDone() && rf12_crc == 0 && rf12_hdr == (RF12_HDR_DST | RF12_HDR_CTL | NODE_ID))
 return 1;
 }
 return 0;
}

So far the node has been running for about 36 hours. The LiPo started at 4.197V according to the ADC (the voltage divider is using 5% resistors, so this may be off a bit, but good enough for this test).

Here is a graph after the first 36 hours:

I find it interesting that the slope isn’t linear. The current voltage is 4.06V. So it burned through ~137mV. Pretty good. The hope is that this can run for at least a week. That should get through any dark periods between solar recharging. Of course, the LED probably sucks the most juice. The final product won’t have the LED or at least will have the option to turn it off (you can do so with the DEBUG var in the sketch). I may have that as an option to turn on/off the indicators remotely.

Here is a graph of a 5 hour  period:

You can clearly see how the battery steps down. Pretty cool. More to come as the experiment progresses.

UPDATE:

So its been a week. Here is the graph:

Current voltage reading is 3.87V, therefore we have used ~ .327V over 7 days. 10,080 data transmissions! I think this is a tribute to JCW @ Jeelabs for developing a sleep setup that really limits the current draw. The MCP1702 says it wants about ~525mA above VREG which should equal3.825V. Hmmm. Curious to see when the system goes down….

Tags: ,