Subversion Repositories FlightCtrl

Rev

Rev 987 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
Copyright 2008, by Michael Walter

All functions written by Michael Walter are free software and can be redistributed and/or modified under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public
License along with this program. If not, see <http://www.gnu.org/licenses/>.

Please note: The software is based on the framework provided by H. Buss and I. Busker in their Mikrokopter projekt. All functions that
are not written by Michael Walter are under the license by H. Buss and I. Busker (license_buss.txt) published by www.mikrokopter.de
unless it is stated otherwise.
*/



/*****************************************************************************
  INCLUDES
**************************************************************************** */

#include "kafi.h"
#include "FlightControl.h"
#include "main.h"
#include "mm3.h"
#include "main.h"
#include "eeprom.c"

/*****************************************************************************
(SYMBOLIC) CONSTANTS
*****************************************************************************/

#define MAX_GAS 250
#define MIN_GAS    15

#define sin45 sin(45.F / 180.F * PI)
#define cos45 cos(45.F / 180.F * PI)

/*****************************************************************************
  VARIABLES
*****************************************************************************/


extern void GPSupdate(void);

f32_t AdNeutralNick = 0.0F, AdNeutralRoll = 0.0F, AdNeutralGier = 0.0F;
int NeutralAccX = 0, NeutralAccY = 0, NeutralAccZ = 0;
int AverageRoll = 0, AverageNick = 0, AverageGier = 0;
int AveragerACC_X = 0, AveragerACC_Y = 0, AveragerACC_Z = 0;

f32_t Roll_X_Offset = 0.F, Roll_Y_Offset = 0.F, Roll_Z_Offset = 0.F;
f32_t ACC_X_Offset = 0.F, ACC_Y_Offset = 0.F,  ACC_Z_Offset = 0.F;

int DeltaAltitude = 0, CurrentAltitude = 0, LastAltitude = 0, InitialAltitude = 0;
int SummeNick=0,SummeRoll=0, StickNick = 0,StickRoll = 0,StickGier = 0, sollGier = 0;
int GierMischanteil, GasMischanteil;

unsigned char Motor_Vorne,Motor_Hinten,Motor_Rechts,Motor_Links, Count;
unsigned char MotorWert[5];
unsigned char SenderOkay = 0;
unsigned int I2CTimeout = 100;
char MotorenEin = 0;
unsigned int  modell_fliegt = 0;

extern unsigned long maxDistance;
extern signed int GPS_Nick,  GPS_Roll;
extern int RemoteLinkLost;
extern int InvalidAttitude;
struct mk_param_struct EE_Parameter;

/* ****************************************************************************
Functionname:     SetNeutral                      */
/*!
Description:    

@param[in]        

  @return           void
  @pre              -
  @post             -
  @author         Michael Walter  
**************************************************************************** */

void SetNeutral(void)
{
  beeptime = 2000;
  Delay_ms(1000);
  if((EE_Parameter.GlobalConfig & CFG_HOEHENREGELUNG))  // Höhenregelung aktiviert?
  {    
    if((AdWertAirPressure_Raw > 950) || (AdWertAirPressure_Raw < 750))
    {
      SucheLuftruckOffset();
    }
  }
 
  LastAltitude = CurrentAltitude;
  Delay_ms_Mess(300);

  ANALOG_OFF;
  AdNeutralNick = (f32_t) AdWertNick_Raw;
  AdNeutralRoll = (f32_t) AdWertRoll_Raw;
  AdNeutralGier = (f32_t) AdWertGier_Raw;
  NeutralAccY = AdWertAccRoll_Raw;
  NeutralAccX = AdWertAccNick_Raw;
  NeutralAccZ = AdWertAccHoch_Raw;
 
  Roll_X_Offset = 0.F;
  Roll_Y_Offset = 0.F;
  Roll_Z_Offset = 0.F;
  ACC_X_Offset = 0.F;
  ACC_Y_Offset = 0.F;
  ACC_Z_Offset = 0.F;
 
  AccumulatedACC_X = 0;
  AccumulatedACC_X_cnt = 0;
  AccumulatedACC_Y = 0;
  AccumulatedACC_Y_cnt = 0;
  AccumulatedACC_Z = 0;
  AccumulatedACC_Z_cnt = 0;
 
  AccumulatedRoll = 0;
  AccumulatedRoll_cnt = 0;
  AccumulatedNick = 0;
  AccumulatedNick_cnt = 0;
  AccumulatedGier = 0;
  AccumulatedGier_cnt = 0;
 
  AveragerACC_X = 0;
  AveragerACC_Y = 0;
  AveragerACC_Z = 0;
 
  AccumulatedACC_X = 0;
  AccumulatedACC_X_cnt = 0;
  AccumulatedACC_Y = 0;
  AccumulatedACC_Y_cnt = 0;
  AccumulatedACC_Z = 0;
  AccumulatedACC_Z_cnt = 0;
  ANALOG_ON;
 
  SummeRoll = 0;
  SummeNick = 0;
 
  sollGier = status.iPsi10;
  InitialAltitude = AdWertAirPressure_Raw;
 
  InvalidAttitude = 0;
  beeptime = 2000;
}


/* ****************************************************************************
Functionname:    GetMeasurements                      */
/*!
Description:    CalculateAverage

@param[in]        

  @return           void
  @pre              -
  @post             -
  @author         Michael Walter  
**************************************************************************** */

void GetMeasurements(void)
{
  static int LongTermAccumulatedRoll = 0;
  static int LongTermAccumulatedNick = 0;
  static int LongTermAccumulatedRoll_Cnt = 0;
  static int LongTermAccumulatedNick_Cnt = 0;
   
  ANALOG_OFF;
  AverageRoll = AccumulatedRoll / AccumulatedRoll_cnt;
  AverageNick = AccumulatedNick / AccumulatedNick_cnt;
  AverageGier = AccumulatedGier / AccumulatedGier_cnt;
 
  /* Get Pressure Differenz */
  CurrentAltitude = InitialAltitude - AccumulatedAirPressure / AccumulatedAirPressure_cnt;
  AccumulatedAirPressure_cnt = 0;
  AccumulatedAirPressure = 0;
 
  static char AirPressureCnt = 0;
  if (AirPressureCnt % 25 == 1)
  {
    DeltaAltitude = CurrentAltitude - LastAltitude;
    LastAltitude = CurrentAltitude;
  }
  AirPressureCnt++;
 
  if (LongTermAccumulatedRoll_Cnt < 500)
  {
    if (abs(LongTermAccumulatedRoll) < 10000)
    {
        LongTermAccumulatedRoll += AverageRoll;
    }
    LongTermAccumulatedRoll_Cnt++;
   
    if(abs(LongTermAccumulatedNick) < 10000)
    {
        LongTermAccumulatedNick += AverageNick;
    }
    LongTermAccumulatedNick_Cnt++;
  }
  else
  {
   static float fPreviousPsi =0.0F;
   static float fPreviousTheta =0.0F;

    //DebugOut.Analog[8] = (int) (((status.Phi - fPreviousPsi) / (0.00001F * fCycleTime)) / LongTermAccumulatedRoll_Cnt );
    //DebugOut.Analog[9] = (int) ((LongTermAccumulatedRoll / LongTermAccumulatedRoll_Cnt));

    AdNeutralRoll += (int) ((LongTermAccumulatedRoll + (status.Phi - fPreviousPsi) / (0.00001F * fCycleTime)) / LongTermAccumulatedRoll_Cnt );
    AdNeutralNick += (int) ((LongTermAccumulatedNick + (status.Theta - fPreviousTheta) / (0.00001F * fCycleTime)) / LongTermAccumulatedNick_Cnt );

    fPreviousPsi = status.Phi;
    fPreviousTheta =  status.Theta;
   
    //AdNeutralRoll += (MAX(-20, MIN(20,LongTermAccumulatedRoll / LongTermAccumulatedRoll_Cnt)));
    //AdNeutralNick += (MAX(-20, MIN(20,LongTermAccumulatedNick / LongTermAccumulatedNick_Cnt)));
       
    LongTermAccumulatedRoll_Cnt = 0;
    LongTermAccumulatedNick_Cnt = 0;
    LongTermAccumulatedRoll = 0;
    LongTermAccumulatedNick = 0;
  }
 
#if 0
  DebugOut.Analog[3] = fSumNick;
  DebugOut.Analog[4] = fSumRoll;
  DebugOut.Analog[5] = fSumGier;
#endif  
 
 
  if((modell_fliegt < 0x250) && 0)
  {
    //if ((GPS_Roll == 0 && GPS_Nick == 0) || (maxDistance / 10 > 10))
    AdNeutralNick = 0.998F * AdNeutralNick + 0.002F * AdWertNick_Raw;
    AdNeutralRoll = 0.998F * AdNeutralRoll + 0.002F * AdWertRoll_Raw;
    if (abs(StickGier) < 15 || MotorenEin == 0)
    {
      AdNeutralGier = 0.998F * AdNeutralGier + 0.002F * AdWertGier_Raw;
    }
  }
  else if(modell_fliegt < 0x2000&& 0)
  {
    //if ((GPS_Roll == 0 && GPS_Nick == 0) || (maxDistance / 10 > 10))
    AdNeutralNick = 0.999F * AdNeutralNick + 0.001F * AdWertNick_Raw;
    AdNeutralRoll = 0.999F * AdNeutralRoll + 0.001F * AdWertRoll_Raw;
    if (abs(StickGier) < 15 || MotorenEin == 0)
    {
      AdNeutralGier = 0.999F * AdNeutralGier + 0.001F * AdWertGier_Raw;
    }
  }
  else
  {
    AdNeutralNick = 0.9995F * AdNeutralNick + 0.0005F * AdWertNick_Raw;
    AdNeutralRoll = 0.9995F * AdNeutralRoll + 0.0005F * AdWertRoll_Raw;
    if (abs(StickGier) < 15 || MotorenEin == 0)
    {
      AdNeutralGier = 0.9995F * AdNeutralGier + 0.0005F * AdWertGier_Raw;
    }
  }
 
#if 1
  DebugOut.Analog[6] = AdWertNick_Raw;
  DebugOut.Analog[7] = AdWertRoll_Raw;
  DebugOut.Analog[8] = AdWertGier_Raw;
 
  DebugOut.Analog[9] = AdNeutralNick;
  DebugOut.Analog[10] = AdNeutralRoll;
  DebugOut.Analog[11] = AdNeutralGier;
#endif

  AccumulatedRoll = 0;
  AccumulatedRoll_cnt = 0;
  AccumulatedNick = 0;
  AccumulatedNick_cnt = 0;
  AccumulatedGier = 0;
  AccumulatedGier_cnt = 0;
 
#if 0
  ACC_X_Offset = 0.9999F * ACC_X_Offset + 0.0001F * ((float) AccumulatedACC_X / (float) AccumulatedACC_X_cnt);
  ACC_Y_Offset = 0.9999F * ACC_Y_Offset + 0.0001F * ((float) AccumulatedACC_Y / (float) AccumulatedACC_Y_cnt);
  ACC_Z_Offset = 0.9999F * ACC_Z_Offset + 0.0001F * ((float) AccumulatedACC_Z / (float) AccumulatedACC_Z_cnt);
#endif
 
  AveragerACC_X =  AccumulatedACC_X / AccumulatedACC_X_cnt;
  AveragerACC_Y =  AccumulatedACC_Y / AccumulatedACC_Y_cnt;
  AveragerACC_Z =  AccumulatedACC_Z / AccumulatedACC_Z_cnt;
 
  AccumulatedACC_X = 0;
  AccumulatedACC_X_cnt = 0;
  AccumulatedACC_Y = 0;
  AccumulatedACC_Y_cnt = 0;
  AccumulatedACC_Z = 0;
  AccumulatedACC_Z_cnt = 0;
 
  ANALOG_ON;
}

/* ****************************************************************************
Functionname:     SendMotorData                      */
/*!
Description:          Senden der Motorwerte per I2C-Bus

  @return           void
  @pre              -
  @post             -
  @author           H. Buss / I. Busker
**************************************************************************** */

void SendMotorData(void)
{
  if(!MotorenEin)
  {
    Motor_Hinten = 0;
    Motor_Vorne = 0;
    Motor_Rechts = 0;
    Motor_Links = 0;
    if(MotorTest[0]) Motor_Vorne = MotorTest[0];
    if(MotorTest[1]) Motor_Hinten = MotorTest[1];
    if(MotorTest[2]) Motor_Links = MotorTest[2];
    if(MotorTest[3]) Motor_Rechts = MotorTest[3];
  }
 
  //Start I2C Interrupt Mode
  twi_state = 0;
  motor = 0;
  i2c_start();
}


/* ****************************************************************************
Functionname:     RemoteControl                      */
/*!
Description:      

  @return           void
  @pre              -
  @post             -
  @author           H. Buss / I. Busker
**************************************************************************** */

void RemoteControl(void)
{
  static unsigned char delay_neutral = 0;
  static unsigned char delay_einschalten = 0,delay_ausschalten = 0;
 
  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Gaswert ermitteln
  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  GasMischanteil = PPM_in[EE_Parameter.Kanalbelegung[K_GAS]] + 120;
  if(GasMischanteil < 0)
  {
    GasMischanteil = 0;
  }
  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Emfang schlecht
  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  if(SenderOkay < 100)
  {
    if(!PcZugriff)
    {
      if(BeepMuster == 0xffff)
      {
        beeptime = 15000;
        BeepMuster = 0x0c00;
      }
    }
  }
  else
  {
    // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    // Emfang gut
    // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    if(SenderOkay > 140)
    {
      if(GasMischanteil > 40)
      {
        if(modell_fliegt < 0xffff)
        {
          modell_fliegt++;
        }
      }
     
     
      if((GasMischanteil > 200) &&
        (MotorenEin == 0))
      {
        // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        // auf Nullwerte kalibrieren
        // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        if(PPM_in[EE_Parameter.Kanalbelegung[K_GIER]] > 75)  // Neutralwerte
        {
          if(++delay_neutral > 50)  // nicht sofort
          {
            MotorenEin = 0;
            delay_neutral = 0;
            modell_fliegt = 0;
            if((EE_Parameter.GlobalConfig & CFG_HOEHENREGELUNG))  // Höhenregelung aktiviert?
            {
              if((AdWertAirPressure_Raw > 950) || (AdWertAirPressure_Raw < 750))
              {
                SucheLuftruckOffset();
              }
            }  
            ReadParameterSet(GetActiveParamSetNumber(), (unsigned char *) &EE_Parameter.Kanalbelegung[0], STRUCT_PARAM_LAENGE);
            SetNeutral();
          }
        }
        else
        {
          delay_neutral = 0;
        }
      }
      // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      // Gas ist unten
      // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      if(GasMischanteil < 35)
      {
        // Starten
        if(PPM_in[EE_Parameter.Kanalbelegung[K_GIER]] < -75)
        {
          // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          // Einschalten
          // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          if(++delay_einschalten > 100)
          {
            MotorenEin = 1;
            modell_fliegt = 1;
            delay_einschalten = 100;
          }          
        }  
        else
        {
          delay_einschalten = 0;
        }
        //Auf Neutralwerte setzen
        // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        // Auschalten
        // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        if(PPM_in[EE_Parameter.Kanalbelegung[K_GIER]] > 75)
        {
          if(++delay_ausschalten > 50)  // nicht sofort
          {
            MotorenEin = 0;
            modell_fliegt = 0;
            delay_ausschalten = 50;
          }
        }
        else
        {
          delay_ausschalten = 0;
        }
      }
    }
  }
}




