Smart Battery via Arduino

Hello,
I tried to implement my own smart battery via I2C and based on the Maxell Battery.
Everything runs on an Arduino.
I managed to send data from the Arduino to the Pixhawk, but the values are strange.
For the single cell voltages I performed some tests:

  • Value on the Arduino / Value in Mission Planner:
  • 0 / 65,28
  • 1 / 65,281
  • 65125 / 65,381
  • 65534 / 65,534
  • 65535 / 0

For the other values the results are similar…
Since it’s always something with 65… I’m guessing it has something to do with the uint_8_max value…

Any idea what I should do to send appropriate voltages?

Thanks in advance
Vabe

Hello ,
Did you wrote the SBS protocol to send the data from arduino to Pixhawk ?
Did you set-up the flight controller to use SMBus Maxwell ?
The read voltage/Current use mV , any data will be divide / 1000.0f

 // read voltage (V)
    if (read_word(BATTMONITOR_SMBUS_VOLTAGE, data)) {
        _state.voltage = (float)data / 1000.0f;
        _state.last_time_micros = tnow;
        _state.healthy = true;
    }
BATTMONITOR_SMBUS_VOLTAGE=9

Check if the word is in the correct order (buff[1] high buff[0] low)

/ read word from register
// returns true if read was successful, false if failed
bool AP_BattMonitor_SMBus::read_word(uint8_t reg, uint16_t& data) const
{
// buffer to hold results (1 extra byte returned holding PEC)
const uint8_t read_size = 2 + (_pec_supported ? 1 : 0);
uint8_t buff[read_size];    // buffer to hold results

// read the appropriate register from the device
if (!_dev->read_registers(reg, buff, sizeof(buff))) {
    return false;
}

// check PEC
if (_pec_supported) {
    const uint8_t pec = get_PEC(AP_BATTMONITOR_SMBUS_I2C_ADDR, reg, true, buff, 2);
    if (pec != buff[2]) {
        return false;
    }
}

// convert buffer to word
data = (uint16_t)buff[1]<<8 | (uint16_t)buff[0];
// return success
return true;
}

Not really, I just looked which registers got called and searched their meaning in the ardupilot code, I didn’t even know about the full protocol.

Yes, I guess if there was a mistake there, i wouldn’t see a change in the single cell voltages, since they method is different for every battery.

I just use Wire.write(value), where I send a number:

uint16_t overall_voltage = 32400;

case 0x09: //overall voltage request
Wire.write(overall_voltage);
break;

I also tried setting a specification_info where pec is not available, since in there there is something changed with the values, but also this didn’t result in the expected numbers…

I’m developing a backend driver for smart battery Battgo by ISDT , the device use a serial to comunicate with the flight controller . In this case I can use a serial port to debug in SITL mode…
I tried to force a value as data=65535 ,the _state.voltage work as expected 65.535…


Sorry , i’m not i2c expert , but could be a problem with speed data ? a sort of data corrupt ?
I think the support for smart battery in ardupilot is not tested very wel. I didn’t find any smart battery in the market . In my opinino only ISDT battery could be a DIY solution .
If you are interested i wrote some informations in Github

IT WORKS!!!
I decided to investigate a bit more into highByte/lowByte and compared it to @ppoirier’s TFMINI to I2C, and in there I found highByte and lowByte, that was the only thing missing.

Now I can create a diy smart battery with an arduino…

I’ve already checked out BattGo, but I’m not really a fan of it, I would love to tinker with ALL values myself.

2 Likes

I finally found the time to assemble the prototype and it works, kinda.

Temperature is still messed up somehow, current isn’t calibrated etc, but as of now, all sensors are detected and shown in Mission Planner, now it’s time to code😀

2 Likes

That is very interesting. I want do the same thing, but I don’t know about the data structures, where can I find it?

I can send you the requests when I get home.
But I hope at some point that I’ll be able to polish the code up and release it on github.
But it’s not that hard to reverse engineer. Look at the BattMonitor Maxwell and there you can see which register gets called for which value, also the SBS protocol is open source, there is a detailed PDF document.

OK, I am reading the code now, and I get what I want.
Thanks

Hi, interesting is there anything from the code published , how the arduiono is talking to the pixhawk controller ?

I’ll polish it up and release it on github, maybe I’ll have time tomorrow

There you go: https://github.com/Vabe7/Smart_Battery_Interface

2 Likes

thank you fot the code.
im trying to to test it with pixhawk cube orange / arduplane.
here is the code i used for testing:
byte register_to_call = 0;

int16_t current = -12340; //charge/discharge rate in mA increments - positive for charge, negative for discharge, 0 to 32,767 mA for charge or 0 to -32,768 mA for discharge

uint16_t remaining_capacity = 0; //remaining charge in mAh or 10mWh

uint16_t temperature = 0; //cell temperature in tenth degree Kelvin increments, 0 to +6553.5°K

uint16_t overall_voltage = 0; //battery terminal voltage in milli-volts, 0 to 65,535 mV

uint16_t cell_voltage[6] = {0, 0, 0, 0, 0, 0}; //battery cell voltage in milli-volts, 0 to 65,535 mV

uint16_t full_charge_capacity = 0; //estimated full charge capacity in mAh or 10mWh

uint16_t cycle_count = 0; //number of times the battery has been charged, 0 to 65535, 65535 indicates that the battery has been charged exactly that many times or more

and the resullts are attached:

any idea why im not reading voltage / batt used / termp correctly? as you can see current is correct.

also changing values in the main loop doesnt affect:

void loop() {
//update values
temperature = 1000;
}

the temp remains 0.
but if i change uint16_t temperature = 1000 then it does work.

EDIT: fixed by adding delay(1); in main loop.

OK i managed to get some data to work:
battery temp
batt used
batt current
the last item i need is voltage (case 0x09) but no matter which value i write for voltage, the mission planner reports Batt3 voltage as 391.68V, its completely frozen - could this be a bug on Arduplane side?

Glad to hear that you got it working, about the voltage I’m not sure. I looked into the ArduPilot code and the call of the register 0x09 requires PEC support, which requires a version greater than 0011b. Maybe this was added after I programmed this.

uint8_t version = (data & 0xF0) >> 4;

    // version less than 0011b (i.e. 3) do not support PEC
    if (version < 3) {
        _pec_supported = false;
        _pec_confirmed = true;
        return true;
    }

Maybe try a large specification info…
The responsible ArduPilot code can be found here: https://github.com/Vabe7/ardupilot/blob/master/libraries/AP_BattMonitor/AP_BattMonitor_SMBus_Generic.cpp