I’ve been flying FPV racing drones for quite some time. For FPV as well as lots of other RC activities, lithium polymer batteries are essential. Typical lipo batteries for large devices have multiple cells. A lipo cell has a no-load resting voltage of 4.2 V when fully charged and 3.7 V when discharged.
It’s important that the cells within a battery are evenly balanced, which is why most of them either have balancing circuitry built into them (your phone battery) or balance ports attached (my drone battery).
Because batteries get put through quite a lot during drone flights, I wanted to build something to monitor mine to make sure they’re still healthy and usable. There are devices used to check cell voltage and rebalance if required, but I wanted a permanent monitoring solution at the time.
This is more of a retelling of my story, not a tutorial. If you’re attempting to reproduce this, do it at your own risk.
Voltage Problems
Unfortunately, the Arduino I was running operates at 3.3 V so that’s the max voltage we can measure. The balance port on cell 4 can deliver 16.8 V and I needed to find a way to bring this down. A Voltage Divider can help out:
We can now find out how much resistance we need in order to get every cell down to 3.3 V. 10 kΩ resistors are used for . So ideally we would have:
Cell1 | 4.2 V | 2.725 kΩ |
Cell2 | 8.4 V | 15.45 kΩ |
Cell3 | 12.6 V | 27.90 kΩ |
Cell4 | 18.6 V | 46.35 kΩ |
Unfortunately, I’m limited to the stuff I have at home so it turned out to be a bit different.
Cell | Max | ||
Cell1 | 4.2 V | 3 kΩ | 3.23 V |
Cell2 | 8.4 V | 18 kΩ | 3.00 V |
Cell3 | 12.6 V | 30 kΩ | 3.15 V |
Cell4 | 18.6 V | 50 kΩ | 3.10 V |
This obviously isn’t perfect but we can easily fix it in software.
void loop() { for (int adcPin = 0; adcPin < 3; adcPin++) { // read once and ignore reading // not sure if this is required, forums said so analogRead(adcPin); delay(50); int total = 0; // read give times and get the average // not sure if this is required, forums said so for (int i = 0; i< 5; i++) { total += analogRead(adcPin); delay(20); } // get average and convert to voltage float voltage = total * 3.29 / 5.0; voltage /= 1023.0; // send via serial, exact format doesn't matter } // wait a few seconds then read them all again delay(5000); }
Now we need to adjust for inaccuracies and my scuffed resistors. For this I’ll use my properly configured voltmeter and calculate a correction factor to multiply the read voltages with.
For Cell 1 my Arduino measured 3.03 V, the voltmeter said 4.06 V. We can now calculate the factor:
Again, this isn’t perfectly accurate. It should not be used to rebalance anything or stuff like that. The idea is to get a general idea if batteries are healthy or require manual checking.