Better battery measurement - testers needed

Batteries are notoriously hard to measure, especially when compared to just looking at a transparent gasoline tank. We’ve come a long way from the simple voltage divider in the first batch to reading full voltage and amperage using the ESCs in the later batches. However the battery percent still isn’t as accurate as it could be.

Here’s what an LiPo battery usually looks like:

Notice that its curved a lot on the beginning and the end. Its a lot like a sigmoid function.

Right now the model we use for battery percentage is a straight line. We can be a bit smarter than that.
Below is a function to map out the LiPo battery percentage vs the red straight line.

(sorry, the second graph has the X and Y flipped)

The code was inspired by the work at the battery sense Arduino project. Check out that readme for more detailed info.

So now the fun part: I updated the code to use the new sigmoidal function and display the battery percentage based on the curve. The percentage should now be more linear since it is modeled after the actual battery discharge.

I’m looking for people that want to try it out and update their controller. It should work on batch 4+
Also feel free to comment on the code, its available here ->

Flash file: openppg-battery-curve.uf2 (141.5 KB)


I’ll give it a try, do you want us to report back our measurements from flights?

That would be great. I’m looking for voltage and then the percent displayed just to make sure its fitting to the curve as expected.
Also let me know what your min and max voltage are set to if it was changed in the config tool.

I updated the original post with a file you can flash with

Hi, can I please confirm, does this flash the controller simply by placing the flash file on a memory card in the hub, then turning it on?

Also, is the curve the same for Li-Ion, and is it set up for 14s? (I’m using 14s Li-Ion) Thanks.

No this is for the controller, not the hub.
If you have batch 5 or 6 your controller comes with a new bootloader that makes it easy to update with the config tool

The curve for LiIon is similar and this should still be a big improvement over just linear. The start and end of the curve just go off of the voltages defined so its theoretically compatible with any number of cells.

First flight with a memory card in the new controller (I have not flashed the update above yet), but my logs are empty on the memory card. I have LOG0.CSV through LOG3.CSV, but when I open them up there is a header row, but no data below. Is there something I need to enable to get the logs?

Have you tried adding up the current used over sample periods of time and reducing the overall capacity. Would obviously change for different battery capacities so that would need to be added as a setting. Issue with voltage curves is the voltage will sag significantly when under high power loads compared to when motors are off so remaining capacity will change drastically when motors are on vs off. Below is the battery code I’m using on my twin motor hang glider power unit.

  // Calculate amps used and remaining battery capacity
  Current_Amps = Data_To_Send.Current_1 + Data_To_Send.Current_2; // This is the data that was just read
  Ave_mAh_Used_Over_Period = ((Previous_Amps + Current_Amps) / 2 * 1000) * (millis() - Last_Rec_Time) / 3600000; // Capacity in [mAh] = current in [mA] * time [ms] / 3600000
  Used_Battery_Capacity_mAh = Used_Battery_Capacity_mAh + Ave_mAh_Used_Over_Period; // Total of all sample periods 

  Remaining_Battery_Capacity = Battery_Size_mAh - Used_Battery_Capacity_mAh; 
  Remaining_Battery_Percent = Map(Remaining_Battery_Capacity,0, Battery_Size_mAh, 0, 100);  //   Throttle is picked up from ESPnow call function
  Last_Rec_Time = millis();
1 Like

This is actually really interesting now that you mention it.

Cell phones, and other devices seem to rely on a combination of voltage measurement and a coloumb counter. When the device is on standby (no load) it reads voltage to get the percentage remaining. However, when under heavy use, as we already know due to voltage sag you cannot rely on voltage, and instead need to rely on the coulomb counter to accumulate current out to project the current % remaining. However, since this is an accumulating value there is drift and you need to “recalibrate” % whenever there is no load on the battery.

I’d be very curious if the amperage readings from the ESC(s) are accurate enough to project battery %, and how much error there would be after X minutes.

Interesting stuff. :smile: More good stuff on Quora. This would be a super fun project!

I think it would be fun to start by checking how often the throttle goes to 0% on an average flight. Every 5 minutes? 15? etc… Wondering if the device logging to the SD already measures this. Once I get my SP140 I’ll be able to play with this… :wink:

1 Like

Another thing I’m curious about is if the SP140 has some form of communication with the battery to determine type and capacity. This would make this type of battery % calculation much more user friendly.

And of course, modern devices even can detect battery wear and “effective” mAh capacity (see MacBook Power settings, as an example). Probably measuring how much power the battery can take when charging?

Is there an App for future use in work?

Yeah that’s the great thing about the SP140 battery being a custom standardized Li-Ion pack. We’ll always know the size and other characteristics.

1 Like

That’s great to hear. I think a voltage curve (like in this PR) is very useful for more accurately measuring % remaining when the battery has no load. I think the natural next step would be tracking current draw to predict % when under load. Which would require some level of battery communication to get effective capacity. :nerd_face:

We could certainly look at it. The SD card logs already have much of the needed information. It would be interesting if someone wanted to do flight data analysis from a few pilots uploading their CSVs. The code is open source for a reason :slight_smile:

I’m not opposed to an app in the future and would help contribute if we have people that have experience building apps.
The simplest form of an app works right now by connecting an android phone to the controller via USB and using the config tool in the browser to change basic settings.


1 Like

Shouldn’t you call millis only once per loop? It looks like you’re not accounting for the time between the first millis() and the second one (when you save it as Last_Rec_Time for your next pass). Whether that is a significant percentage of the total elapsed time, I don’t know.

Good catch thats an except of the code. There is one line missing from my post which is further down in my code. Can add to post when in front of computer.