vbat cells

Post Reply
adivacaru
Posts: 3
Joined: Sat Jul 18, 2015 7:22 pm

vbat cells

Post by adivacaru »

Hello,

I am trying to setup individual cell monitoring i have crius aiop v2 and my setup is as follows:

V bat is connected to A0 using an dividider make of 51k(high side) and 33k(low side) as suggested in the firmware, by v bat i mean the 3rd cel - 11.1V
Second cell(7.4 V) is connected to A1 using a divider made of 114.9k (high side) and 94.7 k(low side)
third cell(3.7V) is connected directly to A2 pin .

This is how is setup the code in config.h

Code: Select all

   #define VBAT              // uncomment this line to activate the vbat code
    #define VBATSCALE       131 // (*) (**) change this value if readed Battery voltage is different than real voltage
    #define VBATNOMINAL     126 // 12,6V full battery nominal voltage - only used for lcd.telemetry
    #define VBATLEVEL_WARN1 107 // (*) (**) 10,7V
    #define VBATLEVEL_WARN2  99 // (*) (**) 9.9V
    #define VBATLEVEL_CRIT   93 // (*) (**) 9.3V - critical condition: if vbat ever goes below this value, permanent alarm is triggered
    #define NO_VBAT          16 // Avoid beeping without any battery
    #define VBAT_OFFSET       0 // offset in 0.1Volts, gets added to voltage value  - useful for zener diodes

    /* for V BAT monitoring of individual cells
     * enable both VBAT and VBAT_CELLS
     */
    #define VBAT_CELLS
    #define VBAT_CELLS_NUM 3 // set this to the number of cells you monitor via analog pins
    #define VBAT_CELLS_PINS {A2, A1, A0} // set this to the sequence of analog pins
    #define VBAT_CELLS_OFFSETS {83, 50, 0} // in 0.1 volts, gets added to voltage value  - useful for zener diodes
    #define VBAT_CELLS_DIVS {98 , 122, 75 } // divisor for proportional part according to resistors - larger value here gives smaller voltage


Can anybody please help how i should setup the FW so that is measures correctly? i cannot figure out how to set the parameters so that it measures correctly the cell voltages, until now i have only measured crap and also the battery monitoring which was working correctly before now is not working anymore after uncommenting #define VBAT_CELLS.

QuadBow
Posts: 532
Joined: Fri Jan 04, 2013 10:06 am

Re: vbat cells

Post by QuadBow »

Hi adivacaru,

I am not so happy with the cell voltage measurement approach implemented in MW2.4 and I have expressed my concerns here http://www.multiwii.com/forum/viewtopic.php?f=8&t=6263.
That means you have to set up offset and division parameters manually by trail and error and those offsets are fixed to the parameter you selected.
But, in reality, the offset depends on the voltage of the first cells. So, there is a systematic failure in the measurement.

In my view, this approach does not make any sense at all and therefore I do not recommend to use VBAT_CELLS.

adivacaru
Posts: 3
Joined: Sat Jul 18, 2015 7:22 pm

Re: vbat cells

Post by adivacaru »

Hy QuadBow,


I got mad after a few tries of getting it right and i reimplenented it in my way :

in config.h

Code: Select all


    #define VBAT_CELLS
    #define VBAT_CELLS_NUM 3 // set this to the number of cells you monitor via analog pins
    #define VBAT_CELLS_PINS {A0, A1, A2} // set this to the sequence of analog pins
    #define VBAT_CELLS_OFFSETS {0, 0, 0} // in 0.1 volts, gets added to voltage value  - useful for zener diodes
    #define VBAT_CELLS_DIVS { 1253 , 898,   462} // divisor for proportional part according to resistors - larger value here gives smaller voltage





the values for VBAT_CELLS_DIVS can be determined using the following formula:

Vcell
|
R1
R1
|
----- ADC INPUT
|
R2
R2
|
GND

VBAT_CELLS_DIVS = ADC_REF * (R2+R1) /R2 Where ADC_REF is the the the whatever reference the chip has for the adc (normally is the supply voltage)
in my case is calculated in 0.01 V
and they also need to be tweaked a little bit in order to get it as accurate as possible.


in multiwii.cpp

Code: Select all


 #if defined(VBAT) && defined(VBAT_CELLS)
      if ( (analogReader<4) || (analogReader>4+VBAT_CELLS_NUM-1) ) break;
      uint8_t ind = analogReader-4;
     
    //  static uint16_t vbatcells_pins[VBAT_CELLS_NUM] = VBAT_CELLS_PINS;
    //  static uint8_t  vbatcells_offset[VBAT_CELLS_NUM] = VBAT_CELLS_OFFSETS;
    //  static uint8_t  vbatcells_div[VBAT_CELLS_NUM] = VBAT_CELLS_DIVS;
     static uint16_t vbatcells_pins[VBAT_CELLS_NUM] = VBAT_CELLS_PINS;
     static uint16_t  vbatcells_div[VBAT_CELLS_NUM] = VBAT_CELLS_DIVS;
     
      uint16_t v = analogRead(vbatcells_pins[ind]);
   //   analog.vbatcells[ind] = vbatcells_offset[ind] + (v << 2) / vbatcells_div[ind]; // result is Vbatt in 0.1V steps
     
       analog.vbatcells[ind] = map (v , 0, 1023, 0 , vbatcells_div[ind] ); // result is Vbatt in 0.1V steps
       
      // Log("\r\n Cell %d Raw = %d, Volt %d  = %d \r\n", ind, v,ind, analog.vbatcells[ind]);
     
     
   //   Log("\r\n  pin %d Analog Vbatcell  %d =  %d, Vbatcell %d =  %d, with div %d \r\n",vbatcells_pins[ind], ind, v ,ind,  analog.vbatcells[ind],vbatcells_div[ind] );
   /*
   
   uint16_t x = analogRead(A0);
   uint16_t y = analogRead(A1);
   uint16_t z = analogRead(A2);
      Log("\r\n Raw A0 =%d , Volt A0 = %d \r\n", x, map (x , 0, 1023, 0 , 127));
      Log("\r\n Raw A1 =%d , Volt A1 = %d \r\n", y ,map (y , 0, 1023, 0 , 91 ));
      Log("\r\n Raw A2 =%d , Volt A2 = %d \r\n", z ,map (z , 0, 1023, 0 , 48 ));
      */
     // if (ind == VBAT_CELLS_NUM -1) analog.vbat = analog.vbatcells[ind];
      if (ind == VBAT_CELLS_NUM -1) {
        analog.vbat = (uint8_t)analog.vbatcells[0];
        analog.vbatx10 = analog.vbatcells[0];
        }



in types.h

Code: Select all


typedef struct {
  uint8_t  vbat;               // battery voltage in 0.1V steps
  uint16_t vbatx10;
  uint16_t intPowerMeterSum;
  uint16_t rssi;              // range: [0;1023]
  uint16_t amperage;          // 1unit == 100mA
  uint16_t watts;             // 1unit == 1W
  uint16_t vbatcells[VBAT_CELLS_NUM];
} analog_t;





and how i actually used the cell voltages :

Code: Select all


setData(analog.vbatcells[0] - analog.vbatcells[1],analog.vbatcells[1] - analog.vbatcells[2],analog.vbatcells[2],0,0,0 );



because the previus code actually measures in

analog.vbatcells[0] = Cell 1+Cell 2 + Cell 3
analog.vbatcells[1] = Cell 1+Cell 2
analog.vbatcells[2] = Cell 3



I need this to send data to my frsky taranis x9d plus using the SPort protocol and the X8R receiver.

The result is pretty good in terms of the voltage measurement .

I posted this maybe is helpful for somebody

QuadBow
Posts: 532
Joined: Fri Jan 04, 2013 10:06 am

Re: vbat cells

Post by QuadBow »

Hi adivacaru,

Good to hear that you found a solution for your configuration.
However, it remains rather specific to your configuration.

Code: Select all

   uint16_t x = analogRead(A0);
   uint16_t y = analogRead(A1);
   uint16_t z = analogRead(A2);

So, my wish would be a solution which is more generous using definitions like

Code: Select all

    #define VBAT_CELLS_PINS {A0, A1, A2} // set this to the sequence of analog pins 
introduced earlier.

adivacaru
Posts: 3
Joined: Sat Jul 18, 2015 7:22 pm

Re: vbat cells

Post by adivacaru »

that with x y z is only to play around, its commented out i only did it this way


Code: Select all

 uint16_t v = analogRead(vbatcells_pins[ind]);
  //   analog.vbatcells[ind] = vbatcells_offset[ind] + (v << 2) / vbatcells_div[ind]; // result is Vbatt in 0.1V steps
      if (ind == 0 ) analog.vbatraw = v;
       analog.vbatcells[ind] = map (v , 0, 1023, 0 , vbatcells_div[ind] ); // result is Vbatt in 0.1V steps




basically i replaced this :

Code: Select all

 analog.vbatcells[ind] = vbatcells_offset[ind] + (v << 2) / vbatcells_div[ind]; // result is Vbatt in 0.1V steps



with

Code: Select all

 analog.vbatcells[ind] = map (v , 0, 1023, 0 , vbatcells_div[ind] );

LutzB
Posts: 67
Joined: Sun Feb 08, 2015 4:01 pm
Location: Germany

Re: vbat cells

Post by LutzB »

I tried setting up vbat cells today in order to implement it into the FrSky s.port telemetry. I also got mad with the values in config.h. :?
My setup is similar to adivacaru:
  • 3S Lipo
  • cell 1 direct on A2
  • cells 1+2 on A1 with 33k/47k resistors
  • cells 1+2+3 on A0 with 51k/33k resistors
If I leave VBAT_CELLS commented out I get a perfect measurement of the total voltage with VBATSCALE = 129. But when I activate VBAT_CELLS even my total voltage is wrong. My settings for the cells:

Code: Select all

#define VBAT_CELLS_NUM 3
#define VBAT_CELLS_PINS { A2, A1, A0 }
#define VBAT_CELLS_OFFSETS { 0, 0, 0 }
#define VBAT_CELLS_DIVS { 10, 10, 10 }

The divs are just a guess. At least now my total voltage tells me something near 14V. If I raise the third div to 11 I get about 10V. Is there any way to calculate the divs?

Thanks in advance,
Lutz

User avatar
Hamburger
Posts: 2578
Joined: Tue Mar 01, 2011 2:14 pm
Location: air
Contact:

Re: vbat cells

Post by Hamburger »

hey,
the vbat cells code does need some fixing. I will get to that during winter. You may also have experienced that infamous side effect of too fast consecutive analog reads influencing results.
Best advice for the moment is: if it works, fine. Else either try and fix it for yourself or leave it for later.
sorry.

LutzB
Posts: 67
Joined: Sun Feb 08, 2015 4:01 pm
Location: Germany

Re: vbat cells

Post by LutzB »

Thank you for the quick reply.
Yesterday I modified the code a bit and changed the calculation in multiwii.cpp to the same that is used for vbat and added prescaler definitions to config.h. After a lot of try and error I found some numbers for VBAT_CELLS_DIV that give me good measurements. I will post my changes when I am satisfied with the result.

Lutz

User avatar
Hamburger
Posts: 2578
Joined: Tue Mar 01, 2011 2:14 pm
Location: air
Contact:

Re: vbat cells

Post by Hamburger »

please check your voltage dividers. If sum of both resistors is too high (whatever that value may be) then the arduino input seems to float and provide phantasy values for analogRead(). One symptom is if arduino value changes drastically once you attach a voltmeter in parallel to the arduino input.

LutzB
Posts: 67
Joined: Sun Feb 08, 2015 4:01 pm
Location: Germany

Re: vbat cells

Post by LutzB »

As it is raining the whole day here I had some time for developing.

I have reworked the cell voltage calculation to take the same parameters as vbat. Namely the new definition VBAT_CELLS_PRESCALER was added and calculation changed. I did not change the measured values, so the problem that you measure cell1, cells 1+2, cells 1+2+3,... still remains.

I also reworked the SPort Telemetry over the weekend. Will post it in the telemetry thread.

config.h with values for my 3S setup:

Code: Select all

#define VBAT_CELLS
#define VBAT_CELLS_NUM 3 // set this to the number of cells you monitor via analog pins
#define VBAT_CELLS_PINS { A2, A1, A0 } // set this to the sequence of analog pins
                                                            // if you want SPort Telemetry, the order must be cell 1, cells 1+2, cells 1+2+3,..., cells 1+2+3+4+5+6
#define VBAT_CELLS_OFFSETS { 0, 0, 0 } // in 0.1 volts, gets added to voltage value  - useful for zener diodes
#define VBAT_CELLS_DIVS { 165, 195, 129 } // divisor for proportional part according to resistors - larger value here gives smaller voltage
#define VBAT_CELLS_PRESCALER { 8, 16, 16 } // this is NEW
 


multiwii.cpp around line 519:

Code: Select all

default: // here analogReader >=4, because of ++ in switch()
{
  #if defined(VBAT) && defined(VBAT_CELLS)
    if ( (analogReader<4) || (analogReader>4+VBAT_CELLS_NUM-1) ) break;
    uint8_t ind = analogReader-4;
    static uint16_t vbatcells_pins[VBAT_CELLS_NUM] = VBAT_CELLS_PINS;
    static uint8_t  vbatcells_offset[VBAT_CELLS_NUM] = VBAT_CELLS_OFFSETS;
    static uint8_t  vbatcells_div[VBAT_CELLS_NUM] = VBAT_CELLS_DIVS;
    static uint8_t  vbatcells_prescaler[VBAT_CELLS_NUM] = VBAT_CELLS_PRESCALER; // this is NEW
    uint16_t v = analogRead(vbatcells_pins[ind]);
    //analog.vbatcells[ind] = vbatcells_offset[ind] + (v << 2) / vbatcells_div[ind]; // result is Vbatt in 0.1V steps; the OLD way
    analog.vbatcells[ind] = vbatcells_offset[ind] + (v*vbatcells_prescaler[ind]) / vbatcells_div[ind]; // result is Vbatt in 0.1V steps; this is NEW
    //debug[ind] = analog.vbatcells[ind];
    if (ind == VBAT_CELLS_NUM -1) analog.vbat = analog.vbatcells[ind];
  #endif // VBAT) && defined(VBAT_CELLS)
  break;
} // end default


Lutz

QuadBow
Posts: 532
Joined: Fri Jan 04, 2013 10:06 am

Re: vbat cells

Post by QuadBow »

Hi LutzB,
I am afraid that your code does not overcome the issues with the current VCELL implemenation I have.
We do have a static offset

Code: Select all

 vbatcells_offset[VBAT_CELLS_NUM]
- why?

The main issue I do have is as follows:
The accumulator consists of some cells in line. So, the voltage of the second (or higher) cell should be measured by calculating the first cell's voltage and subtract it from the voltage measured at the second cell. So we could obtain the voltage of the second cell.

The second (minor) issue is the time consuming use of division

Code: Select all

(v << 2) / vbatcells_div[ind]

My proposal would be the different approach of multiplying first with a variable vbatcells_factor[ind] and then divide by a fixed divisor like 8,16,32,64,128,... This would be less time consuming.

LutzB
Posts: 67
Joined: Sun Feb 08, 2015 4:01 pm
Location: Germany

Re: vbat cells

Post by LutzB »

QuadBow wrote:We do have a static offset

Code: Select all

 vbatcells_offset[VBAT_CELLS_NUM]
- why?

This has nothing to do with the individual cell voltage! It is useful if you have a zener diode in your measuring circuit. You can get a much better resolution of the interesting part of the voltage. So this should not be removed IMHO.

QuadBow wrote:The main issue I do have is as follows:
The accumulator consists of some cells in line. So, the voltage of the second (or higher) cell should be measured by calculating the first cell's voltage and subtract it from the voltage measured at the second cell. So we could obtain the voltage of the second cell.

You are absolutely right. As I was rewriting the SPort telemetry code I have put the calculations there. My intention was to not break anything in the code. It would be much better, if the analog.vbatcells[] values would represent the individual cell voltage and not the measured ones. The easiest way would be to measure all cells in one cycle and do the calculations right there, but I think that would cost too much time. There is a reason for this comment in multiwii.cpp:

Code: Select all

// query at most one multiplexed analog channel per MWii cycle


QuadBow wrote:The second (minor) issue is the time consuming use of division

Code: Select all

(v << 2) / vbatcells_div[ind]

My proposal would be the different approach of multiplying first with a variable vbatcells_factor[ind] and then divide by a fixed divisor like 8,16,32,64,128,... This would be less time consuming.

You are the expert. I have never before coded for arduino, so I have no idea about timing and better or worse implementations. Feel free to optimize the code.

QuadBow
Posts: 532
Joined: Fri Jan 04, 2013 10:06 am

Re: vbat cells

Post by QuadBow »

Hi Lutz,

As Hamburger mentioned, he will take care of the VCELL implementation later.
So, I will not intervene...

Post Reply