Servers by jDrones

Creation of New AP_BattMonitor Library for MODBUS-connected BMS

A new ‘question’ of sorts, but more of a probe into community interest.

The location of this post may be incorrect, and so please inform me if this is better suited to a GitHub issues post (I see feature requests there occasionally). In addition, the Plane category seems rather an odd location - if there’s a category for libraries or features that I glossed over, I will move this elsewhere.

I am interested in integrating a communication-enabled Battery Management System (BMS) with an airframe power system. The BMS in question is commercially available, manufactured by Energus Power Solutions: the Tiny BMS s516. It can handle my power requirements with plenty of overhead, and has the necessary features (balancing, charge control, alarms) and - most critically - digital monitoring. The BMS is fully configurable by provided software - so, while it is not open source, the basic amenities to utilize it are provided, and the necessary commands to interact with it are specified.

The interface offered by the BMS is a simple UART header, which serves as a carrier for a partial MODBUS implementation (only the software level is MODBUS, physical layer is regular UART).
I see that in some way, shape, or form the Ardupilot code base has brushed up against MODBUS in the past, per this repository. So, given an available MODBUS- compatible command set, it is a single call away from getting all the registers of the BMS (cell voltages, total pack voltage, state of charge, current, temperature(s), faults, etc). The full datasheet of the BMS can be found on the page above, or here.

Naturally, such a library/driver would most at home in the AP_BattMonitor family, functioning much like the SMBUS, Maxell, and Solo battery drivers which support similar levels of battery monitoring.

Given the somewhat costly nature of the BMS, I don’t expect many to ‘embrace’ the feature on the scale of SMBUS-enabled batteries, and so I am certainly willing to be the only one putting time into the creation of the feature. That said . . . I actually have no idea where to start. My interactions with the ArduPilot code base until now have been limited to simple modifications here and there, never having to toy with the overarching structure of the thing. In fact, my strongest languages are in Python, Java, and MATLAB (say what one will), and so I am starting at square 1.5 for C code that does more than loop mindlessly as an Arduino sketch. I say 1.5, as I am currently taking a real-time systems course that is heavily C-focused, though with vxworks as an RTOS.

What I’m asking here, is if someone is interested in this idea, and if they are willing to direct me on the proper development path for understanding the code base, the Ardupilot coding practices, and how best to integrate with the AP_BattMonitor and AP_SerialManager family, implementing the (I assume derelict) MODBUS library. Do things need to change for the up-and-coming ChibiOS transition? Is this too resource-intensive for a firmware nearing the 1MB flash limit? There are many things I don’t know about charging headlong into adding a new feature, and I’m afraid of stepping on others’ toes.

I have another option worth mentioning, which is the usage of a little 32u4-based microcontroller to fetch data from the BMS using the Arduino (. . .) MODBUS library, and effectively ‘faking’ a battery supporting SBS (Smart Battery Specification) by taking advantage of the pre-existing Maxell and Solo battery drivers. That said, I’ve spent the past couple days poking around forums, and I’m finding a lot of uncertainty regarding the usage of Arduino’s Wire library in an SMBUS environment. Evidently not many have successfully attempted to mimic SBS with Arduino as a starting point. Additionally (and more critically), it adds to the number of failure modes by adding hardware and software. As such, I first brought up the native MODBUS option, directly integrated with ArduPilot.

1 Like

Hi Evan,

I’d be happy to help point you along the way with implementing a modbus backend to AP_BattMonitor. (I’m maintaining the offical maintainer of the SMBus backends, and probably the defacto battery monitor maintainer since I’ve been reworking it heavily recently). It’s probably not a BMS I will using in my vehicles, but it does look quite reasonable at first glance, and should provide a more off the shelf way for people to get into smart batteries. I’ll check around to make sure I’m not the only one who thinks that though.

As far as the 1MB limit what we usually do with features like that we would stick them behind the HAL_MINIMIZE_FEATURES define. This causes the feature to be excluded from a PX4FMUv2 (or other low memory/storage hardware), but includes the feature in FMUv3 (which you can use on a Pixhawk1 if it has a processor that doesn’t suffer the 1MB bug), and other builds.

The ChibiOS change shouldn’t cause you any pain with this feature. Libraries like AP_BattMonitor rarely interact with the RTOS at that level. Instead they interact with our HAL (Hardware Abstraction Layer) which means that provided we do our job correctly with the RTOS support for the HAL should allow the libraries to work without any issues. (For example we didn’t have to make any changes to the GPS library for ChibiOS to work with all of our supported GPS units).

