UAVX Multicopter Flight Controller.

Dependencies:   mbed

Committer:
gke
Date:
Tue Apr 26 12:12:29 2011 +0000
Revision:
2:90292f8bd179
Parent:
1:1e3318a30ddd
Not flightworthy. Posted for others to make use of the I2C SW code.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
gke 0:62a1c91a859a 1 // ===============================================================================================
gke 0:62a1c91a859a 2 // = UAVXArm Quadrocopter Controller =
gke 0:62a1c91a859a 3 // = Copyright (c) 2008 by Prof. Greg Egan =
gke 0:62a1c91a859a 4 // = Original V3.15 Copyright (c) 2007 Ing. Wolfgang Mahringer =
gke 2:90292f8bd179 5 // = http://code.google.com/p/uavp-mods/ =
gke 0:62a1c91a859a 6 // ===============================================================================================
gke 0:62a1c91a859a 7
gke 0:62a1c91a859a 8 // This is part of UAVXArm.
gke 0:62a1c91a859a 9
gke 0:62a1c91a859a 10 // UAVXArm is free software: you can redistribute it and/or modify it under the terms of the GNU
gke 0:62a1c91a859a 11 // General Public License as published by the Free Software Foundation, either version 3 of the
gke 0:62a1c91a859a 12 // License, or (at your option) any later version.
gke 0:62a1c91a859a 13
gke 0:62a1c91a859a 14 // UAVXArm is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without
gke 0:62a1c91a859a 15 // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
gke 0:62a1c91a859a 16 // See the GNU General Public License for more details.
gke 0:62a1c91a859a 17
gke 0:62a1c91a859a 18 // You should have received a copy of the GNU General Public License along with this program.
gke 0:62a1c91a859a 19 // If not, see http://www.gnu.org/licenses/
gke 0:62a1c91a859a 20
gke 0:62a1c91a859a 21 #include "UAVXArm.h"
gke 0:62a1c91a859a 22
gke 0:62a1c91a859a 23 void ReadParameters(void);
gke 0:62a1c91a859a 24 void UseDefaultParameters(void);
gke 0:62a1c91a859a 25 void UpdateWhichParamSet(void);
gke 0:62a1c91a859a 26 boolean ParameterSanityCheck(void);
gke 0:62a1c91a859a 27 void InitParameters(void);
gke 0:62a1c91a859a 28
gke 0:62a1c91a859a 29 const uint8 ESCLimits [] = { OUT_MAXIMUM, OUT_HOLGER_MAXIMUM, OUT_X3D_MAXIMUM, OUT_YGEI2C_MAXIMUM };
gke 0:62a1c91a859a 30
gke 0:62a1c91a859a 31 #ifdef MULTICOPTER
gke 0:62a1c91a859a 32 #include "uavx_multicopter.h"
gke 0:62a1c91a859a 33 #else
gke 0:62a1c91a859a 34 #ifdef HELICOPTER
gke 0:62a1c91a859a 35 #include "uavx_helicopter.h"
gke 0:62a1c91a859a 36 #else
gke 0:62a1c91a859a 37 #ifdef ELEVONS
gke 0:62a1c91a859a 38 #include "uavx_elevon.h"
gke 0:62a1c91a859a 39 #else
gke 0:62a1c91a859a 40 #include "uavx_aileron.h"
gke 0:62a1c91a859a 41 #endif
gke 0:62a1c91a859a 42 #endif
gke 0:62a1c91a859a 43 #endif
gke 0:62a1c91a859a 44
gke 0:62a1c91a859a 45 uint8 ParamSet;
gke 0:62a1c91a859a 46 boolean ParametersChanged, SaveAllowTurnToWP;
gke 0:62a1c91a859a 47
gke 0:62a1c91a859a 48 int8 P[MAX_PARAMETERS];
gke 0:62a1c91a859a 49 real32 K[MAX_PARAMETERS]; // Arm rescaled legacy parameters as appropriate
gke 0:62a1c91a859a 50
gke 0:62a1c91a859a 51 real32 OSin[48], OCos[48];
gke 0:62a1c91a859a 52
gke 0:62a1c91a859a 53 uint8 Orientation , PolarOrientation;
gke 0:62a1c91a859a 54 uint8 UAVXAirframe;
gke 0:62a1c91a859a 55
gke 0:62a1c91a859a 56 void Legacy(void) {
gke 0:62a1c91a859a 57 static uint8 p;
gke 1:1e3318a30ddd 58
gke 2:90292f8bd179 59 for ( p = 0; p < MAX_PARAMETERS; p++ ) // brute force
gke 0:62a1c91a859a 60 K[p] = (float)P[p];
gke 2:90292f8bd179 61
gke 2:90292f8bd179 62 GRollKp = K[RollKp];
gke 2:90292f8bd179 63 GRollKi = K[RollKi];
gke 2:90292f8bd179 64 GRollKd = K[RollKd];
gke 0:62a1c91a859a 65
gke 2:90292f8bd179 66 GPitchKp = K[PitchKp];
gke 2:90292f8bd179 67 GPitchKi = K[PitchKi];
gke 2:90292f8bd179 68 GPitchKd = K[PitchKd];
gke 0:62a1c91a859a 69
gke 2:90292f8bd179 70 K[RollIntLimit] *= (DEGRAD * 10.0);
gke 2:90292f8bd179 71 K[PitchIntLimit] *= (DEGRAD * 10.0);
gke 0:62a1c91a859a 72
gke 0:62a1c91a859a 73 // Altitude Hold
gke 0:62a1c91a859a 74 K[AltKp] *= 0.625;
gke 0:62a1c91a859a 75 K[AltKi] *= 25.0;
gke 0:62a1c91a859a 76 K[AltKd] *= 0.125;
gke 0:62a1c91a859a 77
gke 0:62a1c91a859a 78 // Navigation
gke 0:62a1c91a859a 79 K[NavKi] *= 0.08;
gke 0:62a1c91a859a 80 K[NavKd] *= 0.0008;
gke 0:62a1c91a859a 81
gke 0:62a1c91a859a 82 K[Balance] = ( 128.0 + (float)P[Balance])/128.0;
gke 0:62a1c91a859a 83
gke 2:90292f8bd179 84 K[CompassKp] = P[CompassKp] * 0.01;
gke 2:90292f8bd179 85
gke 2:90292f8bd179 86 K[YawKp] *= 2.6;
gke 2:90292f8bd179 87 K[YawKi] *= 4.14; // was 41.4
gke 2:90292f8bd179 88
gke 0:62a1c91a859a 89 K[YawIntLimit] = P[YawIntLimit] * 256.0 /1000.0;
gke 0:62a1c91a859a 90
gke 0:62a1c91a859a 91 // Camera
gke 0:62a1c91a859a 92 K[CamRollKp] *= 5.0;
gke 0:62a1c91a859a 93 K[CamPitchKp] *= 5.0;
gke 0:62a1c91a859a 94
gke 0:62a1c91a859a 95 // Acceleration Neutrals
gke 0:62a1c91a859a 96 K[MiddleBF] = P[MiddleBF] * 0.001; // mG
gke 0:62a1c91a859a 97 K[MiddleLR] = P[MiddleLR] * 0.001;
gke 0:62a1c91a859a 98 K[MiddleUD] = P[MiddleUD] * 0.001;
gke 0:62a1c91a859a 99
gke 0:62a1c91a859a 100 K[LowVoltThres] *= 0.2;
gke 0:62a1c91a859a 101
gke 0:62a1c91a859a 102 } // Legacy
gke 0:62a1c91a859a 103
gke 0:62a1c91a859a 104 void ReadParameters(void) {
gke 0:62a1c91a859a 105 static int8 i, b, a;
gke 0:62a1c91a859a 106
gke 0:62a1c91a859a 107 if ( ParametersChanged ) { // overkill if only a single parameter has changed but is not in flight loop
gke 0:62a1c91a859a 108 a = (ParamSet - 1)* MAX_PARAMETERS;
gke 0:62a1c91a859a 109 for ( i = 0; i < MAX_PARAMETERS; i++)
gke 0:62a1c91a859a 110 P[i] = ReadPX(a + i);
gke 0:62a1c91a859a 111
gke 0:62a1c91a859a 112 Legacy();
gke 0:62a1c91a859a 113
gke 0:62a1c91a859a 114 ESCMax = ESCLimits[P[ESCType]];
gke 0:62a1c91a859a 115 if ( P[ESCType] == ESCPPM )
gke 0:62a1c91a859a 116 ESCMin = 1;
gke 0:62a1c91a859a 117 else {
gke 0:62a1c91a859a 118 ESCMin = 0;
gke 0:62a1c91a859a 119 for ( i = 0; i < NoOfI2CESCOutputs; i++ )
gke 0:62a1c91a859a 120 ESCI2CFail[i] = 0;
gke 0:62a1c91a859a 121 InitI2CESCs();
gke 0:62a1c91a859a 122 }
gke 0:62a1c91a859a 123
gke 0:62a1c91a859a 124 b = P[ServoSense];
gke 0:62a1c91a859a 125 for ( i = 0; i < 8; i++ ) {
gke 0:62a1c91a859a 126 if ( b & 1 )
gke 0:62a1c91a859a 127 PWMSense[i] = -1;
gke 0:62a1c91a859a 128 else
gke 0:62a1c91a859a 129 PWMSense[i] = 1;
gke 0:62a1c91a859a 130 b >>=1;
gke 0:62a1c91a859a 131 }
gke 0:62a1c91a859a 132
gke 0:62a1c91a859a 133 F.UsingPositionHoldLock = ( (P[ConfigBits] & UsePositionHoldLockMask ) != 0);
gke 0:62a1c91a859a 134 F.UsingPolarCoordinates = ( (P[ConfigBits] & UsePolarMask ) != 0);
gke 0:62a1c91a859a 135
gke 0:62a1c91a859a 136 for ( i = 0; i < CONTROLS; i++) // make reverse map
gke 0:62a1c91a859a 137 RMap[Map[P[TxRxType]][i]] = i;
gke 0:62a1c91a859a 138
gke 0:62a1c91a859a 139 IdleThrottle = Limit((int16)P[PercentIdleThr], 10, 30); // 10-30%
gke 0:62a1c91a859a 140 IdleThrottle = (IdleThrottle * OUT_MAXIMUM )/100L;
gke 0:62a1c91a859a 141 CruiseThrottle = ((int16)P[PercentCruiseThr] * OUT_MAXIMUM )/100L;
gke 0:62a1c91a859a 142 MaxCruiseThrottle = (RC_MAXIMUM * 60L * OUT_MAXIMUM)/100L; // 60%
gke 0:62a1c91a859a 143
gke 0:62a1c91a859a 144 NavNeutralRadius = Limit((int16)P[NeutralRadius], 0, NAV_MAX_NEUTRAL_RADIUS);
gke 0:62a1c91a859a 145 NavNeutralRadius = ConvertMToGPS(NavNeutralRadius);
gke 0:62a1c91a859a 146
gke 0:62a1c91a859a 147 NavYCorrLimit = Limit((int16)P[NavYawLimit], 5, 50);
gke 0:62a1c91a859a 148
gke 0:62a1c91a859a 149 MagDeviation = (real32)P[NavMagVar] * DEGRAD;
gke 0:62a1c91a859a 150 CompassOffset = ((real32)((int16)P[CompassOffsetQtr] * 90L) * DEGRAD );
gke 0:62a1c91a859a 151 InitCompass();
gke 0:62a1c91a859a 152
gke 0:62a1c91a859a 153 #ifdef MULTICOPTER
gke 0:62a1c91a859a 154 Orientation = P[Orient];
gke 0:62a1c91a859a 155 if (Orientation == 0xff ) // uninitialised
gke 0:62a1c91a859a 156 Orientation = 0;
gke 0:62a1c91a859a 157 #else
gke 0:62a1c91a859a 158 Orientation = 0;
gke 0:62a1c91a859a 159 #endif // MULTICOPTER
gke 0:62a1c91a859a 160
gke 0:62a1c91a859a 161 F.UsingSerialPPM = ( P[TxRxType] == FrSkyDJT_D8R ) || ( P[TxRxType] == ExternalDecoder ) || ( (P[ConfigBits] & RxSerialPPMMask ) != 0);
gke 0:62a1c91a859a 162 DoRxPolarity();
gke 0:62a1c91a859a 163 PPM_Index = PrevEdge = 0;
gke 0:62a1c91a859a 164
gke 0:62a1c91a859a 165 F.UsingPolar = ((P[ConfigBits] & UsePolarMask) != 0);
gke 0:62a1c91a859a 166 F.RFInInches = ((P[ConfigBits] & RFInchesMask) != 0);
gke 0:62a1c91a859a 167
gke 0:62a1c91a859a 168 F.UsingTxMode2 = ((P[ConfigBits] & TxMode2Mask) != 0);
gke 0:62a1c91a859a 169
gke 0:62a1c91a859a 170 if ( P[GyroRollPitchType] == IRSensors )
gke 0:62a1c91a859a 171 F.UsingAngleControl = true;
gke 0:62a1c91a859a 172 else
gke 0:62a1c91a859a 173 F.UsingAngleControl = ((P[ConfigBits] & UseAngleControlMask) != 0);
gke 0:62a1c91a859a 174
gke 0:62a1c91a859a 175 F.UsingRTHAutoDescend = ((P[ConfigBits] & UseRTHDescendMask) != 0);
gke 0:62a1c91a859a 176 NavRTHTimeoutmS = (uint24)P[DescentDelayS]*1000L;
gke 0:62a1c91a859a 177
gke 0:62a1c91a859a 178 BatteryVolts = K[LowVoltThres];
gke 0:62a1c91a859a 179 BatteryCurrent = 0;
gke 0:62a1c91a859a 180
gke 0:62a1c91a859a 181 F.ParametersValid = ParameterSanityCheck();
gke 0:62a1c91a859a 182
gke 0:62a1c91a859a 183 ParametersChanged = false;
gke 0:62a1c91a859a 184
gke 0:62a1c91a859a 185 }
gke 0:62a1c91a859a 186 } // ReadParameters
gke 0:62a1c91a859a 187
gke 0:62a1c91a859a 188 void UseDefaultParameters(void) { // loads a representative set of initial parameters as a base for tuning
gke 0:62a1c91a859a 189 int8 p, d;
gke 0:62a1c91a859a 190 static int16 a;
gke 0:62a1c91a859a 191
gke 0:62a1c91a859a 192 for ( a = 0; a < PX_LENGTH; a++ )
gke 0:62a1c91a859a 193 PX[a] = 0xff;
gke 0:62a1c91a859a 194
gke 0:62a1c91a859a 195 for ( p = 0; p < MAX_PARAMETERS; p++ ) {
gke 0:62a1c91a859a 196 d = DefaultParams[p][0];
gke 0:62a1c91a859a 197 WritePX(p, d);
gke 0:62a1c91a859a 198 WritePX(p+MAX_PARAMETERS, d);
gke 0:62a1c91a859a 199 }
gke 0:62a1c91a859a 200
gke 0:62a1c91a859a 201 WritePX(NAV_NO_WP, 0); // set NoOfWaypoints to zero
gke 0:62a1c91a859a 202
gke 0:62a1c91a859a 203 WritePXImagefile();
gke 0:62a1c91a859a 204
gke 0:62a1c91a859a 205 TxString("\r\nDefault Parameters Loaded\r\n");
gke 0:62a1c91a859a 206 TxString("Do a READ CONFIG to refresh the UAVPSet parameter display\r\n");
gke 0:62a1c91a859a 207 } // UseDefaultParameters
gke 0:62a1c91a859a 208
gke 0:62a1c91a859a 209 void UpdateParamSetChoice(void) {
gke 0:62a1c91a859a 210 #define STICK_WINDOW 30
gke 0:62a1c91a859a 211
gke 0:62a1c91a859a 212 uint8 NewParamSet, NewAllowNavAltitudeHold, NewAllowTurnToWP;
gke 0:62a1c91a859a 213 int8 Selector;
gke 0:62a1c91a859a 214
gke 0:62a1c91a859a 215 NewParamSet = ParamSet;
gke 0:62a1c91a859a 216 NewAllowNavAltitudeHold = F.AllowNavAltitudeHold;
gke 0:62a1c91a859a 217 NewAllowTurnToWP = F.AllowTurnToWP;
gke 0:62a1c91a859a 218
gke 0:62a1c91a859a 219 if ( F.UsingTxMode2 )
gke 0:62a1c91a859a 220 Selector = DesiredRoll;
gke 0:62a1c91a859a 221 else
gke 0:62a1c91a859a 222 Selector = -DesiredYaw;
gke 0:62a1c91a859a 223
gke 0:62a1c91a859a 224 if ( (abs(DesiredPitch) > STICK_WINDOW) && (abs(Selector) > STICK_WINDOW) ) {
gke 0:62a1c91a859a 225 if ( DesiredPitch > STICK_WINDOW ) { // bottom
gke 0:62a1c91a859a 226 if ( Selector < -STICK_WINDOW ) // left
gke 0:62a1c91a859a 227 { // bottom left
gke 0:62a1c91a859a 228 NewParamSet = 1;
gke 0:62a1c91a859a 229 NewAllowNavAltitudeHold = true;
gke 0:62a1c91a859a 230 } else
gke 0:62a1c91a859a 231 if ( Selector > STICK_WINDOW ) // right
gke 0:62a1c91a859a 232 { // bottom right
gke 0:62a1c91a859a 233 NewParamSet = 2;
gke 0:62a1c91a859a 234 NewAllowNavAltitudeHold = true;
gke 0:62a1c91a859a 235 }
gke 0:62a1c91a859a 236 } else
gke 0:62a1c91a859a 237 if ( DesiredPitch < -STICK_WINDOW ) { // top
gke 0:62a1c91a859a 238 if ( Selector < -STICK_WINDOW ) { // left
gke 0:62a1c91a859a 239 NewAllowNavAltitudeHold = false;
gke 0:62a1c91a859a 240 NewParamSet = 1;
gke 0:62a1c91a859a 241 } else
gke 0:62a1c91a859a 242 if ( Selector > STICK_WINDOW ) { // right
gke 0:62a1c91a859a 243 NewAllowNavAltitudeHold = false;
gke 0:62a1c91a859a 244 NewParamSet = 2;
gke 0:62a1c91a859a 245 }
gke 0:62a1c91a859a 246 }
gke 0:62a1c91a859a 247
gke 0:62a1c91a859a 248 if ( ( NewParamSet != ParamSet ) || ( NewAllowNavAltitudeHold != F.AllowNavAltitudeHold ) ) {
gke 0:62a1c91a859a 249 ParamSet = NewParamSet;
gke 0:62a1c91a859a 250 F.AllowNavAltitudeHold = NewAllowNavAltitudeHold;
gke 0:62a1c91a859a 251 LEDBlue_ON;
gke 0:62a1c91a859a 252 DoBeep100mS(2, 2);
gke 0:62a1c91a859a 253 if ( ParamSet == (uint8)2 )
gke 0:62a1c91a859a 254 DoBeep100mS(2, 2);
gke 0:62a1c91a859a 255 if ( F.AllowNavAltitudeHold )
gke 0:62a1c91a859a 256 DoBeep100mS(4, 4);
gke 0:62a1c91a859a 257 ParametersChanged |= true;
gke 2:90292f8bd179 258 //zzz Beeper_OFF;
gke 0:62a1c91a859a 259 LEDBlue_OFF;
gke 0:62a1c91a859a 260 }
gke 0:62a1c91a859a 261 }
gke 0:62a1c91a859a 262
gke 0:62a1c91a859a 263 if ( F.UsingTxMode2 )
gke 0:62a1c91a859a 264 Selector = -DesiredYaw;
gke 0:62a1c91a859a 265 else
gke 0:62a1c91a859a 266 Selector = DesiredRoll;
gke 0:62a1c91a859a 267
gke 0:62a1c91a859a 268 if ( (abs(RC[ThrottleC]) < STICK_WINDOW) && (abs(Selector) > STICK_WINDOW ) ) {
gke 0:62a1c91a859a 269 if ( Selector < -STICK_WINDOW ) // left
gke 0:62a1c91a859a 270 NewAllowTurnToWP = false;
gke 0:62a1c91a859a 271 else
gke 0:62a1c91a859a 272 if ( Selector > STICK_WINDOW ) // left
gke 0:62a1c91a859a 273 NewAllowTurnToWP = true; // right
gke 0:62a1c91a859a 274
gke 0:62a1c91a859a 275 if ( NewAllowTurnToWP != F.AllowTurnToWP ) {
gke 0:62a1c91a859a 276 F.AllowTurnToWP = NewAllowTurnToWP;
gke 0:62a1c91a859a 277 LEDBlue_ON;
gke 0:62a1c91a859a 278 // if ( F.AllowTurnToWP )
gke 0:62a1c91a859a 279 DoBeep100mS(4, 2);
gke 0:62a1c91a859a 280
gke 0:62a1c91a859a 281 LEDBlue_OFF;
gke 0:62a1c91a859a 282 }
gke 0:62a1c91a859a 283 }
gke 0:62a1c91a859a 284
gke 0:62a1c91a859a 285 SaveAllowTurnToWP = F.AllowTurnToWP;
gke 0:62a1c91a859a 286
gke 0:62a1c91a859a 287 } // UpdateParamSetChoice
gke 0:62a1c91a859a 288
gke 0:62a1c91a859a 289 boolean ParameterSanityCheck(void) {
gke 0:62a1c91a859a 290 static boolean Fail;
gke 0:62a1c91a859a 291
gke 0:62a1c91a859a 292 Fail = (P[RollKp] == 0) ||
gke 0:62a1c91a859a 293 (P[PitchKp] == 0) ||
gke 0:62a1c91a859a 294 (P[YawKp] == 0);
gke 0:62a1c91a859a 295
gke 0:62a1c91a859a 296 return ( !Fail );
gke 0:62a1c91a859a 297 } // ParameterSanityCheck
gke 0:62a1c91a859a 298
gke 0:62a1c91a859a 299 void InitParameters(void) {
gke 0:62a1c91a859a 300 static int8 i;
gke 0:62a1c91a859a 301 static real32 A;
gke 0:62a1c91a859a 302
gke 0:62a1c91a859a 303 F.ParametersValid = false;
gke 0:62a1c91a859a 304 if ( !ReadPXImagefile() )
gke 0:62a1c91a859a 305 UseDefaultParameters();
gke 0:62a1c91a859a 306
gke 0:62a1c91a859a 307 UAVXAirframe = AF_TYPE;
gke 0:62a1c91a859a 308
gke 0:62a1c91a859a 309 for (i = 0; i < 48; i++) {
gke 0:62a1c91a859a 310 A = ((real32)i * PI)/24.0;
gke 0:62a1c91a859a 311 OSin[i] = sin(A);
gke 0:62a1c91a859a 312 OCos[i] = cos(A);
gke 0:62a1c91a859a 313 }
gke 0:62a1c91a859a 314 Orientation = 0;
gke 0:62a1c91a859a 315
gke 0:62a1c91a859a 316 ALL_LEDS_ON;
gke 0:62a1c91a859a 317
gke 0:62a1c91a859a 318 ParametersChanged = true;
gke 0:62a1c91a859a 319 ParamSet = 1;
gke 0:62a1c91a859a 320 ReadParameters();
gke 0:62a1c91a859a 321
gke 0:62a1c91a859a 322 ALL_LEDS_OFF;
gke 0:62a1c91a859a 323 } // InitParameters
gke 0:62a1c91a859a 324
gke 0:62a1c91a859a 325