Skip to content

fix(development): BATTERY_STATUS_V2 proposed changes - #2471

Closed
hamishwillee wants to merge 1 commit into
masterfrom
hamishwillee-dev-bat-stat2-soc
Closed

fix(development): BATTERY_STATUS_V2 proposed changes#2471
hamishwillee wants to merge 1 commit into
masterfrom
hamishwillee-dev-bat-stat2-soc

Conversation

@hamishwillee

@hamishwillee hamishwillee commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

This proposes updates for discussion in BATTERY_STATUS_V2 following review of first implementation by @MaEtUgR in PX4/PX4-Autopilot#25347 (review)

  • Do we need critical/emergency/warning status flags.

See comments inline for discussion start points. There are no live implementations so we can still udpate if we want.

@peterbarker @auturgy Can you suggest who in ArduPilot might like to comment. FWIW I tend to think if SoC is a standard term we should use it. Rest need more discussion.

Note

The action "Propose replace percent_remaining with industry standard SoC" was agreed and merged in #2503

Comment thread message_definitions/v1.0/development.xml Outdated
Comment thread message_definitions/v1.0/development.xml
@hamishwillee

hamishwillee commented May 4, 2026

Copy link
Copy Markdown
Contributor Author

@hendjoshsr71 I was wondering if you would like to comment on the proposed changes to BATTERY_STATUS_V2. I am inclined to accept them - in particular state-of-charge instead of battery remaining as it does appear more industry standard.

<field type="int16_t" name="temperature" units="cdegC" invalid="INT16_MAX">Temperature of the whole battery pack (not internal electronics). INT16_MAX field not provided.</field>
<field type="float" name="voltage" units="V" invalid="NaN">Battery voltage (total). NaN: field not provided.</field>
<field type="float" name="current" units="A" invalid="NaN">Battery current (through all cells/loads). Positive value when discharging and negative if charging. NaN: field not provided.</field>
<field type="float" name="capacity_consumed" units="Ah" invalid="NaN">Consumed charge. NaN: field not provided. This is either the consumption since power-on or since the battery was full, depending on the value of MAV_BATTERY_STATUS_FLAGS_CAPACITY_RELATIVE_TO_FULL.</field>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I should propose SI unit for energy Wh such that we can disucss that as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hendjoshsr71 Thoughts on this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO common convention > SI units. Every battery is labelled with Ah.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of SI vs common convention has been an argument that has gone back and forth over the years. I prefer common conventions in most cases because as presentation values they are are more intuitive to users, and thereby avoid a conversion. Similarly, I prefer SI values if to use them you will likely have a conversion to the SI value anyway.

I have a slight leaning towards Wh as a measure as it is independent of voltage and battery chemistry.
I'm not sure it matters though - for display user only care about the % left or the available flight time. If you're using a particular vehicle it is likely the same battery will be used all the time, so if you were to look at the value you'd become familar with Ah or Wh that was shown to you.

If there is a technical reason why it is better as Wh in real scenarios then we should switch.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional:
In case you want opinions from the crowd, I like this as-is (capacity_consumed, Ah, Charge consumed). I'd even prefer in the description "time-integral of measured current" but that might be too mathy for average users. As-written, I concluded that's what's meant. (In case that conclusion is wrong, that might prompt further consideration.)

IMO if you switch to Wh, should also rename like "energy_consumed". And description 'Consumed charge' isn't quite right, but I would be ok with it as a known abuse of terminology.

By "optional" I mean that I don't expect response nor changes. Use or ignore my input as best suits you! And keep up the great work.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with calculating useable Wh remaining is that it heavily depends on voltage curve and system losses.
Power consumption based prediction is the most accurate but requires battery resistance curve and system losses to be known Wh

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LupusTheCanine You do not need any internal resistance nor voltage curve, you only need the instantaneous voltage with every current measurement when you integrate which any battery monitoring provides hence the voltage field in this message.

Unit SI unit for Integral of "Advantage" Real world
Wh energy ∫ current * voltage * dt Correlates to actual flight time and hence % Requires voltage measurement
Ah electric charge ∫ current * dt Inaccurately assuming constant voltage Battery marketing, label, common hobby lingo

