Auto shutoff for LiPo battery

Hey guys,

For a battery powered tool I'm designing, I'm looking for a way to monitor the charge of an 11.1V (3 cell) LiPo battery with my Arduino and preventing the arduino from running if the voltage is too low. To my understanding 3.2 V per cell is a safe minimum voltage for this kind of battery pack.

What I want to do is the following (excuse the 'verbal' explanation, I'm not currently in posession of circuit drawing software):

A momentary ON switch pulls the input of a solid state relays switching power to the arduino high. This allows the arduino to power up. In the setup part of the sketch a batteryControlPin also wired to the SSR is set HIGH, keeping power on. During the operation of the arduino, the battery voltage is monitored with an analog input and a voltage divider. If it gets below 9.6 V for several cycles (to make sure that switching transient don't trigger shut-down) a batteryEmpty variable is set high, triggering an if-statement at the end of the sketch which sets the voltage on the batteryControlPin to LOW, removing power from the Arduino.

The above could be extended with a batteryLow LED that glows when battery voltage is below say 9.8 V.

Does anyone see any problems, like feedback issues?

Thanks!

Does anyone see any problems, like feedback issues?

No, you seem to understand the issues and task required. Keep in mind that there are Li-Po battery cells that have built in over-discharge and over-charge cut-off function, but of course they don't have a feedback signal to let you know that it has disconnected the cell from the output terminals.

Lefty

I think that was a great description of how it should work Doornroos.
I would check on the discharge voltage. I'm thinking you don't want to get below 3.7V/cell.
3 Cells would be ~12.3 to 12.6V fully charged, and 11.1V when pretty discharged.

CrossRoads:
I think that was a great description of how it should work Doornroos.
I would check on the discharge voltage. I'm thinking you don't want to get below 3.7V/cell.
3 Cells would be ~12.3 to 12.6V fully charged, and 11.1V when pretty discharged.

No, 3.7 vdc represents approximately the 50% remaining charge level and is often the 'nominal' voltage rating given when talking about a Li-Po cell. 3.0 is considered a good low cutoff value, and 4.2 is considered the fully charged voltage. So a 3 series cell Li-Po would could use 9 to 12.6 as it's safe workable voltage range.

Lefty

Hey Guys,

Thanks for your feedback! I checked the safety instructions on my battery and it recommends safe discharge down to 3.0 V per cell, so Retrolefty seems to be right. I'll try it and see if it works once I have a working FTDI cable... the one I got seems to be broken.

Cheers

Ok, guess my recall is a little off on the LiPo voltages.

Hey guys,

I've been trying to get things to work but I'm running into a strange problem. (Bye the way, I'm using a 5V 16 MHz Arduino Pro 328)
I'm building a kind of battery driven digital level tool, if the tool is within lowLim degrees from level, a green LED lights (inLEDPin) and a buzzer sounds (inBuzzPin, otherwise one of two red LED's (outLEDPinLeft or outLEDPinRight) are lit, indicating in which direction to tilt the tool in order for it to be level. For the code, see below. First I've build the level part, which works like a charm. Now I added the part where the Arduino can 'control' its own power (no measuring of the LiPo voltage is taking place yet) and that's where it goes wrong.

The power to the arduino is controlled by two LH 1540 relays connected in parallel. The first is connected to a pushbutton momentary switch, the second to digital output 6. If I push the pushbutton for a second or so, the Arduino has powered up and sets pin 6 high, so I can release the switch and it keeps working. So far so good. However, if I then tilt the test setup to where the tilt angle goes beyond lowLim, the moment the indicator LED's are switched, the signal from pin 6 drops to zero too, and only comes back up after a little while. Does anybody see what I'm doing wrong?

FYI: I currently only have the green led attached through a NPN transistor with a 10k base resistor, powering the led from the LiPo. The LH1540 is attached to output 6 with a 1 k current limiting resistor in series. Furthermore, the ADXL 345 is powered from the board. The LiPo's voltage doesn't drop at all when switching.

//////////////////////////////////////////////////////////////////
//Bildr design modified by Doornroos
//////////////////////////////////////////////////////////////////

//Analog read gravity sensor pins
const int xPin = 0;
const int yPin = 1;
const int zPin = 2;

//Signal out pins
const int outLEDPinRight = 9;
const int outLEDPinLeft = 8;
const int inLEDPin = 10;
const int inBuzzPin = 7;
const int battOn = 6;

//Running average filter constants
const int numReadings = 10;

double yReadings[numReadings];      // the readings from the analog input
int index = 0;                  // the index of the current reading
double ySum = 0;                  // the running total
double yAvg = 0;                // the average

//The minimum and maximum values that came from
//the accelerometer while standing still
//You very well may need to change these
int xMinVal = 388;
int xMaxVal = 622;
int yMinVal = 397;
int yMaxVal = 629;
int zMinVal = 398;
int zMaxVal = 609;

//In range lower and upper bounds (degrees)
int lowLim = 1;
int upLim = 45;


//to hold the caculated values
double x;
double y;
double z;

void setup(){
  Serial.begin(9600);
  
  pinMode(outLEDPinRight, OUTPUT);
  pinMode(outLEDPinLeft, OUTPUT);
  pinMode(inLEDPin, OUTPUT);
  pinMode(inBuzzPin, OUTPUT); 
  pinMode(battOn, OUTPUT) ;
  
  //Set battOn high
  digitalWrite(battOn, HIGH);
 
  //Initialize Red LEDs off
  digitalWrite(outLEDPinRight, LOW);
  digitalWrite(outLEDPinLeft, LOW);
  
  //Sound buzzer And blink green light to indicate ON
  int nTimes = 3;
  for (int i = 1; i <= nTimes; i++) { 
    digitalWrite(inLEDPin, HIGH);
    digitalWrite(inBuzzPin, HIGH);  
    delay(500);
    digitalWrite(inLEDPin, LOW);
    digitalWrite(inBuzzPin, LOW);
    delay(500);
  }
  
  //Initialize readings to zero
  for (int ind = 0; ind < numReadings; ind++)
    yReadings[ind] = 0;   
  
}

void loop(){

  //read the analog values from the accelerometer
  int xRead = analogRead(xPin);
  int yRead = analogRead(yPin);
  int zRead = analogRead(zPin);

  //convert read values to degrees -90 to 90 - Needed for atan2
  int xAng = map(xRead, xMinVal, xMaxVal, -90, 90);
  int yAng = map(yRead, yMinVal, yMaxVal, -90, 90);
  int zAng = map(zRead, zMinVal, zMaxVal, -90, 90);

  //Caculate 360deg values like so: atan2(-yAng, -zAng)
  //atan2 outputs the value of -? to ? (radians)
  //We are then converting the radians to degrees
  x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI);
  y = RAD_TO_DEG * (atan2(-xAng, -zAng) + PI);
  z = RAD_TO_DEG * (atan2(-yAng, -xAng) + PI);
  
  //Any correction or zeroing operations
  y = y + 1.5;
  
  //Map values between -180 and 180
  if (y > 180){
    y = y - 360;
  }
  
  //Store y-value to yReading array and calculate average:  
  //Substract last reading from ySum
  ySum = ySum - yReadings[index];
  //Store y value in array
  yReadings[index] = y;
  //Add reading to ySum
  ySum = ySum + yReadings[index];
  //Advance to next position of array
  index = index + 1;
  
  //If end of array is reached
  if (index >= numReadings)
    // wrap around to beginning
    index = 0;
    
  //Calculate average y value
  yAvg = ySum / numReadings;
  
  //Test the rotation around the x-axis and adjust signal outputs accordingly
  
  if (abs(yAvg) <= lowLim) {
    digitalWrite(inLEDPin, HIGH);
    digitalWrite(inBuzzPin, HIGH);
    digitalWrite(outLEDPinRight, LOW);
    digitalWrite(outLEDPinLeft, LOW);
    //Serial.println("Status: GREEN");
  }
  else if (upLim > abs(yAvg) && yAvg < -lowLim) {
    digitalWrite(inLEDPin, LOW);
    digitalWrite(inBuzzPin, LOW); 
    digitalWrite(outLEDPinRight, HIGH);
    digitalWrite(outLEDPinLeft, LOW);
    //Serial.println("Status: RED");
  }   
  else if (upLim > abs(yAvg) && yAvg > lowLim) {
    digitalWrite(inLEDPin, LOW);
    digitalWrite(inBuzzPin, LOW); 
    digitalWrite(outLEDPinRight, LOW);
    digitalWrite(outLEDPinLeft, HIGH);
    //Serial.println("Status: RED");
  }   
  else { //Set all pins to LOW
    digitalWrite(inLEDPin, LOW);
    digitalWrite(inBuzzPin, LOW);
    digitalWrite(outLEDPinRight, LOW);
    digitalWrite(outLEDPinLeft, LOW);
    //Serial.println("Status: ELSE");
  }

  delay(10); //To ensure stable functioning
}

I think you should be monitoring the voltage of each pack. In your description you seem to be assuming that all three packs are balanced and if they remain balanced through the discharge cycle it will work fine. When I worked with large LiPo packs I always checked the voltage of each cell to know when to turn off the draw.

wade

Good point wwbrown. I'll keep that in mind. Anyone has any suggestions on the voltage dip proplem?

which sets the voltage on the batteryControlPin to LOW, removing power from the Arduino.

The above could be extended with a batteryLow LED that glows when battery voltage is below say 9.8 V.

When you remove power from the Arduino, what happens to those LED indicators?

I think rather than removing power from the Arduino, you want the Arduino to go into some emergency / low-power mode, like removing power to a motor, or reducing power to it gradually (emergency landing for example), etc. The arduino consumes very little power and removing power from it provides few benefits to justify.

Hey dhenry, I think removing power from the arduino entirely is necessary, since even a (very) small current would in time drain the battery beyond the safe charge voltage, and I don't want that to happen. When the power is removed from the arduino, the leds go out too, but that's fine. Would you know what causes the voltage to drop on an output that is not switched by the code? I can imagine that that could happen when too much current is drawn, but that's not the case here.