2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
29 #include "build/debug.h"
31 #include "common/maths.h"
32 #include "common/filter.h"
34 #include "fc/runtime_config.h"
36 #include "flight/position.h"
37 #include "flight/imu.h"
38 #include "flight/pid.h"
42 #include "scheduler/scheduler.h"
44 #include "sensors/sensors.h"
45 #include "sensors/barometer.h"
48 #include "pg/pg_ids.h"
50 static int32_t estimatedAltitudeCm
= 0; // in cm
52 static pt2Filter_t baroDerivativeLpf
;
61 PG_REGISTER_WITH_RESET_TEMPLATE(positionConfig_t
, positionConfig
, PG_POSITION
, 2);
63 PG_RESET_TEMPLATE(positionConfig_t
, positionConfig
,
65 .altNumSatsGpsUse
= POSITION_DEFAULT_ALT_NUM_SATS_GPS_USE
,
66 .altNumSatsBaroFallback
= POSITION_DEFAULT_ALT_NUM_SATS_BARO_FALLBACK
,
70 static int16_t estimatedVario
= 0; // in cm/s
72 int16_t calculateEstimatedVario(float baroAltVelocity
)
74 baroAltVelocity
= applyDeadband(baroAltVelocity
, 10.0f
); // cm/s, so ignore climb rates less than 0.1 m/s
75 return constrain(lrintf(baroAltVelocity
), -1500, 1500);
79 #if defined(USE_BARO) || defined(USE_GPS)
80 static bool altitudeOffsetSetBaro
= false;
81 static bool altitudeOffsetSetGPS
= false;
83 void calculateEstimatedAltitude()
85 static float baroAltOffset
= 0;
86 static float gpsAltOffset
= 0;
89 float baroAltVelocity
= 0;
91 uint8_t gpsNumSat
= 0;
93 #if defined(USE_GPS) && defined(USE_VARIO)
94 float gpsVertSpeed
= 0;
96 float gpsTrust
= 0.3; //conservative default
97 bool haveBaroAlt
= false;
98 bool haveGpsAlt
= false;
100 if (sensors(SENSOR_BARO
)) {
101 static float lastBaroAlt
= 0;
102 static bool initBaroFilter
= false;
103 if (!initBaroFilter
) {
104 const float cutoffHz
= barometerConfig()->baro_vario_lpf
/ 100.0f
;
105 const float sampleTimeS
= HZ_TO_INTERVAL(TASK_ALTITUDE_RATE_HZ
);
106 const float gain
= pt2FilterGain(cutoffHz
, sampleTimeS
);
107 pt2FilterInit(&baroDerivativeLpf
, gain
);
108 initBaroFilter
= true;
110 baroAlt
= baroUpsampleAltitude();
111 const float baroAltVelocityRaw
= (baroAlt
- lastBaroAlt
) * TASK_ALTITUDE_RATE_HZ
; // cm/s
112 baroAltVelocity
= pt2FilterApply(&baroDerivativeLpf
, baroAltVelocityRaw
);
113 lastBaroAlt
= baroAlt
;
114 if (baroIsCalibrated()) {
121 if (sensors(SENSOR_GPS
) && STATE(GPS_FIX
)) {
122 gpsAlt
= gpsSol
.llh
.altCm
;
123 gpsNumSat
= gpsSol
.numSat
;
125 gpsVertSpeed
= GPS_verticalSpeedInCmS
;
129 if (gpsSol
.hdop
!= 0) {
130 gpsTrust
= 100.0 / gpsSol
.hdop
;
132 // always use at least 10% of other sources besides gps if available
133 gpsTrust
= MIN(gpsTrust
, 0.9f
);
137 if (ARMING_FLAG(ARMED
) && !altitudeOffsetSetBaro
) {
138 baroAltOffset
= baroAlt
;
139 altitudeOffsetSetBaro
= true;
140 } else if (!ARMING_FLAG(ARMED
) && altitudeOffsetSetBaro
) {
141 altitudeOffsetSetBaro
= false;
144 baroAlt
-= baroAltOffset
;
150 goodGpsSats
= positionConfig()->altNumSatsGpsUse
;
151 badGpsSats
= positionConfig()->altNumSatsBaroFallback
;
154 if (ARMING_FLAG(ARMED
)) {
155 if (!altitudeOffsetSetGPS
&& gpsNumSat
>= goodGpsSats
) {
156 gpsAltOffset
= gpsAlt
- baroAlt
;
157 altitudeOffsetSetGPS
= true;
158 } else if (gpsNumSat
<= badGpsSats
) {
159 altitudeOffsetSetGPS
= false;
161 } else if (!ARMING_FLAG(ARMED
) && altitudeOffsetSetGPS
) {
162 altitudeOffsetSetGPS
= false;
165 gpsAlt
-= gpsAltOffset
;
167 if (!altitudeOffsetSetGPS
) {
172 if (haveGpsAlt
&& haveBaroAlt
&& positionConfig()->altSource
== DEFAULT
) {
173 if (ARMING_FLAG(ARMED
)) {
174 estimatedAltitudeCm
= gpsAlt
* gpsTrust
+ baroAlt
* (1 - gpsTrust
);
176 estimatedAltitudeCm
= gpsAlt
; //absolute altitude is shown before arming, ignore baro
179 // baro is a better source for vario, so ignore gpsVertSpeed
180 estimatedVario
= calculateEstimatedVario(baroAltVelocity
);
182 } else if (haveGpsAlt
&& (positionConfig()->altSource
== GPS_ONLY
|| positionConfig()->altSource
== DEFAULT
)) {
183 estimatedAltitudeCm
= gpsAlt
;
184 #if defined(USE_VARIO) && defined(USE_GPS)
185 estimatedVario
= gpsVertSpeed
;
187 } else if (haveBaroAlt
&& (positionConfig()->altSource
== BARO_ONLY
|| positionConfig()->altSource
== DEFAULT
)) {
188 estimatedAltitudeCm
= baroAlt
;
190 estimatedVario
= calculateEstimatedVario(baroAltVelocity
); // cm/s
194 DEBUG_SET(DEBUG_ALTITUDE
, 0, (int32_t)(100 * gpsTrust
));
195 DEBUG_SET(DEBUG_ALTITUDE
, 1, baroAlt
);
196 DEBUG_SET(DEBUG_ALTITUDE
, 2, gpsAlt
);
198 DEBUG_SET(DEBUG_ALTITUDE
, 3, estimatedVario
);
202 bool isAltitudeOffset(void)
204 return altitudeOffsetSetBaro
|| altitudeOffsetSetGPS
;
208 int32_t getEstimatedAltitudeCm(void)
210 return estimatedAltitudeCm
;
214 int16_t getEstimatedVario(void)
216 return estimatedVario
;