I don't see how integrating voltage * current is more complicated than just current. Just one more multiplication to get the quanity you actually care about. I assume it has more to do with RC hobby battery marketing, popularity or complexity?

Every battery is labelled with Ah.

@dakejahl Along with a nominal voltage and Energy (Wh) = Electric charge (Ah) * Nominal voltage (V)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • It's not SI vs hobby lingo. Ah is a scaled coulomb (1 Ah = 3600 C), and the coulomb is as SI as the joule. The real question is which quantity to carry: charge or energy.

  • Ah doesn't "assume constant voltage." ∫ I·dt assumes nothing about voltage — it's a direct measurement of a (nearly) conserved quantity.

  • You can only integrate the past. Consumed energy is exact, but capacity_remaining is a claim about the future. Remaining Wh depends on the future load profile (I²R loss: harder flying = fewer Wh delivered), so it needs exactly the resistance curve @LupusTheCanine described. Remaining Ah is just full_charge_capacity − consumed and is nearly rate-invariant for Li chemistries.

  • This is why fuel gauges coulomb-count — including the Impedance Track BQ parts — and why SoC (the industry term adopted in this message) is defined as a charge ratio. The energy ratio is a different, load-dependent quantity (SoE).

  • Wh = Ah × nominal V is exactly the constant-voltage assumption your table criticizes. The real exchange rate is E/Q — the current-weighted average voltage of that particular discharge — which runs ~4.1 V/cell over the first 20% of charge, ~3.4 V over the last 20%, and drops another 5–9% under hard load (I·R sag). A fixed scalar is ±10% in practice. So pick one: if ±10% is acceptable, Ah carries the same information and the table's case against it evaporates; if it isn't, every consumer with mAh-denominated config (BATT_CAPACITY, failsafe thresholds, the pack label) must compute Ah = Wh ÷ V with no correct V to use — the true value is inside an integral only the producer saw. Carrying Wh doesn't eliminate the conversion error, it relocates it from the one node that can integrate exactly into every consumer.

  • Conversion cost is asymmetric. Capacity params, failsafe thresholds, labels, and pack-health checks are all mAh. Ah on the wire: nobody converts. Wh on the wire: producer does one exact multiply, every consumer does a lossy divide by an ill-defined voltage.

Sorry to hit you with the AI analysis 😆 I'm just not convinced Wh is better because W is not what is being measured.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced either. I think the arguments here are pretty compelling to stick with Ah as "actually reflecting what we're measuring".

Can I consider this resolved?>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_> @LupusTheCanine You do not need any internal resistance nor voltage curve, you only need the instantaneous voltage with every current measurement when you integrate which any battery monitoring provides hence the voltage field in this message.

Unit SI unit for Integral of "Advantage" Real world
Wh energy ∫ current * voltage * dt Correlates to actual flight time and hence % Requires voltage measurement
Ah electric charge ∫ current * dt Inaccurately assuming constant voltage Battery marketing, label, common hobby lingo
I don't see how integrating voltage * current is more complicated than just current. Just one more multiplication to get the quanity you actually care about. I assume it has more to do with RC hobby battery marketing, popularity or complexity?

Integrating current times voltage over time is about as simple as current alone, the problem is lack of fixed reference energy capacity.

Imagine magic battery that has 10Ah/100Wh@20°C capacity, always outputs 10V+0.01V/K OC and has internal resistance of 0.1ohm.
If I dischrge it at 10A and 20°C I get 90Wh out of the battery (10Wh go to battery losses), if instead dischgarge at 20A I would only get 80Wh out with 20Wh going to battery losses). If we go back to 10A but drop the temperature to 0°C I would only get 88Wh with 10Wh going to losses, if my resistance was temperature dependent I could get something like 84Wh with 14Wh going to losses.

What should the "full energy" be for the above battery?
100Wh, 90Wh, 80Wh or 88Wh?

Accurately predicting energy remaining requires simulating discharge which requires at a minimum OCV vs SOC curve at given battery condition if we assume that enery remaining includes what will be lost inside the battery.

