Better Deadband Implementation

Post Reply
PeterPilot
Posts: 19
Joined: Fri Jun 17, 2011 10:08 am

Better Deadband Implementation

Post by PeterPilot »

Hi Community,

I recently noticed an issue with our current Deadband feature.
In the picture below you can see what happens to our rcData when it gets processed by the deadband code.

rcRate set to 100 (2 in GUI), rcExpo set to 0, deadband set to 50 (to make effect clear)
rcRate set to 100 (2 in GUI), rcExpo set to 0, deadband set to 50 (to make effect clear)

As you can see there is a "step" in the rcCommand. This step causes a significant loss in steering precision around the center of the roll and pitch-stick.

So I developed a (in my opinion) better solution, where the deadband is not applyed to the rcCommand, but to the rcData.

The code consists of two parts in the multiwii.pde and the definition in the condig.h

multiwii.pde (line 98)

Code: Select all

#if defined(DEADBAND)  
  static uint16_t deadbandfactor = (500-DEADBAND)/DEADBAND;
#endif


multiwii.pde (line ~250, right above the old deadband implementation, which then must be deleted)

Code: Select all

for(axis=0;axis<2;axis++) {
    uint16_t tmp = abs(rcData[axis]-MIDRC);
    #if defined(DEADBAND)
      if (tmp>DEADBAND) {
        tmp -= DEADBAND-((tmp-DEADBAND)/deadbandfactor);
      }
      else { tmp=0; }
    #endif
    uint16_t tmp2 = tmp/100;
    rcCommand[axis] = lookupRX[tmp2] + (tmp-tmp2*100) * (lookupRX[tmp2+1]-lookupRX[tmp2]) / 100;
    if (rcData[axis]<MIDRC) rcCommand[axis] = -rcCommand[axis];
  }
 
  rcCommand[THROTTLE] = MINTHROTTLE + (int32_t)(MAXTHROTTLE-MINTHROTTLE)* (rcData[THROTTLE]-MINCHECK)/(2000-MINCHECK);
 
  rcCommand[YAW] = abs(rcData[YAW]-MIDRC);
 
  #if defined(DEADBAND)
    if (rcCommand[YAW]>DEADBAND) {
      rcCommand[YAW] -= DEADBAND-((rcCommand[YAW]-DEADBAND)/deadbandfactor);
    }
    else { rcCommand[YAW]=0; }
  #endif
 
  if (rcData[YAW]<MIDRC) rcCommand[YAW] = -rcCommand[YAW];


config.h

Code: Select all

/* introduce a deadband around the stick center */
//Must be greater than zero, comment if you dont want a deadband on roll, pitch and yaw
#define DEADBAND 5


I tested the code and it works but it would be great if someone of the wise guys could also check the code.

Best regards,
Peter

PeterPilot
Posts: 19
Joined: Fri Jun 17, 2011 10:08 am

Re: Better Deadband Implementation

Post by PeterPilot »

It is really a pitty that no one seems to check that code out!
The good news is: As I was very sure it would work flawlessly I testet the code in flight.
12 LiPo-Charges later I now can say: You ALL should try it!
No TX is perfect and sends perfect Mid-Signals when the Sticks are centerd. The values always change a little bit up and down. So Deadband is probably useful for everyone who does not only fast flying but also precise hovering.
With this mod you will have perfect sensitive steering around the center (not like the old deadband implementation) and perfect zero values when the sticks are centered.
Best regards,
Peter

ziss_dm
Posts: 529
Joined: Tue Mar 08, 2011 5:26 am

Re: Better Deadband Implementation

Post by ziss_dm »

Hi PeterPilot,
The biggest problem from my point of view - too complex calculations.
Have you tried just to shift zero point instead of scaling?

Like Centurian suggested here:
viewtopic.php?f=8&t=353&hilit=PID+precision&start=10

Code: Select all

else if rcCommand[PITCH])< 5 rcCommand[PITCH] += 5;
else if rcCommand[PITCH])> 5 rcCommand[PITCH] -= 5;


regards,
ziss_dm

PeterPilot
Posts: 19
Joined: Fri Jun 17, 2011 10:08 am

Re: Better Deadband Implementation

Post by PeterPilot »

Hi Ziss_dm,

I was trying to get a clean implementation without lowering the maximum signal on the axis where deadband is used.
This is why I use scaling and not a simple substraction.

I generally agree that there are more simple ways to get a deadband.
But I would still suggest to apply the deadband to the rcData and not to the rcCommand.
The range of the values sent by a certain TX when the sicks are centerd is typical for that TX so why should we apply the deadband to a variable which is influenced by rcRate and rcExpo.

So we could do:

Code: Select all

else if rcData[PITCH])< 5 rcData[PITCH] += 5;
else if rcData[PITCH])> 5 rcData[PITCH] -= 5;

and so on.

But at first I would like to understand the computeRC() function a little better.

Code: Select all

