Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Smart_Battery_Info MAVLink message #16167

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

hendjoshsr71
Copy link
Member

@hendjoshsr71 hendjoshsr71 commented Dec 30, 2020

This adds the MAVLink message 370 SMART_BATTERY_INFO to send serial number, cycles, capacity, product name, etc.

PR to add the message to ArduPilot/mavlink here: ArduPilot/mavlink#181
One small documentation change on the MAVLink side here: mavlink/mavlink#1551

serial_number: I wasn't sure the best way/place to deal with the conversion from int32_t  to char[16].
AP_BattMonitor.h: get_serial_number()  that is used by AP_BattMonitor_UAVCAN.h not sure how to combine this together and limit the extra functions

SIM_BattMonitor_SMBus.cpp Issue: The method to fill the registers for manufacturer_name and device_name causes the data from device name to write over all but the first char of the manufacturer_name.  (Fixed here #16228)

@amilcarlucas
Copy link
Contributor

The message is marked as "work-in-progress". Is it a good idea to bring it in? I do like your changes though.

Copy link
Contributor

@peterbarker peterbarker left a comment

Choose a reason for hiding this comment

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

I love the addition to the simulated battery.

There might be some push-back on having the method returning a string for the serial number. We'll see.

@magicrub you might be interested in options to pass more CAN battery information back to the GCS with this message.

This looks pretty good, really.

libraries/AP_BattMonitor/AP_BattMonitor.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_Backend.h Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_Backend.h Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus.h Outdated Show resolved Hide resolved
libraries/GCS_MAVLink/GCS_Common.cpp Outdated Show resolved Hide resolved
libraries/GCS_MAVLink/GCS_Common.cpp Outdated Show resolved Hide resolved
libraries/GCS_MAVLink/GCS_Common.cpp Outdated Show resolved Hide resolved
Comment on lines 4511 to 5089
for(uint8_t i = 0; i < battery.num_instances(); i++) {
if (battery.get_type(i) != AP_BattMonitor::Type::NONE) {
CHECK_PAYLOAD_SIZE(SMART_BATTERY_INFO);
send_smart_battery_info(i);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

@WickedShell has grown to dislike this pattern, preferring to keep some state around indicating the last instance we successfully sent.

Copy link
Member Author

Choose a reason for hiding this comment

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

The pattern for the other battery message like you describe has to be modified with the comment below due to where I have the message being sent from. Suggestions?

for(uint8_t i = 0; i < battery.num_instances(); i++) {
    const uint8_t battery_id = (last_smart_battery_info_idx + 1) % AP_BATT_MONITOR_MAX_INSTANCES;
    if (battery.get_type(battery_id) != AP_BattMonitor::Type::NONE) {
        CHECK_PAYLOAD_SIZE(SMART_BATTERY_INFO);
        send_smart_battery_info(battery_id);
        last_smart_battery_info_idx = battery_id;
        //return true;
    } else {
        last_smart_battery_info_idx = battery_id;
    }
}
return true;

Copy link
Contributor

@peterbarker peterbarker left a comment

Choose a reason for hiding this comment

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

I'm going to mark this for discussion at the European DevCall. I want more people to chime in on the send-as-part-of-banner thing.

libraries/AP_BattMonitor/AP_BattMonitor.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus.cpp Outdated Show resolved Hide resolved
libraries/GCS_MAVLink/GCS_Common.cpp Outdated Show resolved Hide resolved
@peterbarker
Copy link
Contributor

@hendjoshsr71 let me know if you'd like me to rebase this on the changes I've just made to the simulated-smbus stuff - it obviously conflicted. I think the commit in your list here can just be removed.

@hendjoshsr71
Copy link
Member Author

I got it. Thanks for the update! Adding in capacity and other fields to the sim and will reupload once working.

@hendjoshsr71
Copy link
Member Author

Added design capacity and few more items to SITL_SMBus model

@amilcarlucas
Copy link
Contributor

This needs a rebase

@hendjoshsr71 hendjoshsr71 force-pushed the smart_batt_mavlink branch 2 times, most recently from efaab7e to d901a36 Compare March 2, 2021 21:09
@hendjoshsr71
Copy link
Member Author

Rebase complete.

Copy link
Contributor

@peterbarker peterbarker left a comment

Choose a reason for hiding this comment

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

Once this is merged we should send a message to the gcs-maintainers mailing list letting them know that they can request the message...

@WickedShell you're going to want to be happy with this before merge, I think?

libraries/AP_BattMonitor/AP_BattMonitor.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus.h Outdated Show resolved Hide resolved
@hendjoshsr71
Copy link
Member Author

Thanks @peterbarker for the all the reviews!!

Moved the SMBUS stuff to the backends.
Moved the logging of the BATI message to the new AP_BattMonito_Logging.cpp file
Fixed hopefully all the trailing whitespaces...

@peterbarker
Copy link
Contributor

peterbarker commented Mar 15, 2021 via email

@hendjoshsr71
Copy link
Member Author

On Mon, 15 Mar 2021, Josh Henderson wrote: Used, for the snprintf's in the serial number, product, device, and manufacturer name functions
In the header?

Ahh I think I see your point it should be in the `AP_BattMonitor_SMBus.cpp' instead?

@hendjoshsr71 hendjoshsr71 force-pushed the smart_batt_mavlink branch 2 times, most recently from c45751c to fc3bc5d Compare March 15, 2021 21:54
@hendjoshsr71
Copy link
Member Author

Changed the capacity functions to int32_t as smbus spec of uint16 doesn't leave much room at 65,536 mAh
Still need to handle the strncpy truncation warnings
Could add manufactured date?

Copy link
Contributor

@tridge tridge left a comment

Choose a reason for hiding this comment

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

i think we need to use HAL_MINIMIZE_FEATURES for this feature, to prevent the flash and ram cost for small boards with 1M flash

libraries/AP_BattMonitor/AP_BattMonitor_SMBus.h Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus.h Outdated Show resolved Hide resolved
libraries/SITL/SIM_BattMonitor_SMBus.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_Logging.cpp Outdated Show resolved Hide resolved
@tridge
Copy link
Contributor

tridge commented Jun 29, 2021

added DelayMerge for delay after final rebase for 4.1.0

@hendjoshsr71 hendjoshsr71 force-pushed the smart_batt_mavlink branch 2 times, most recently from 1875af3 to ce802c4 Compare June 30, 2021 06:13
Copy link
Member Author

@hendjoshsr71 hendjoshsr71 left a comment

Choose a reason for hiding this comment

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

Fixed the GCS_send so that false only gets returned if there is no space on the link.

Tested with 2 analog battmons, 1 smbus_generic, 1 rotoye, and 1 maxell. That logging and mavlink send works with my mavproxy submodule

Tested with SMART_BATTERY_INFO disabled and checked logs such that all makes sense for given monitor type.

@amilcarlucas
Copy link
Contributor

This requires 2440 bytes on Durandal (arducopter)

Copy link
Contributor

@WickedShell WickedShell left a comment

Choose a reason for hiding this comment

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

Some nitpicks. I didn't have time to fully tell but the initialization bit still looks worrisome to me, as I'm not seeing a path where we don't try and spend a ton of I2C bandwidth talking to batteries that aren't there....

logger->Write_Power();

#if HAL_SMART_BATTERY_INFO_ENABLED
// Check if the log_count has changed as logging can open/close at anytime
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be moved down into the other #if check below? It would help keep the ideas closer together and make the file more readable

Copy link
Member Author

Choose a reason for hiding this comment

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

I moved it, but now it all gets called inside the loop more times than necessary on each read cycle.

#endif

for (uint8_t i=0; i<_num_instances; i++) {
if (drivers[i] == nullptr || get_type(i) == Type::NONE) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's remove the check for type being none. Changing type already needs a restart, and it helps save some flash cost. (Unless there's a different/better reason I'm missing here?)

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed. What about L298 below? I think I've missed the point of checking Type::NONE that was here before this PR.

for (uint8_t i=0; i<_num_instances; i++) {
        if (drivers[i] != nullptr && get_type(i) != Type::NONE) {
            drivers[i]->read();
            drivers[i]->update_resistance_estimate();
        }
    }

libraries/AP_BattMonitor/AP_BattMonitor_Logging.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_Backend.h Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus.h Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus_Generic.cpp Outdated Show resolved Hide resolved
const uint8_t read_size = bufflen + 1 + (_pec_supported ? 1 : 0);
uint8_t buff[read_size];
// check cell count
if (_state.healthy) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Unless I've missed something healthy isn't actual true initially, and it's normally toggled by the polling loop. Why are we looking at it at all inside of the initialization block?

Especially since this is called repeatedly during polling until the initialized flag (which can only be set by entering here) doesn't this mean we might repeatedly poll for all the smart battery info for ever on a non healthy battery and massively bring down the I2C bus by accident?

Copy link
Member Author

Choose a reason for hiding this comment

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

We would only continue to poll for smart battery info. that hasn't already been successfully read, but...

I think your right about pulling it down due to the possible delays in SMBus. The crux of the issue is the termination condition & its placement for reading these registers. I've added a separate timer for reading info register termination.

However, guidance on the appropriate termination condition for reading the info. registers would be appreciated.

  • Use a timeout?
  • for each called register only allow one attempt to read
  • only call initialize() Z number of times

If I brought back all of the bool returns from the read_zz() I could OR those and return before timeout as well? (But that costs flash.)

The // check cell count section of code appears to be an initialization task to set _cell_count_fixed. I was trying to pull out initialization tasks into here. For now I'm going to put this block back and leave getting that into here for another day.

Copy link
Member Author

Choose a reason for hiding this comment

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

I really wish there was way to run these initialization type tasks first on the bus before registering the timer()

Copy link
Member Author

@hendjoshsr71 hendjoshsr71 left a comment

Choose a reason for hiding this comment

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

@WickedShell Addressed most of your comments. But I have left a question or two about the termination condition for the initialization function.

logger->Write_Power();

#if HAL_SMART_BATTERY_INFO_ENABLED
// Check if the log_count has changed as logging can open/close at anytime
Copy link
Member Author

Choose a reason for hiding this comment

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

I moved it, but now it all gets called inside the loop more times than necessary on each read cycle.

#endif

for (uint8_t i=0; i<_num_instances; i++) {
if (drivers[i] == nullptr || get_type(i) == Type::NONE) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Removed. What about L298 below? I think I've missed the point of checking Type::NONE that was here before this PR.

for (uint8_t i=0; i<_num_instances; i++) {
        if (drivers[i] != nullptr && get_type(i) != Type::NONE) {
            drivers[i]->read();
            drivers[i]->update_resistance_estimate();
        }
    }

libraries/AP_BattMonitor/AP_BattMonitor_Backend.h Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus.cpp Outdated Show resolved Hide resolved
libraries/AP_BattMonitor/AP_BattMonitor_SMBus.cpp Outdated Show resolved Hide resolved
const uint8_t read_size = bufflen + 1 + (_pec_supported ? 1 : 0);
uint8_t buff[read_size];
// check cell count
if (_state.healthy) {
Copy link
Member Author

Choose a reason for hiding this comment

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

We would only continue to poll for smart battery info. that hasn't already been successfully read, but...

I think your right about pulling it down due to the possible delays in SMBus. The crux of the issue is the termination condition & its placement for reading these registers. I've added a separate timer for reading info register termination.

However, guidance on the appropriate termination condition for reading the info. registers would be appreciated.

  • Use a timeout?
  • for each called register only allow one attempt to read
  • only call initialize() Z number of times

If I brought back all of the bool returns from the read_zz() I could OR those and return before timeout as well? (But that costs flash.)

The // check cell count section of code appears to be an initialization task to set _cell_count_fixed. I was trying to pull out initialization tasks into here. For now I'm going to put this block back and leave getting that into here for another day.

const uint8_t read_size = bufflen + 1 + (_pec_supported ? 1 : 0);
uint8_t buff[read_size];
// check cell count
if (_state.healthy) {
Copy link
Member Author

Choose a reason for hiding this comment

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

I really wish there was way to run these initialization type tasks first on the bus before registering the timer()

@hendjoshsr71
Copy link
Member Author

Rebased due to #if HAL_GCS_ENABLED change

@hendjoshsr71 hendjoshsr71 force-pushed the smart_batt_mavlink branch 2 times, most recently from 2f23d42 to ed01ef5 Compare November 17, 2021 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants