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/>.
24 #include "build/debug.h"
26 #include "common/maths.h"
27 #include "common/axis.h"
28 #include "common/utils.h"
29 #include "common/filter.h"
31 #include "config/feature.h"
32 #include "config/parameter_group.h"
33 #include "config/parameter_group_ids.h"
35 #include "fc/config.h"
36 #include "fc/controlrate_profile.h"
37 #include "fc/fc_core.h"
39 #include "fc/rc_controls.h"
40 #include "fc/runtime_config.h"
44 #include "scheduler/scheduler.h"
46 #include "flight/failsafe.h"
47 #include "flight/imu.h"
48 #include "flight/pid.h"
50 static float setpointRate
[3], rcDeflection
[3], rcDeflectionAbs
[3];
51 static float throttlePIDAttenuation
;
53 float getSetpointRate(int axis
) {
54 return setpointRate
[axis
];
57 float getRcDeflection(int axis
) {
58 return rcDeflection
[axis
];
61 float getRcDeflectionAbs(int axis
) {
62 return rcDeflectionAbs
[axis
];
65 float getThrottlePIDAttenuation(void) {
66 return throttlePIDAttenuation
;
69 #define THROTTLE_LOOKUP_LENGTH 12
70 static int16_t lookupThrottleRC
[THROTTLE_LOOKUP_LENGTH
]; // lookup table for expo & mid THROTTLE
72 void generateThrottleCurve(void)
76 for (i
= 0; i
< THROTTLE_LOOKUP_LENGTH
; i
++) {
77 int16_t tmp
= 10 * i
- currentControlRateProfile
->thrMid8
;
80 y
= 100 - currentControlRateProfile
->thrMid8
;
82 y
= currentControlRateProfile
->thrMid8
;
83 lookupThrottleRC
[i
] = 10 * currentControlRateProfile
->thrMid8
+ tmp
* (100 - currentControlRateProfile
->thrExpo8
+ (int32_t) currentControlRateProfile
->thrExpo8
* (tmp
* tmp
) / (y
* y
)) / 10;
84 lookupThrottleRC
[i
] = PWM_RANGE_MIN
+ (PWM_RANGE_MAX
- PWM_RANGE_MIN
) * lookupThrottleRC
[i
] / 1000; // [MINTHROTTLE;MAXTHROTTLE]
88 int16_t rcLookupThrottle(int32_t tmp
)
90 const int32_t tmp2
= tmp
/ 100;
91 // [0;1000] -> expo -> [MINTHROTTLE;MAXTHROTTLE]
92 return lookupThrottleRC
[tmp2
] + (tmp
- tmp2
* 100) * (lookupThrottleRC
[tmp2
+ 1] - lookupThrottleRC
[tmp2
]) / 100;
95 #define SETPOINT_RATE_LIMIT 1998.0f
96 #define RC_RATE_INCREMENTAL 14.54f
98 static void calculateSetpointRate(int axis
)
103 rcExpo
= currentControlRateProfile
->rcExpo8
;
104 rcRate
= currentControlRateProfile
->rcRate8
/ 100.0f
;
106 rcExpo
= currentControlRateProfile
->rcYawExpo8
;
107 rcRate
= currentControlRateProfile
->rcYawRate8
/ 100.0f
;
110 rcRate
+= RC_RATE_INCREMENTAL
* (rcRate
- 2.0f
);
113 float rcCommandf
= rcCommand
[axis
] / 500.0f
;
114 rcDeflection
[axis
] = rcCommandf
;
115 const float rcCommandfAbs
= ABS(rcCommandf
);
116 rcDeflectionAbs
[axis
] = rcCommandfAbs
;
119 const float expof
= rcExpo
/ 100.0f
;
120 rcCommandf
= rcCommandf
* power3(rcCommandfAbs
) * expof
+ rcCommandf
* (1-expof
);
123 float angleRate
= 200.0f
* rcRate
* rcCommandf
;
124 if (currentControlRateProfile
->rates
[axis
]) {
125 const float rcSuperfactor
= 1.0f
/ (constrainf(1.0f
- (rcCommandfAbs
* (currentControlRateProfile
->rates
[axis
] / 100.0f
)), 0.01f
, 1.00f
));
126 angleRate
*= rcSuperfactor
;
129 DEBUG_SET(DEBUG_ANGLERATE
, axis
, angleRate
);
131 setpointRate
[axis
] = constrainf(angleRate
, -SETPOINT_RATE_LIMIT
, SETPOINT_RATE_LIMIT
); // Rate limit protection (deg/sec)
134 static void scaleRcCommandToFpvCamAngle(void) {
135 //recalculate sin/cos only when rxConfig()->fpvCamAngleDegrees changed
136 static uint8_t lastFpvCamAngleDegrees
= 0;
137 static float cosFactor
= 1.0;
138 static float sinFactor
= 0.0;
140 if (lastFpvCamAngleDegrees
!= rxConfig()->fpvCamAngleDegrees
){
141 lastFpvCamAngleDegrees
= rxConfig()->fpvCamAngleDegrees
;
142 cosFactor
= cos_approx(rxConfig()->fpvCamAngleDegrees
* RAD
);
143 sinFactor
= sin_approx(rxConfig()->fpvCamAngleDegrees
* RAD
);
146 float roll
= setpointRate
[ROLL
];
147 float yaw
= setpointRate
[YAW
];
148 setpointRate
[ROLL
] = constrainf(roll
* cosFactor
- yaw
* sinFactor
, -SETPOINT_RATE_LIMIT
, SETPOINT_RATE_LIMIT
);
149 setpointRate
[YAW
] = constrainf(yaw
* cosFactor
+ roll
* sinFactor
, -SETPOINT_RATE_LIMIT
, SETPOINT_RATE_LIMIT
);
152 #define THROTTLE_BUFFER_MAX 20
153 #define THROTTLE_DELTA_MS 100
155 static void checkForThrottleErrorResetState(uint16_t rxRefreshRate
) {
157 static int16_t rcCommandThrottlePrevious
[THROTTLE_BUFFER_MAX
];
158 const int rxRefreshRateMs
= rxRefreshRate
/ 1000;
159 const int indexMax
= constrain(THROTTLE_DELTA_MS
/ rxRefreshRateMs
, 1, THROTTLE_BUFFER_MAX
);
160 const int16_t throttleVelocityThreshold
= (feature(FEATURE_3D
)) ? currentPidProfile
->itermThrottleThreshold
/ 2 : currentPidProfile
->itermThrottleThreshold
;
162 rcCommandThrottlePrevious
[index
++] = rcCommand
[THROTTLE
];
163 if (index
>= indexMax
)
166 const int16_t rcCommandSpeed
= rcCommand
[THROTTLE
] - rcCommandThrottlePrevious
[index
];
168 if(ABS(rcCommandSpeed
) > throttleVelocityThreshold
)
169 pidSetItermAccelerator(0.0001f
* currentPidProfile
->itermAcceleratorGain
);
171 pidSetItermAccelerator(1.0f
);
174 void processRcCommand(void)
176 static int16_t lastCommand
[4] = { 0, 0, 0, 0 };
177 static int16_t deltaRC
[4] = { 0, 0, 0, 0 };
178 static int16_t factor
, rcInterpolationFactor
;
179 static uint16_t currentRxRefreshRate
;
180 const uint8_t interpolationChannels
= rxConfig()->rcInterpolationChannels
+ 2;
181 uint16_t rxRefreshRate
;
182 bool readyToCalculateRate
= false;
183 uint8_t readyToCalculateRateAxisCnt
= 0;
186 currentRxRefreshRate
= constrain(getTaskDeltaTime(TASK_RX
),1000,20000);
187 if (isAntiGravityModeActive()) {
188 checkForThrottleErrorResetState(currentRxRefreshRate
);
192 if (rxConfig()->rcInterpolation
|| flightModeFlags
) {
193 // Set RC refresh rate for sampling and channels to filter
194 switch(rxConfig()->rcInterpolation
) {
195 case(RC_SMOOTHING_AUTO
):
196 rxRefreshRate
= currentRxRefreshRate
+ 1000; // Add slight overhead to prevent ramps
198 case(RC_SMOOTHING_MANUAL
):
199 rxRefreshRate
= 1000 * rxConfig()->rcInterpolationInterval
;
201 case(RC_SMOOTHING_OFF
):
202 case(RC_SMOOTHING_DEFAULT
):
204 rxRefreshRate
= rxGetRefreshRate();
208 rcInterpolationFactor
= rxRefreshRate
/ targetPidLooptime
+ 1;
210 if (debugMode
== DEBUG_RC_INTERPOLATION
) {
211 for(int axis
= 0; axis
< 2; axis
++) debug
[axis
] = rcCommand
[axis
];
212 debug
[3] = rxRefreshRate
;
215 for (int channel
=ROLL
; channel
< interpolationChannels
; channel
++) {
216 deltaRC
[channel
] = rcCommand
[channel
] - (lastCommand
[channel
] - deltaRC
[channel
] * factor
/ rcInterpolationFactor
);
217 lastCommand
[channel
] = rcCommand
[channel
];
220 factor
= rcInterpolationFactor
- 1;
225 // Interpolate steps of rcCommand
227 for (int channel
=ROLL
; channel
< interpolationChannels
; channel
++) {
228 rcCommand
[channel
] = lastCommand
[channel
] - deltaRC
[channel
] * factor
/rcInterpolationFactor
;
229 readyToCalculateRateAxisCnt
= MAX(channel
,FD_YAW
); // throttle channel doesn't require rate calculation
230 readyToCalculateRate
= true;
236 factor
= 0; // reset factor in case of level modes flip flopping
239 if (readyToCalculateRate
|| isRXDataNew
) {
241 readyToCalculateRateAxisCnt
= FD_YAW
;
243 for (int axis
= 0; axis
<= readyToCalculateRateAxisCnt
; axis
++)
244 calculateSetpointRate(axis
);
246 // Scaling of AngleRate to camera angle (Mixing Roll and Yaw)
247 if (rxConfig()->fpvCamAngleDegrees
&& IS_RC_MODE_ACTIVE(BOXFPVANGLEMIX
) && !FLIGHT_MODE(HEADFREE_MODE
))
248 scaleRcCommandToFpvCamAngle();
254 void updateRcCommands(void)
256 // PITCH & ROLL only dynamic PID adjustment, depending on throttle value
258 if (rcData
[THROTTLE
] < currentControlRateProfile
->tpa_breakpoint
) {
260 throttlePIDAttenuation
= 1.0f
;
262 if (rcData
[THROTTLE
] < 2000) {
263 prop
= 100 - (uint16_t)currentControlRateProfile
->dynThrPID
* (rcData
[THROTTLE
] - currentControlRateProfile
->tpa_breakpoint
) / (2000 - currentControlRateProfile
->tpa_breakpoint
);
265 prop
= 100 - currentControlRateProfile
->dynThrPID
;
267 throttlePIDAttenuation
= prop
/ 100.0f
;
270 for (int axis
= 0; axis
< 3; axis
++) {
271 // non coupled PID reduction scaler used in PID controller 1 and PID controller 2.
273 int32_t tmp
= MIN(ABS(rcData
[axis
] - rxConfig()->midrc
), 500);
274 if (axis
== ROLL
|| axis
== PITCH
) {
275 if (tmp
> rcControlsConfig()->deadband
) {
276 tmp
-= rcControlsConfig()->deadband
;
280 rcCommand
[axis
] = tmp
;
282 if (tmp
> rcControlsConfig()->yaw_deadband
) {
283 tmp
-= rcControlsConfig()->yaw_deadband
;
287 rcCommand
[axis
] = tmp
* -GET_DIRECTION(rcControlsConfig()->yaw_control_reversed
);
289 if (rcData
[axis
] < rxConfig()->midrc
) {
290 rcCommand
[axis
] = -rcCommand
[axis
];
295 if (feature(FEATURE_3D
)) {
296 tmp
= constrain(rcData
[THROTTLE
], PWM_RANGE_MIN
, PWM_RANGE_MAX
);
297 tmp
= (uint32_t)(tmp
- PWM_RANGE_MIN
);
299 tmp
= constrain(rcData
[THROTTLE
], rxConfig()->mincheck
, PWM_RANGE_MAX
);
300 tmp
= (uint32_t)(tmp
- rxConfig()->mincheck
) * PWM_RANGE_MIN
/ (PWM_RANGE_MAX
- rxConfig()->mincheck
);
303 rcCommand
[THROTTLE
] = rcLookupThrottle(tmp
);
305 if (feature(FEATURE_3D
) && IS_RC_MODE_ACTIVE(BOX3DDISABLESWITCH
) && !failsafeIsActive()) {
306 fix12_t throttleScaler
= qConstruct(rcCommand
[THROTTLE
] - 1000, 1000);
307 rcCommand
[THROTTLE
] = rxConfig()->midrc
+ qMultiply(throttleScaler
, PWM_RANGE_MAX
- rxConfig()->midrc
);
310 if (FLIGHT_MODE(HEADFREE_MODE
)) {
311 const float radDiff
= degreesToRadians(DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
) - headFreeModeHold
);
312 const float cosDiff
= cos_approx(radDiff
);
313 const float sinDiff
= sin_approx(radDiff
);
314 const int16_t rcCommand_PITCH
= rcCommand
[PITCH
] * cosDiff
+ rcCommand
[ROLL
] * sinDiff
;
315 rcCommand
[ROLL
] = rcCommand
[ROLL
] * cosDiff
- rcCommand
[PITCH
] * sinDiff
;
316 rcCommand
[PITCH
] = rcCommand_PITCH
;
320 void resetYawAxis(void) {
322 setpointRate
[YAW
] = 0;