void computeRC() {
  static uint8_t rc4ValuesIndex = 0;
  uint8_t chan,a;

  rc4ValuesIndex++;
  for (chan = 0; chan < 8; chan++) {
    rcData4Values[chan][rc4ValuesIndex%4] = readRawRC(chan);
    rcDataMean[chan] = 0;
    for (a=0;a<4;a++) rcDataMean[chan] += rcData4Values[chan][a];
    rcDataMean[chan]= (rcDataMean[chan]+2)/4;
    if ( rcDataMean[chan] < rcData[chan] -3)  rcData[chan] = rcDataMean[chan]+2;
    if ( rcDataMean[chan] > rcData[chan] +3)  rcData[chan] = rcDataMean[chan]-2;
  }
}


Is it really necessary to do all this math to get a simple PWM signal-value? (This is not a rhetorical question - I really don't know that.)
I'm asking because I'm wondering why the rcData always is an even number.

Best regards,
Peter

PeterPilot
Posts: 19
Joined: Fri Jun 17, 2011 10:08 am

Re: Better Deadband Implementation

Post by PeterPilot »

Ok, this might be the final version. The code is even shorter than the old one.

multiwii.pde (line ~246, right above the old deadband implementation, which then must be deleted)

Code: Select all

  for(axis=0;axis<3;axis++) {
    uint16_t tmp = abs(rcData[axis]-MIDRC);
   
    #if defined(DEADBAND)
      if (tmp>DEADBAND) { tmp -= DEADBAND; }
      else { tmp=0; }
    #endif
   
    if(axis!=2) {
      uint16_t tmp2 = tmp/100;
      rcCommand[axis] = lookupRX[tmp2] + (tmp-tmp2*100) * (lookupRX[tmp2+1]-lookupRX[tmp2]) / 100;
    }
    else {
      rcCommand[axis] = tmp;
    }
   
    if (rcData[axis]<MIDRC) rcCommand[axis] = -rcCommand[axis];
  }
 
  rcCommand[THROTTLE] = MINTHROTTLE + (int32_t)(MAXTHROTTLE-MINTHROTTLE)* (rcData[THROTTLE]-MINCHECK)/(2000-MINCHECK);


The only downside of this code is the constant reduction of the rcData-Signal (which should not be noticable if DEADBAND is not defined to a high number like 20 for example).

The definition is still done in the config.h:

Code: Select all

/* introduce a deadband around the stick center */
//Must be greater than zero, comment if you dont want a deadband on roll, pitch and yaw
#define DEADBAND 6


I think this should be a suitable solution for everyone and it is still much better than the one implemented right now.

Best regards,
Peter

Alexinparis
Posts: 1630
Joined: Wed Jan 19, 2011 9:07 pm

Re: Better Deadband Implementation

Post by Alexinparis »

Hi,
I like the last suggestion.
But in case DEADBAND is not used, the computation time is still longer and this part would be useless: abs(rcData[axis]-MIDRC); and then if (rcData[axis]<MIDRC) rcCommand[axis] = -rcCommand[axis];

PeterPilot
Posts: 19
Joined: Fri Jun 17, 2011 10:08 am

Re: Better Deadband Implementation

Post by PeterPilot »

Hi Alex,
this is true but it is just useless for the YAW-Channel - for the Roll and Pitch-Channel the code would be the same like now.

Code: Select all

  for(axis=0;axis<2;axis++) {
    uint16_t tmp = abs(rcData[axis]-MIDRC);
   
    #if defined(DEADBAND)
      if (tmp>DEADBAND) { tmp -= DEADBAND; }
      else { tmp=0; }
    #endif
   
    uint16_t tmp2 = tmp/100;
    rcCommand[axis] = lookupRX[tmp2] + (tmp-tmp2*100) * (lookupRX[tmp2+1]-lookupRX[tmp2]) / 100;

    if (rcData[axis]<MIDRC) rcCommand[axis] = -rcCommand[axis];
  }
 
  rcCommand[THROTTLE] = MINTHROTTLE + (int32_t)(MAXTHROTTLE-MINTHROTTLE)* (rcData[THROTTLE]-MINCHECK)/(2000-MINCHECK);
   
  #if defined(DEADBAND)
    rcCommand[YAW] = abs(rcData[YAW]-MIDRC);
    if (rcCommand[YAW]>DEADBAND) { rcCommand[YAW] -= DEADBAND; }
    else { rcCommand[YAW]=0; }
    if (rcData[YAW]<MIDRC) rcCommand[YAW] = -rcCommand[YAW];
  #else
    rcCommand[YAW]      = rcData[YAW]-MIDRC;
  #endif


With this version the code without deadband will be without any useless operations but when using deadband the code will be 70 bytes bigger than with the last version where all three axis were calculated in a single for loop.
It's a matter of the point of view which is better. But the readability of the code was better with that last version...

I use a very slim version of the multiwii-software and I have constant cycle-times of around 1900 (never over 2000) and the deadband doesen't seem to affect this cycle-time.

Best regards,
Peter

Alexinparis
Posts: 1630
Joined: Wed Jan 19, 2011 9:07 pm

Re: Better Deadband Implementation

Post by Alexinparis »

Hi Peter,

So ok for this new implementation, I will add it in a new rev
The cycle time is not impacted because this function is inserted in the annexCode (a function which is used to "wait" before a new gyro sensor reading, this function must not last more 650 microseconds. If less, there is no impact)

Post Reply