Comment thread message_definitions/v1.0/development.xml Outdated
<field type="float" name="capacity_consumed" units="Ah" invalid="NaN">Consumed charge. NaN: field not provided. This is either the consumption since power-on or since the battery was full, depending on the value of MAV_BATTERY_STATUS_FLAGS_CAPACITY_RELATIVE_TO_FULL.</field>
<field type="float" name="capacity_remaining" units="Ah" invalid="NaN">Remaining charge (until empty). NaN: field not provided. Note: If MAV_BATTERY_STATUS_FLAGS_CAPACITY_RELATIVE_TO_FULL is unset, this value is based on the assumption the battery was full when the system was powered.</field>
<field type="uint8_t" name="percent_remaining" units="%" invalid="UINT8_MAX">Remaining battery energy. Values: [0-100], UINT8_MAX: field not provided.</field>
<field type="float" name="state_of_charge" units="%" invalid="NaN">State of Charge (SoC). Remaining capacity relative to current maximum capacity as a percentage (designed max capacity can be used if current max capacity is not known). Values: [0-100], NaN: field not provided.</field>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, float for consistency, and considered useful for very large batteries.

@LupusTheCanine LupusTheCanine Jun 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want to keep this message small, uint16_t is perfectly adequate for reporting SoC to FC and GCS as it gives 1 step per second for 18 hours discharge, for GCS even 12 bits would have been fine (1 step per second on 1h discharge).

The big problem is that we are designing a message that is intended for onboard and offboard communication at the same time. Ideally OTA battery status consists of temperature, voltage, current and SoC. Sending mAh consumed and remaining is redundant as they can be reconstructed from data that can be transmitted at much lower rate in BATTERY_INFO type message.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The big problem is that we are designing a message that is intended for onboard and offboard communication at the same time

MAVLink really should not be used for onboard comms, we need to get away from this use-case as fast as possible. That's why DDS and Zenoh exist, MAVLink should serve as the GCS link protocol first-class.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MaEtUgR view on this field

State of charge industry term for %, remaining battery, definitely the most interesting for all types of reports. I highly suggested the rename (standard) and asked to consider a more granular representation than 100 steps, float might be overkill but if we're using uint16 I'd define 10'000 as 100%. The reason is to allow more continuous display. On an accurate smart battery with slow discharge using 1% could take multiple minutes even in flight.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upshot, if this can be a unit16 and provide the needed resolution, then sure.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAVLink really should not be used for onboard comms, we need to get away from this use-case as fast as possible. That's why DDS and Zenoh exist, MAVLink should serve as the GCS link protocol first-class.

@dakejahl that would be great but unless the protocol can coexist on the same physical port with MAVLink it will be PITA to do. Not to mention all the "legacy" hardware that isn't going anywhere.

@LupusTheCanine LupusTheCanine Jun 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAVLink really should not be used for onboard comms, we need to get away from this use-case as fast as possible. That's why DDS and Zenoh exist, MAVLink should serve as the GCS link protocol first-class.

@dakejahl that would be great but unless the protocol can coexist on the same physical port with MAVLink it will be PITA to do. Not to mention all the "legacy" hardware that isn't going anywhere.

@MaEtUgR we are paying for the whole uint16, we should use the whole uint16, or at least close to it (eg. 1-50001) with 0 meaning not available.

PS: I mean't 50001 not 5001 😅.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no practical need for that level of accuracty it is easier for people to scale if we use a factor of 100.

@hamishwillee
hamishwillee force-pushed the hamishwillee-dev-bat-stat2-soc branch from 6da1cb7 to 380ec7a Compare May 27, 2026 06:26
@peterbarker

peterbarker commented Jun 13, 2026 via email

Copy link
Copy Markdown
Contributor

@peterbarker

Copy link
Copy Markdown
Contributor

So the only thing the GCS display really cares about (IMO) is the SoC and an estimate of flight time remaining.

Speaking with @hunt0r I suggested eliminating the other capacity remaining fields IIRC.

Hunt0r is currently reworking his ArduPilot implementation of this message, so we'll both be a bit more informed in a little while.

@hamishwillee

Copy link
Copy Markdown
Contributor Author

This #2526 implements the agreed changes from here - removing the capacity fields and scaling the SoC. We discussed in the dev call, and it would be better to have a separate message for conveying the system power status - with time_remaining, percentage remaining, and warning levels - rather than using this message for that purpose.

The main reasons being that we don't want to add time to this message or the warning levels, or constrain our fuel type to battery.

I'm closing this, because I think all the open issues have been addressed by that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants