UAVX Multicopter Flight Controller.

Dependencies:   mbed

Revision:
2:90292f8bd179
Parent:
1:1e3318a30ddd
--- a/control.c	Fri Feb 25 01:35:24 2011 +0000
+++ b/control.c	Tue Apr 26 12:12:29 2011 +0000
@@ -2,7 +2,7 @@
 // =                              UAVXArm Quadrocopter Controller                                =
 // =                           Copyright (c) 2008 by Prof. Greg Egan                             =
 // =                 Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer                   =
-// =                     http://code.google.com/p/uavp-mods/ http://uavp.ch                      =
+// =                           http://code.google.com/p/uavp-mods/                               =
 // ===============================================================================================
 
 //    This is part of UAVXArm.
@@ -20,12 +20,10 @@
 
 #include "UAVXArm.h"
 
-real32 PTerm, ITerm, DTerm;
-
 void DoAltitudeHold(void);
 void UpdateAltitudeSource(void);
+real32 AltitudeCF( real32, real32);
 void AltitudeHold(void);
-void InertialDamping(void);
 void DoOrientationTransform(void);
 void DoControl(void);
 
@@ -33,20 +31,20 @@
 void LightsAndSirens(void);
 void InitControl(void);
 
-real32 Angle[3], Anglep[3], Rate[3], Ratep[3]; // Milliradians
-real32 Comp[4];
+real32 Angle[3], Anglep[3], Rate[3], Ratep[3], YawRateIntE;
+real32 AccAltComp, AltComp;
 real32 DescentComp;
 
-real32 AngleE[3], AngleIntE[3];
-
 real32 GS;
 real32 Rl, Pl, Yl, Ylp;
 int16 HoldYaw;
 int16 CruiseThrottle, MaxCruiseThrottle, DesiredThrottle, IdleThrottle, InitialThrottle, StickThrottle;
-int16 DesiredRoll, DesiredPitch, DesiredYaw, DesiredHeading, DesiredCamPitchTrim;
-real32 ControlRoll, ControlPitch, ControlRollP, ControlPitchP;
+int16 DesiredRoll, DesiredPitch, DesiredYaw, DesiredCamPitchTrim;
+real32 DesiredHeading;
+real32 ControlRoll, ControlPitch;
 real32 CameraRollAngle, CameraPitchAngle;
 int16 CurrMaxRollPitch;
+int16 Trim[3];
 
 int16 AttitudeHoldResetCount;
 real32 AltDiffSum, AltD, AltDSum;
@@ -55,12 +53,47 @@
 
 uint32 AltuSp;
 int16 DescentLimiter;
+uint32 ControlUpdateTimeuS;
 
 real32 GRollKp, GRollKi, GRollKd, GPitchKp, GPitchKi, GPitchKd;
 
-boolean    FirstPass;
+boolean FirstPass;
 int8 BeepTick = 0;
 
+
+
+real32 AltCF = 0.0;
+real32 AltF[3] = { 0.0, 0.0, 0.0};
+
+real32 AltitudeCF( real32 AltE, real32 dT ) {
+
+    // Complementary Filter originally authored by RoyLB originally for attitude estimation
+    // http://www.rcgroups.com/forums/showpost.php?p=12082524&postcount=1286
+    
+    // Using acceleration as an alias for vertical displacement to avoid integration "issues"
+    
+    static real32 TauCF;
+     
+    TauCF = K[VertDamp];
+
+    if ( F.AccelerationsValid && F.NearLevel ) {
+
+        AltF[0] = (AltE - AltCF) * Sqr(TauCF);
+        AltF[2] += AltF[0] * dT;
+        
+        AltF[1] =  AltF[2] + (AltE - AltCF) * 2.0 * TauCF + ( 0.5 *  Acc[UD] * Sqr(dT) ); // ??? some scaling on Acc perhaps
+        AltCF += AltF[1] * dT;
+
+    } else
+        AltCF = AltE;
+        
+    AccAltComp = AltCF - AltE;
+
+    return( AltCF );
+
+} // AltitudeCF
+
+
 void DoAltitudeHold(void) { // Syncronised to baro intervals independant of active altitude source
 
     static int16 NewAltComp;
@@ -75,36 +108,32 @@
     AltdTR = 1.0 / AltdT;
     AltuSp = Now;
 
-    AltE = DesiredAltitude - Altitude;
-    LimAltE = Limit(AltE, -ALT_BAND_M, ALT_BAND_M);
+    AltE = AltitudeCF( DesiredAltitude - Altitude, AltdT );
+    LimAltE = Limit1(AltE, ALT_BAND_M);
 
     AltP = LimAltE * K[AltKp];
-    AltP = Limit(AltP, -ALT_MAX_THR_COMP, ALT_MAX_THR_COMP);
+    AltP = Limit1(AltP, ALT_MAX_THR_COMP);
 
     AltDiffSum += LimAltE;
-    AltDiffSum = Limit(AltDiffSum, -ALT_INT_WINDUP_LIMIT, ALT_INT_WINDUP_LIMIT);
+    AltDiffSum = Limit1(AltDiffSum, ALT_INT_WINDUP_LIMIT);
     AltI = AltDiffSum * K[AltKi] * AltdT;
-    AltI = Limit(AltDiffSum, -K[AltIntLimit], K[AltIntLimit]);
+    AltI = Limit1(AltDiffSum, K[AltIntLimit]);
 
     ROC = ( Altitude - AltitudeP ) * AltdTR; // may neeed filtering - noisy
     AltitudeP = Altitude;
 
     AltD = ROC * K[AltKd];
-    AltD = Limit(AltD, -ALT_MAX_THR_COMP, ALT_MAX_THR_COMP);
+    AltD = Limit1(AltD, ALT_MAX_THR_COMP);
 
     if ( ROC < ( -K[MaxDescentRateDmpS] * 10.0 ) ) {
         DescentLimiter += 1;
         DescentLimiter = Limit(DescentLimiter, 0, ALT_MAX_THR_COMP * 2.0);
-
     } else
         DescentLimiter = DecayX(DescentLimiter, 1);
 
     NewAltComp = AltP + AltI + AltD + AltDSum + DescentLimiter;
-
-    NewAltComp = Limit(NewAltComp, -ALT_MAX_THR_COMP, ALT_MAX_THR_COMP);
-
-    Comp[Alt] = SlewLimit(Comp[Alt], NewAltComp, 1.0);
-
+    NewAltComp = Limit1(NewAltComp, ALT_MAX_THR_COMP);
+    AltComp = SlewLimit(AltComp, NewAltComp, 1.0);
 
     if ( ROC > Stats[MaxROCS] )
         Stats[MaxROCS] = ROC;
@@ -142,11 +171,11 @@
                 if ( F.ThrottleMoving ) {
                     F.HoldingAlt = false;
                     DesiredAltitude = Altitude;
-                    Comp[Alt] = Decay1(Comp[Alt]);
+                    AltComp = Decay1(AltComp);
                 } else {
                     F.HoldingAlt = true;
                     if ( fabs(ROC) < ALT_HOLD_MAX_ROC_MPS  ) {
-                        NewCruiseThrottle = DesiredThrottle + Comp[Alt];
+                        NewCruiseThrottle = DesiredThrottle + AltComp;
                         CruiseThrottle = HardFilter(CruiseThrottle, NewCruiseThrottle);
                         CruiseThrottle = Limit( CruiseThrottle , IdleThrottle, MaxCruiseThrottle );
                     }
@@ -154,54 +183,12 @@
                 }
         }
     } else {
-        Comp[Alt] = Decay1(Comp[Alt]);
+        AltComp = Decay1(AltComp);
         ROC = 0.0;
         F.HoldingAlt = false;
     }
 } // AltitudeHold
 
