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/>.
22 #include "build_config.h"
26 #include "common/axis.h"
27 #include "common/maths.h"
28 #include "common/filter.h"
30 #include "drivers/system.h"
31 #include "drivers/sensor.h"
32 #include "drivers/accgyro.h"
34 #include "sensors/sensors.h"
35 #include "sensors/acceleration.h"
36 #include "sensors/boardalignment.h"
38 #include "io/beeper.h"
41 #include "flight/pid.h"
42 #include "flight/imu.h"
43 #include "flight/navigation_rewrite.h"
44 #include "flight/navigation_rewrite_private.h"
46 #include "config/runtime_config.h"
47 #include "config/config.h"
49 /*-----------------------------------------------------------
50 * Compatibility for home position
51 *-----------------------------------------------------------*/
52 gpsLocation_t GPS_home
;
53 uint16_t GPS_distanceToHome
; // distance to home point in meters
54 int16_t GPS_directionToHome
; // direction to home point in degrees
57 navigationPosControl_t posControl
;
58 navSystemStatus_t NAV_Status
;
60 #if defined(NAV_BLACKBOX)
61 int16_t navCurrentState
;
62 int16_t navActualVelocity
[3];
63 int16_t navDesiredVelocity
[3];
64 int16_t navActualHeading
;
65 int16_t navDesiredHeading
;
66 int16_t navTargetPosition
[3];
67 int32_t navLatestActualPosition
[3];
69 int16_t navTargetSurface
;
70 int16_t navActualSurface
;
74 static void updateDesiredRTHAltitude(void);
75 static void resetAltitudeController(void);
76 static void resetPositionController(void);
77 static void setupAltitudeController(void);
78 void resetNavigation(void);
80 static void calcualteAndSetActiveWaypoint(navWaypoint_t
* waypoint
);
81 static void calcualteAndSetActiveWaypointToLocalPosition(t_fp_vector
* pos
);
82 void calculateInitialHoldPosition(t_fp_vector
* pos
);
83 void calculateFarAwayTarget(t_fp_vector
* farAwayPos
, int32_t yaw
, int32_t distance
);
85 /*************************************************************************************************/
86 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_IDLE(navigationFSMState_t previousState
);
87 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_ALTHOLD_INITIALIZE(navigationFSMState_t previousState
);
88 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_ALTHOLD_IN_PROGRESS(navigationFSMState_t previousState
);
89 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_POSHOLD_2D_INITIALIZE(navigationFSMState_t previousState
);
90 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_POSHOLD_2D_IN_PROGRESS(navigationFSMState_t previousState
);
91 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_POSHOLD_3D_INITIALIZE(navigationFSMState_t previousState
);
92 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_POSHOLD_3D_IN_PROGRESS(navigationFSMState_t previousState
);
93 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_INITIALIZE(navigationFSMState_t previousState
);
94 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_2D_INITIALIZE(navigationFSMState_t previousState
);
95 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_2D_HEAD_HOME(navigationFSMState_t previousState
);
96 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_2D_GPS_FAILING(navigationFSMState_t previousState
);
97 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_2D_FINISHING(navigationFSMState_t previousState
);
98 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_2D_FINISHED(navigationFSMState_t previousState
);
99 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_INITIALIZE(navigationFSMState_t previousState
);
100 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_CLIMB_TO_SAFE_ALT(navigationFSMState_t previousState
);
101 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_HEAD_HOME(navigationFSMState_t previousState
);
102 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_GPS_FAILING(navigationFSMState_t previousState
);
103 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_HOVER_PRIOR_TO_LANDING(navigationFSMState_t previousState
);
104 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_LANDING(navigationFSMState_t previousState
);
105 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_FINISHING(navigationFSMState_t previousState
);
106 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_FINISHED(navigationFSMState_t previousState
);
107 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_WAYPOINT_INITIALIZE(navigationFSMState_t previousState
);
108 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_WAYPOINT_PRE_ACTION(navigationFSMState_t previousState
);
109 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_WAYPOINT_IN_PROGRESS(navigationFSMState_t previousState
);
110 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_WAYPOINT_REACHED(navigationFSMState_t previousState
);
111 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_WAYPOINT_FINISHED(navigationFSMState_t previousState
);
112 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_EMERGENCY_LANDING_INITIALIZE(navigationFSMState_t previousState
);
113 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_EMERGENCY_LANDING_IN_PROGRESS(navigationFSMState_t previousState
);
114 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_EMERGENCY_LANDING_FINISHED(navigationFSMState_t previousState
);
116 static navigationFSMStateDescriptor_t navFSM
[NAV_STATE_COUNT
] = {
117 /** Idle state ******************************************************/
119 .onEntry
= navOnEnteringState_NAV_STATE_IDLE
,
122 .mapToFlightModes
= 0,
123 .mwState
= MW_NAV_STATE_NONE
,
124 .mwError
= MW_NAV_ERROR_NONE
,
126 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
127 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
] = NAV_STATE_POSHOLD_2D_INITIALIZE
,
128 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
] = NAV_STATE_POSHOLD_3D_INITIALIZE
,
129 [NAV_FSM_EVENT_SWITCH_TO_RTH
] = NAV_STATE_RTH_INITIALIZE
,
130 [NAV_FSM_EVENT_SWITCH_TO_WAYPOINT
] = NAV_STATE_WAYPOINT_INITIALIZE
,
131 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
135 /** ALTHOLD mode ***************************************************/
136 [NAV_STATE_ALTHOLD_INITIALIZE
] = {
137 .onEntry
= navOnEnteringState_NAV_STATE_ALTHOLD_INITIALIZE
,
139 .stateFlags
= NAV_CTL_ALT
| NAV_REQUIRE_ANGLE_FW
| NAV_REQUIRE_THRTILT
,
140 .mapToFlightModes
= NAV_ALTHOLD_MODE
,
141 .mwState
= MW_NAV_STATE_NONE
,
142 .mwError
= MW_NAV_ERROR_NONE
,
144 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_ALTHOLD_IN_PROGRESS
,
145 [NAV_FSM_EVENT_ERROR
] = NAV_STATE_IDLE
,
146 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
150 [NAV_STATE_ALTHOLD_IN_PROGRESS
] = {
151 .onEntry
= navOnEnteringState_NAV_STATE_ALTHOLD_IN_PROGRESS
,
153 .stateFlags
= NAV_CTL_ALT
| NAV_REQUIRE_ANGLE_FW
| NAV_REQUIRE_THRTILT
| NAV_RC_ALT
,
154 .mapToFlightModes
= NAV_ALTHOLD_MODE
,
155 .mwState
= MW_NAV_STATE_NONE
,
156 .mwError
= MW_NAV_ERROR_NONE
,
158 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_ALTHOLD_IN_PROGRESS
, // re-process the state
159 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
160 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
] = NAV_STATE_POSHOLD_2D_INITIALIZE
,
161 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
] = NAV_STATE_POSHOLD_3D_INITIALIZE
,
162 [NAV_FSM_EVENT_SWITCH_TO_RTH
] = NAV_STATE_RTH_INITIALIZE
,
163 [NAV_FSM_EVENT_SWITCH_TO_WAYPOINT
] = NAV_STATE_WAYPOINT_INITIALIZE
,
164 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
168 /** POSHOLD_2D mode ************************************************/
169 [NAV_STATE_POSHOLD_2D_INITIALIZE
] = {
170 .onEntry
= navOnEnteringState_NAV_STATE_POSHOLD_2D_INITIALIZE
,
172 .stateFlags
= NAV_CTL_POS
| NAV_REQUIRE_ANGLE
,
173 .mapToFlightModes
= NAV_POSHOLD_MODE
,
174 .mwState
= MW_NAV_STATE_HOLD_INFINIT
,
175 .mwError
= MW_NAV_ERROR_NONE
,
177 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_POSHOLD_2D_IN_PROGRESS
,
178 [NAV_FSM_EVENT_ERROR
] = NAV_STATE_IDLE
,
179 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
183 [NAV_STATE_POSHOLD_2D_IN_PROGRESS
] = {
184 .onEntry
= navOnEnteringState_NAV_STATE_POSHOLD_2D_IN_PROGRESS
,
186 .stateFlags
= NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_RC_POS
| NAV_RC_YAW
,
187 .mapToFlightModes
= NAV_POSHOLD_MODE
,
188 .mwState
= MW_NAV_STATE_HOLD_INFINIT
,
189 .mwError
= MW_NAV_ERROR_NONE
,
191 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_POSHOLD_2D_IN_PROGRESS
, // re-process the state
192 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
193 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
194 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
] = NAV_STATE_POSHOLD_3D_INITIALIZE
,
195 [NAV_FSM_EVENT_SWITCH_TO_RTH
] = NAV_STATE_RTH_INITIALIZE
,
196 [NAV_FSM_EVENT_SWITCH_TO_WAYPOINT
] = NAV_STATE_WAYPOINT_INITIALIZE
,
197 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
201 /** POSHOLD_3D mode ************************************************/
202 [NAV_STATE_POSHOLD_3D_INITIALIZE
] = {
203 .onEntry
= navOnEnteringState_NAV_STATE_POSHOLD_3D_INITIALIZE
,
205 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_THRTILT
,
206 .mapToFlightModes
= NAV_ALTHOLD_MODE
| NAV_POSHOLD_MODE
,
207 .mwState
= MW_NAV_STATE_HOLD_INFINIT
,
208 .mwError
= MW_NAV_ERROR_NONE
,
210 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_POSHOLD_3D_IN_PROGRESS
,
211 [NAV_FSM_EVENT_ERROR
] = NAV_STATE_IDLE
,
212 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
216 [NAV_STATE_POSHOLD_3D_IN_PROGRESS
] = {
217 .onEntry
= navOnEnteringState_NAV_STATE_POSHOLD_3D_IN_PROGRESS
,
219 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_THRTILT
| NAV_RC_ALT
| NAV_RC_POS
| NAV_RC_YAW
,
220 .mapToFlightModes
= NAV_ALTHOLD_MODE
| NAV_POSHOLD_MODE
,
221 .mwState
= MW_NAV_STATE_HOLD_INFINIT
,
222 .mwError
= MW_NAV_ERROR_NONE
,
224 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_POSHOLD_3D_IN_PROGRESS
, // re-process the state
225 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
226 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
227 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
] = NAV_STATE_POSHOLD_2D_INITIALIZE
,
228 [NAV_FSM_EVENT_SWITCH_TO_RTH
] = NAV_STATE_RTH_INITIALIZE
,
229 [NAV_FSM_EVENT_SWITCH_TO_WAYPOINT
] = NAV_STATE_WAYPOINT_INITIALIZE
,
230 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
234 /** RTH mode entry point ************************************************/
235 [NAV_STATE_RTH_INITIALIZE
] = {
236 .onEntry
= navOnEnteringState_NAV_STATE_RTH_INITIALIZE
,
238 .stateFlags
= NAV_REQUIRE_ANGLE
| NAV_AUTO_RTH
,
239 .mapToFlightModes
= NAV_RTH_MODE
,
240 .mwState
= MW_NAV_STATE_RTH_START
,
241 .mwError
= MW_NAV_ERROR_SPOILED_GPS
, // we are stuck in this state only if GPS is compromised
243 [NAV_FSM_EVENT_SWITCH_TO_RTH_2D
] = NAV_STATE_RTH_2D_INITIALIZE
,
244 [NAV_FSM_EVENT_SWITCH_TO_RTH_3D
] = NAV_STATE_RTH_3D_INITIALIZE
,
245 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
246 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
250 /** RTH_2D mode ************************************************/
251 [NAV_STATE_RTH_2D_INITIALIZE
] = {
252 .onEntry
= navOnEnteringState_NAV_STATE_RTH_2D_INITIALIZE
,
254 .stateFlags
= NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_AUTO_RTH
,
255 .mapToFlightModes
= NAV_RTH_MODE
,
256 .mwState
= MW_NAV_STATE_RTH_START
,
257 .mwError
= MW_NAV_ERROR_NONE
,
259 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_RTH_2D_INITIALIZE
, // re-process the state
260 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_RTH_2D_HEAD_HOME
,
261 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
262 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
266 [NAV_STATE_RTH_2D_HEAD_HOME
] = {
267 .onEntry
= navOnEnteringState_NAV_STATE_RTH_2D_HEAD_HOME
,
269 .stateFlags
= NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_AUTO_RTH
| NAV_RC_POS
| NAV_RC_YAW
,
270 .mapToFlightModes
= NAV_RTH_MODE
,
271 .mwState
= MW_NAV_STATE_RTH_ENROUTE
,
272 .mwError
= MW_NAV_ERROR_NONE
,
274 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_RTH_2D_HEAD_HOME
, // re-process the state
275 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_RTH_2D_FINISHING
,
276 [NAV_FSM_EVENT_ERROR
] = NAV_STATE_RTH_2D_GPS_FAILING
,
277 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
278 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
279 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
] = NAV_STATE_POSHOLD_2D_INITIALIZE
,
280 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
] = NAV_STATE_POSHOLD_3D_INITIALIZE
,
284 [NAV_STATE_RTH_2D_GPS_FAILING
] = {
285 .onEntry
= navOnEnteringState_NAV_STATE_RTH_2D_GPS_FAILING
,
287 .stateFlags
= NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_AUTO_RTH
| NAV_RC_POS
| NAV_RC_YAW
,
288 .mapToFlightModes
= NAV_RTH_MODE
,
289 .mwState
= MW_NAV_STATE_RTH_ENROUTE
,
290 .mwError
= MW_NAV_ERROR_SPOILED_GPS
,
292 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_RTH_2D_GPS_FAILING
, // re-process the state
293 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_RTH_2D_HEAD_HOME
,
294 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
295 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
296 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
300 [NAV_STATE_RTH_2D_FINISHING
] = {
301 .onEntry
= navOnEnteringState_NAV_STATE_RTH_2D_FINISHING
,
303 .stateFlags
= NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_AUTO_RTH
| NAV_RC_POS
| NAV_RC_YAW
,
304 .mapToFlightModes
= NAV_RTH_MODE
,
305 .mwState
= MW_NAV_STATE_RTH_ENROUTE
,
306 .mwError
= MW_NAV_ERROR_NONE
,
308 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_RTH_2D_FINISHED
,
312 [NAV_STATE_RTH_2D_FINISHED
] = {
313 .onEntry
= navOnEnteringState_NAV_STATE_RTH_2D_FINISHED
,
315 .stateFlags
= NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_AUTO_RTH
| NAV_RC_POS
| NAV_RC_YAW
,
316 .mapToFlightModes
= NAV_RTH_MODE
,
317 .mwState
= MW_NAV_STATE_RTH_ENROUTE
,
318 .mwError
= MW_NAV_ERROR_NONE
,
320 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_RTH_2D_FINISHED
, // re-process the state
321 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
322 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
323 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
] = NAV_STATE_POSHOLD_2D_INITIALIZE
,
324 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
] = NAV_STATE_POSHOLD_3D_INITIALIZE
,
325 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
329 /** RTH_3D mode ************************************************/
330 [NAV_STATE_RTH_3D_INITIALIZE
] = {
331 .onEntry
= navOnEnteringState_NAV_STATE_RTH_3D_INITIALIZE
,
333 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_REQUIRE_THRTILT
| NAV_AUTO_RTH
,
334 .mapToFlightModes
= NAV_RTH_MODE
| NAV_ALTHOLD_MODE
,
335 .mwState
= MW_NAV_STATE_RTH_START
,
336 .mwError
= MW_NAV_ERROR_NONE
,
338 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_RTH_3D_INITIALIZE
, // re-process the state
339 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_RTH_3D_CLIMB_TO_SAFE_ALT
,
340 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
341 [NAV_FSM_EVENT_SWITCH_TO_RTH_3D_LANDING
] = NAV_STATE_RTH_3D_HOVER_PRIOR_TO_LANDING
,
342 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
346 [NAV_STATE_RTH_3D_CLIMB_TO_SAFE_ALT
] = {
347 .onEntry
= navOnEnteringState_NAV_STATE_RTH_3D_CLIMB_TO_SAFE_ALT
,
349 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_REQUIRE_THRTILT
| NAV_AUTO_RTH
| NAV_RC_POS
| NAV_RC_YAW
, // allow pos adjustment while climbind to safe alt
350 .mapToFlightModes
= NAV_RTH_MODE
| NAV_ALTHOLD_MODE
,
351 .mwState
= MW_NAV_STATE_RTH_ENROUTE
,
352 .mwError
= MW_NAV_ERROR_WAIT_FOR_RTH_ALT
,
354 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_RTH_3D_CLIMB_TO_SAFE_ALT
, // re-process the state
355 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_RTH_3D_HEAD_HOME
,
356 [NAV_FSM_EVENT_ERROR
] = NAV_STATE_RTH_3D_GPS_FAILING
,
357 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
358 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
359 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
] = NAV_STATE_POSHOLD_2D_INITIALIZE
,
360 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
] = NAV_STATE_POSHOLD_3D_INITIALIZE
,
364 [NAV_STATE_RTH_3D_HEAD_HOME
] = {
365 .onEntry
= navOnEnteringState_NAV_STATE_RTH_3D_HEAD_HOME
,
367 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_REQUIRE_THRTILT
| NAV_AUTO_RTH
| NAV_RC_ALT
| NAV_RC_POS
| NAV_RC_YAW
,
368 .mapToFlightModes
= NAV_RTH_MODE
| NAV_ALTHOLD_MODE
,
369 .mwState
= MW_NAV_STATE_RTH_ENROUTE
,
370 .mwError
= MW_NAV_ERROR_NONE
,
372 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_RTH_3D_HEAD_HOME
, // re-process the state
373 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_RTH_3D_HOVER_PRIOR_TO_LANDING
,
374 [NAV_FSM_EVENT_ERROR
] = NAV_STATE_RTH_3D_GPS_FAILING
,
375 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
376 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
377 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
] = NAV_STATE_POSHOLD_2D_INITIALIZE
,
378 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
] = NAV_STATE_POSHOLD_3D_INITIALIZE
,
382 [NAV_STATE_RTH_3D_GPS_FAILING
] = {
383 .onEntry
= navOnEnteringState_NAV_STATE_RTH_3D_GPS_FAILING
,
385 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_REQUIRE_THRTILT
| NAV_AUTO_RTH
| NAV_RC_ALT
| NAV_RC_POS
| NAV_RC_YAW
,
386 .mapToFlightModes
= NAV_RTH_MODE
,
387 .mwState
= MW_NAV_STATE_RTH_ENROUTE
,
388 .mwError
= MW_NAV_ERROR_SPOILED_GPS
,
390 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_RTH_3D_GPS_FAILING
, // re-process the state
391 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_RTH_3D_HEAD_HOME
,
392 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
393 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
397 [NAV_STATE_RTH_3D_HOVER_PRIOR_TO_LANDING
] = {
398 .onEntry
= navOnEnteringState_NAV_STATE_RTH_3D_HOVER_PRIOR_TO_LANDING
,
400 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_REQUIRE_THRTILT
| NAV_AUTO_RTH
| NAV_RC_ALT
| NAV_RC_POS
| NAV_RC_YAW
,
401 .mapToFlightModes
= NAV_RTH_MODE
| NAV_ALTHOLD_MODE
,
402 .mwState
= MW_NAV_STATE_LAND_SETTLE
,
403 .mwError
= MW_NAV_ERROR_NONE
,
405 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_RTH_3D_LANDING
,
406 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
407 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
408 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
] = NAV_STATE_POSHOLD_2D_INITIALIZE
,
409 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
] = NAV_STATE_POSHOLD_3D_INITIALIZE
,
410 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
414 [NAV_STATE_RTH_3D_LANDING
] = {
415 .onEntry
= navOnEnteringState_NAV_STATE_RTH_3D_LANDING
,
417 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_REQUIRE_THRTILT
| NAV_AUTO_RTH
| NAV_RC_POS
| NAV_RC_YAW
,
418 .mapToFlightModes
= NAV_RTH_MODE
| NAV_ALTHOLD_MODE
,
419 .mwState
= MW_NAV_STATE_LAND_IN_PROGRESS
,
420 .mwError
= MW_NAV_ERROR_LANDING
,
422 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_RTH_3D_LANDING
, // re-process state
423 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_RTH_3D_FINISHING
,
424 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
425 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
426 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
] = NAV_STATE_POSHOLD_2D_INITIALIZE
,
427 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
] = NAV_STATE_POSHOLD_3D_INITIALIZE
,
428 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
432 [NAV_STATE_RTH_3D_FINISHING
] = {
433 .onEntry
= navOnEnteringState_NAV_STATE_RTH_3D_FINISHING
,
435 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_REQUIRE_THRTILT
| NAV_AUTO_RTH
,
436 .mapToFlightModes
= NAV_RTH_MODE
| NAV_ALTHOLD_MODE
,
437 .mwState
= MW_NAV_STATE_LAND_IN_PROGRESS
,
438 .mwError
= MW_NAV_ERROR_LANDING
,
440 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_RTH_3D_FINISHED
,
441 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
445 [NAV_STATE_RTH_3D_FINISHED
] = {
446 .onEntry
= navOnEnteringState_NAV_STATE_RTH_3D_FINISHED
,
448 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_REQUIRE_THRTILT
| NAV_AUTO_RTH
,
449 .mapToFlightModes
= NAV_RTH_MODE
| NAV_ALTHOLD_MODE
,
450 .mwState
= MW_NAV_STATE_LANDED
,
451 .mwError
= MW_NAV_ERROR_NONE
,
453 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_RTH_3D_FINISHED
, // re-process state
454 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
455 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
456 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
] = NAV_STATE_POSHOLD_2D_INITIALIZE
,
457 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
] = NAV_STATE_POSHOLD_3D_INITIALIZE
,
458 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
462 /** WAYPOINT mode ************************************************/
463 [NAV_STATE_WAYPOINT_INITIALIZE
] = {
464 .onEntry
= navOnEnteringState_NAV_STATE_WAYPOINT_INITIALIZE
,
466 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_REQUIRE_THRTILT
| NAV_AUTO_WP
,
467 .mapToFlightModes
= NAV_WP_MODE
| NAV_ALTHOLD_MODE
,
468 .mwState
= MW_NAV_STATE_PROCESS_NEXT
,
469 .mwError
= MW_NAV_ERROR_NONE
,
471 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_WAYPOINT_PRE_ACTION
,
472 [NAV_FSM_EVENT_ERROR
] = NAV_STATE_IDLE
,
473 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
474 [NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_FINISHED
] = NAV_STATE_WAYPOINT_FINISHED
,
478 [NAV_STATE_WAYPOINT_PRE_ACTION
] = {
479 .onEntry
= navOnEnteringState_NAV_STATE_WAYPOINT_PRE_ACTION
,
481 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_REQUIRE_THRTILT
| NAV_AUTO_WP
,
482 .mapToFlightModes
= NAV_WP_MODE
| NAV_ALTHOLD_MODE
,
483 .mwState
= MW_NAV_STATE_PROCESS_NEXT
,
484 .mwError
= MW_NAV_ERROR_NONE
,
486 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_WAYPOINT_IN_PROGRESS
,
487 [NAV_FSM_EVENT_ERROR
] = NAV_STATE_IDLE
,
488 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
489 [NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_FINISHED
] = NAV_STATE_WAYPOINT_FINISHED
,
493 [NAV_STATE_WAYPOINT_IN_PROGRESS
] = {
494 .onEntry
= navOnEnteringState_NAV_STATE_WAYPOINT_IN_PROGRESS
,
496 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_REQUIRE_THRTILT
| NAV_AUTO_WP
,
497 .mapToFlightModes
= NAV_WP_MODE
| NAV_ALTHOLD_MODE
,
498 .mwState
= MW_NAV_STATE_WP_ENROUTE
,
499 .mwError
= MW_NAV_ERROR_NONE
,
501 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_WAYPOINT_IN_PROGRESS
, // re-process the state
502 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_WAYPOINT_REACHED
, // successfully reached waypoint
503 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
504 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
505 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
] = NAV_STATE_POSHOLD_2D_INITIALIZE
,
506 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
] = NAV_STATE_POSHOLD_3D_INITIALIZE
,
507 [NAV_FSM_EVENT_SWITCH_TO_RTH
] = NAV_STATE_RTH_INITIALIZE
,
508 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
512 [NAV_STATE_WAYPOINT_REACHED
] = {
513 .onEntry
= navOnEnteringState_NAV_STATE_WAYPOINT_REACHED
,
515 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_REQUIRE_THRTILT
| NAV_AUTO_WP
,
516 .mapToFlightModes
= NAV_WP_MODE
| NAV_ALTHOLD_MODE
,
517 .mwState
= MW_NAV_STATE_PROCESS_NEXT
,
518 .mwError
= MW_NAV_ERROR_NONE
,
520 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_WAYPOINT_PRE_ACTION
,
521 [NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_FINISHED
] = NAV_STATE_WAYPOINT_FINISHED
,
522 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
523 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
524 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
] = NAV_STATE_POSHOLD_2D_INITIALIZE
,
525 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
] = NAV_STATE_POSHOLD_3D_INITIALIZE
,
526 [NAV_FSM_EVENT_SWITCH_TO_RTH
] = NAV_STATE_RTH_INITIALIZE
,
527 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
531 [NAV_STATE_WAYPOINT_FINISHED
] = {
532 .onEntry
= navOnEnteringState_NAV_STATE_WAYPOINT_FINISHED
,
534 .stateFlags
= NAV_CTL_ALT
| NAV_CTL_POS
| NAV_CTL_YAW
| NAV_REQUIRE_ANGLE
| NAV_REQUIRE_MAGHOLD
| NAV_REQUIRE_THRTILT
| NAV_AUTO_WP
,
535 .mapToFlightModes
= NAV_WP_MODE
| NAV_ALTHOLD_MODE
,
536 .mwState
= MW_NAV_STATE_WP_ENROUTE
,
537 .mwError
= MW_NAV_ERROR_FINISH
,
539 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
540 [NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
] = NAV_STATE_ALTHOLD_INITIALIZE
,
541 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
] = NAV_STATE_POSHOLD_2D_INITIALIZE
,
542 [NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
] = NAV_STATE_POSHOLD_3D_INITIALIZE
,
543 [NAV_FSM_EVENT_SWITCH_TO_RTH
] = NAV_STATE_RTH_INITIALIZE
,
544 [NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
548 /** EMERGENCY LANDING ************************************************/
549 [NAV_STATE_EMERGENCY_LANDING_INITIALIZE
] = {
550 .onEntry
= navOnEnteringState_NAV_STATE_EMERGENCY_LANDING_INITIALIZE
,
552 .stateFlags
= NAV_CTL_EMERG
| NAV_REQUIRE_ANGLE
,
553 .mapToFlightModes
= 0,
554 .mwState
= MW_NAV_STATE_LAND_START
,
555 .mwError
= MW_NAV_ERROR_LANDING
,
557 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_EMERGENCY_LANDING_IN_PROGRESS
,
558 [NAV_FSM_EVENT_ERROR
] = NAV_STATE_IDLE
,
559 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
563 [NAV_STATE_EMERGENCY_LANDING_IN_PROGRESS
] = {
564 .onEntry
= navOnEnteringState_NAV_STATE_EMERGENCY_LANDING_IN_PROGRESS
,
566 .stateFlags
= NAV_CTL_EMERG
| NAV_REQUIRE_ANGLE
,
567 .mapToFlightModes
= 0,
568 .mwState
= MW_NAV_STATE_LAND_IN_PROGRESS
,
569 .mwError
= MW_NAV_ERROR_LANDING
,
571 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_EMERGENCY_LANDING_IN_PROGRESS
, // re-process the state
572 [NAV_FSM_EVENT_SUCCESS
] = NAV_STATE_EMERGENCY_LANDING_FINISHED
,
573 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
577 [NAV_STATE_EMERGENCY_LANDING_FINISHED
] = {
578 .onEntry
= navOnEnteringState_NAV_STATE_EMERGENCY_LANDING_FINISHED
,
580 .stateFlags
= NAV_CTL_EMERG
| NAV_REQUIRE_ANGLE
,
581 .mapToFlightModes
= 0,
582 .mwState
= MW_NAV_STATE_LANDED
,
583 .mwError
= MW_NAV_ERROR_LANDING
,
585 [NAV_FSM_EVENT_TIMEOUT
] = NAV_STATE_EMERGENCY_LANDING_FINISHED
,
586 [NAV_FSM_EVENT_SWITCH_TO_IDLE
] = NAV_STATE_IDLE
,
591 static navigationFSMStateFlags_t
navGetStateFlags(navigationFSMState_t state
)
593 return navFSM
[state
].stateFlags
;
596 static flightModeFlags_e
navGetMappedFlightModes(navigationFSMState_t state
)
598 return navFSM
[state
].mapToFlightModes
;
601 navigationFSMStateFlags_t
navGetCurrentStateFlags(void)
603 return navGetStateFlags(posControl
.navState
);
606 /*************************************************************************************************/
607 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_IDLE(navigationFSMState_t previousState
)
609 UNUSED(previousState
);
611 return NAV_FSM_EVENT_NONE
;
614 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_ALTHOLD_INITIALIZE(navigationFSMState_t previousState
)
616 /* If previous controller was NOT executing NAV_CTL_ALT controller, we must reset altitude setpoint */
617 if ((navGetStateFlags(previousState
) & NAV_CTL_ALT
) == 0) {
618 resetAltitudeController();
619 setupAltitudeController();
620 setDesiredPosition(&posControl
.actualState
.pos
, posControl
.actualState
.yaw
, NAV_POS_UPDATE_Z
); // This will reset surface offset
623 return NAV_FSM_EVENT_SUCCESS
;
626 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_ALTHOLD_IN_PROGRESS(navigationFSMState_t previousState
)
628 UNUSED(previousState
);
630 // If we enable terrain mode and surface offset is not set yet - do it
631 if (posControl
.flags
.hasValidSurfaceSensor
&& posControl
.flags
.isTerrainFollowEnabled
&& posControl
.desiredState
.surface
< 0) {
632 setDesiredSurfaceOffset(posControl
.actualState
.surface
);
635 return NAV_FSM_EVENT_NONE
;
638 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_POSHOLD_2D_INITIALIZE(navigationFSMState_t previousState
)
640 navigationFSMStateFlags_t prevFlags
= navGetStateFlags(previousState
);
642 if ((prevFlags
& NAV_CTL_POS
) == 0) {
643 resetPositionController();
646 if (((prevFlags
& NAV_CTL_POS
) == 0) || ((prevFlags
& NAV_AUTO_RTH
) != 0) || ((prevFlags
& NAV_AUTO_WP
) != 0)) {
647 t_fp_vector targetHoldPos
;
648 calculateInitialHoldPosition(&targetHoldPos
);
649 setDesiredPosition(&targetHoldPos
, posControl
.actualState
.yaw
, NAV_POS_UPDATE_XY
| NAV_POS_UPDATE_HEADING
);
652 return NAV_FSM_EVENT_SUCCESS
;
655 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_POSHOLD_2D_IN_PROGRESS(navigationFSMState_t previousState
)
657 UNUSED(previousState
);
658 return NAV_FSM_EVENT_NONE
;
661 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_POSHOLD_3D_INITIALIZE(navigationFSMState_t previousState
)
663 navigationFSMStateFlags_t prevFlags
= navGetStateFlags(previousState
);
665 if ((prevFlags
& NAV_CTL_POS
) == 0) {
666 resetPositionController();
669 if ((prevFlags
& NAV_CTL_ALT
) == 0) {
670 resetAltitudeController();
671 setupAltitudeController();
674 if (((prevFlags
& NAV_CTL_ALT
) == 0) || ((prevFlags
& NAV_AUTO_RTH
) != 0) || ((prevFlags
& NAV_AUTO_WP
) != 0)) {
675 setDesiredPosition(&posControl
.actualState
.pos
, posControl
.actualState
.yaw
, NAV_POS_UPDATE_Z
); // This will reset surface offset
678 if (((prevFlags
& NAV_CTL_POS
) == 0) || ((prevFlags
& NAV_AUTO_RTH
) != 0) || ((prevFlags
& NAV_AUTO_WP
) != 0)) {
679 t_fp_vector targetHoldPos
;
680 calculateInitialHoldPosition(&targetHoldPos
);
681 setDesiredPosition(&targetHoldPos
, posControl
.actualState
.yaw
, NAV_POS_UPDATE_XY
| NAV_POS_UPDATE_HEADING
);
684 return NAV_FSM_EVENT_SUCCESS
;
687 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_POSHOLD_3D_IN_PROGRESS(navigationFSMState_t previousState
)
689 UNUSED(previousState
);
691 // If we enable terrain mode and surface offset is not set yet - do it
692 if (posControl
.flags
.hasValidSurfaceSensor
&& posControl
.flags
.isTerrainFollowEnabled
&& posControl
.desiredState
.surface
< 0) {
693 setDesiredSurfaceOffset(posControl
.actualState
.surface
);
696 return NAV_FSM_EVENT_NONE
;
699 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_INITIALIZE(navigationFSMState_t previousState
)
701 if (STATE(GPS_FIX_HOME
) && posControl
.flags
.hasValidHeadingSensor
) {
702 navigationFSMStateFlags_t prevFlags
= navGetStateFlags(previousState
);
704 if ((prevFlags
& NAV_CTL_POS
) == 0) {
705 resetPositionController();
708 if ((prevFlags
& NAV_CTL_ALT
) == 0) {
709 resetAltitudeController();
710 setupAltitudeController();
713 // Switch between 2D and 3D RTH depending on altitude sensor availability
714 if (posControl
.flags
.hasValidAltitudeSensor
) {
715 // We might have GPS unavailable - in case of 3D RTH set current altitude target
716 setDesiredPosition(&posControl
.actualState
.pos
, 0, NAV_POS_UPDATE_Z
);
718 return NAV_FSM_EVENT_SWITCH_TO_RTH_3D
;
721 return NAV_FSM_EVENT_SWITCH_TO_RTH_2D
;
725 // No home position set or no heading sensor
726 return NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
;
730 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_2D_INITIALIZE(navigationFSMState_t previousState
)
732 UNUSED(previousState
);
734 if (STATE(FIXED_WING
) && (posControl
.homeDistance
< posControl
.navConfig
->min_rth_distance
)) {
735 // Prevent RTH from activating on airplanes if too close to home
736 return NAV_FSM_EVENT_SWITCH_TO_IDLE
;
739 if (posControl
.flags
.hasValidPositionSensor
) {
740 // If close to home - reset home position
741 if (posControl
.homeDistance
< posControl
.navConfig
->min_rth_distance
) {
742 setHomePosition(&posControl
.actualState
.pos
, posControl
.actualState
.yaw
);
745 return NAV_FSM_EVENT_SUCCESS
;
747 /* Position sensor failure timeout - land */
748 else if (checkForPositionSensorTimeout()) {
749 return NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
;
751 /* No valid POS sensor but still within valid timeout - wait */
753 return NAV_FSM_EVENT_NONE
;
758 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_2D_HEAD_HOME(navigationFSMState_t previousState
)
760 UNUSED(previousState
);
762 // If no position sensor available - switch to NAV_STATE_RTH_2D_GPS_FAILING
763 if (!(posControl
.flags
.hasValidPositionSensor
&& posControl
.flags
.hasValidHeadingSensor
)) {
764 return NAV_FSM_EVENT_ERROR
; // NAV_STATE_RTH_2D_GPS_FAILING
767 if (isWaypointReached(&posControl
.homeWaypointAbove
)) {
768 // Successfully reached position target
769 return NAV_FSM_EVENT_SUCCESS
; // NAV_STATE_RTH_2D_FINISHING
772 // Update XY-position target
773 if (posControl
.navConfig
->flags
.rth_tail_first
&& !STATE(FIXED_WING
)) {
774 setDesiredPosition(&posControl
.homeWaypointAbove
.pos
, 0, NAV_POS_UPDATE_XY
| NAV_POS_UPDATE_BEARING_TAIL_FIRST
);
777 setDesiredPosition(&posControl
.homeWaypointAbove
.pos
, 0, NAV_POS_UPDATE_XY
| NAV_POS_UPDATE_BEARING
);
780 return NAV_FSM_EVENT_NONE
;
784 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_2D_GPS_FAILING(navigationFSMState_t previousState
)
786 UNUSED(previousState
);
788 /* Wait for GPS to be online again */
789 if (posControl
.flags
.hasValidPositionSensor
&& posControl
.flags
.hasValidHeadingSensor
&& STATE(GPS_FIX_HOME
)) {
790 return NAV_FSM_EVENT_SUCCESS
; // NAV_STATE_RTH_2D_HEAD_HOME
792 /* No HOME set or position sensor failure timeout - land */
793 else if (!STATE(GPS_FIX_HOME
) || !posControl
.flags
.hasValidHeadingSensor
|| checkForPositionSensorTimeout()) {
794 return NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
;
796 /* No valid POS sensor but still within valid timeout - wait */
798 return NAV_FSM_EVENT_NONE
;
802 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_2D_FINISHING(navigationFSMState_t previousState
)
804 UNUSED(previousState
);
805 setDesiredPosition(&posControl
.homeWaypointAbove
.pos
, posControl
.homeWaypointAbove
.yaw
, NAV_POS_UPDATE_XY
| NAV_POS_UPDATE_HEADING
);
806 return NAV_FSM_EVENT_SUCCESS
;
809 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_2D_FINISHED(navigationFSMState_t previousState
)
811 // Same logic as PH_2D
812 return navOnEnteringState_NAV_STATE_POSHOLD_2D_IN_PROGRESS(previousState
);
815 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_INITIALIZE(navigationFSMState_t previousState
)
817 UNUSED(previousState
);
819 if (STATE(FIXED_WING
) && (posControl
.homeDistance
< posControl
.navConfig
->min_rth_distance
)) {
820 // Prevent RTH from activating on airplanes if too close to home
821 return NAV_FSM_EVENT_SWITCH_TO_IDLE
;
824 if (posControl
.flags
.hasValidPositionSensor
) {
825 // If close to home - reset home position and land
826 if (posControl
.homeDistance
< posControl
.navConfig
->min_rth_distance
) {
827 setHomePosition(&posControl
.actualState
.pos
, posControl
.actualState
.yaw
);
828 setDesiredPosition(&posControl
.actualState
.pos
, 0, NAV_POS_UPDATE_XY
| NAV_POS_UPDATE_Z
);
830 return NAV_FSM_EVENT_SWITCH_TO_RTH_3D_LANDING
; // NAV_STATE_RTH_3D_HOVER_PRIOR_TO_LANDING
833 t_fp_vector targetHoldPos
;
835 if (!STATE(FIXED_WING
)) {
836 // Multicopter, hover and climb
837 calculateInitialHoldPosition(&targetHoldPos
);
839 // Airplane - climbout before turning around
840 calculateFarAwayTarget(&targetHoldPos
, posControl
.actualState
.yaw
, 100000.0f
); // 1km away
843 setDesiredPosition(&targetHoldPos
, 0, NAV_POS_UPDATE_XY
);
845 return NAV_FSM_EVENT_SUCCESS
; // NAV_STATE_RTH_3D_CLIMB_TO_SAFE_ALT
848 /* Position sensor failure timeout - land */
849 else if (checkForPositionSensorTimeout()) {
850 return NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
;
852 /* No valid POS sensor but still within valid timeout - wait */
854 return NAV_FSM_EVENT_NONE
;
859 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_CLIMB_TO_SAFE_ALT(navigationFSMState_t previousState
)
861 UNUSED(previousState
);
863 // If no position sensor available - land immediately
864 if (!(posControl
.flags
.hasValidPositionSensor
&& posControl
.flags
.hasValidHeadingSensor
) && checkForPositionSensorTimeout()) {
865 return NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
;
868 if ((posControl
.actualState
.pos
.V
.Z
- posControl
.homeWaypointAbove
.pos
.V
.Z
) > -50.0f
) {
869 return NAV_FSM_EVENT_SUCCESS
; // NAV_STATE_RTH_3D_HEAD_HOME
872 // Climb to safe altitude and turn to correct direction
873 if (posControl
.navConfig
->flags
.rth_tail_first
&& !STATE(FIXED_WING
)) {
874 setDesiredPosition(&posControl
.homeWaypointAbove
.pos
, 0, NAV_POS_UPDATE_Z
| NAV_POS_UPDATE_BEARING_TAIL_FIRST
);
877 setDesiredPosition(&posControl
.homeWaypointAbove
.pos
, 0, NAV_POS_UPDATE_Z
| NAV_POS_UPDATE_BEARING
);
880 return NAV_FSM_EVENT_NONE
;
884 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_HEAD_HOME(navigationFSMState_t previousState
)
886 UNUSED(previousState
);
888 // If no position sensor available - land immediately
889 if (!(posControl
.flags
.hasValidPositionSensor
&& posControl
.flags
.hasValidHeadingSensor
)) {
890 return NAV_FSM_EVENT_ERROR
; // NAV_STATE_RTH_3D_GPS_FAILING
893 if (isWaypointReached(&posControl
.homeWaypointAbove
)) {
894 if (!STATE(FIXED_WING
)) {
895 // Successfully reached position target - update XYZ-position
896 setDesiredPosition(&posControl
.homeWaypointAbove
.pos
, posControl
.homeWaypointAbove
.yaw
, NAV_POS_UPDATE_XY
| NAV_POS_UPDATE_Z
| NAV_POS_UPDATE_HEADING
);
897 return NAV_FSM_EVENT_SUCCESS
; // NAV_STATE_RTH_3D_HOVER_PRIOR_TO_LANDING
899 // Don't switch to landing for airplanes
900 return NAV_FSM_EVENT_NONE
;
904 // Update XYZ-position target
905 if (posControl
.navConfig
->flags
.rth_tail_first
&& !STATE(FIXED_WING
)) {
906 setDesiredPosition(&posControl
.homeWaypointAbove
.pos
, 0, NAV_POS_UPDATE_XY
| NAV_POS_UPDATE_Z
| NAV_POS_UPDATE_BEARING_TAIL_FIRST
);
909 setDesiredPosition(&posControl
.homeWaypointAbove
.pos
, 0, NAV_POS_UPDATE_XY
| NAV_POS_UPDATE_Z
| NAV_POS_UPDATE_BEARING
);
911 return NAV_FSM_EVENT_NONE
;
915 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_GPS_FAILING(navigationFSMState_t previousState
)
917 /* Same logic as for 2D GPS RTH */
918 return navOnEnteringState_NAV_STATE_RTH_2D_GPS_FAILING(previousState
);
921 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_HOVER_PRIOR_TO_LANDING(navigationFSMState_t previousState
)
923 UNUSED(previousState
);
925 // If no position sensor available - land immediately
926 if (!(posControl
.flags
.hasValidPositionSensor
&& posControl
.flags
.hasValidHeadingSensor
) && checkForPositionSensorTimeout()) {
927 return NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
;
930 resetLandingDetector();
932 return NAV_FSM_EVENT_NONE
;
935 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_LANDING(navigationFSMState_t previousState
)
937 UNUSED(previousState
);
939 if (!ARMING_FLAG(ARMED
)) {
940 return NAV_FSM_EVENT_SUCCESS
;
942 else if (isLandingDetected()) {
943 return NAV_FSM_EVENT_SUCCESS
;
946 // A safeguard - if sonar is available and it is reading < 50cm altitude - drop to low descend speed
947 if (posControl
.flags
.hasValidSurfaceSensor
&& posControl
.actualState
.surface
>= 0 && posControl
.actualState
.surface
< 50.0f
) {
948 // land_descent_rate == 200 : descend speed = 30 cm/s, gentle touchdown
949 updateAltitudeTargetFromClimbRate(-0.15f
* posControl
.navConfig
->land_descent_rate
, CLIMB_RATE_RESET_SURFACE_TARGET
);
952 // Gradually reduce descent speed depending on actual altitude.
953 if (posControl
.actualState
.pos
.V
.Z
> (posControl
.homePosition
.pos
.V
.Z
+ 1500.0f
)) {
954 updateAltitudeTargetFromClimbRate(-1.0f
* posControl
.navConfig
->land_descent_rate
, CLIMB_RATE_RESET_SURFACE_TARGET
);
956 else if (posControl
.actualState
.pos
.V
.Z
> (posControl
.homePosition
.pos
.V
.Z
+ 500.0f
)) {
957 updateAltitudeTargetFromClimbRate(-0.5f
* posControl
.navConfig
->land_descent_rate
, CLIMB_RATE_RESET_SURFACE_TARGET
);
960 updateAltitudeTargetFromClimbRate(-0.25f
* posControl
.navConfig
->land_descent_rate
, CLIMB_RATE_RESET_SURFACE_TARGET
);
964 return NAV_FSM_EVENT_NONE
;
968 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_FINISHING(navigationFSMState_t previousState
)
970 UNUSED(previousState
);
972 if (posControl
.navConfig
->flags
.disarm_on_landing
) {
976 return NAV_FSM_EVENT_SUCCESS
;
979 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_RTH_3D_FINISHED(navigationFSMState_t previousState
)
981 // Stay in this state
982 UNUSED(previousState
);
983 updateAltitudeTargetFromClimbRate(-0.3f
* posControl
.navConfig
->land_descent_rate
, CLIMB_RATE_RESET_SURFACE_TARGET
); // FIXME
984 return NAV_FSM_EVENT_NONE
;
987 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_WAYPOINT_INITIALIZE(navigationFSMState_t previousState
)
989 UNUSED(previousState
);
991 if (posControl
.waypointCount
== 0 || !posControl
.waypointListValid
) {
992 return NAV_FSM_EVENT_ERROR
;
995 // Prepare controllers
996 resetPositionController();
997 resetAltitudeController();
998 setupAltitudeController();
1000 posControl
.activeWaypointIndex
= 0;
1001 return NAV_FSM_EVENT_SUCCESS
; // will switch to NAV_STATE_WAYPOINT_PRE_ACTION
1005 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_WAYPOINT_PRE_ACTION(navigationFSMState_t previousState
)
1007 /* A helper function to do waypoint-specific action */
1008 UNUSED(previousState
);
1010 switch (posControl
.waypointList
[posControl
.activeWaypointIndex
].action
) {
1011 case NAV_WP_ACTION_WAYPOINT
:
1012 calcualteAndSetActiveWaypoint(&posControl
.waypointList
[posControl
.activeWaypointIndex
]);
1013 return NAV_FSM_EVENT_SUCCESS
; // will switch to NAV_STATE_WAYPOINT_IN_PROGRESS
1015 case NAV_WP_ACTION_RTH
:
1017 calcualteAndSetActiveWaypointToLocalPosition(&posControl
.homeWaypointAbove
.pos
);
1018 return NAV_FSM_EVENT_SUCCESS
; // will switch to NAV_STATE_WAYPOINT_IN_PROGRESS
1022 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_WAYPOINT_IN_PROGRESS(navigationFSMState_t previousState
)
1024 UNUSED(previousState
);
1026 // If no position sensor available - land immediately
1027 if (posControl
.flags
.hasValidPositionSensor
&& posControl
.flags
.hasValidHeadingSensor
) {
1028 switch (posControl
.waypointList
[posControl
.activeWaypointIndex
].action
) {
1029 case NAV_WP_ACTION_WAYPOINT
:
1030 case NAV_WP_ACTION_RTH
:
1032 if (isWaypointReached(&posControl
.activeWaypoint
) || isWaypointMissed(&posControl
.activeWaypoint
)) {
1034 return NAV_FSM_EVENT_SUCCESS
; // will switch to NAV_STATE_WAYPOINT_REACHED
1037 // Update XY-position target to active waypoint
1038 setDesiredPosition(&posControl
.activeWaypoint
.pos
, 0, NAV_POS_UPDATE_XY
| NAV_POS_UPDATE_BEARING
);
1039 return NAV_FSM_EVENT_NONE
; // will re-process state in >10ms
1044 /* No pos sensor available for NAV_WAIT_FOR_GPS_TIMEOUT_MS - land */
1045 else if (checkForPositionSensorTimeout()) {
1046 return NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
;
1049 return NAV_FSM_EVENT_NONE
; // will re-process state in >10ms
1053 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_WAYPOINT_REACHED(navigationFSMState_t previousState
)
1055 UNUSED(previousState
);
1057 bool isLastWaypoint
= (posControl
.waypointList
[posControl
.activeWaypointIndex
].flag
== NAV_WP_FLAG_LAST
) ||
1058 (posControl
.activeWaypointIndex
>= (posControl
.waypointCount
- 1));
1060 if (isLastWaypoint
) {
1061 // Last waypoint reached
1062 return NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_FINISHED
;
1065 // Waypoint reached, do something and move on to next waypoint
1066 posControl
.activeWaypointIndex
++;
1067 return NAV_FSM_EVENT_SUCCESS
; // will switch to NAV_STATE_WAYPOINT_PRE_ACTION
1071 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_WAYPOINT_FINISHED(navigationFSMState_t previousState
)
1073 UNUSED(previousState
);
1075 // If no position sensor available - land immediately
1076 if (posControl
.flags
.hasValidPositionSensor
&& posControl
.flags
.hasValidHeadingSensor
) {
1077 return NAV_FSM_EVENT_NONE
;
1079 /* No pos sensor available for NAV_WAIT_FOR_GPS_TIMEOUT_MS - land */
1080 else if (checkForPositionSensorTimeout()) {
1081 return NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING
;
1084 return NAV_FSM_EVENT_NONE
; // will re-process state in >10ms
1088 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_EMERGENCY_LANDING_INITIALIZE(navigationFSMState_t previousState
)
1091 UNUSED(previousState
);
1093 // Emergency landing MAY use common altitude controller if vertical position is valid - initialize it
1094 resetAltitudeController();
1096 return NAV_FSM_EVENT_SUCCESS
;
1099 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_EMERGENCY_LANDING_IN_PROGRESS(navigationFSMState_t previousState
)
1102 UNUSED(previousState
);
1103 return NAV_FSM_EVENT_NONE
;
1106 static navigationFSMEvent_t
navOnEnteringState_NAV_STATE_EMERGENCY_LANDING_FINISHED(navigationFSMState_t previousState
)
1109 UNUSED(previousState
);
1110 return NAV_FSM_EVENT_SUCCESS
;
1113 static navigationFSMState_t
navSetNewFSMState(navigationFSMState_t newState
)
1115 navigationFSMState_t previousState
;
1117 previousState
= posControl
.navState
;
1118 posControl
.navState
= newState
;
1119 return previousState
;
1122 static void navProcessFSMEvents(navigationFSMEvent_t injectedEvent
)
1124 uint32_t currentMillis
= millis();
1125 navigationFSMState_t previousState
;
1126 static uint32_t lastStateProcessTime
= 0;
1128 /* If timeout event defined and timeout reached - switch state */
1129 if ((navFSM
[posControl
.navState
].timeoutMs
> 0) && (navFSM
[posControl
.navState
].onEvent
[NAV_FSM_EVENT_TIMEOUT
] != NAV_STATE_UNDEFINED
) &&
1130 ((currentMillis
- lastStateProcessTime
) >= navFSM
[posControl
.navState
].timeoutMs
)) {
1132 previousState
= navSetNewFSMState(navFSM
[posControl
.navState
].onEvent
[NAV_FSM_EVENT_TIMEOUT
]);
1134 /* Call new state's entry function */
1135 while (navFSM
[posControl
.navState
].onEntry
) {
1136 navigationFSMEvent_t newEvent
= navFSM
[posControl
.navState
].onEntry(previousState
);
1138 if ((newEvent
!= NAV_FSM_EVENT_NONE
) && (navFSM
[posControl
.navState
].onEvent
[newEvent
] != NAV_STATE_UNDEFINED
)) {
1139 previousState
= navSetNewFSMState(navFSM
[posControl
.navState
].onEvent
[newEvent
]);
1146 lastStateProcessTime
= currentMillis
;
1149 /* Inject new event */
1150 if (injectedEvent
!= NAV_FSM_EVENT_NONE
&& navFSM
[posControl
.navState
].onEvent
[injectedEvent
] != NAV_STATE_UNDEFINED
) {
1152 previousState
= navSetNewFSMState(navFSM
[posControl
.navState
].onEvent
[injectedEvent
]);
1154 /* Call new state's entry function */
1155 while (navFSM
[posControl
.navState
].onEntry
) {
1156 navigationFSMEvent_t newEvent
= navFSM
[posControl
.navState
].onEntry(previousState
);
1158 if ((newEvent
!= NAV_FSM_EVENT_NONE
) && (navFSM
[posControl
.navState
].onEvent
[newEvent
] != NAV_STATE_UNDEFINED
)) {
1159 previousState
= navSetNewFSMState(navFSM
[posControl
.navState
].onEvent
[newEvent
]);
1166 lastStateProcessTime
= currentMillis
;
1169 /* Update public system state information */
1170 NAV_Status
.mode
= MW_GPS_MODE_NONE
;
1172 if (ARMING_FLAG(ARMED
)) {
1173 navigationFSMStateFlags_t navStateFlags
= navGetStateFlags(posControl
.navState
);
1175 if (navStateFlags
& NAV_AUTO_RTH
) {
1176 NAV_Status
.mode
= MW_GPS_MODE_RTH
;
1178 else if (navStateFlags
& NAV_AUTO_WP
) {
1179 NAV_Status
.mode
= MW_GPS_MODE_NAV
;
1181 else if (navStateFlags
& NAV_CTL_EMERG
) {
1182 NAV_Status
.mode
= MW_GPS_MODE_EMERG
;
1184 else if (navStateFlags
& NAV_CTL_POS
) {
1185 NAV_Status
.mode
= MW_GPS_MODE_HOLD
;
1189 NAV_Status
.state
= navFSM
[posControl
.navState
].mwState
;
1190 NAV_Status
.error
= navFSM
[posControl
.navState
].mwError
;
1192 NAV_Status
.flags
= 0;
1193 if (posControl
.flags
.isAdjustingPosition
) NAV_Status
.flags
|= MW_NAV_FLAG_ADJUSTING_POSITION
;
1194 if (posControl
.flags
.isAdjustingAltitude
) NAV_Status
.flags
|= MW_NAV_FLAG_ADJUSTING_ALTITUDE
;
1196 NAV_Status
.activeWpNumber
= posControl
.activeWaypointIndex
+ 1;
1197 NAV_Status
.activeWpAction
= 0;
1198 if ((posControl
.activeWaypointIndex
>= 0) && (posControl
.activeWaypointIndex
< NAV_MAX_WAYPOINTS
)) {
1199 NAV_Status
.activeWpAction
= posControl
.waypointList
[posControl
.activeWaypointIndex
].action
;
1203 /*-----------------------------------------------------------
1204 * Float point PID-controller implementation
1205 *-----------------------------------------------------------*/
1206 // Implementation of PID with back-calculation I-term anti-windup
1207 // Control System Design, Lecture Notes for ME 155A by Karl Johan Åström (p.228)
1208 // http://www.cds.caltech.edu/~murray/courses/cds101/fa02/caltech/astrom-ch6.pdf
1209 float navPidApply2(float setpoint
, float measurement
, float dt
, pidController_t
*pid
, float outMin
, float outMax
, bool dTermErrorTracking
)
1211 float newProportional
, newDerivative
;
1212 float error
= setpoint
- measurement
;
1215 newProportional
= error
* pid
->param
.kP
;
1218 if (dTermErrorTracking
) {
1219 /* Error-tracking D-term */
1220 newDerivative
= (error
- pid
->last_input
) / dt
;
1221 pid
->last_input
= error
;
1224 /* Measurement tracking D-term */
1225 newDerivative
= -(measurement
- pid
->last_input
) / dt
;
1226 pid
->last_input
= measurement
;
1229 newDerivative
= pid
->param
.kD
* filterApplyPt1(newDerivative
, &pid
->dterm_filter_state
, NAV_DTERM_CUT_HZ
, dt
);
1231 /* Pre-calculate output and limit it if actuator is saturating */
1232 float outVal
= newProportional
+ pid
->integrator
+ newDerivative
;
1233 float outValConstrained
= constrainf(outVal
, outMin
, outMax
);
1236 pid
->integrator
+= (error
* pid
->param
.kI
* dt
) + ((outValConstrained
- outVal
) * pid
->param
.kT
* dt
);
1238 return outValConstrained
;
1241 void navPidReset(pidController_t
*pid
)
1243 pid
->integrator
= 0.0f
;
1244 pid
->last_input
= 0.0f
;
1245 pid
->dterm_filter_state
.state
= 0.0f
;
1246 pid
->dterm_filter_state
.RC
= 0.0f
;
1249 void navPidInit(pidController_t
*pid
, float _kP
, float _kI
, float _kD
)
1251 pid
->param
.kP
= _kP
;
1252 pid
->param
.kI
= _kI
;
1253 pid
->param
.kD
= _kD
;
1255 if (_kI
> 1e-6f
&& _kP
> 1e-6f
) {
1256 float Ti
= _kP
/ _kI
;
1257 float Td
= _kD
/ _kP
;
1258 pid
->param
.kT
= 2.0f
/ (Ti
+ Td
);
1261 pid
->param
.kI
= 0.0;
1262 pid
->param
.kT
= 0.0;
1268 /*-----------------------------------------------------------
1269 * Float point P-controller implementation
1270 *-----------------------------------------------------------*/
1271 void navPInit(pController_t
*p
, float _kP
)
1276 /*-----------------------------------------------------------
1277 * Detects if thrust vector is facing downwards
1278 *-----------------------------------------------------------*/
1279 bool isThrustFacingDownwards(void)
1281 // Tilt angle <= 80 deg; cos(80) = 0.17364817766693034885171662676931
1282 return (calculateCosTiltAngle() >= 0.173648178f
);
1285 /*-----------------------------------------------------------
1286 * Checks if position sensor (GPS) is failing for a specified timeout (if enabled)
1287 *-----------------------------------------------------------*/
1288 bool checkForPositionSensorTimeout(void)
1290 if (posControl
.navConfig
->pos_failure_timeout
) {
1291 if (!posControl
.flags
.hasValidPositionSensor
&& ((millis() - posControl
.lastValidPositionTimeMs
) > (1000 * posControl
.navConfig
->pos_failure_timeout
))) {
1299 // Timeout not defined, never fail
1304 /*-----------------------------------------------------------
1305 * Processes an update to XY-position and velocity
1306 *-----------------------------------------------------------*/
1307 void updateActualHorizontalPositionAndVelocity(bool hasValidSensor
, float newX
, float newY
, float newVelX
, float newVelY
)
1309 posControl
.actualState
.pos
.V
.X
= newX
;
1310 posControl
.actualState
.pos
.V
.Y
= newY
;
1312 posControl
.actualState
.vel
.V
.X
= newVelX
;
1313 posControl
.actualState
.vel
.V
.Y
= newVelY
;
1315 posControl
.flags
.hasValidPositionSensor
= hasValidSensor
;
1316 posControl
.flags
.hasValidHeadingSensor
= isImuHeadingValid();
1318 if (hasValidSensor
) {
1319 posControl
.flags
.horizontalPositionNewData
= 1;
1320 posControl
.lastValidPositionTimeMs
= millis();
1323 posControl
.flags
.horizontalPositionNewData
= 0;
1326 #if defined(NAV_BLACKBOX)
1327 navLatestActualPosition
[X
] = newX
;
1328 navLatestActualPosition
[Y
] = newY
;
1329 navActualVelocity
[X
] = constrain(newVelX
, -32678, 32767);
1330 navActualVelocity
[Y
] = constrain(newVelY
, -32678, 32767);
1334 /*-----------------------------------------------------------
1335 * Processes an update to Z-position and velocity
1336 *-----------------------------------------------------------*/
1337 void updateActualAltitudeAndClimbRate(bool hasValidSensor
, float newAltitude
, float newVelocity
)
1339 posControl
.actualState
.pos
.V
.Z
= newAltitude
;
1340 posControl
.actualState
.vel
.V
.Z
= newVelocity
;
1342 posControl
.flags
.hasValidAltitudeSensor
= hasValidSensor
;
1344 // Update altitude that would be used when executing RTH
1345 if (hasValidSensor
) {
1346 updateDesiredRTHAltitude();
1347 posControl
.flags
.verticalPositionNewData
= 1;
1348 posControl
.lastValidAltitudeTimeMs
= millis();
1351 posControl
.flags
.verticalPositionNewData
= 0;
1354 #if defined(NAV_BLACKBOX)
1355 navLatestActualPosition
[Z
] = constrain(newAltitude
, -32678, 32767);
1356 navActualVelocity
[Z
] = constrain(newVelocity
, -32678, 32767);
1360 /*-----------------------------------------------------------
1361 * Processes an update to surface distance
1362 *-----------------------------------------------------------*/
1363 void updateActualSurfaceDistance(bool hasValidSensor
, float surfaceDistance
, float surfaceVelocity
)
1365 posControl
.actualState
.surface
= surfaceDistance
;
1366 posControl
.actualState
.surfaceVel
= surfaceVelocity
;
1368 if (ARMING_FLAG(ARMED
)) {
1369 if (surfaceDistance
> 0) {
1370 if (posControl
.actualState
.surfaceMin
> 0) {
1371 posControl
.actualState
.surfaceMin
= MIN(posControl
.actualState
.surfaceMin
, surfaceDistance
);
1374 posControl
.actualState
.surfaceMin
= surfaceDistance
;
1379 posControl
.actualState
.surfaceMin
= -1;
1382 posControl
.flags
.hasValidSurfaceSensor
= hasValidSensor
;
1384 if (hasValidSensor
) {
1385 posControl
.flags
.surfaceDistanceNewData
= 1;
1388 posControl
.flags
.surfaceDistanceNewData
= 0;
1391 #if defined(NAV_BLACKBOX)
1392 navActualSurface
= surfaceDistance
;
1396 /*-----------------------------------------------------------
1397 * Processes an update to estimated heading
1398 *-----------------------------------------------------------*/
1399 void updateActualHeading(int32_t newHeading
)
1401 /* Update heading */
1402 posControl
.actualState
.yaw
= newHeading
;
1404 /* Precompute sin/cos of yaw angle */
1405 posControl
.actualState
.sinYaw
= sin_approx(CENTIDEGREES_TO_RADIANS(newHeading
));
1406 posControl
.actualState
.cosYaw
= cos_approx(CENTIDEGREES_TO_RADIANS(newHeading
));
1408 posControl
.flags
.headingNewData
= 1;
1411 /*-----------------------------------------------------------
1412 * Calculates distance and bearing to destination point
1413 *-----------------------------------------------------------*/
1414 uint32_t calculateDistanceToDestination(t_fp_vector
* destinationPos
)
1416 float deltaX
= destinationPos
->V
.X
- posControl
.actualState
.pos
.V
.X
;
1417 float deltaY
= destinationPos
->V
.Y
- posControl
.actualState
.pos
.V
.Y
;
1419 return sqrtf(sq(deltaX
) + sq(deltaY
));
1422 int32_t calculateBearingToDestination(t_fp_vector
* destinationPos
)
1424 float deltaX
= destinationPos
->V
.X
- posControl
.actualState
.pos
.V
.X
;
1425 float deltaY
= destinationPos
->V
.Y
- posControl
.actualState
.pos
.V
.Y
;
1427 return wrap_36000(RADIANS_TO_CENTIDEGREES(atan2_approx(deltaY
, deltaX
)));
1430 /*-----------------------------------------------------------
1431 * Check if waypoint is/was reached. Assume that waypoint-yaw stores initial bearing
1432 *-----------------------------------------------------------*/
1433 bool isWaypointMissed(navWaypointPosition_t
* waypoint
)
1435 int32_t bearingError
= calculateBearingToDestination(&waypoint
->pos
) - waypoint
->yaw
;
1436 bearingError
= wrap_18000(bearingError
);
1438 return ABS(bearingError
) > 10000; // TRUE if we passed the waypoint by 100 degrees
1441 bool isWaypointReached(navWaypointPosition_t
* waypoint
)
1443 // We consider waypoint reached if within specified radius
1444 uint32_t wpDistance
= calculateDistanceToDestination(&waypoint
->pos
);
1445 return (wpDistance
<= posControl
.navConfig
->waypoint_radius
);
1448 static void updateHomePositionCompatibility(void)
1450 geoConvertLocalToGeodetic(&posControl
.gpsOrigin
, &posControl
.homePosition
.pos
, &GPS_home
);
1451 GPS_distanceToHome
= posControl
.homeDistance
/ 100;
1452 GPS_directionToHome
= posControl
.homeDirection
/ 100;
1455 /*-----------------------------------------------------------
1456 * Reset home position to current position
1457 *-----------------------------------------------------------*/
1458 static void updateDesiredRTHAltitude(void)
1460 if (ARMING_FLAG(ARMED
)) {
1461 if (!(navGetStateFlags(posControl
.navState
) & NAV_AUTO_RTH
)) {
1462 switch (posControl
.navConfig
->flags
.rth_alt_control_style
) {
1463 case NAV_RTH_NO_ALT
:
1464 posControl
.homeWaypointAbove
.pos
.V
.Z
= posControl
.actualState
.pos
.V
.Z
;
1466 case NAX_RTH_EXTRA_ALT
: // Maintain current altitude + predefined safety margin
1467 posControl
.homeWaypointAbove
.pos
.V
.Z
= posControl
.actualState
.pos
.V
.Z
+ posControl
.navConfig
->rth_altitude
;
1469 case NAV_RTH_MAX_ALT
:
1470 posControl
.homeWaypointAbove
.pos
.V
.Z
= MAX(posControl
.homeWaypointAbove
.pos
.V
.Z
, posControl
.actualState
.pos
.V
.Z
);
1472 case NAV_RTH_AT_LEAST_ALT
: // Climb to at least some predefined altitude above home
1473 posControl
.homeWaypointAbove
.pos
.V
.Z
= MAX(posControl
.homePosition
.pos
.V
.Z
+ posControl
.navConfig
->rth_altitude
, posControl
.actualState
.pos
.V
.Z
);
1475 case NAV_RTH_CONST_ALT
: // Climb/descend to predefined altitude above home
1477 posControl
.homeWaypointAbove
.pos
.V
.Z
= posControl
.homePosition
.pos
.V
.Z
+ posControl
.navConfig
->rth_altitude
;
1483 posControl
.homeWaypointAbove
.pos
.V
.Z
= posControl
.actualState
.pos
.V
.Z
;
1487 /*-----------------------------------------------------------
1488 * Reset home position to current position
1489 *-----------------------------------------------------------*/
1490 void setHomePosition(t_fp_vector
* pos
, int32_t yaw
)
1492 posControl
.homePosition
.pos
= *pos
;
1493 posControl
.homePosition
.yaw
= yaw
;
1495 posControl
.homeDistance
= 0;
1496 posControl
.homeDirection
= 0;
1498 // Update target RTH altitude as a waypoint above home
1499 posControl
.homeWaypointAbove
= posControl
.homePosition
;
1500 updateDesiredRTHAltitude();
1502 updateHomePositionCompatibility();
1503 ENABLE_STATE(GPS_FIX_HOME
);
1506 /*-----------------------------------------------------------
1507 * Update home position, calculate distance and bearing to home
1508 *-----------------------------------------------------------*/
1509 void updateHomePosition(void)
1511 // Disarmed and have a valid position, constantly update home
1512 if (!ARMING_FLAG(ARMED
)) {
1513 if (posControl
.flags
.hasValidPositionSensor
) {
1514 setHomePosition(&posControl
.actualState
.pos
, posControl
.actualState
.yaw
);
1518 // If pilot so desires he may reset home position to current position
1519 if (IS_RC_MODE_ACTIVE(BOXHOMERESET
) && !FLIGHT_MODE(NAV_RTH_MODE
) && !FLIGHT_MODE(NAV_WP_MODE
) && posControl
.flags
.hasValidPositionSensor
) {
1520 setHomePosition(&posControl
.actualState
.pos
, posControl
.actualState
.yaw
);
1523 // Update distance and direction to home if armed (home is not updated when armed)
1524 if (STATE(GPS_FIX_HOME
)) {
1525 posControl
.homeDistance
= calculateDistanceToDestination(&posControl
.homePosition
.pos
);
1526 posControl
.homeDirection
= calculateBearingToDestination(&posControl
.homePosition
.pos
);
1527 updateHomePositionCompatibility();
1532 /*-----------------------------------------------------------
1533 * Set surface tracking target
1534 *-----------------------------------------------------------*/
1535 void setDesiredSurfaceOffset(float surfaceOffset
)
1537 if (surfaceOffset
> 0) {
1538 posControl
.desiredState
.surface
= constrainf(surfaceOffset
, 1.0f
, INAV_SURFACE_MAX_DISTANCE
);
1541 posControl
.desiredState
.surface
= -1;
1544 #if defined(NAV_BLACKBOX)
1545 navTargetSurface
= constrain(lrintf(posControl
.desiredState
.surface
), -32678, 32767);
1549 /*-----------------------------------------------------------
1550 * Calculate platform-specific hold position (account for deceleration)
1551 *-----------------------------------------------------------*/
1552 void calculateInitialHoldPosition(t_fp_vector
* pos
)
1554 if (STATE(FIXED_WING
)) { // FIXED_WING
1555 calculateFixedWingInitialHoldPosition(pos
);
1558 calculateMulticopterInitialHoldPosition(pos
);
1562 /*-----------------------------------------------------------
1563 * Set active XYZ-target and desired heading
1564 *-----------------------------------------------------------*/
1565 void setDesiredPosition(t_fp_vector
* pos
, int32_t yaw
, navSetWaypointFlags_t useMask
)
1568 if ((useMask
& NAV_POS_UPDATE_XY
) != 0) {
1569 posControl
.desiredState
.pos
.V
.X
= pos
->V
.X
;
1570 posControl
.desiredState
.pos
.V
.Y
= pos
->V
.Y
;
1574 if ((useMask
& NAV_POS_UPDATE_Z
) != 0) {
1575 posControl
.desiredState
.surface
= -1; // When we directly set altitude target we must reset surface tracking
1576 posControl
.desiredState
.pos
.V
.Z
= pos
->V
.Z
;
1580 if ((useMask
& NAV_POS_UPDATE_HEADING
) != 0) {
1582 posControl
.desiredState
.yaw
= yaw
;
1584 else if ((useMask
& NAV_POS_UPDATE_BEARING
) != 0) {
1585 posControl
.desiredState
.yaw
= calculateBearingToDestination(pos
);
1587 else if ((useMask
& NAV_POS_UPDATE_BEARING_TAIL_FIRST
) != 0) {
1588 posControl
.desiredState
.yaw
= wrap_36000(calculateBearingToDestination(pos
) - 18000);
1591 #if defined(NAV_BLACKBOX)
1592 navTargetPosition
[X
] = constrain(lrintf(posControl
.desiredState
.pos
.V
.X
), -32678, 32767);
1593 navTargetPosition
[Y
] = constrain(lrintf(posControl
.desiredState
.pos
.V
.Y
), -32678, 32767);
1594 navTargetPosition
[Z
] = constrain(lrintf(posControl
.desiredState
.pos
.V
.Z
), -32678, 32767);
1595 navTargetSurface
= constrain(lrintf(posControl
.desiredState
.surface
), -32678, 32767);
1599 void calculateFarAwayTarget(t_fp_vector
* farAwayPos
, int32_t yaw
, int32_t distance
)
1601 farAwayPos
->V
.X
= posControl
.actualState
.pos
.V
.X
+ distance
* cos_approx(CENTIDEGREES_TO_RADIANS(yaw
));
1602 farAwayPos
->V
.Y
= posControl
.actualState
.pos
.V
.Y
+ distance
* sin_approx(CENTIDEGREES_TO_RADIANS(yaw
));
1603 farAwayPos
->V
.Z
= posControl
.actualState
.pos
.V
.Z
;
1606 /*-----------------------------------------------------------
1608 *-----------------------------------------------------------*/
1609 static uint32_t landingTimer
;
1611 void resetLandingDetector(void)
1613 landingTimer
= micros();
1616 bool isLandingDetected(void)
1618 bool landingDetected
;
1620 if (STATE(FIXED_WING
)) { // FIXED_WING
1621 landingDetected
= isFixedWingLandingDetected(&landingTimer
);
1624 landingDetected
= isMulticopterLandingDetected(&landingTimer
);
1627 return landingDetected
;
1630 /*-----------------------------------------------------------
1631 * Z-position controller
1632 *-----------------------------------------------------------*/
1633 void updateAltitudeTargetFromClimbRate(float climbRate
, navUpdateAltitudeFromRateMode_e mode
)
1635 // FIXME: On FIXED_WING and multicopter this should work in a different way
1636 // Calculate new altitude target
1638 /* Move surface tracking setpoint if it is set */
1639 if (mode
== CLIMB_RATE_RESET_SURFACE_TARGET
) {
1640 posControl
.desiredState
.surface
= -1;
1643 if (posControl
.flags
.isTerrainFollowEnabled
) {
1644 if (posControl
.actualState
.surface
>= 0.0f
&& posControl
.flags
.hasValidSurfaceSensor
&& (mode
== CLIMB_RATE_UPDATE_SURFACE_TARGET
)) {
1645 posControl
.desiredState
.surface
= constrainf(posControl
.actualState
.surface
+ (climbRate
/ (posControl
.pids
.pos
[Z
].param
.kP
* posControl
.pids
.surface
.param
.kP
)), 1.0f
, INAV_SURFACE_MAX_DISTANCE
);
1649 posControl
.desiredState
.surface
= -1;
1653 posControl
.desiredState
.pos
.V
.Z
= posControl
.actualState
.pos
.V
.Z
+ (climbRate
/ posControl
.pids
.pos
[Z
].param
.kP
);
1655 #if defined(NAV_BLACKBOX)
1656 navTargetPosition
[Z
] = constrain(lrintf(posControl
.desiredState
.pos
.V
.Z
), -32678, 32767);
1657 navTargetSurface
= constrain(lrintf(posControl
.desiredState
.surface
), -32678, 32767);
1661 static void resetAltitudeController(void)
1663 if (STATE(FIXED_WING
)) {
1664 resetFixedWingAltitudeController();
1667 resetMulticopterAltitudeController();
1671 static void setupAltitudeController(void)
1673 if (STATE(FIXED_WING
)) {
1674 setupFixedWingAltitudeController();
1677 setupMulticopterAltitudeController();
1681 static bool adjustAltitudeFromRCInput(void)
1683 if (STATE(FIXED_WING
)) {
1684 return adjustFixedWingAltitudeFromRCInput();
1687 return adjustMulticopterAltitudeFromRCInput();
1691 /*-----------------------------------------------------------
1692 * Heading controller (pass-through to MAG mode)
1693 *-----------------------------------------------------------*/
1694 static void resetHeadingController(void)
1696 if (STATE(FIXED_WING
)) {
1697 resetFixedWingHeadingController();
1700 resetMulticopterHeadingController();
1704 static bool adjustHeadingFromRCInput(void)
1706 if (STATE(FIXED_WING
)) {
1707 return adjustFixedWingHeadingFromRCInput();
1710 return adjustMulticopterHeadingFromRCInput();
1714 /*-----------------------------------------------------------
1715 * XY Position controller
1716 *-----------------------------------------------------------*/
1717 static void resetPositionController(void)
1719 if (STATE(FIXED_WING
)) {
1720 resetFixedWingPositionController();
1723 resetMulticopterPositionController();
1727 static bool adjustPositionFromRCInput(void)
1729 if (STATE(FIXED_WING
)) {
1730 return adjustFixedWingPositionFromRCInput();
1733 return adjustMulticopterPositionFromRCInput();
1736 #if defined(NAV_BLACKBOX)
1737 navTargetPosition
[X
] = constrain(lrintf(posControl
.desiredState
.pos
.V
.X
), -32678, 32767);
1738 navTargetPosition
[Y
] = constrain(lrintf(posControl
.desiredState
.pos
.V
.Y
), -32678, 32767);
1742 /*-----------------------------------------------------------
1744 *-----------------------------------------------------------*/
1745 void getWaypoint(uint8_t wpNumber
, navWaypoint_t
* wpData
)
1747 /* Default waypoint to send */
1748 wpData
->action
= NAV_WP_ACTION_RTH
;
1755 wpData
->flag
= NAV_WP_FLAG_LAST
;
1757 // WP #0 - special waypoint - HOME
1758 if (wpNumber
== 0) {
1759 if (STATE(GPS_FIX_HOME
)) {
1760 wpData
->lat
= GPS_home
.lat
;
1761 wpData
->lon
= GPS_home
.lon
;
1762 wpData
->alt
= GPS_home
.alt
;
1765 // WP #255 - special waypoint - directly get actualPosition
1766 else if (wpNumber
== 255) {
1767 gpsLocation_t wpLLH
;
1769 geoConvertLocalToGeodetic(&posControl
.gpsOrigin
, &posControl
.actualState
.pos
, &wpLLH
);
1771 wpData
->lat
= wpLLH
.lat
;
1772 wpData
->lon
= wpLLH
.lon
;
1773 wpData
->alt
= wpLLH
.alt
;
1775 // WP #1 - #15 - common waypoints - pre-programmed mission
1776 else if ((wpNumber
>= 1) && (wpNumber
<= NAV_MAX_WAYPOINTS
)) {
1777 if (wpNumber
<= posControl
.waypointCount
) {
1778 *wpData
= posControl
.waypointList
[wpNumber
- 1];
1783 void setWaypoint(uint8_t wpNumber
, navWaypoint_t
* wpData
)
1785 gpsLocation_t wpLLH
;
1786 navWaypointPosition_t wpPos
;
1788 // Pre-fill structure to convert to local coordinates
1789 wpLLH
.lat
= wpData
->lat
;
1790 wpLLH
.lon
= wpData
->lon
;
1791 wpLLH
.alt
= wpData
->alt
;
1793 // WP #0 - special waypoint - HOME
1794 if ((wpNumber
== 0) && ARMING_FLAG(ARMED
) && posControl
.flags
.hasValidPositionSensor
&& posControl
.gpsOrigin
.valid
) {
1795 // Forcibly set home position. Note that this is only valid if already armed, otherwise home will be reset instantly
1796 geoConvertGeodeticToLocal(&posControl
.gpsOrigin
, &wpLLH
, &wpPos
.pos
, GEO_ALT_RELATIVE
);
1797 setHomePosition(&wpPos
.pos
, 0);
1799 // WP #255 - special waypoint - directly set desiredPosition
1800 // Only valid when armed and in poshold mode
1801 else if ((wpNumber
== 255) && (wpData
->action
== NAV_WP_ACTION_WAYPOINT
) &&
1802 ARMING_FLAG(ARMED
) && posControl
.flags
.hasValidPositionSensor
&& posControl
.gpsOrigin
.valid
&& posControl
.flags
.isGCSAssistedNavigationEnabled
&&
1803 (posControl
.navState
== NAV_STATE_POSHOLD_2D_IN_PROGRESS
|| posControl
.navState
== NAV_STATE_POSHOLD_3D_IN_PROGRESS
)) {
1804 // Convert to local coordinates
1805 geoConvertGeodeticToLocal(&posControl
.gpsOrigin
, &wpLLH
, &wpPos
.pos
, GEO_ALT_RELATIVE
);
1807 navSetWaypointFlags_t waypointUpdateFlags
= NAV_POS_UPDATE_XY
;
1809 // If we received global altitude == 0, use current altitude
1810 if (wpData
->alt
!= 0) {
1811 waypointUpdateFlags
|= NAV_POS_UPDATE_Z
;
1814 if (wpData
->p1
> 0 && wpData
->p1
< 360) {
1815 waypointUpdateFlags
|= NAV_POS_UPDATE_HEADING
;
1818 setDesiredPosition(&wpPos
.pos
, DEGREES_TO_DECIDEGREES(wpData
->p1
), waypointUpdateFlags
);
1820 // WP #1 - #15 - common waypoints - pre-programmed mission
1821 else if ((wpNumber
>= 1) && (wpNumber
<= NAV_MAX_WAYPOINTS
) && !ARMING_FLAG(ARMED
)) {
1822 if (wpData
->action
== NAV_WP_ACTION_WAYPOINT
|| wpData
->action
== NAV_WP_ACTION_RTH
) {
1823 // Only allow upload next waypoint (continue upload mission) or first waypoint (new mission)
1824 if (wpNumber
== (posControl
.waypointCount
+ 1) || wpNumber
== 1) {
1825 posControl
.waypointList
[wpNumber
- 1] = *wpData
;
1826 posControl
.waypointCount
= wpNumber
;
1827 posControl
.waypointListValid
= (wpData
->flag
== NAV_WP_FLAG_LAST
);
1833 void resetWaypointList(void)
1835 /* Can only reset waypoint list if not armed */
1836 if (!ARMING_FLAG(ARMED
)) {
1837 posControl
.waypointCount
= 0;
1838 posControl
.waypointListValid
= false;
1842 static void calcualteAndSetActiveWaypointToLocalPosition(t_fp_vector
* pos
)
1844 posControl
.activeWaypoint
.pos
= *pos
;
1846 // Calculate initial bearing towards waypoint and store it in waypoint yaw parameter (this will further be used to detect missed waypoints)
1847 posControl
.activeWaypoint
.yaw
= calculateBearingToDestination(pos
);
1849 // Set desired position to next waypoint (XYZ-controller)
1850 setDesiredPosition(&posControl
.activeWaypoint
.pos
, posControl
.activeWaypoint
.yaw
, NAV_POS_UPDATE_XY
| NAV_POS_UPDATE_Z
| NAV_POS_UPDATE_HEADING
);
1853 static void calcualteAndSetActiveWaypoint(navWaypoint_t
* waypoint
)
1855 gpsLocation_t wpLLH
;
1856 t_fp_vector localPos
;
1858 wpLLH
.lat
= waypoint
->lat
;
1859 wpLLH
.lon
= waypoint
->lon
;
1860 wpLLH
.alt
= waypoint
->alt
;
1862 geoConvertGeodeticToLocal(&posControl
.gpsOrigin
, &wpLLH
, &localPos
, GEO_ALT_RELATIVE
);
1863 calcualteAndSetActiveWaypointToLocalPosition(&localPos
);
1867 * Returns TRUE if we are in WP mode and executing last waypoint on the list, or in RTH mode, or in PH mode
1868 * In RTH mode our only and last waypoint is home
1869 * In PH mode our waypoint is hold position */
1870 bool isApproachingLastWaypoint(void)
1872 if (navGetStateFlags(posControl
.navState
) & NAV_AUTO_WP
) {
1873 if (posControl
.waypointCount
== 0) {
1877 else if ((posControl
.activeWaypointIndex
== (posControl
.waypointCount
- 1)) ||
1878 (posControl
.waypointList
[posControl
.activeWaypointIndex
].flag
== NAV_WP_FLAG_LAST
)) {
1885 else if (navGetStateFlags(posControl
.navState
) & NAV_CTL_POS
) {
1886 // If POS controller is active we are in Poshold or RTH mode - assume last waypoint
1894 float getActiveWaypointSpeed(void)
1896 uint16_t waypointSpeed
= posControl
.navConfig
->max_speed
;
1898 if (navGetStateFlags(posControl
.navState
) & NAV_AUTO_WP
) {
1899 if (posControl
.waypointCount
> 0 && posControl
.waypointList
[posControl
.activeWaypointIndex
].action
== NAV_WP_ACTION_WAYPOINT
) {
1900 waypointSpeed
= posControl
.waypointList
[posControl
.activeWaypointIndex
].p1
;
1902 if (waypointSpeed
< 50 || waypointSpeed
> posControl
.navConfig
->max_speed
) {
1903 waypointSpeed
= posControl
.navConfig
->max_speed
;
1908 return waypointSpeed
;
1911 /*-----------------------------------------------------------
1912 * A function to reset navigation PIDs and states
1913 *-----------------------------------------------------------*/
1914 void resetNavigation(void)
1916 resetAltitudeController();
1917 resetHeadingController();
1918 resetPositionController();
1921 /*-----------------------------------------------------------
1922 * Process adjustments to alt, pos and yaw controllers
1923 *-----------------------------------------------------------*/
1924 static void processNavigationRCAdjustments(void)
1926 /* Process pilot's RC input. Disable all pilot's input when in FAILSAFE_MODE */
1927 navigationFSMStateFlags_t navStateFlags
= navGetStateFlags(posControl
.navState
);
1928 if ((navStateFlags
& NAV_RC_ALT
) && (!FLIGHT_MODE(FAILSAFE_MODE
))) {
1929 posControl
.flags
.isAdjustingAltitude
= adjustAltitudeFromRCInput();
1932 posControl
.flags
.isAdjustingAltitude
= false;
1935 if ((navStateFlags
& NAV_RC_POS
) && (!FLIGHT_MODE(FAILSAFE_MODE
))) {
1936 posControl
.flags
.isAdjustingPosition
= adjustPositionFromRCInput();
1939 posControl
.flags
.isAdjustingPosition
= false;
1942 if ((navStateFlags
& NAV_RC_YAW
) && (!FLIGHT_MODE(FAILSAFE_MODE
))) {
1943 posControl
.flags
.isAdjustingHeading
= adjustHeadingFromRCInput();
1946 posControl
.flags
.isAdjustingHeading
= false;
1950 /*-----------------------------------------------------------
1951 * A main function to call position controllers at loop rate
1952 *-----------------------------------------------------------*/
1953 void applyWaypointNavigationAndAltitudeHold(void)
1955 uint32_t currentTime
= micros();
1957 #if defined(NAV_BLACKBOX)
1959 if (posControl
.flags
.hasValidAltitudeSensor
) navFlags
|= (1 << 0);
1960 if (posControl
.flags
.hasValidSurfaceSensor
) navFlags
|= (1 << 1);
1961 if (posControl
.flags
.hasValidPositionSensor
) navFlags
|= (1 << 2);
1962 if ((STATE(GPS_FIX
) && gpsSol
.numSat
>= posControl
.navConfig
->inav
.gps_min_sats
)) navFlags
|= (1 << 3);
1963 if (isGPSGlitchDetected()) navFlags
|= (1 << 4);
1966 // No navigation when disarmed
1967 if (!ARMING_FLAG(ARMED
)) {
1968 // If we are disarmed, abort forced RTH
1969 posControl
.flags
.forcedRTHActivated
= false;
1973 /* Process controllers */
1974 navigationFSMStateFlags_t navStateFlags
= navGetStateFlags(posControl
.navState
);
1975 if (STATE(FIXED_WING
)) {
1976 applyFixedWingNavigationController(navStateFlags
, currentTime
);
1979 applyMulticopterNavigationController(navStateFlags
, currentTime
);
1982 #if defined(NAV_BLACKBOX)
1983 if (posControl
.flags
.isAdjustingPosition
) navFlags
|= (1 << 5);
1984 if (posControl
.flags
.isAdjustingAltitude
) navFlags
|= (1 << 6);
1985 if (posControl
.flags
.isAdjustingHeading
) navFlags
|= (1 << 7);
1989 /*-----------------------------------------------------------
1990 * Set CF's FLIGHT_MODE from current NAV_MODE
1991 *-----------------------------------------------------------*/
1992 void swithNavigationFlightModes(void)
1994 flightModeFlags_e enabledNavFlightModes
= navGetMappedFlightModes(posControl
.navState
);
1995 flightModeFlags_e disabledFlightModes
= (NAV_ALTHOLD_MODE
| NAV_RTH_MODE
| NAV_POSHOLD_MODE
| NAV_WP_MODE
) & (~enabledNavFlightModes
);
1996 DISABLE_FLIGHT_MODE(disabledFlightModes
);
1997 ENABLE_FLIGHT_MODE(enabledNavFlightModes
);
2000 /*-----------------------------------------------------------
2001 * desired NAV_MODE from combination of FLIGHT_MODE flags
2002 *-----------------------------------------------------------*/
2003 static bool canActivateAltHoldMode(void)
2005 return posControl
.flags
.hasValidAltitudeSensor
;
2008 static bool canActivatePosHoldMode(void)
2010 return posControl
.flags
.hasValidPositionSensor
&& posControl
.flags
.hasValidHeadingSensor
;
2013 static navigationFSMEvent_t
selectNavEventFromBoxModeInput(void)
2015 static bool canActivateWaypoint
= false;
2017 //We can switch modes only when ARMED
2018 if (ARMING_FLAG(ARMED
)) {
2019 // Flags if we can activate certain nav modes (check if we have required sensors and they provide valid data)
2020 bool canActivateAltHold
= canActivateAltHoldMode();
2021 bool canActivatePosHold
= canActivatePosHoldMode();
2023 // RTH/Failsafe_RTH can override PASSTHRU
2024 if (posControl
.flags
.forcedRTHActivated
|| IS_RC_MODE_ACTIVE(BOXNAVRTH
)) {
2025 // If we request forced RTH - attempt to activate it no matter what
2026 // This might switch to emergency landing controller if GPS is unavailable
2027 canActivateWaypoint
= false; // Block WP mode if we switched to RTH for whatever reason
2028 return NAV_FSM_EVENT_SWITCH_TO_RTH
;
2031 // PASSTHRU mode has priority over WP/PH/AH
2032 if (IS_RC_MODE_ACTIVE(BOXPASSTHRU
)) {
2033 canActivateWaypoint
= false; // Block WP mode if we are in PASSTHROUGH mode
2034 return NAV_FSM_EVENT_SWITCH_TO_IDLE
;
2037 if (IS_RC_MODE_ACTIVE(BOXNAVWP
)) {
2038 if ((FLIGHT_MODE(NAV_WP_MODE
)) || (canActivateWaypoint
&& canActivatePosHold
&& canActivateAltHold
&& STATE(GPS_FIX_HOME
) && ARMING_FLAG(ARMED
) && posControl
.waypointListValid
&& (posControl
.waypointCount
> 0)))
2039 return NAV_FSM_EVENT_SWITCH_TO_WAYPOINT
;
2042 // Arm the state variable if the WP BOX mode is not enabled
2043 canActivateWaypoint
= true;
2046 if (IS_RC_MODE_ACTIVE(BOXNAVPOSHOLD
) && IS_RC_MODE_ACTIVE(BOXNAVALTHOLD
)) {
2047 if ((FLIGHT_MODE(NAV_ALTHOLD_MODE
) && FLIGHT_MODE(NAV_POSHOLD_MODE
)) || (canActivatePosHold
&& canActivateAltHold
))
2048 return NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D
;
2051 if (IS_RC_MODE_ACTIVE(BOXNAVPOSHOLD
)) {
2052 if ((FLIGHT_MODE(NAV_POSHOLD_MODE
)) || (canActivatePosHold
))
2053 return NAV_FSM_EVENT_SWITCH_TO_POSHOLD_2D
;
2056 if (IS_RC_MODE_ACTIVE(BOXNAVALTHOLD
)) {
2057 if ((FLIGHT_MODE(NAV_ALTHOLD_MODE
)) || (canActivateAltHold
))
2058 return NAV_FSM_EVENT_SWITCH_TO_ALTHOLD
;
2062 canActivateWaypoint
= false;
2065 return NAV_FSM_EVENT_SWITCH_TO_IDLE
;
2068 /*-----------------------------------------------------------
2069 * An indicator that throttle tilt compensation is forced
2070 *-----------------------------------------------------------*/
2071 bool navigationRequiresThrottleTiltCompensation(void)
2073 return !STATE(FIXED_WING
) && (navGetStateFlags(posControl
.navState
) & NAV_REQUIRE_THRTILT
);
2076 /*-----------------------------------------------------------
2077 * An indicator that ANGLE mode must be forced per NAV requirement
2078 *-----------------------------------------------------------*/
2079 bool naivationRequiresAngleMode(void)
2081 navigationFSMStateFlags_t currentState
= navGetStateFlags(posControl
.navState
);
2082 return (currentState
& NAV_REQUIRE_ANGLE
) || ((currentState
& NAV_REQUIRE_ANGLE_FW
) && STATE(FIXED_WING
));
2086 * An indicator that NAV is in charge of heading control (a signal to disable other heading controllers)
2088 int8_t naivationGetHeadingControlState(void)
2090 if (navGetStateFlags(posControl
.navState
) & NAV_REQUIRE_MAGHOLD
) {
2091 if (posControl
.flags
.isAdjustingHeading
) {
2092 return NAV_HEADING_CONTROL_MANUAL
;
2095 return NAV_HEADING_CONTROL_AUTO
;
2099 return NAV_HEADING_CONTROL_NONE
;
2103 bool naivationBlockArming(void)
2105 bool shouldBlockArming
= false;
2107 if (!posControl
.navConfig
->flags
.extra_arming_safety
)
2110 // Apply extra arming safety only if pilot has any of GPS modes configured
2111 if ((isUsingNavigationModes() || failsafeMayRequireNavigationMode()) && !(posControl
.flags
.hasValidPositionSensor
&& STATE(GPS_FIX_HOME
))) {
2112 shouldBlockArming
= true;
2115 // Don't allow arming if any of NAV modes is active
2116 if ((!ARMING_FLAG(ARMED
)) && (IS_RC_MODE_ACTIVE(BOXNAVRTH
) || IS_RC_MODE_ACTIVE(BOXNAVWP
) || IS_RC_MODE_ACTIVE(BOXNAVPOSHOLD
))) {
2117 shouldBlockArming
= true;
2120 return shouldBlockArming
;
2124 bool navigationPositionEstimateIsHealthy(void)
2126 return posControl
.flags
.hasValidPositionSensor
&& STATE(GPS_FIX_HOME
);
2130 * Indicate ready/not ready status
2132 static void updateReadyStatus(void)
2134 static bool posReadyBeepDone
= false;
2136 /* Beep out READY_BEEP once when position lock is firstly acquired and HOME set */
2137 if (navigationPositionEstimateIsHealthy() && !posReadyBeepDone
) {
2138 beeper(BEEPER_READY_BEEP
);
2139 posReadyBeepDone
= true;
2143 void updateFlightBehaviorModifiers(void)
2145 posControl
.flags
.isGCSAssistedNavigationEnabled
= IS_RC_MODE_ACTIVE(BOXGCSNAV
);
2146 posControl
.flags
.isTerrainFollowEnabled
= IS_RC_MODE_ACTIVE(BOXSURFACE
);
2150 * Process NAV mode transition and WP/RTH state machine
2151 * Update rate: RX (data driven or 50Hz)
2153 void updateWaypointsAndNavigationMode(void)
2155 /* Initiate home position update */
2156 updateHomePosition();
2158 /* Update NAV ready status */
2159 updateReadyStatus();
2161 // Update flight behaviour modifiers
2162 updateFlightBehaviorModifiers();
2164 // Process switch to a different navigation mode (if needed)
2165 navProcessFSMEvents(selectNavEventFromBoxModeInput());
2167 // Process pilot's RC input to adjust behaviour
2168 processNavigationRCAdjustments();
2170 // Map navMode back to enabled flight modes
2171 swithNavigationFlightModes();
2173 #if defined(NAV_BLACKBOX)
2174 navCurrentState
= (int16_t)posControl
.navState
;
2178 /*-----------------------------------------------------------
2179 * NAV main control functions
2180 *-----------------------------------------------------------*/
2181 void navigationUseConfig(navConfig_t
*navConfigToUse
)
2183 posControl
.navConfig
= navConfigToUse
;
2186 void navigationUseRcControlsConfig(rcControlsConfig_t
*initialRcControlsConfig
)
2188 posControl
.rcControlsConfig
= initialRcControlsConfig
;
2191 void navigationUseFlight3DConfig(flight3DConfig_t
* initialFlight3DConfig
)
2193 posControl
.flight3DConfig
= initialFlight3DConfig
;
2196 void navigationUseRxConfig(rxConfig_t
* initialRxConfig
)
2198 posControl
.rxConfig
= initialRxConfig
;
2201 void navigationUseEscAndServoConfig(escAndServoConfig_t
* initialEscAndServoConfig
)
2203 posControl
.escAndServoConfig
= initialEscAndServoConfig
;
2206 void navigationUsePIDs(pidProfile_t
*initialPidProfile
)
2210 posControl
.pidProfile
= initialPidProfile
;
2212 // Brake time parameter
2213 posControl
.posDecelerationTime
= (float)posControl
.pidProfile
->I8
[PIDPOS
] / 100.0f
;
2215 // Position controller expo (taret vel expo for MC)
2216 posControl
.posResponseExpo
= constrainf((float)posControl
.pidProfile
->D8
[PIDPOS
] / 100.0f
, 0.0f
, 1.0f
);
2218 // Initialize position hold P-controller
2219 for (axis
= 0; axis
< 2; axis
++) {
2220 navPInit(&posControl
.pids
.pos
[axis
], (float)posControl
.pidProfile
->P8
[PIDPOS
] / 100.0f
);
2222 navPidInit(&posControl
.pids
.vel
[axis
], (float)posControl
.pidProfile
->P8
[PIDPOSR
] / 100.0f
,
2223 (float)posControl
.pidProfile
->I8
[PIDPOSR
] / 100.0f
,
2224 (float)posControl
.pidProfile
->D8
[PIDPOSR
] / 100.0f
);
2227 // Initialize altitude hold PID-controllers (pos_z, vel_z, acc_z
2228 navPInit(&posControl
.pids
.pos
[Z
], (float)posControl
.pidProfile
->P8
[PIDALT
] / 100.0f
);
2230 navPidInit(&posControl
.pids
.vel
[Z
], (float)posControl
.pidProfile
->P8
[PIDVEL
] / 100.0f
,
2231 (float)posControl
.pidProfile
->I8
[PIDVEL
] / 100.0f
,
2232 (float)posControl
.pidProfile
->D8
[PIDVEL
] / 100.0f
);
2234 // Initialize surface tracking PID
2235 navPidInit(&posControl
.pids
.surface
, 2.0f
,
2239 // Initialize fixed wing PID controllers
2240 navPidInit(&posControl
.pids
.fw_nav
, (float)posControl
.pidProfile
->P8
[PIDNAVR
] / 100.0f
,
2241 (float)posControl
.pidProfile
->I8
[PIDNAVR
] / 100.0f
,
2242 (float)posControl
.pidProfile
->D8
[PIDNAVR
] / 100.0f
);
2244 navPidInit(&posControl
.pids
.fw_alt
, (float)posControl
.pidProfile
->P8
[PIDALT
] / 100.0f
,
2245 (float)posControl
.pidProfile
->I8
[PIDALT
] / 100.0f
,
2246 (float)posControl
.pidProfile
->D8
[PIDALT
] / 100.0f
);
2249 void navigationInit(navConfig_t
*initialnavConfig
,
2250 pidProfile_t
*initialPidProfile
,
2251 rcControlsConfig_t
*initialRcControlsConfig
,
2252 rxConfig_t
* initialRxConfig
,
2253 flight3DConfig_t
* initialFlight3DConfig
,
2254 escAndServoConfig_t
* initialEscAndServoConfig
)
2257 posControl
.navState
= NAV_STATE_IDLE
;
2259 posControl
.flags
.horizontalPositionNewData
= 0;
2260 posControl
.flags
.verticalPositionNewData
= 0;
2261 posControl
.flags
.surfaceDistanceNewData
= 0;
2262 posControl
.flags
.headingNewData
= 0;
2264 posControl
.flags
.hasValidAltitudeSensor
= 0;
2265 posControl
.flags
.hasValidPositionSensor
= 0;
2266 posControl
.flags
.hasValidSurfaceSensor
= 0;
2267 posControl
.flags
.hasValidHeadingSensor
= 0;
2269 posControl
.flags
.forcedRTHActivated
= 0;
2270 posControl
.waypointCount
= 0;
2271 posControl
.activeWaypointIndex
= 0;
2272 posControl
.waypointListValid
= false;
2274 /* Set initial surface invalid */
2275 posControl
.actualState
.surface
= -1.0f
;
2276 posControl
.actualState
.surfaceVel
= 0.0f
;
2277 posControl
.actualState
.surfaceMin
= -1.0f
;
2279 /* Use system config */
2280 navigationUseConfig(initialnavConfig
);
2281 navigationUsePIDs(initialPidProfile
);
2282 navigationUseRcControlsConfig(initialRcControlsConfig
);
2283 navigationUseRxConfig(initialRxConfig
);
2284 navigationUseEscAndServoConfig(initialEscAndServoConfig
);
2285 navigationUseFlight3DConfig(initialFlight3DConfig
);
2288 /*-----------------------------------------------------------
2289 * Access to estimated position/velocity data
2290 *-----------------------------------------------------------*/
2291 float getEstimatedActualVelocity(int axis
)
2293 return posControl
.actualState
.vel
.A
[axis
];
2296 float getEstimatedActualPosition(int axis
)
2298 return posControl
.actualState
.pos
.A
[axis
];
2301 /*-----------------------------------------------------------
2302 * Ability to execute RTH on external event
2303 *-----------------------------------------------------------*/
2304 void activateForcedRTH(void)
2306 posControl
.flags
.forcedRTHActivated
= true;
2307 navProcessFSMEvents(selectNavEventFromBoxModeInput());
2310 void abortForcedRTH(void)
2312 posControl
.flags
.forcedRTHActivated
= false;
2313 navProcessFSMEvents(selectNavEventFromBoxModeInput());
2316 rthState_e
getStateOfForcedRTH(void)
2318 /* If forced RTH activated and in AUTO_RTH or EMERG state */
2319 if (posControl
.flags
.forcedRTHActivated
&& (navGetStateFlags(posControl
.navState
) & (NAV_AUTO_RTH
| NAV_CTL_EMERG
))) {
2320 if (posControl
.navState
== NAV_STATE_RTH_2D_FINISHED
|| posControl
.navState
== NAV_STATE_RTH_3D_FINISHED
|| posControl
.navState
== NAV_STATE_EMERGENCY_LANDING_FINISHED
) {
2321 return RTH_HAS_LANDED
;
2324 return RTH_IN_PROGRESS
;
2335 /* Fallback if navigation is not compiled in - handle GPS home coordinates */
2336 static float GPS_scaleLonDown
;
2338 static void GPS_distance_cm_bearing(int32_t currentLat1
, int32_t currentLon1
, int32_t destinationLat2
, int32_t destinationLon2
, uint32_t *dist
, int32_t *bearing
)
2340 float dLat
= destinationLat2
- currentLat1
; // difference of latitude in 1/10 000 000 degrees
2341 float dLon
= (float)(destinationLon2
- currentLon1
) * GPS_scaleLonDown
;
2343 *dist
= sqrtf(sq(dLat
) + sq(dLon
)) * DISTANCE_BETWEEN_TWO_LONGITUDE_POINTS_AT_EQUATOR
;
2345 *bearing
= 9000.0f
+ RADIANS_TO_CENTIDEGREES(atan2_approx(-dLat
, dLon
)); // Convert the output radians to 100xdeg
2353 if (!(sensors(SENSOR_GPS
) && STATE(GPS_FIX
) && gpsSol
.numSat
>= 5))
2356 if (ARMING_FLAG(ARMED
)) {
2357 if (STATE(GPS_FIX_HOME
)) {
2360 GPS_distance_cm_bearing(gpsSol
.llh
.lat
, gpsSol
.llh
.lon
, GPS_home
.lat
, GPS_home
.lon
, &dist
, &dir
);
2361 GPS_distanceToHome
= dist
/ 100;
2362 GPS_directionToHome
= dir
/ 100;
2364 GPS_distanceToHome
= 0;
2365 GPS_directionToHome
= 0;
2369 // Set home position to current GPS coordinates
2370 ENABLE_STATE(GPS_FIX_HOME
);
2371 GPS_home
.lat
= gpsSol
.llh
.lat
;
2372 GPS_home
.lon
= gpsSol
.llh
.lon
;
2373 GPS_home
.alt
= gpsSol
.llh
.alt
;
2374 GPS_distanceToHome
= 0;
2375 GPS_directionToHome
= 0;
2376 GPS_scaleLonDown
= cos_approx((ABS((float)gpsSol
.llh
.lat
) / 10000000.0f
) * 0.0174532925f
);