Acc g scaling with DSP
[inav.git] / src / main / fc / rc_controls.c
blob67f9273d2622b64268618ad48a54661d275ed491
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>
22 #include <math.h>
24 #include "platform.h"
26 #include "build/debug.h"
28 #include "blackbox/blackbox.h"
30 #include "cms/cms.h"
32 #include "common/axis.h"
33 #include "common/maths.h"
34 #include "common/utils.h"
36 #include "config/feature.h"
37 #include "config/parameter_group.h"
38 #include "config/parameter_group_ids.h"
40 #include "drivers/time.h"
42 #include "fc/cli.h"
43 #include "fc/config.h"
44 #include "fc/controlrate_profile.h"
45 #include "fc/fc_core.h"
46 #include "fc/rc_controls.h"
47 #include "fc/rc_curves.h"
48 #include "fc/rc_modes.h"
49 #include "fc/runtime_config.h"
50 #include "fc/settings.h"
52 #include "flight/pid.h"
53 #include "flight/failsafe.h"
55 #include "io/gps.h"
56 #include "io/beeper.h"
58 #include "navigation/navigation.h"
60 #include "rx/rx.h"
62 #include "sensors/barometer.h"
63 #include "sensors/battery.h"
64 #include "sensors/sensors.h"
65 #include "sensors/gyro.h"
66 #include "sensors/acceleration.h"
68 #define AIRMODE_DEADBAND 25
69 #define MIN_RC_TICK_INTERVAL_MS 20
70 #define DEFAULT_RC_SWITCH_DISARM_DELAY_MS 250 // Wait at least 250ms before disarming via switch
71 #define DEFAULT_PREARM_TIMEOUT 10000 // Prearm is invalidated after 10 seconds
73 stickPositions_e rcStickPositions;
75 FASTRAM int16_t rcCommand[4]; // interval [1000;2000] for THROTTLE and [-500;+500] for ROLL/PITCH/YAW
77 PG_REGISTER_WITH_RESET_TEMPLATE(rcControlsConfig_t, rcControlsConfig, PG_RC_CONTROLS_CONFIG, 3);
79 PG_RESET_TEMPLATE(rcControlsConfig_t, rcControlsConfig,
80 .deadband = SETTING_DEADBAND_DEFAULT,
81 .yaw_deadband = SETTING_YAW_DEADBAND_DEFAULT,
82 .pos_hold_deadband = SETTING_POS_HOLD_DEADBAND_DEFAULT,
83 .control_deadband = SETTING_CONTROL_DEADBAND_DEFAULT,
84 .alt_hold_deadband = SETTING_ALT_HOLD_DEADBAND_DEFAULT,
85 .mid_throttle_deadband = SETTING_3D_DEADBAND_THROTTLE_DEFAULT,
86 .airmodeHandlingType = SETTING_AIRMODE_TYPE_DEFAULT,
87 .airmodeThrottleThreshold = SETTING_AIRMODE_THROTTLE_THRESHOLD_DEFAULT,
90 PG_REGISTER_WITH_RESET_TEMPLATE(armingConfig_t, armingConfig, PG_ARMING_CONFIG, 2);
92 PG_RESET_TEMPLATE(armingConfig_t, armingConfig,
93 .fixed_wing_auto_arm = SETTING_FIXED_WING_AUTO_ARM_DEFAULT,
94 .disarm_kill_switch = SETTING_DISARM_KILL_SWITCH_DEFAULT,
95 .switchDisarmDelayMs = SETTING_SWITCH_DISARM_DELAY_DEFAULT,
96 .prearmTimeoutMs = SETTING_PREARM_TIMEOUT_DEFAULT,
99 bool areSticksInApModePosition(uint16_t ap_mode)
101 return ABS(rcCommand[ROLL]) < ap_mode && ABS(rcCommand[PITCH]) < ap_mode;
104 bool areSticksDeflected(void)
106 return (ABS(rcCommand[ROLL]) > rcControlsConfig()->control_deadband) || (ABS(rcCommand[PITCH]) > rcControlsConfig()->control_deadband) || (ABS(rcCommand[YAW]) > rcControlsConfig()->control_deadband);
109 bool isRollPitchStickDeflected(uint8_t deadband)
111 return (ABS(rcCommand[ROLL]) > deadband) || (ABS(rcCommand[PITCH]) > deadband);
114 throttleStatus_e FAST_CODE NOINLINE calculateThrottleStatus(throttleStatusType_e type)
116 int value = rxGetChannelValue(THROTTLE); // THROTTLE_STATUS_TYPE_RC
117 if (type == THROTTLE_STATUS_TYPE_COMMAND) {
118 value = rcCommand[THROTTLE];
121 const uint16_t mid_throttle_deadband = rcControlsConfig()->mid_throttle_deadband;
122 bool midThrottle = value > (PWM_RANGE_MIDDLE - mid_throttle_deadband) && value < (PWM_RANGE_MIDDLE + mid_throttle_deadband);
123 if ((feature(FEATURE_REVERSIBLE_MOTORS) && midThrottle) || (!feature(FEATURE_REVERSIBLE_MOTORS) && (value < rxConfig()->mincheck))) {
124 return THROTTLE_LOW;
127 return THROTTLE_HIGH;
130 bool throttleStickIsLow(void)
132 return calculateThrottleStatus(feature(FEATURE_REVERSIBLE_MOTORS) ? THROTTLE_STATUS_TYPE_COMMAND : THROTTLE_STATUS_TYPE_RC) == THROTTLE_LOW;
135 int16_t throttleStickMixedValue(void)
137 int16_t throttleValue;
139 throttleValue = constrain(rxGetChannelValue(THROTTLE), rxConfig()->mincheck, PWM_RANGE_MAX);
140 throttleValue = (uint16_t)(throttleValue - rxConfig()->mincheck) * PWM_RANGE_MIN / (PWM_RANGE_MAX - rxConfig()->mincheck); // [MINCHECK;2000] -> [0;1000]
141 return rcLookupThrottle(throttleValue);
144 rollPitchStatus_e calculateRollPitchCenterStatus(void)
146 if (((rxGetChannelValue(PITCH) < (PWM_RANGE_MIDDLE + AIRMODE_DEADBAND)) && (rxGetChannelValue(PITCH) > (PWM_RANGE_MIDDLE -AIRMODE_DEADBAND)))
147 && ((rxGetChannelValue(ROLL) < (PWM_RANGE_MIDDLE + AIRMODE_DEADBAND)) && (rxGetChannelValue(ROLL) > (PWM_RANGE_MIDDLE -AIRMODE_DEADBAND))))
148 return CENTERED;
150 return NOT_CENTERED;
153 stickPositions_e getRcStickPositions(void)
155 return rcStickPositions;
158 bool checkStickPosition(stickPositions_e stickPos)
160 const uint8_t mask[4] = { ROL_LO | ROL_HI, PIT_LO | PIT_HI, YAW_LO | YAW_HI, THR_LO | THR_HI };
161 for (int i = 0; i < 4; i++) {
162 if (((stickPos & mask[i]) != 0) && ((stickPos & mask[i]) != (rcStickPositions & mask[i]))) {
163 return false;
167 return true;
170 static void updateRcStickPositions(void)
172 stickPositions_e tmp = 0;
174 tmp |= ((rxGetChannelValue(ROLL) > rxConfig()->mincheck) ? 0x02 : 0x00) << (ROLL * 2);
175 tmp |= ((rxGetChannelValue(ROLL) < rxConfig()->maxcheck) ? 0x01 : 0x00) << (ROLL * 2);
177 tmp |= ((rxGetChannelValue(PITCH) > rxConfig()->mincheck) ? 0x02 : 0x00) << (PITCH * 2);
178 tmp |= ((rxGetChannelValue(PITCH) < rxConfig()->maxcheck) ? 0x01 : 0x00) << (PITCH * 2);
180 tmp |= ((rxGetChannelValue(YAW) > rxConfig()->mincheck) ? 0x02 : 0x00) << (YAW * 2);
181 tmp |= ((rxGetChannelValue(YAW) < rxConfig()->maxcheck) ? 0x01 : 0x00) << (YAW * 2);
183 tmp |= ((rxGetChannelValue(THROTTLE) > rxConfig()->mincheck) ? 0x02 : 0x00) << (THROTTLE * 2);
184 tmp |= ((rxGetChannelValue(THROTTLE) < rxConfig()->maxcheck) ? 0x01 : 0x00) << (THROTTLE * 2);
186 rcStickPositions = tmp;
189 void processRcStickPositions(bool isThrottleLow)
191 static timeMs_t lastTickTimeMs = 0;
192 static uint8_t rcDelayCommand; // this indicates the number of time (multiple of RC measurement at 50Hz) the sticks must be maintained to run or switch off motors
193 static uint32_t rcSticks; // this hold sticks position for command combos
194 static timeMs_t rcDisarmTimeMs; // this is an extra guard for disarming through switch to prevent that one frame can disarm it
195 const timeMs_t currentTimeMs = millis();
197 updateRcStickPositions();
199 uint32_t stTmp = getRcStickPositions();
200 if (stTmp == rcSticks) {
201 if (rcDelayCommand < 250) {
202 if ((currentTimeMs - lastTickTimeMs) >= MIN_RC_TICK_INTERVAL_MS) {
203 lastTickTimeMs = currentTimeMs;
204 rcDelayCommand++;
207 } else {
208 rcDelayCommand = 0;
211 rcSticks = stTmp;
213 // perform actions
214 bool armingSwitchIsActive = IS_RC_MODE_ACTIVE(BOXARM);
216 if (STATE(AIRPLANE) && feature(FEATURE_MOTOR_STOP) && armingConfig()->fixed_wing_auto_arm) {
217 // Auto arm on throttle when using fixedwing and motorstop
218 if (!isThrottleLow) {
219 tryArm();
220 return;
223 else {
224 if (armingSwitchIsActive) {
225 rcDisarmTimeMs = currentTimeMs;
226 tryArm();
227 } else {
228 emergencyArmingUpdate(armingSwitchIsActive);
229 // Disarming via ARM BOX
230 // Don't disarm via switch if failsafe is active or receiver doesn't receive data - we can't trust receiver
231 // and can't afford to risk disarming in the air
232 if (ARMING_FLAG(ARMED) && !IS_RC_MODE_ACTIVE(BOXFAILSAFE) && rxIsReceivingSignal() && !failsafeIsActive()) {
233 const timeMs_t disarmDelay = currentTimeMs - rcDisarmTimeMs;
234 if (disarmDelay > armingConfig()->switchDisarmDelayMs) {
235 if (armingConfig()->disarm_kill_switch || isThrottleLow) {
236 disarm(DISARM_SWITCH);
240 else {
241 rcDisarmTimeMs = currentTimeMs;
245 // KILLSWITCH disarms instantly
246 if (IS_RC_MODE_ACTIVE(BOXKILLSWITCH)) {
247 disarm(DISARM_KILLSWITCH);
251 if (rcDelayCommand != 20) {
252 return;
255 /* Disable stick commands when armed, in CLI mode or CMS is active */
256 bool disableStickCommands = ARMING_FLAG(ARMED) || cliMode;
257 #ifdef USE_CMS
258 disableStickCommands = disableStickCommands || cmsInMenu;
259 #endif
260 if (disableStickCommands) {
261 return;
264 /* REMAINING SECTION HANDLES STICK COMANDS ONLY */
266 // GYRO calibration
267 if (rcSticks == THR_LO + YAW_LO + PIT_LO + ROL_CE) {
268 gyroStartCalibration();
269 return;
273 #if defined(NAV_NON_VOLATILE_WAYPOINT_STORAGE)
274 // Save waypoint list
275 if (rcSticks == THR_LO + YAW_CE + PIT_HI + ROL_LO) {
276 const bool success = saveNonVolatileWaypointList();
277 beeper(success ? BEEPER_ACTION_SUCCESS : BEEPER_ACTION_FAIL);
280 // Load waypoint list
281 if (rcSticks == THR_LO + YAW_CE + PIT_HI + ROL_HI) {
282 const bool success = loadNonVolatileWaypointList(false);
283 beeper(success ? BEEPER_ACTION_SUCCESS : BEEPER_ACTION_FAIL);
285 #ifdef USE_MULTI_MISSION
286 // Increment multi mission index up
287 if (rcSticks == THR_LO + YAW_CE + PIT_CE + ROL_HI) {
288 selectMultiMissionIndex(1);
289 rcDelayCommand = 0;
290 return;
293 // Decrement multi mission index down
294 if (rcSticks == THR_LO + YAW_CE + PIT_CE + ROL_LO) {
295 selectMultiMissionIndex(-1);
296 rcDelayCommand = 0;
297 return;
299 #endif
300 if (rcSticks == THR_LO + YAW_CE + PIT_LO + ROL_HI) {
301 resetWaypointList();
302 beeper(BEEPER_ACTION_FAIL); // The above cannot fail, but traditionally, we play FAIL for not-loading
304 #endif
306 // Multiple configuration profiles
307 if (feature(FEATURE_TX_PROF_SEL)) {
309 uint8_t i = 0;
311 if (rcSticks == THR_LO + YAW_LO + PIT_CE + ROL_LO) // ROLL left -> Profile 1
312 i = 1;
313 else if (rcSticks == THR_LO + YAW_LO + PIT_HI + ROL_CE) // PITCH up -> Profile 2
314 i = 2;
315 else if (rcSticks == THR_LO + YAW_LO + PIT_CE + ROL_HI) // ROLL right -> Profile 3
316 i = 3;
318 if (i) {
319 setConfigProfileAndWriteEEPROM(i - 1);
320 return;
323 i = 0;
325 // Multiple battery configuration profiles
326 if (rcSticks == THR_HI + YAW_LO + PIT_CE + ROL_LO) // ROLL left -> Profile 1
327 i = 1;
328 else if (rcSticks == THR_HI + YAW_LO + PIT_HI + ROL_CE) // PITCH up -> Profile 2
329 i = 2;
330 else if (rcSticks == THR_HI + YAW_LO + PIT_CE + ROL_HI) // ROLL right -> Profile 3
331 i = 3;
333 if (i) {
334 setConfigBatteryProfileAndWriteEEPROM(i - 1);
335 batteryDisableProfileAutoswitch();
336 activateBatteryProfile();
337 return;
342 // Save config
343 if (rcSticks == THR_LO + YAW_LO + PIT_LO + ROL_HI) {
344 saveConfigAndNotify();
347 // Calibrating Acc
348 if (rcSticks == THR_HI + YAW_LO + PIT_LO + ROL_CE) {
349 accStartCalibration();
350 return;
353 // Calibrating Mag
354 if (rcSticks == THR_HI + YAW_HI + PIT_LO + ROL_CE) {
355 ENABLE_STATE(CALIBRATE_MAG);
356 return;
359 // Accelerometer Trim
360 if (rcSticks == THR_HI + YAW_CE + PIT_HI + ROL_CE) {
361 applyAndSaveBoardAlignmentDelta(0, -2);
362 rcDelayCommand = 10;
363 return;
364 } else if (rcSticks == THR_HI + YAW_CE + PIT_LO + ROL_CE) {
365 applyAndSaveBoardAlignmentDelta(0, 2);
366 rcDelayCommand = 10;
367 return;
368 } else if (rcSticks == THR_HI + YAW_CE + PIT_CE + ROL_HI) {
369 applyAndSaveBoardAlignmentDelta(-2, 0);
370 rcDelayCommand = 10;
371 return;
372 } else if (rcSticks == THR_HI + YAW_CE + PIT_CE + ROL_LO) {
373 applyAndSaveBoardAlignmentDelta(2, 0);
374 rcDelayCommand = 10;
375 return;
379 int32_t getRcStickDeflection(int32_t axis) {
380 return MIN(ABS(rxGetChannelValue(axis) - PWM_RANGE_MIDDLE), 500);