-void InertialDamping(void) { // Uses accelerometer to damp disturbances while holding altitude
-    static uint8 i;
-
-    if ( F.AccelerationsValid  && F.NearLevel ) {
-        // Up - Down
-
-        Vel[UD] += Acc[UD] * dT;
-        Comp[UD] = Vel[UD] * K[VertDampKp];
-        Comp[UD] = Limit(Comp[UD], DAMP_VERT_LIMIT_LOW, DAMP_VERT_LIMIT_HIGH);
-
-        Vel[UD] = DecayX(Vel[UD], K[VertDampDecay]);
-
-        // Lateral compensation only when holding altitude
-        if ( F.HoldingAlt && F.AttitudeHold ) {
-            if ( F.WayPointCentred ) {
-                // Left - Right
-                Vel[LR] += Acc[LR] * dT;
-                Comp[LR] = Vel[LR] * K[HorizDampKp];
-                Comp[LR] = Limit(Comp[LR], -DAMP_HORIZ_LIMIT, DAMP_HORIZ_LIMIT);
-                Vel[LR] = DecayX(Vel[LR], K[HorizDampDecay]);
-
-                // Back - Front
-                Vel[BF] += Acc[BF] * dT;
-                Comp[BF] = Vel[BF] * K[HorizDampKp];
-                Comp[BF] = Limit(Comp[BF], -DAMP_HORIZ_LIMIT, DAMP_HORIZ_LIMIT);
-                Vel[BF] = DecayX(Vel[BF], K[HorizDampDecay]);
-            } else {
-                Vel[LR] = Vel[BF] = 0;
-                Comp[LR] = Decay1(Comp[LR]);
-                Comp[BF] = Decay1(Comp[BF]);
-            }
-        } else {
-            Vel[LR] = Vel[BF] = 0;
-
-            Comp[LR] = Decay1(Comp[LR]);
-            Comp[BF] = Decay1(Comp[BF]);
-        }
-    } else
-        for ( i = 0; i < (uint8)3; i++ )
-            Comp[i] = Vel[i] = 0.0;
-
-} // InertialDamping
 
 void DoOrientationTransform(void) {
     static real32 OSO, OCO;
@@ -222,13 +209,13 @@
 
     // PC+RS
     ControlPitch = (int16)( DesiredPitch * OCO + DesiredRoll * OSO );
-    
+
     CameraRollAngle = Angle[Pitch] * OSO + Angle[Roll] * OCO;
     CameraPitchAngle = Angle[Pitch] * OCO - Angle[Roll] * OSO;
 
 } // DoOrientationTransform
 
