PX4 / PX4-Autopilot

PX4 Autopilot Software
https://px4.io
BSD 3-Clause "New" or "Revised" License
8.33k stars 13.44k forks source link

Battery Estimation Problems #2 #2529

Closed orangelynx closed 8 years ago

orangelynx commented 9 years ago

Hi again,

after the recent fix for the battery voltage estimation https://github.com/PX4/Firmware/commit/9e223f0c268ff79436b5f4ce5673ffe1061c3cfe I did some more testing / research and came to the following conclusion:

It's one of the RC enthusiast's minor grievances that internal resistance of a LiPo battery is not directly linked the the load it is under but rather depends on battery cell temperature and other factors. Thus the voltage will not instantly drop when flipping the throttle stick up and will not instantly recover when throttle is removed.

Please have a look at the following measurement graph I did: bat_v vs bat_remaining vs throttle

As you can see, the voltage (blue) decreases constantly and smoothly as the load draws capacity and increasing cell temperature increases voltage drop. Battery capacity (red) follow correctly.

Suddenly reducing throttle (yellow) will make the code think that no voltage drop is present anymore and interpret the battery voltage as critical, starting the battery failsafe.

float bat_v_empty_dynamic = bat_v_empty - (bat_v_load_drop * throttle_normalized);
/* the range from full to empty is the same for batteries under load and without load,
 * since the voltage drop applies to both the full and empty state
 */
float voltage_range = (bat_v_full - bat_v_empty)
float remaining_voltage = (voltage - (bat_n_cells * bat_v_empty_dynamic)) / (bat_n_cells * voltage_range);

This behaviour obviously is not "correct" and we should think about a better solution. This isn't easy as - due to the complex internal resistance - the voltage drop can hardly be estimated correctly.

The fact that noone else has complained before on the other hand indicates that the voltage drop estimation only comes into play when using "badly suited" batteries with a high voltage drop under load.

My suggestion (until I can think of a better one :P) is to use a critical voltage limit that must not be crossed and rely on current measurement / integration instead (if available).

One could also consider a good old fashioned flight timer.

Thoughts please :)

LorenzMeier commented 9 years ago