/* ****************************************************************************
Functionname:     PD_Regler                      */
/*!
Description:

  @return           void
  @pre              -
  @post             -
  @author           Michael Walter
**************************************************************************** */

void PD_Regler(void)
{
  int StickNick45,StickRoll45;
  int DiffNick,DiffRoll, DiffGier;    
  int motorwert = 0;
  int pd_ergebnis;
 
  /*****************************************************************************
  Update noimial attitude
  **************************************************************************** */

  if(!NewPpmData--)  
  {
    StickNick = (StickNick * 3 + PPM_in[EE_Parameter.Kanalbelegung[K_NICK]] * EE_Parameter.Stick_P) / 4;
    StickRoll = (StickRoll * 3 + PPM_in[EE_Parameter.Kanalbelegung[K_ROLL]] * EE_Parameter.Stick_P) / 4;
    StickGier = -PPM_in[EE_Parameter.Kanalbelegung[K_GIER]];
  } // Ende neue Funken-Werte
 
#ifdef USE_GPS
 /* G P S   U p d a t e */
  GPSupdate();
#endif
 
  static float AverageGasMischanteil = 50.F;
  if((GasMischanteil > 30) &&
    (MotorenEin == 1) &&
    (RemoteLinkLost == 0) )
  {  /* Average the average throttle to find the hover setting */
    AverageGasMischanteil = 0.999F * AverageGasMischanteil + 0.001F * GasMischanteil;
  }
  /* Overide GasMischanteil */
  static unsigned int DescentCnt = 32000;
  if ((RemoteLinkLost == 1) &&
    (MotorenEin == 1))
  {
    if ((UBat < 100) || /* Start to descent in case of low loltage or in case*/
    (maxDistance / 10 < 12)) /* we reached our target position */
    {
      if (DescentCnt > 0)
      {
        DescentCnt--;
      }
      else
      {  /* We reached our target (hopefully) */
        MotorenEin = 0;
        RemoteLinkLost = 0;
      }
    }
    else
    {
      DescentCnt = 32000;
    }
    /* Bias the throttle for a slow descent */
    GasMischanteil = (int) ((AverageGasMischanteil + 5.0F) * (DescentCnt / 32000.F));
  }
  else
  {
    DescentCnt = 32000;
  }
 
  //DebugOut.Analog[13] = (int) GasMischanteil;
 
#ifdef X_FORMATION
  /* Overide in case the remote link got lost */
  if (RemoteLinkLost == 0)
  { /* We are flying in X-Formation */
    StickRoll45 = (int) (0.707F *  (float)(StickRoll - GPS_Roll) - 0.707F * (float)(StickNick - GPS_Nick));
    StickNick45 = (int) (0.707F *  (float)(StickRoll - GPS_Roll) + 0.707F * (float)(StickNick - GPS_Nick));
  }
  else
  {  /* GPS overide is aktive */
    StickRoll45 = (int) (0.707F *  (float)(-GPS_Roll) - 0.707F * (float)(-GPS_Nick));
    StickNick45 = (int) (0.707F *  (float)(-GPS_Roll) + 0.707F * (float)(-GPS_Nick));
    StickGier = 0;
  }
#else
  /* Overide in case the remote link got lost */
  if (RemoteLinkLost == 0)
  { /* We are flying in X-Formation */
    StickRoll45 = StickRoll - GPS_Roll;
    StickNick45 = StickNick - GPS_Nick;
  }
  else
  {  /* GPS overide is aktive */
    StickRoll45 = -GPS_Roll;
    StickNick45 = -GPS_Nick;
    StickGier = 0;
  }
#endif
 
  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  //  Yaw
  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
  if(GasMischanteil < 20)
  {
    sollGier = status.iPsi10;
    SummeRoll = 0;
    SummeNick = 0;
  }
 
  /* Gier-Anteil */
  if (abs(StickGier) > 4)
  {
    sollGier = status.iPsi10 + 4 * StickGier;  
  }
  DiffGier = (sollGier - status.iPsi10);
  GierMischanteil = (int) (-4 *  DiffGier - 4* (AdWertGier_Raw - (int) AdNeutralGier)) / 10;
 
#define MUL_G  0.8
  if(GierMischanteil > MUL_G * GasMischanteil)
  {
    GierMischanteil = MUL_G * GasMischanteil;
  }
  if(GierMischanteil < -MUL_G * GasMischanteil)
  {
    GierMischanteil = -MUL_G * GasMischanteil;
  }
  if(GierMischanteil > 50)
  {
    GierMischanteil = 50;
  }
  if(GierMischanteil < -50)
  {
    GierMischanteil = -50;
  }

  /*****************************************************************************
  PD-Control
  **************************************************************************** */

  int scale_p;
  int scale_d;
 
  scale_p = (MAX(0, (PPM_in[EE_Parameter.Kanalbelegung[K_POTI1]] + 170)) / 20);
  scale_d = (MAX(0, (PPM_in[EE_Parameter.Kanalbelegung[K_POTI2]] + 170)) / 20);  
 
  scale_p = 6;
  scale_d = 7;
 
  //DebugOut.Analog[14] =  scale_p;
  //DebugOut.Analog[15] =  scale_d;
 
  /* Pitch */
  DiffNick = -(status.iTheta10 + StickNick45);
  /* R o l l */
  DiffRoll = -(status.iPhi10 + StickRoll45);
 
  SummeNick += DiffNick;
  if(SummeNick >  10000)
  {
    SummeNick =  10000;
  }
  if(SummeNick < -10000)
  {
    SummeNick = -10000;
  }
 
  SummeRoll += DiffRoll;  
  if(SummeRoll >  10000)
  {
    SummeRoll =  10000;
  }
  if(SummeRoll < -10000)
  {
    SummeRoll = -10000;
  }
 
  pd_ergebnis = ((scale_p *DiffNick + scale_d * (AdWertNick_Raw - (int) AdNeutralNick)) / 10) ; // + (int)(SummeNick / 2000);
  if(pd_ergebnis >  (GasMischanteil + abs(GierMischanteil)))
  {
    pd_ergebnis =  (GasMischanteil + abs(GierMischanteil));
  }
  if(pd_ergebnis < -(GasMischanteil + abs(GierMischanteil)))
  {
    pd_ergebnis = -(GasMischanteil + abs(GierMischanteil));
  }
 
  /* M o t o r   V o r n */
  motorwert = GasMischanteil + pd_ergebnis + GierMischanteil;
  if ((motorwert < 0))
  {
    motorwert = 0;
  }
  else if(motorwert > MAX_GAS)
  {
    motorwert = MAX_GAS;
  }
  if (motorwert < MIN_GAS)
  {
    motorwert = MIN_GAS;
  }
  Motor_Vorne = motorwert;  
 
  /* M o t o r   H e c k */
  motorwert = GasMischanteil - pd_ergebnis + GierMischanteil;
  if ((motorwert < 0))
  {
    motorwert = 0;
  }
  else if(motorwert > MAX_GAS)
  {
    motorwert = MAX_GAS;
  }
  if (motorwert < MIN_GAS)
  {
    motorwert = MIN_GAS;
  }
  Motor_Hinten = motorwert;
 
  pd_ergebnis =  ((scale_p * DiffRoll + scale_d * (AdWertRoll_Raw - (int) AdNeutralRoll)) / 10) ; //+ (int)(SummeRoll / 2000);
  if(pd_ergebnis >  (GasMischanteil + abs(GierMischanteil)))
  {
    pd_ergebnis =  (GasMischanteil + abs(GierMischanteil));
  }
  if(pd_ergebnis < -(GasMischanteil + abs(GierMischanteil)))
  {
    pd_ergebnis = -(GasMischanteil + abs(GierMischanteil));
  }
 
  /* M o t o r   L i n k s */
  motorwert = GasMischanteil + pd_ergebnis - GierMischanteil;
  if(motorwert > MAX_GAS)
  {
    motorwert = MAX_GAS;
  }
  if (motorwert < MIN_GAS)
  {
    motorwert = MIN_GAS;
  }
  Motor_Links = motorwert;
 
  /* M o t o r   R e c h t s */
  motorwert = GasMischanteil - pd_ergebnis - GierMischanteil;
  if(motorwert > MAX_GAS)
  {
    motorwert = MAX_GAS;
  }
  if (motorwert < MIN_GAS)
  {
    motorwert = MIN_GAS;
  }
  Motor_Rechts = motorwert;
 
#if 1
  DebugOut.Analog[0] = status.iTheta10;
  DebugOut.Analog[1] = status.iPhi10;
  DebugOut.Analog[2] = status.iPsi10 / 10;
#endif
}