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:
- wake-up
- turn on LED
- read temp
- read voltage
- send to receiver via RF12B
- wait for ACK
- resend if necc, if got ACK then,
- 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] <<
| 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….




Hi!
I am very interested in you project because I would like to use the JeeNodes for a dance performance and therefore reduce the size of the battery as much as possible. I am absolutly not a technician and so here my simple question. My JeeNodes are constantly sending data from different sensors ans switches. Can I operate the JeeNode with this lipo you mention for let’s say 2-3 hours with constant transmission. I know this should be calculated and depends on the sensors, but can you give me an estimation or an advice. Another option would be to stay with the AA-Power Board from JeeLabs with a single AAA cell. This would make the device a little bigger.
Greetings from Vienna, Thomas
Sounds like a great project.
As you note, the battery life is going to be hard to predict in different situations (how often you send the data, the size of the packets, the power requirements of the sensors, etc.). The only real option is to try one and see.
It is hard to recommend the Eflite 120mAh, because it does not have undervoltage protection. According to their site, it says it has a protection circuit, but you can run it down below 1.2V. I emailed Eflite and after a few weeks they wrote back that it does not have any protection. Obviously, bringing a LiPo battery that low isn’t safe.
OK, thank you!
I’ll try it with a button cell like this:
http://www.conrad.at/ce/de/product/252225/KNOPFZELLENAKKU-LITHIUM-LIR2477/SHOP_AREA_14715&promotionareaSearchDetail=005
Could you explain me how to do this for a non technician (in small steps):
>> a voltage divider circuit to measure the battery voltage
How could I manage to measure the V of my cell inside the JeeNode and print it to serial port?
Thanks a lot,
Thomas