You can use the current-based estimation which counts mAh and is already implemented (see here: https://github.com/mavlink/qgroundcontrol/pull/1703#issuecomment-118533142). I've also pushed a commit on beta which should help. More testing appreciated (with plots).

orangelynx commented 9 years ago

Hi Lorenz,

low-passing throttle is a good idea, didn't think of that! Will do some test to see how it performs. Anyway, your comment in the commit is spot on - smart batteries are in fact the best solution.

The implemented coulomb-counting mechanism works fine, however is no good if it gets bypassed by a prioritized (potentially flawed) remaining voltage estimation:

ret = fminf(remaining_voltage, 1.0f - discharged / bat_capacity);
LorenzMeier commented 9 years ago

My proposal would be to still do the voltage as lower bound, but with some time delay and hysteresis (e.g. only if lower for 15 seconds and only if lower more than 5% or at zero). How about you install the toolchain and get coding? It would be much, much faster that way for you.

orangelynx commented 9 years ago

In fact its already compiling^^. While we are on the topic, if I get the code right, the percentages at which battery warning and battery critical are triggered are hard-coded to 18% and 9% respectively. Some RC guys would consider this "too low". Although if one knows the algo and the parameters well, one can simply adjust the remaining parameters to fit one's needs but do you think it would make sense to make those two values configurable?

LorenzMeier commented 9 years ago

Yes, making them configurable makes sense I guess. @dogmaphobic is probably happy to add them to the UI.

dogmaphobic commented 9 years ago

All right. I trade with @orangelynx. I was setting up a test bench for measuring the true current consumption to see if the Pixhawk's current/voltage sensor is accurate. He can do that and I handle the UI :)

kd0aij commented 9 years ago

@orangelynx Great work! I had been wondering about the premature low batt warnings. @dogmaphobic My comparisons between recharge amp-hours and log data indicate the log is showing 75-85% of actual consumption.

dogmaphobic commented 9 years ago

That is, assuming there is a new parameter to set it. Right now the 18% and 9% are hardcoded. How do you want to handle this?

if (status.condition_battery_voltage_valid && status.battery_remaining < 0.18f && !low_battery_voltage_actions_done) {
} else if (!status.usb_connected && status.condition_battery_voltage_valid && status.battery_remaining < 0.09f
dogmaphobic commented 9 years ago

The fact that noone else has complained before on the other hand indicates that the voltage drop estimation only comes into play when using "badly suited" batteries with a high voltage drop under load.

I have! :)

orangelynx commented 9 years ago

@dogmaphobic I'd suggest to simply add parameters like BAT_LEVEL_WARNING and BAT_LEVEL_CRITICAL. I will dig through the code base to get to know it better and try to propose a commit.

As for voltage and current sensing, the readings are pretty decent by default, but one can always tweak the scaling parameters for each reading to improve them. There's also a saying that "one cannot measure voltage and current correctly at the same time" but that shouldn't be taken too seriously for real applications.

Only thing that might be worth analyzing is the low pass filtering of the voltage...

dogmaphobic commented 9 years ago

I'm just trying to understand. The code reads the ADC and makes some computation based on battery_amp_pervolt and battery_ampbias. Whatever that does, is the resulting _currenta supposed to be the measured current for that sample time? I'm just wondering because right now, the value (_currenta) is oscillating between 6 and 13, while the measured current is pretty steady at 380mA.

    /*
      ibatt contains the raw ADC count, as 12 bit ADC
      value, with full range being 3.3v
    */
    battery_status.current_a = ibatt * (3.3f / 4096.0f) * _battery_amp_per_volt;
    battery_status.current_a += _battery_amp_bias;
dogmaphobic commented 9 years ago

Never mind. That code is only for FMU V1...

dogmaphobic commented 9 years ago

Ok. I found the code:

float current = (buf_adc[i].am_data * _parameters.battery_current_scaling);

The question remains. Is this current meant to be the actual current in mA sampled at that point in time? If it is, the default scaling is completely off for me for some reason. This is the graph using a scale factor of 1.0 to show actual ADC values (it could also use a bit of filtering I guess):

screen shot 2015-07-04 at 4 08 24 pm

orangelynx commented 9 years ago

yep it's the current alright. Your graph however does look pretty weird... if the scale is in mA, then jumps that big over such short time definitely aren't normal. What powermodule / Flight Controller are you using? is this under load?

The scaling factor however won't fix this, its merely a constant that scaled the ADC measurement. My readings are much more stable (pixhawk + 3DR power module)

LorenzMeier commented 9 years ago

I think you want this commit, which is on beta and master: https://github.com/PX4/Firmware/commit/a74cc5bf494b05f48e796190d3ea3e43c849aa31

apart from that I would not be surprised by variance at low values, plus filtering is not making the estimate better - it can lead to aliasing. What you want to look at is the BATTERY_STATUS.current_consumed field. That should increment very steadily.

dogmaphobic commented 9 years ago

Indeed, it was obvious once you pointed it out. The load I was using was only 340mA, which is pretty close to bottom. I applied a constant 5A load and the reading stabilized but I had to use a factor of 0.1588 to get a proper conversion (as opposed to the current BAT_C_SCALING default, which is 0.0124). This is all before a74cc5bf494b05f48e796190d3ea3e43c849aa31. I will load the beta firmware and check. I now realize I am running master. I will check it again tomorrow...

orangelynx commented 9 years ago

I just went out to collect some real flight data and I'm now going to try to find a model that can accurately determine the voltage drop at the time. Most likely the model will be some combination of a low-pass modeling the thermal dissipation (increasing internal resistance) and a low-pass modeling thermal radiation (cooling) (decreasing internal resistance). Hard part will be simplifying the stuff to make it feasible calculating it live.

My guess is that it will be best to give the user a guide to calibrate the current sensor and then rely on coulomb counting and an additional critical voltage level defined by the user...

LorenzMeier commented 9 years ago

Yes. So you should be aiming with your model for two main objectives:

orangelynx commented 9 years ago

Okay one thing I realized by looking at real flight data: once the voltage drop has kicked in (cells have heated up), it won't really go away till the end of the mission. To actually give the battery sufficient time to recover, one would actually have to land.

Low passing throttle might not be the best idea after all. Battery Voltage drop under load originates from temperature, which originates from current. Current however doesn't directly have to be linked to throttle (e.g. a quadrocopter doing a turn will have higher current at same throttle i suppose).

For now I'd suggest letting the user set lower bounds directly in the groundstation, give them a guide to calibrate the current sensor and rely on colomb counting / the user configured lower bounds. I may have time to code a proposal tomorrow.

orangelynx commented 9 years ago

Okay, so here's my proposal. https://github.com/orangelynx/PX4-Firmware/commit/0d8b7150492fabeef37c47f4e1437b638f2c97cd

It's not tested yet, therefore I'll wait with the pull request. I just thought I'll post it here so you can get a first look at it. I will add a full list of changes and motivations into the pull request. Short version is:

orangelynx commented 9 years ago

just a quick update: I'm still on this. Had alot of wind lately so flight tests weren't always possible. The system seems to work fine, but I still want to verify the recorded data. Unfortunately, the px4logs can't be easily fed into matlab for analysis, so it might take a little while longer.

LorenzMeier commented 9 years ago

@orangelynx This export script for Matlab doesn't work for you? https://github.com/PX4/Firmware/tree/master/Tools/sdlog2

orangelynx commented 9 years ago

@LorenzMeier Oh right.. That will do. Good thing this script isn't mentioned on https://pixhawk.org/firmware/apps/sdlog2 :tired_face:

Thanks though :+1:

kd0aij commented 9 years ago

you can lead a horse to water... :)

orangelynx commented 9 years ago

Hm seems like the py script has trouble converting the px4log. FlightPlot hat no problems but then again is too limited for proper data analysis. Can someone confirm the current version of the py script is working? I'm getting an invalid header exception.

This is the log in question: https://www.dropbox.com/s/5nwtu2mg3t9eb0w/17_29_09.px4log?dl=0

kd0aij commented 9 years ago

I get a header error on your log also. Works on my recent logs though.

On Wed, Jul 15, 2015 at 1:28 PM, orangelynx notifications@github.com wrote:

Hm seems like the py script has trouble converting the px4log. FlightPlot hat no problems but then again is too limited for proper data analysis. Can someone confirm the current version of the py script is working? I'm getting an invalid header exception.

This is the log in question: https://www.dropbox.com/s/5nwtu2mg3t9eb0w/17_29_09.px4log?dl=0

— Reply to this email directly or view it on GitHub https://github.com/PX4/Firmware/issues/2529#issuecomment-121721165.

Mark Whitehorn kd0aij@gmail.com

orangelynx commented 9 years ago

I can work around the error using the -e option, however this causes the logconv.m MATLAB script to throw errors, because the generated CVS file is missing the TIME field. This MIGHT be because I may have flown without GPS lock (can't remember...) so I'm going to create new logs tomorrow and hopefully those will work.

orangelynx commented 9 years ago

Please see https://github.com/PX4/Firmware/pull/2591