-void GainSchedule(boolean UseAngle) {
+void GainSchedule(void) {
 
     /*
     // rudimentary gain scheduling (linear)
@@ -258,21 +245,64 @@
 
     GS = 1.0; // Temp
 
-    GRollKp = K[RollKp];
-    GRollKi = K[RollKi];
-    GRollKd = K[RollKd];
 
-    GPitchKp = K[PitchKp];
-    GPitchKi = K[PitchKi];
-    GPitchKd = K[PitchKd];
 
 } // GainSchedule
 
+const real32 RelayKcu = ( 4.0 * 10 )/ ( PI * 0.8235 ); // stimulus 10 => Kcu 15.5
+const real32 RelayPd  = 2.0 * 1.285;
+const real32 RelayStim = 3.0;
+
+real32 RelayA = 0.0;
+real32 RelayTau = 0.0;
+uint32 RelayIteration = 0;
+real32 RelayP, RelayW;
+
+void DoRelayTuning(void) {
+
+    static real32 Temp;
+
+    Temp = fabs(Angle[Roll]);
+    if ( Temp > RelayA ) RelayA = Temp;
+
+    if ( ( RelayP < 0.0 ) && ( Angle[Roll] >= 0.0 ) ) {
+
+        RelayTau = RelayIteration * dT;
+
+        RelayP = - (PI * RelayA) / (4.0 * RelayStim);
+        RelayW = (2.0 * PI) / RelayTau;
+
+#ifndef PID_RAW
+        SendPIDTuning();
+#endif // PID_RAW
+
+        RelayA = 0.0;
+        RelayIteration = 0;
+    }
+
+    RelayIteration++;
+    RelayP = Angle[Roll];
+
+} // DoRelayTuning
+
+void Relay(void) {
+
+    if ( Angle[Roll] < 0.0 )
+        Rl = -RelayStim;
+    else
+        Rl = +RelayStim;
+
+    DesiredRoll = Rl;
+
+} // Relay
+
 void DoControl(void) {
 
+    static real32 RateE;
+
+
     GetAttitude();
     AltitudeHold();
-    InertialDamping();
 
 #ifdef SIMULATE
 
@@ -290,78 +320,70 @@
 
     DoOrientationTransform();
 
-    GainSchedule(F.UsingAngleControl);
+    GainSchedule();
 
 #ifdef DISABLE_EXTRAS
     // for commissioning
-    Comp[BF] = Comp[LR] = Comp[UD] = Comp[Alt] = 0;
+    AccAltComp = AltComp = 0.0;
     NavCorr[Roll] = NavCorr[Pitch] = NavCorr[Yaw] = 0;
-    F.UsingAngleControl = false;
 #endif // DISABLE_EXTRAS
 
-    if ( F.UsingAngleControl ) {
-        // Roll
-
-        AngleE[Roll] = ( ControlRoll * ATTITUDE_SCALE ) - Angle[Roll];
-        AngleIntE[Roll] += AngleE[Roll] * dT;
-        AngleIntE[Roll] = Limit(AngleIntE[Roll], -K[RollIntLimit], K[RollIntLimit]);
-        Rl  = -(AngleE[Roll] * GRollKp + AngleIntE[Roll] * GRollKi + Rate[Roll] * GRollKd * dTR);
-        Rl -=  NavCorr[Roll] - Comp[LR];
+    // Roll
 
-        // Pitch
+#ifdef USE_ANGLE_DERIVED_RATE  // Gyro rate noisy so compute from angle
+    RateE = ( Angle[Roll] - Anglep[Roll] ) * dTR;
+#else
+    RateE = Rate[Roll];
+#endif // USE_ANGLE_DERIVED_RATE
+    Rl  = RateE * GRollKp + Angle[Roll] * GRollKi + ( RateE - Ratep[Roll] ) * GRollKd * dTR;
+    Rl += ControlRoll + NavCorr[Roll];
 
-        AngleE[Pitch] = ( ControlPitch * ATTITUDE_SCALE ) - Angle[Pitch];
-        AngleIntE[Pitch] += AngleE[Pitch] * dT;
-        AngleIntE[Pitch] = Limit(AngleIntE[Pitch], -K[PitchIntLimit], K[PitchIntLimit]);
-        Pl  = -(AngleE[Pitch] * GPitchKp + AngleIntE[Pitch] * GPitchKi + Rate[Pitch] * GPitchKd * dTR);
-        Pl -= NavCorr[Pitch] - Comp[BF];
-
-    } else {
-        // Roll
+#ifdef USE_ANGLE_DERIVED_RATE
+    Ratep[Roll] = RateE;
+    Anglep[Roll] = Angle[Roll];
+#else
+    Ratep[Roll] = Rate[Roll];
+#endif // USE_ANGLE_DERIVED_RATE
 
-        AngleE[Roll] = Limit(Angle[Roll],  -K[RollIntLimit], K[RollIntLimit]);
-        Rl  = Rate[Roll] * GRollKp + AngleE[Roll] * GRollKi + (Rate[Roll]-Ratep[Roll]) * GRollKd * dTR;
-        Rl -=  NavCorr[Roll] - Comp[LR];
-          
-        Rl *= GS;
-
-        Rl -= ControlRoll;
-
-        ControlRollP = ControlRoll;
-        Ratep[Roll] = Rate[Roll];
+    // Pitch
 
-        // Pitch
+#ifdef USE_ANGLE_DERIVED_RATE // Gyro rate noisy so compute from angle
+    RateE = ( Angle[Pitch] - Anglep[Pitch] ) * dTR;
+#else
+    RateE = Rate[Pitch];
+#endif // USE_ANGLE_DERIVED_RATE
+    Pl  = RateE * GPitchKp + Angle[Pitch] * GPitchKi + ( RateE - Ratep[Pitch] ) * GPitchKd * dTR;
+    Pl += ControlPitch + NavCorr[Pitch];
 
-        AngleE[Pitch] = Limit(Angle[Pitch],  -K[PitchIntLimit], K[PitchIntLimit]);
-        Pl  = Rate[Pitch] * GPitchKp + AngleE[Pitch] * GPitchKi + (Rate[Pitch]-Ratep[Pitch]) * GPitchKd * dTR;
-        Pl -= NavCorr[Pitch] - Comp[BF];
-        
-        Pl *= GS;
-
-        Pl -= ControlPitch;
-
-        ControlPitchP = ControlPitch;
-        Ratep[Pitch] = Rate[Pitch];
-    }
+#ifdef USE_ANGLE_DERIVED_RATE
+    Ratep[Pitch] = RateE;
+    Anglep[Pitch] = Angle[Pitch];
+#else
+    Ratep[Pitch] = Rate[Pitch];
+#endif // USE_ANGLE_DERIVED_RATE    
 
     // Yaw
 
-    Rate[Yaw] -= NavCorr[Yaw];
-    if ( abs(DesiredYaw) > 5 )
-        Rate[Yaw] -= DesiredYaw;
+#define MAX_YAW_RATE  (HALFPI / RC_NEUTRAL)  // Radians/Sec e.g. HalfPI is 90deg/sec
+
+    DoLegacyYawComp(AttitudeMethod); // returns Angle as heading error along with compensated rate
 
-    Yl  = Rate[Yaw] * K[YawKp] + Angle[Yaw] * K[YawKi] + (Rate[Yaw]-Ratep[Yaw]) * K[YawKd] * dTR;
-    Ratep[Yaw] = Rate[Yaw];
+    RateE =  Rate[Yaw] + ( DesiredYaw + NavCorr[Yaw] ) * MAX_YAW_RATE;
+
+    YawRateIntE += RateE;
+    YawRateIntE = Limit1(YawRateIntE, YawIntLimit);
+
+    Yl =  RateE * K[YawKp] + YawRateIntE * K[YawKi];
 
 #ifdef TRICOPTER
     Yl = SlewLimit(Ylp, Yl, 2.0);
     Ylp = Yl;
-    Yl = Limit(Yl, -K[YawLimit] * 4.0, K[YawLimit] * 4.0);
+    Yl = Limit1(Yl, K[YawLimit] * 4.0);
 #else
-    Yl = Limit(Yl, -K[YawLimit], K[YawLimit]);
+    Yl = Limit1(Yl, K[YawLimit]); // currently 25 default
 #endif // TRICOPTER
 
-#endif // SIMULATE        
+#endif // SIMULATE 
 
 } // DoControl
 
@@ -435,8 +457,14 @@
     AltuSp = DescentLimiter = 0;
 
     for ( i = 0; i < (uint8)3; i++ )
-        AngleE[i] = AngleIntE[i] = Angle[i] = Anglep[i] = Rate[i] = Trim[i] = Vel[i] = Comp[i] = 0.0;
+        Angle[i] = Anglep[i] = Rate[i] = Vel[i] =  0.0;
+       
+    AccAltComp = AltComp = 0.0;
 
-    Comp[Alt] = AltSum = Ylp = ControlRollP = ControlPitchP = AltitudeP = 0.0;
+    YawRateIntE = 0.0;
+
+    AltSum = Ylp =  AltitudeP = 0.0;
+    ControlUpdateTimeuS = 0;
 
 } // InitControl
+