2 * This file is part of Betaflight.
4 * Betaflight 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 * Betaflight 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 Betaflight. If not, see <http://www.gnu.org/licenses/>.
21 #ifdef USE_ALTITUDE_HOLD
23 #include "build/debug.h"
24 #include "common/maths.h"
25 #include "config/config.h"
28 #include "fc/runtime_config.h"
30 #include "flight/autopilot.h"
31 #include "flight/failsafe.h"
32 #include "flight/position.h"
35 #include "pg/autopilot.h"
39 static const float taskIntervalSeconds
= HZ_TO_INTERVAL(ALTHOLD_TASK_RATE_HZ
); // i.e. 0.01 s
43 float targetAltitudeCm
;
47 bool allowStickAdjustment
;
50 altHoldState_t altHold
;
52 void altHoldReset(void)
54 resetAltitudeControl();
55 altHold
.targetAltitudeCm
= getAltitudeCm();
56 altHold
.targetVelocity
= 0.0f
;
59 void altHoldInit(void)
61 altHold
.isActive
= false;
62 altHold
.deadband
= altHoldConfig()->alt_hold_deadband
/ 100.0f
;
63 altHold
.allowStickAdjustment
= altHoldConfig()->alt_hold_deadband
;
64 altHold
.maxVelocity
= altHoldConfig()->alt_hold_adjust_rate
* 10.0f
; // 50 in CLI means 500cm/s
68 void altHoldProcessTransitions(void) {
70 if (FLIGHT_MODE(ALT_HOLD_MODE
)) {
71 if (!altHold
.isActive
) {
73 altHold
.isActive
= true;
76 altHold
.isActive
= false;
79 // ** the transition out of alt hold (exiting altHold) may be rough. Some notes... **
80 // The original PR had a gradual transition from hold throttle to pilot control throttle
81 // using !(altHoldRequested && altHold.isAltHoldActive) to run an exit function
82 // a cross-fade factor was sent to mixer.c based on time since the flight mode request was terminated
83 // it was removed primarily to simplify this PR
85 // hence in this PR's the user's throttle needs to be close to the hover throttle value on exiting altHold
86 // its not so bad because the 'target adjustment' by throttle requires that
87 // user throttle must be not more than half way out from hover for a stable hold
90 void altHoldUpdateTargetAltitude(void)
92 // User can adjust the target altitude with throttle, but only when
93 // - throttle is outside deadband, and
94 // - throttle is not low (zero), and
95 // - deadband is not configured to zero
97 float stickFactor
= 0.0f
;
99 if (altHold
.allowStickAdjustment
&& calculateThrottleStatus() != THROTTLE_LOW
) {
100 const float rcThrottle
= rcCommand
[THROTTLE
];
101 const float lowThreshold
= apConfig()->hover_throttle
- altHold
.deadband
* (apConfig()->hover_throttle
- PWM_RANGE_MIN
);
102 const float highThreshold
= apConfig()->hover_throttle
+ altHold
.deadband
* (PWM_RANGE_MAX
- apConfig()->hover_throttle
);
104 if (rcThrottle
< lowThreshold
) {
105 stickFactor
= scaleRangef(rcThrottle
, PWM_RANGE_MIN
, lowThreshold
, -1.0f
, 0.0f
);
106 } else if (rcThrottle
> highThreshold
) {
107 stickFactor
= scaleRangef(rcThrottle
, highThreshold
, PWM_RANGE_MAX
, 0.0f
, 1.0f
);
111 // if failsafe is active, and we get here, we are in failsafe landing mode, it controls throttle
112 if (failsafeIsActive()) {
113 // descend at up to 10 times faster when high
114 // default landing timeout is now 60s; must to get the quad down within this limit
115 // need a rapid descent when initiated high, and must slow down closer to ground
116 // this code doubles descent rate at 20m, to max 10x (10m/s on defaults) at 200m
117 // the deceleration may be a bit rocky if it starts very high up
118 // constant (set) deceleration target in the last 2m
119 stickFactor
= -(0.9f
+ constrainf(getAltitudeCm() / 2000.0f
, 0.1f
, 9.0f
));
121 altHold
.targetVelocity
= stickFactor
* altHold
.maxVelocity
;
123 // prevent stick input from moving target altitude too far away from current altitude
124 // otherwise it can be difficult to bring target altitude close to current altitude in a reasonable time
125 // using maxVelocity means the stick can bring altitude target to current within 1s
126 // this constrains the P and I response to user target changes, but not D of F responses
127 // Range is compared to distance that might be traveled in one second
128 if (fabsf(getAltitudeCm() - altHold
.targetAltitudeCm
) < altHold
.maxVelocity
* 1.0 /* s */) {
129 altHold
.targetAltitudeCm
+= altHold
.targetVelocity
* taskIntervalSeconds
;
133 void altHoldUpdate(void)
135 // check if the user has changed the target altitude using sticks
136 if (altHoldConfig()->alt_hold_adjust_rate
) {
137 altHoldUpdateTargetAltitude();
139 altitudeControl(altHold
.targetAltitudeCm
, taskIntervalSeconds
, altHold
.targetVelocity
);
142 void updateAltHold(timeUs_t currentTimeUs
) {
143 UNUSED(currentTimeUs
);
145 // check for enabling Alt Hold, otherwise do as little as possible while inactive
146 altHoldProcessTransitions();
148 if (altHold
.isActive
) {
153 bool isAltHoldActive(void) {
154 return altHold
.isActive
;