Merge some betaflight changes into CF.
[betaflight.git] / src / main / flight / pid_mw23.c
blob15330f01de35f769bf933b1621c7bf0eb3435efc
1 /*
2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <string.h>
21 #include <math.h>
23 #include <platform.h>
25 #include "build/build_config.h"
27 #ifdef USE_PID_MW23
29 #include "common/axis.h"
30 #include "common/maths.h"
31 #include "common/filter.h"
33 #include "config/parameter_group.h"
34 #include "config/config_unittest.h"
36 #include "drivers/sensor.h"
37 #include "drivers/accgyro.h"
38 #include "drivers/gyro_sync.h"
40 #include "sensors/sensors.h"
41 #include "sensors/gyro.h"
42 #include "sensors/acceleration.h"
44 #include "rx/rx.h"
46 #include "fc/rc_controls.h"
47 #include "fc/rate_profile.h"
48 #include "fc/runtime_config.h"
50 #include "flight/pid.h"
51 #include "flight/imu.h"
52 #include "flight/navigation.h"
53 #include "flight/gtune.h"
54 #include "flight/mixer.h"
56 static int32_t ITermAngle[2];
58 uint8_t dynP8[3], dynI8[3], dynD8[3];
60 extern float dT;
61 extern uint8_t motorCount;
63 #ifdef BLACKBOX
64 extern int32_t axisPID_P[3], axisPID_I[3], axisPID_D[3];
65 #endif
66 extern int32_t lastITerm[3], ITermLimit[3];
68 extern pt1Filter_t deltaFilter[3];
71 void pidResetITermAngle(void)
73 ITermAngle[AI_ROLL] = 0;
74 ITermAngle[AI_PITCH] = 0;
77 void pidMultiWii23(const pidProfile_t *pidProfile, const controlRateConfig_t *controlRateConfig,
78 uint16_t max_angle_inclination, const rollAndPitchTrims_t *angleTrim, const rxConfig_t *rxConfig)
80 UNUSED(rxConfig);
82 pidInitFilters(pidProfile);
84 int axis, prop = 0;
85 int32_t rc, error, errorAngle, delta, gyroError;
86 int32_t PTerm, ITerm, PTermACC, ITermACC, DTerm;
87 static int16_t lastErrorForDelta[2];
88 static int32_t delta1[2], delta2[2];
90 if (FLIGHT_MODE(HORIZON_MODE)) {
91 prop = MIN(MAX(ABS(rcCommand[PITCH]), ABS(rcCommand[ROLL])), 512);
94 // PITCH & ROLL
95 for (axis = 0; axis < 2; axis++) {
97 rc = rcCommand[axis] << 1;
99 gyroError = gyroADC[axis] / 4;
101 error = rc - gyroError;
102 lastITerm[axis] = constrain(lastITerm[axis] + error, -16000, +16000); // WindUp 16 bits is ok here
104 if (ABS(gyroADC[axis]) > (640 * 4)) {
105 lastITerm[axis] = 0;
108 // Anti windup protection
109 if (rcModeIsActive(BOXAIRMODE)) {
110 if (STATE(ANTI_WINDUP) || motorLimitReached) {
111 lastITerm[axis] = constrain(lastITerm[axis], -ITermLimit[axis], ITermLimit[axis]);
112 } else {
113 ITermLimit[axis] = ABS(lastITerm[axis]);
117 ITerm = (lastITerm[axis] >> 7) * pidProfile->I8[axis] >> 6; // 16 bits is ok here 16000/125 = 128 ; 128*250 = 32000
119 PTerm = (int32_t)rc * pidProfile->P8[axis] >> 6;
121 if (FLIGHT_MODE(ANGLE_MODE) || FLIGHT_MODE(HORIZON_MODE)) { // axis relying on ACC
122 // 50 degrees max inclination
123 #ifdef GPS
124 errorAngle = constrain(2 * rcCommand[axis] + GPS_angle[axis], -((int) max_angle_inclination),
125 +max_angle_inclination) - attitude.raw[axis] + angleTrim->raw[axis];
126 #else
127 errorAngle = constrain(2 * rcCommand[axis], -((int) max_angle_inclination),
128 +max_angle_inclination) - attitude.raw[axis] + angleTrim->raw[axis];
129 #endif
131 ITermAngle[axis] = constrain(ITermAngle[axis] + errorAngle, -10000, +10000); // WindUp //16 bits is ok here
133 PTermACC = ((int32_t)errorAngle * pidProfile->P8[PIDLEVEL]) >> 7; // 32 bits is needed for calculation: errorAngle*P8 could exceed 32768 16 bits is ok for result
135 int16_t limit = pidProfile->D8[PIDLEVEL] * 5;
136 PTermACC = constrain(PTermACC, -limit, +limit);
138 ITermACC = ((int32_t)ITermAngle[axis] * pidProfile->I8[PIDLEVEL]) >> 12; // 32 bits is needed for calculation:10000*I8 could exceed 32768 16 bits is ok for result
140 ITerm = ITermACC + ((ITerm - ITermACC) * prop >> 9);
141 PTerm = PTermACC + ((PTerm - PTermACC) * prop >> 9);
144 PTerm -= ((int32_t)gyroError * dynP8[axis]) >> 6; // 32 bits is needed for calculation
146 //-----calculate D-term based on the configured approach (delta from measurement or deltafromError)
147 // Delta from measurement
148 delta = -(gyroError - lastErrorForDelta[axis]);
149 lastErrorForDelta[axis] = gyroError;
150 if (pidProfile->dterm_lpf_hz) {
151 // Dterm delta low pass
152 DTerm = delta;
153 DTerm = lrintf(pt1FilterApply4(&deltaFilter[axis], (float)DTerm, pidProfile->dterm_lpf_hz, dT)) * 3; // Keep same scaling as unfiltered DTerm
154 } else {
155 // When dterm filter disabled apply moving average to reduce noise
156 DTerm = delta1[axis] + delta2[axis] + delta;
157 delta2[axis] = delta1[axis];
158 delta1[axis] = delta;
160 DTerm = ((int32_t)DTerm * dynD8[axis]) >> 5; // 32 bits is needed for calculation
162 axisPID[axis] = PTerm + ITerm + DTerm;
164 #ifdef GTUNE
165 if (FLIGHT_MODE(GTUNE_MODE) && ARMING_FLAG(ARMED)) {
166 calculate_Gtune(axis);
168 #endif
170 #ifdef BLACKBOX
171 axisPID_P[axis] = PTerm;
172 axisPID_I[axis] = ITerm;
173 axisPID_D[axis] = DTerm;
174 #endif
177 //YAW
178 rc = (int32_t)rcCommand[YAW] * (2 * controlRateConfig->rates[YAW] + 30) >> 5;
179 #ifdef ALIENWFLIGHT
180 error = rc - gyroADC[FD_YAW];
181 #else
182 error = rc - (gyroADC[FD_YAW] / 4);
183 #endif
184 lastITerm[FD_YAW] += (int32_t)error * pidProfile->I8[FD_YAW];
185 lastITerm[FD_YAW] = constrain(lastITerm[FD_YAW], 2 - ((int32_t)1 << 28), -2 + ((int32_t)1 << 28));
186 if (ABS(rc) > 50) lastITerm[FD_YAW] = 0;
188 PTerm = (int32_t)error * pidProfile->P8[FD_YAW] >> 6; // TODO: Bitwise shift on a signed integer is not recommended
190 // Constrain YAW by D value if not servo driven in that case servolimits apply
191 if(motorCount >= 4 && pidProfile->yaw_p_limit < YAW_P_LIMIT_MAX) {
192 PTerm = constrain(PTerm, -pidProfile->yaw_p_limit, pidProfile->yaw_p_limit);
195 ITerm = constrain((int16_t)(lastITerm[FD_YAW] >> 13), -GYRO_I_MAX, +GYRO_I_MAX);
197 axisPID[FD_YAW] = PTerm + ITerm;
199 #ifdef GTUNE
200 if (FLIGHT_MODE(GTUNE_MODE) && ARMING_FLAG(ARMED)) {
201 calculate_Gtune(FD_YAW);
203 #endif
205 #ifdef BLACKBOX
206 axisPID_P[FD_YAW] = PTerm;
207 axisPID_I[FD_YAW] = ITerm;
208 axisPID_D[FD_YAW] = 0;
209 #endif
212 #endif