Inav: Open Battery Data Link (help!)

Created on 23 Oct 2017  路  21Comments  路  Source: iNavFlight/inav

Hello. I'm trying to create a new type of battery sensor that can provide more detailed information about the batteries on an UAV. It's called Open Battery Data Link. I already have a working prototype and now I want to integrate it to INAV, but I'm having hard time doing it.

On the RCGroups Thread stronnag recommended me to use UAV Interconnect Bus to do the communication with Flight Controller. I spent some hours trying to figure out how to do it until I reach a point that I'm starting to rethink my computer programmer career. I just can't understand it.

So, the question is: Is there an example of some implementation of this UAV Interconnect Bus? As I could figure out, it is a way to connect more than one device to the same UART port. I never saw this until this weekend... I just use one UART for each device (GPS on UART1, SBUS on UART2, etc).

There's really necessary to implement new hardware using this specification? I really want to do it the right way, because I plan this to become a standard in RC autopilot community.

Inactive

Most helpful comment

I've reached out to BattGo - if they will cooperate we'll be able to use smart batteries with INAV.

All 21 comments

I would actually suggest using the I2C protocol instead. Since you're using an Arduino-based microcontroller, you can easily communicate over an I2C bus with existing mature libraries. As long as the I2C ID is different, you could attach many modules without conflict. Also, you could share the port with (for example) an existing magnatometer and/or barometer without a problem (as long as the IDs are different of course).

Thanks for replying @teckel12 , I guess I2C will be easier to do, but as little I could read about it, there's some reliability issues... If somehow I disconnect one device from I2C bus, the entire bus will stop working until reboot. Is that right?
Since battery information is not crucial to keep UAV flying, I'll feel more confident if I can just disconnect my battery sensor and FC still works... Just like disconnecting GPS or RX midflight (and these are far more important than a simple battery sensor).

I don't know about the disconnect, I would think the connection would be made before booting anyway, and it wouldn't disconnect mid-flight would it?

Also, the problem with using a UART is that no one has any UARTs available. Most people want to add more things (telemetry, GPS, VTX channel control, ESC out, etc. but can't). I don't think the interconnect bus allows you to share an already used UART. All devices that share the UART would need to adhere to the same protocol.

Basically, I think I2C is your only option. For example, I would try your battery meter if it was on I2C but couldn't if it used a UART as I have none available. That's typical for 99% of the models out there.

I do not recommend using I2C at all. It's very unreliable if not designed correctly on the FCs (a vary rare case lately).

@danarrib Heed digitalentity's warning. If I were you I would make it work via standardrd serial for testing (super easy with Arduino). Then convert to the interconnect protocol once you got everything working.

Given the popularity of iSDT chargers, there is speculation if BattGo will take off. Regardless, their "development board" looks like it's a very small device. Couldn't hurt to reach out to them for a dev kit to poke at it and see if the heavy lifting parts had already been done: http://www.battgo.org

I've reached out to BattGo - if they will cooperate we'll be able to use smart batteries with INAV.

Ok, thanks for all replies. I'll try to do it using serial for testing purposes, then I'll ask for help again about UAV Interconnect Bus.

BattGo can address almost everything I'm trying to do. But it lacks some important things:

  • It's not Open, it's Proprietary. I couldn't access it's SDK to see how it works.
  • Only few battery brands are using it. There's no way to convert "dumb" batteries in smart ones.
  • As far as I could research, It cannot provide current sensing information. Only individual cells voltage.

It appears to be designed more as a historical information system than a in-flight information system.

My intention with Open Battery Data Link is to create an Open in-flight battery information system. It's in a very early stage of development, but my idea is to expand it at a point some large electronics manufacturer become interested in build and sell sensor modules for cheap price, so anyone can use. (Just like MinimOSD).

@danarrib please don't close this issue - let's keep track of it. I think your solution will be very useful for dumb batteries and eventually should make it to INAV.

I have defined a simple message that my module sensor outputs using the TX pin (I'll wire it to some RX uart on FC).

It's a 20-byte data packet. Starts with character "S", then 18 bytes of data, then character "E" for end.

typedef struct {
  uint8_t PackNumber;          // 1 byte
  uint8_t CellCount;           // 1 byte
  uint32_t PackVoltage;        // 4 bytes
  uint16_t HigherCellVoltage;   // 2 bytes
  uint16_t LowerCellVoltage;    // 2 bytes
  uint16_t AverageCellVoltage;  // 2 bytes
  uint32_t TotalmAhUsed;       // 4 bytes
  uint16_t CurrentmAhUsed;      // 2 bytes
} openbattdl_pack_info_t;

Now I'm trying to figure out how to do the Inav part of communication. Hope you guys can help.

@danarrib I would add a checksum bit or better yet a CRC to insure the packet is good.

@danarrib a few thoughts on your data struct:
uint32_t PackVoltage - is probably an overkill. uint16_t will still allow millivolt accuracy for packs up to 15S
uint16_t AverageCellVoltage - this is redundant. PackVoltage / CellCount will give precisely this value
uint32_t TotalmAhUsed and uint16_t CurrentmAhUsed - what's the difference?

To be able to use UIB in future we'll need to squeze the pack into 16 bytes (lower if possible). For the moment wen can add it as a "peripheral" device for common UARTs.

@teckel12 I'll add a checksum bit. Thanks for the tip.

@digitalentity , I did choose to use uint16_t because it's max value is 65535 while uint8_t is 255. If I have only one decimal digit, max voltage will be 25.5V, or 6S pack. It probably will do for most cases, but if someone needs to monitor a 8S or 12S pack, it wont work.

But due to the UIB requirements, I'll accept your tip.

The TotalmAhUsed and CurrentmAhUsed are not the same (But I agree, the names are terrible). I have changed the name for better understanding.

typedef struct {
  uint8_t PackNumber;          // 1 byte
  uint8_t CellCount;           // 1 byte
  uint8_t PackVoltage;         // 2 bytes (2 decimal digit)
  uint16_t HigherCellVoltage;  // 2 bytes (2 decimal digits)
  uint16_t LowerCellVoltage;   // 2 bytes (2 decimal digits)
  uint32_t TotalmAhUsed;       // 4 bytes (no decimal digits)
  uint16_t AmpsDraw;           // 2 bytes (2 decimal digits)
} openbattdl_pack_info_t;

Now it's 14 byte long. Or 16 with Starting and Ending bytes.
End byte will no longer be "E" character. Instead, It'll be a checksum bit.

I probably could reduce the number of bytes by replacing the PackNumber and CellCount datatype for another (255 is overkill - 7 each will do). But I don't know how to do a 3-bit int.

Thanks for all the tips. I'm learning a lot in last days.
Now I'm hitting my head on the wall trying to understand how to integrate with Inav. I'm trying to understand "rcSplit" implementation. I guess it's a good starting point.

Why bother with a checksum, the transport layer (UIB, MSP, LTM etc.) provide that.

@stronnag As long as the communication protocol has a checksum, no need to waste another byte.

@danarrib PackVoltage is uint8_t but noted as 2 bytes? I think you have package room for uint16_t with 2 digits accuracy for consistency.

Ok I was distracted. Sorry.

typedef struct {
  uint8_t PackNumber;          // 1 byte (max value 255)
  uint8_t CellCount;           // 1 byte (max value 255)
  uint16_t PackVoltage;        // 2 bytes (2 decimal digits, max value 655.35)
  uint16_t HigherCellVoltage;  // 2 bytes (2 decimal digits, max value 655.35)
  uint16_t LowerCellVoltage;   // 2 bytes (2 decimal digits, max value 655.35)
  uint16_t TotalmAhUsed;       // 2 bytes (no decimal digits, max value 65535)
  uint16_t AmpsDraw;           // 2 bytes (2 decimal digits, max value 655.35)
} openbattdl_pack_info_t;

Now packet is 14-byte long including Starting and Ending bytes.

I have modified the TotalmAhUsed from uint32 for uint16 to save 2 bytes as hardly someone will fly a battery pack greater than 65A.

I did some research and I figured out how to combine PackNumber and CellCount together into a uint8_t value. In fact, I can make a much smaller packet by combining smaller numbers, but it'll increase complexity. You guys tell me if it worth the work of doing it.

Ex:
PackNumber (3-bit, max 7)
CellCount (4-bit, max 15)
PackVoltage (13-bit, max 81.91)
HigherCellVoltage (9-bit, max 5.11)
LowerCellVoltage (9-bit, max 5.11)
TotalmAhUsed (18-bit, max 262143)
AmpsDraw (15-bit, max 327.67)

Total 71 bits, or 9 bytes (11 with Starting and Ending bytes). We get another 5 bytes to grow in the future.

I also will not use checksum as UIB provides it. Also, battery information is not a critical information, so if some packets were eventually lost, there's no problem, aircraft is still flyable.

For now, I'm not using UIB, just plain serial communication. Hope someone help to improve implementation after first release.

Data structure looks ok to me now

@danarrib I'd keep it simple and not share bytes, there's not much savings and everything fits already.

I would make the starting byte indicate packet version. For example, the starting byte could be 1 initially. Then, in the future you could make changes to the packet, make the starting byte 2 and then each packet could be decoded as version 2. Because I've learned that no matter how well you plan, there will always be a better way in the future.

You could also make the starting byte announce the packet version and size. For example, first 4 bytes the version and last 4 bytes the packet size. You may be able to skip the ending byte if you already know the packet size. But, it depends on the protocol.

This issue / pull request has been automatically marked as stale because it has not had any activity in 60 days. The resources of the INAV team are limited, and so we are asking for your help.
This issue / pull request will be closed if no further activity occurs within two weeks.

Automatically closing as inactive.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ricardodeazambuja picture ricardodeazambuja  路  4Comments

ghost picture ghost  路  4Comments

mrcottonmouth picture mrcottonmouth  路  3Comments

aa-calvo picture aa-calvo  路  3Comments

SweetBear1 picture SweetBear1  路  4Comments