Measuring LiPo Voltage using an Arduino

Measuring LiPo Voltage using an Arduino

Created
Jan 13, 2022 06:08 PM
Last edited time
Last updated January 22, 2023
Tags
Electronics
notion image

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).
JST-XH connector for cell balancing
JST-XH connector for cell balancing
 
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:
notion image
 
 
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.