The PX4Nuttx layer is on the way out however, but it’s also not the best way to implement drivers either, as it ties it to PX4 based boards only, and excludes it from Linux users, or future boards. Instead drivers are developed directly within the ArduPilot libraries and then work on all supported boards through the HAL. So this does mean you will be developing the driver from scratch, although it doesn’t look to difficult. (Although I don’t see any documentation on what they are using for a CRC protocol, so that will have to be found)

As you identified you would need to add a new protocol to the list in SerialManager, which should be straightforward. Then a driver in AP_BattMonitor is needed. This will actually look a lot like a combination of existing battery drivers, and GPS drivers (since these are actually reading/writing from UART’s).

If I haven’t scared you off, I’m happy to continue in more detail down this road and as you encounter issues. I’m going to move this to the Development Team category, rather then leaving it in the Plane section.

They also seam to support CAN at the physical level.

1 Like


From my understanding, they support a physical CAN interface by means of an adapter/interface: an external unit, linked to the same UART mentioned prior. I do generally prefer CAN as an interface to standardize upon, as it has considerable electrical benefits in spite of its additional complexity.

The reason I highlighted the plain UART is two-fold:

  1. The UART is native to the BMS. The CAN adapter adds hardware and software (assumption) layers which will introduce new failure modes.
  2. The CAN interface presented by the adapter has an as-of-yet unknown top-level protocol, which is most certainly not UAVCAN - the protocol supported natively by ArduPilot. Support for other layer types has been proposed (such as SAEJ1939, an automotive standard) but has garnered limited interest. Developing for CAN also seems a more arduous task, compared to something so ubiquitous as UART.

I look forward to battery monitors utilizing UAVCAN, the likes of which have been developed and prototyped by OlliW, though the current implementation of the UAVCAN batteryinfo message does not seem to have the same level of feature support (thorough battery faults, lifecycle status, cell voltages, etc). I would like to see an extension to a full SBS 1.1/2.0 -esque implementation, but I have neither the experience nor the knowledge to dig into that - I have even less an inclination to bug existing developers for such niche features.


I’ve spent the past few days getting up to speed on the different elements required to make this work.

I’ve found that a better approach to MODBUS support may be to start from the Arduino library I’ll be using for initial testing of the BMS. It is full-featured, Apache 2.0 licensed, and appears to be of good quality. If I can get the Arduino hardware working with the BMS (I’ll have one to work with in short order), I (naively) expect that some revisions to meet coding specifications and types would bring the library to a compatible state with ArduPilot - I anticipate the difficult part will be hooking into the HAL UART driver.

On that note, I’m still trying to understand the SerialManager organization and what features I need to specify (it seems to vary widely - from nothing (GPS) to very specific (Volz servo protocol)). The actual serial implementation appears to consist of simple calls to AP_HAL and UARTDriver (once configured properly per SerialManager?). Little needs to be done actively by the library, as each read of the BMS state is atomic.

For the moment, I will focus on the MODBUS implementation, waiting to work on the tie-in with AP_BatteryMonitor until I am confident in the underlying features. This will allow me to get a rough implementation working quickly (using Arduino to hack things together), leaving more time for formal work.

@Evan110011 You are of course free to pursue whatever direction you want on getting it going (and having a working reference implementation is always very useful). I’ve only briefly skimmed through it at the moment, but it doesn’t appear to be behaving the way you would want to write the driver for usage on ArduPilot (mainly it seems to be blocking when requesting registers, which will need to be avoided in the ArduPilot side). The workaround to this is what you see GPS drivers do, in their 50Hz read task (typically 10Hz for batteries), they fire off one or more requests for a register/data on the outgoing buffer, and parse any data that was available on the incoming stream. (A bit of timer/progress logic is needed to check if a request got lost, although on Smart batteries this tends to be much easier to recover from, as the BMS is doing the current integration for you).

You will have probably noted that the SmartBattery drivers are not doing this type of fire and forget reading of data. This is due to the fact that they run on a dedicated I2C thread which while waiting for data off the bus allows other threads to be running.

On the SerialManager side I think behaving like the GPS style is absolutely fine. The GPS library has a tendency to manage baud rates itself later, but it will work with the baud rate specified by the serial parameters as well.

Let me know how it goes!

Any progress on this @Evan110011 ?

Servers by jDrones