2 ******************************************************************************
3 * @addtogroup OpenPilotLibraries OpenPilot Libraries
5 * @addtogroup Navigation
6 * @brief setups RTH/PH and other pathfollower/pathplanner status
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2014.
12 * @see The GNU Public License (GPL) Version 3
14 ******************************************************************************/
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include <openpilot.h>
33 #include <attitudesettings.h>
34 #include <takeofflocation.h>
35 #include <pathdesired.h>
36 #include <positionstate.h>
37 #include <flightmodesettings.h>
38 #include <flightstatus.h>
39 #include <velocitystate.h>
40 #include <manualcontrolcommand.h>
41 #include <attitudestate.h>
42 #include <vtolpathfollowersettings.h>
43 #include <stabilizationbank.h>
44 #include <stabilizationdesired.h>
45 #include <sin_lookup.h>
46 #include <sanitycheck.h>
47 #include <statusvtolautotakeoff.h>
49 #define UPDATE_EXPECTED 0.02f
50 #define UPDATE_MIN 1.0e-6f
51 #define UPDATE_MAX 1.0f
52 #define UPDATE_ALPHA 1.0e-2f
55 static float applyExpo(float value
, float expo
);
58 static float applyExpo(float value
, float expo
)
60 // note: fastPow makes a small error, therefore result needs to be bound
61 float exp
= boundf(fastPow(1.00695f
, expo
), 0.5f
, 2.0f
);
63 // magic number scales expo
65 // expo=100 yields value**10
66 // expo=0 yields value**1
67 // expo=-100 yields value**(1/10)
68 // (pow(2.0,1/100)~=1.00695)
70 return boundf(fastPow(value
, exp
), 0.0f
, 1.0f
);
71 } else if (value
< -0.0f
) {
72 return boundf(-fastPow(-value
, exp
), -1.0f
, 0.0f
);
80 * @brief initialize UAVOs and structs used by this library
82 void plan_initialize()
84 TakeOffLocationInitialize();
85 PositionStateInitialize();
86 PathDesiredInitialize();
87 FlightModeSettingsInitialize();
88 FlightStatusInitialize();
89 AttitudeStateInitialize();
90 ManualControlCommandInitialize();
91 VelocityStateInitialize();
92 VtolPathFollowerSettingsInitialize();
93 StabilizationBankInitialize();
94 StabilizationDesiredInitialize();
98 * @brief setup pathplanner/pathfollower for positionhold
100 void plan_setup_positionHold()
102 PositionStateData positionState
;
104 PositionStateGet(&positionState
);
105 PathDesiredData pathDesired
;
106 // re-initialise in setup stage
107 memset(&pathDesired
, 0, sizeof(PathDesiredData
));
109 FlightModeSettingsPositionHoldOffsetData offset
;
110 FlightModeSettingsPositionHoldOffsetGet(&offset
);
112 pathDesired
.End
.North
= positionState
.North
;
113 pathDesired
.End
.East
= positionState
.East
;
114 pathDesired
.End
.Down
= positionState
.Down
;
115 pathDesired
.Start
.North
= positionState
.North
+ offset
.Horizontal
; // in FlyEndPoint the direction of this vector does not matter
116 pathDesired
.Start
.East
= positionState
.East
;
117 pathDesired
.Start
.Down
= positionState
.Down
;
118 pathDesired
.StartingVelocity
= 0.0f
;
119 pathDesired
.EndingVelocity
= 0.0f
;
120 pathDesired
.Mode
= PATHDESIRED_MODE_GOTOENDPOINT
;
122 PathDesiredSet(&pathDesired
);
127 * @brief setup pathplanner/pathfollower for return to base
129 void plan_setup_returnToBase()
131 // Simple Return To Base mode - keep altitude the same applying configured delta, fly to takeoff position
132 float positionStateDown
;
134 PositionStateDownGet(&positionStateDown
);
136 PathDesiredData pathDesired
;
137 // re-initialise in setup stage
138 memset(&pathDesired
, 0, sizeof(PathDesiredData
));
140 TakeOffLocationData takeoffLocation
;
141 TakeOffLocationGet(&takeoffLocation
);
143 // TODO: right now VTOLPF does fly straight to destination altitude.
144 // For a safer RTB destination altitude will be the higher between takeofflocation and current position (corrected with safety margin)
147 FlightModeSettingsReturnToBaseAltitudeOffsetGet(&destDown
);
148 destDown
= MIN(positionStateDown
, takeoffLocation
.Down
) - destDown
;
149 FlightModeSettingsPositionHoldOffsetData offset
;
150 FlightModeSettingsPositionHoldOffsetGet(&offset
);
152 pathDesired
.End
.North
= takeoffLocation
.North
;
153 pathDesired
.End
.East
= takeoffLocation
.East
;
154 pathDesired
.End
.Down
= destDown
;
156 pathDesired
.Start
.North
= takeoffLocation
.North
+ offset
.Horizontal
; // in FlyEndPoint the direction of this vector does not matter
157 pathDesired
.Start
.East
= takeoffLocation
.East
;
158 pathDesired
.Start
.Down
= destDown
;
160 pathDesired
.StartingVelocity
= 0.0f
;
161 pathDesired
.EndingVelocity
= 0.0f
;
163 FlightModeSettingsReturnToBaseNextCommandOptions ReturnToBaseNextCommand
;
164 FlightModeSettingsReturnToBaseNextCommandGet(&ReturnToBaseNextCommand
);
165 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_GOTOENDPOINT_NEXTCOMMAND
] = (float)ReturnToBaseNextCommand
;
166 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_GOTOENDPOINT_UNUSED1
] = 0.0f
;
167 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_GOTOENDPOINT_UNUSED2
] = 0.0f
;
168 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_GOTOENDPOINT_UNUSED3
] = 0.0f
;
169 pathDesired
.Mode
= PATHDESIRED_MODE_GOTOENDPOINT
;
171 PathDesiredSet(&pathDesired
);
174 void plan_setup_AutoTakeoff()
176 PathDesiredData pathDesired
;
178 memset(&pathDesired
, 0, sizeof(PathDesiredData
));
179 PositionStateData positionState
;
181 PositionStateGet(&positionState
);
182 float autotakeoff_height
;
184 FlightModeSettingsAutoTakeOffHeightGet(&autotakeoff_height
);
185 autotakeoff_height
= fabsf(autotakeoff_height
);
187 pathDesired
.Start
.North
= positionState
.North
;
188 pathDesired
.Start
.East
= positionState
.East
;
189 pathDesired
.Start
.Down
= positionState
.Down
;
190 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_AUTOTAKEOFF_NORTH
] = 0.0f
;
191 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_AUTOTAKEOFF_EAST
] = 0.0f
;
192 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_AUTOTAKEOFF_DOWN
] = 0.0f
;
193 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_AUTOTAKEOFF_CONTROLSTATE
] = 0.0f
;
195 pathDesired
.End
.North
= positionState
.North
;
196 pathDesired
.End
.East
= positionState
.East
;
197 pathDesired
.End
.Down
= positionState
.Down
- autotakeoff_height
;
199 pathDesired
.StartingVelocity
= 0.0f
;
200 pathDesired
.EndingVelocity
= 0.0f
;
201 pathDesired
.Mode
= PATHDESIRED_MODE_AUTOTAKEOFF
;
202 PathDesiredSet(&pathDesired
);
205 static void plan_setup_land_helper(PathDesiredData
*pathDesired
)
207 PositionStateData positionState
;
209 PositionStateGet(&positionState
);
212 FlightModeSettingsLandingVelocityGet(&velocity_down
);
214 pathDesired
->Start
.North
= positionState
.North
;
215 pathDesired
->Start
.East
= positionState
.East
;
216 pathDesired
->Start
.Down
= positionState
.Down
;
217 pathDesired
->ModeParameters
[PATHDESIRED_MODEPARAMETER_LAND_VELOCITYVECTOR_NORTH
] = 0.0f
;
218 pathDesired
->ModeParameters
[PATHDESIRED_MODEPARAMETER_LAND_VELOCITYVECTOR_EAST
] = 0.0f
;
219 pathDesired
->ModeParameters
[PATHDESIRED_MODEPARAMETER_LAND_VELOCITYVECTOR_DOWN
] = velocity_down
;
221 pathDesired
->End
.North
= positionState
.North
;
222 pathDesired
->End
.East
= positionState
.East
;
223 pathDesired
->End
.Down
= positionState
.Down
;
225 pathDesired
->StartingVelocity
= 0.0f
;
226 pathDesired
->EndingVelocity
= 0.0f
;
227 pathDesired
->Mode
= PATHDESIRED_MODE_LAND
;
228 pathDesired
->ModeParameters
[PATHDESIRED_MODEPARAMETER_LAND_OPTIONS
] = (float)PATHDESIRED_MODEPARAMETER_LAND_OPTION_HORIZONTAL_PH
;
231 void plan_setup_land()
233 PathDesiredData pathDesired
;
235 // re-initialise in setup stage
236 memset(&pathDesired
, 0, sizeof(PathDesiredData
));
238 plan_setup_land_helper(&pathDesired
);
239 PathDesiredSet(&pathDesired
);
242 static void plan_setup_land_from_velocityroam()
245 FlightStatusAssistedControlStateOptions assistedControlFlightMode
;
246 assistedControlFlightMode
= FLIGHTSTATUS_ASSISTEDCONTROLSTATE_HOLD
;
247 FlightStatusAssistedControlStateSet(&assistedControlFlightMode
);
251 * @brief positionvario functionality
253 static bool vario_hold
= true;
254 static float hold_position
[3];
255 static float vario_control_lowpass
[3];
256 static float vario_course
= 0.0f
;
258 static void plan_setup_PositionVario()
261 vario_control_lowpass
[0] = 0.0f
;
262 vario_control_lowpass
[1] = 0.0f
;
263 vario_control_lowpass
[2] = 0.0f
;
264 AttitudeStateYawGet(&vario_course
);
265 plan_setup_positionHold();
268 void plan_setup_CourseLock()
270 plan_setup_PositionVario();
273 void plan_setup_PositionRoam()
275 plan_setup_PositionVario();
278 void plan_setup_VelocityRoam()
280 vario_control_lowpass
[0] = 0.0f
;
281 vario_control_lowpass
[1] = 0.0f
;
282 vario_control_lowpass
[2] = 0.0f
;
283 AttitudeStateYawGet(&vario_course
);
286 void plan_setup_HomeLeash()
288 plan_setup_PositionVario();
291 void plan_setup_AbsolutePosition()
293 plan_setup_PositionVario();
297 #define DEADBAND 0.1f
298 static bool normalizeDeadband(float controlVector
[4])
302 // roll, pitch, yaw between -1 and +1
303 // thrust between 0 and 1 mapped to -1 to +1
304 controlVector
[3] = (2.0f
* controlVector
[3]) - 1.0f
;
307 for (t
= 0; t
< 4; t
++) {
308 if (controlVector
[t
] < -DEADBAND
) {
310 controlVector
[t
] += DEADBAND
;
311 } else if (controlVector
[t
] > DEADBAND
) {
313 controlVector
[t
] -= DEADBAND
;
315 controlVector
[t
] = 0.0f
;
317 // deadband has been cut out, scale value back to [-1,+1]
318 controlVector
[t
] *= (1.0f
/ (1.0f
- DEADBAND
));
319 controlVector
[t
] = boundf(controlVector
[t
], -1.0f
, 1.0f
);
325 typedef enum { COURSE
, FPV
, LOS
, NSEW
} vario_type
;
327 static void getVector(float controlVector
[4], vario_type type
)
329 FlightModeSettingsPositionHoldOffsetData offset
;
331 FlightModeSettingsPositionHoldOffsetGet(&offset
);
333 // scale controlVector[3] (thrust) by vertical/horizontal to have vertical plane less sensitive
334 controlVector
[3] *= offset
.Vertical
/ offset
.Horizontal
;
336 float length
= sqrtf(controlVector
[0] * controlVector
[0] + controlVector
[1] * controlVector
[1] + controlVector
[3] * controlVector
[3]);
338 if (length
<= 1e-9f
) {
339 length
= 1.0f
; // should never happen as getVector is not called if control within deadband
342 float direction
[3] = {
343 controlVector
[1] / length
, // pitch is north
344 controlVector
[0] / length
, // roll is east
345 controlVector
[3] / length
// thrust is down
347 controlVector
[0] = direction
[0];
348 controlVector
[1] = direction
[1];
349 controlVector
[2] = direction
[2];
351 controlVector
[3] = length
* offset
.Horizontal
;
353 // rotate north and east - rotation angle based on type
357 angle
= vario_course
;
361 // NSEW no rotation takes place
364 // local rotation, using current yaw
365 AttitudeStateYawGet(&angle
);
368 // determine location based on vector from takeoff to current location
370 PositionStateData positionState
;
371 PositionStateGet(&positionState
);
372 TakeOffLocationData takeoffLocation
;
373 TakeOffLocationGet(&takeoffLocation
);
374 angle
= RAD2DEG(atan2f(positionState
.East
- takeoffLocation
.East
, positionState
.North
- takeoffLocation
.North
));
378 // rotate horizontally by angle
381 controlVector
[0] * cos_lookup_deg(angle
) - controlVector
[1] * sin_lookup_deg(angle
),
382 controlVector
[0] * sin_lookup_deg(angle
) + controlVector
[1] * cos_lookup_deg(angle
)
384 controlVector
[0] = rotated
[0];
385 controlVector
[1] = rotated
[1];
390 static void plan_run_PositionVario(vario_type type
)
392 float controlVector
[4];
394 PathDesiredData pathDesired
;
396 // Reuse the existing pathdesired object as setup in the setup to avoid
397 // updating values already set.
398 PathDesiredGet(&pathDesired
);
400 FlightModeSettingsPositionHoldOffsetData offset
;
401 FlightModeSettingsPositionHoldOffsetGet(&offset
);
404 ManualControlCommandRollGet(&controlVector
[0]);
405 ManualControlCommandPitchGet(&controlVector
[1]);
406 ManualControlCommandYawGet(&controlVector
[2]);
407 ManualControlCommandThrustGet(&controlVector
[3]);
410 FlightModeSettingsVarioControlLowPassAlphaGet(&alpha
);
411 vario_control_lowpass
[0] = alpha
* vario_control_lowpass
[0] + (1.0f
- alpha
) * controlVector
[0];
412 vario_control_lowpass
[1] = alpha
* vario_control_lowpass
[1] + (1.0f
- alpha
) * controlVector
[1];
413 vario_control_lowpass
[2] = alpha
* vario_control_lowpass
[2] + (1.0f
- alpha
) * controlVector
[2];
414 controlVector
[0] = vario_control_lowpass
[0];
415 controlVector
[1] = vario_control_lowpass
[1];
416 controlVector
[2] = vario_control_lowpass
[2];
418 // check if movement is desired
419 if (normalizeDeadband(controlVector
) == false) {
420 // no movement desired, re-enter positionHold at current start-position
424 // new hold position is the position that was previously the start position
425 pathDesired
.End
.North
= hold_position
[0];
426 pathDesired
.End
.East
= hold_position
[1];
427 pathDesired
.End
.Down
= hold_position
[2];
428 // while the new start position has the same offset as in position hold
429 pathDesired
.Start
.North
= pathDesired
.End
.North
+ offset
.Horizontal
; // in FlyEndPoint the direction of this vector does not matter
430 pathDesired
.Start
.East
= pathDesired
.End
.East
;
431 pathDesired
.Start
.Down
= pathDesired
.End
.Down
;
433 // set mode explicitly
435 PathDesiredSet(&pathDesired
);
438 PositionStateData positionState
;
439 PositionStateGet(&positionState
);
441 // flip pitch to have pitch down (away) point north
442 controlVector
[1] = -controlVector
[1];
443 getVector(controlVector
, type
);
445 // layout of control Vector : unitVector in movement direction {0,1,2} vector length {3} velocity {4}
447 // start position is the position that was previously the hold position
449 hold_position
[0] = pathDesired
.End
.North
;
450 hold_position
[1] = pathDesired
.End
.East
;
451 hold_position
[2] = pathDesired
.End
.Down
;
453 // start position is advanced according to movement - in the direction of ControlVector only
454 // projection using scalar product
455 float kp
= (positionState
.North
- hold_position
[0]) * controlVector
[0]
456 + (positionState
.East
- hold_position
[1]) * controlVector
[1]
457 + (positionState
.Down
- hold_position
[2]) * -controlVector
[2];
459 hold_position
[0] += kp
* controlVector
[0];
460 hold_position
[1] += kp
* controlVector
[1];
461 hold_position
[2] += kp
* -controlVector
[2];
464 // new destination position is advanced based on controlVector
465 pathDesired
.End
.North
= hold_position
[0] + controlVector
[0] * controlVector
[3];
466 pathDesired
.End
.East
= hold_position
[1] + controlVector
[1] * controlVector
[3];
467 pathDesired
.End
.Down
= hold_position
[2] - controlVector
[2] * controlVector
[3];
468 // the new start position has the same offset as in position hold
469 pathDesired
.Start
.North
= pathDesired
.End
.North
+ offset
.Horizontal
; // in FlyEndPoint the direction of this vector does not matter
470 pathDesired
.Start
.East
= pathDesired
.End
.East
;
471 pathDesired
.Start
.Down
= pathDesired
.End
.Down
;
472 PathDesiredSet(&pathDesired
);
476 void plan_run_VelocityRoam()
479 PathDesiredData pathDesired
;
481 // velocity roam code completely sets pathdesired object. it was not set in setup phase
482 memset(&pathDesired
, 0, sizeof(PathDesiredData
));
483 FlightStatusAssistedControlStateOptions assistedControlFlightMode
;
484 FlightStatusFlightModeOptions flightMode
;
486 FlightModeSettingsPositionHoldOffsetData offset
;
487 FlightModeSettingsPositionHoldOffsetGet(&offset
);
488 FlightStatusAssistedControlStateGet(&assistedControlFlightMode
);
489 FlightStatusFlightModeGet(&flightMode
);
490 StabilizationBankData stabSettings
;
491 StabilizationBankGet(&stabSettings
);
493 ManualControlCommandData cmd
;
494 ManualControlCommandGet(&cmd
);
496 cmd
.Roll
= applyExpo(cmd
.Roll
, stabSettings
.StickExpo
.Roll
);
497 cmd
.Pitch
= applyExpo(cmd
.Pitch
, stabSettings
.StickExpo
.Pitch
);
498 cmd
.Yaw
= applyExpo(cmd
.Yaw
, stabSettings
.StickExpo
.Yaw
);
500 bool flagRollPitchHasInput
= (fabsf(cmd
.Roll
) > 0.0f
|| fabsf(cmd
.Pitch
) > 0.0f
);
502 if (!flagRollPitchHasInput
) {
503 // no movement desired, re-enter positionHold at current start-position
504 if (assistedControlFlightMode
== FLIGHTSTATUS_ASSISTEDCONTROLSTATE_PRIMARY
) {
505 // initiate braking and change assisted control flight mode to braking
506 if (flightMode
== FLIGHTSTATUS_FLIGHTMODE_LAND
) {
507 // avoid brake then hold sequence to continue descent.
508 plan_setup_land_from_velocityroam();
510 plan_setup_assistedcontrol();
513 // otherwise nothing to do in braking/hold modes
515 PositionStateData positionState
;
516 PositionStateGet(&positionState
);
518 // Revert assist control state to primary, which in this case implies
519 // we are in roaming state (a GPS vector assisted velocity roam)
520 assistedControlFlightMode
= FLIGHTSTATUS_ASSISTEDCONTROLSTATE_PRIMARY
;
522 // Calculate desired velocity in each direction
524 AttitudeStateYawGet(&angle
);
525 angle
= DEG2RAD(angle
);
526 float cos_angle
= cosf(angle
);
527 float sine_angle
= sinf(angle
);
529 -cmd
.Pitch
* cos_angle
- cmd
.Roll
* sine_angle
,
530 -cmd
.Pitch
* sine_angle
+ cmd
.Roll
* cos_angle
532 // flip pitch to have pitch down (away) point north
533 float horizontalVelMax
;
534 float verticalVelMax
;
535 VtolPathFollowerSettingsHorizontalVelMaxGet(&horizontalVelMax
);
536 VtolPathFollowerSettingsVerticalVelMaxGet(&verticalVelMax
);
537 float velocity_north
= rotated
[0] * horizontalVelMax
;
538 float velocity_east
= rotated
[1] * horizontalVelMax
;
539 float velocity_down
= 0.0f
;
541 if (flightMode
== FLIGHTSTATUS_FLIGHTMODE_LAND
) {
542 FlightModeSettingsLandingVelocityGet(&velocity_down
);
545 float velocity
= velocity_north
* velocity_north
+ velocity_east
* velocity_east
;
546 velocity
= sqrtf(velocity
);
548 // if one stick input (pitch or roll) should we use fly by vector? set arbitrary distance of say 20m after which we
549 // expect new stick input
550 // if two stick input pilot is fighting wind manually and we use fly by velocity
551 // in reality setting velocity desired to zero will fight wind anyway.
553 pathDesired
.Start
.North
= positionState
.North
;
554 pathDesired
.Start
.East
= positionState
.East
;
555 pathDesired
.Start
.Down
= positionState
.Down
;
556 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_VELOCITY_VELOCITYVECTOR_NORTH
] = velocity_north
;
557 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_VELOCITY_VELOCITYVECTOR_EAST
] = velocity_east
;
558 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_VELOCITY_VELOCITYVECTOR_DOWN
] = velocity_down
;
560 pathDesired
.End
.North
= positionState
.North
;
561 pathDesired
.End
.East
= positionState
.East
;
562 pathDesired
.End
.Down
= positionState
.Down
;
564 pathDesired
.StartingVelocity
= velocity
;
565 pathDesired
.EndingVelocity
= velocity
;
566 pathDesired
.Mode
= PATHDESIRED_MODE_VELOCITY
;
567 if (flightMode
== FLIGHTSTATUS_FLIGHTMODE_LAND
) {
568 pathDesired
.Mode
= PATHDESIRED_MODE_LAND
;
569 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_LAND_OPTIONS
] = (float)PATHDESIRED_MODEPARAMETER_LAND_OPTION_NONE
;
571 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_VELOCITY_UNUSED
] = 0.0f
;
573 PathDesiredSet(&pathDesired
);
574 FlightStatusAssistedControlStateSet(&assistedControlFlightMode
);
578 void plan_run_CourseLock()
580 plan_run_PositionVario(COURSE
);
583 void plan_run_PositionRoam()
585 plan_run_PositionVario(FPV
);
588 void plan_run_HomeLeash()
590 plan_run_PositionVario(LOS
);
593 void plan_run_AbsolutePosition()
595 plan_run_PositionVario(NSEW
);
600 * @brief setup pathplanner/pathfollower for AutoCruise
602 static PiOSDeltatimeConfig actimeval
;
603 void plan_setup_AutoCruise()
605 PositionStateData positionState
;
607 PositionStateGet(&positionState
);
609 PathDesiredData pathDesired
;
610 // setup needs to reinitialise the pathdesired object
611 memset(&pathDesired
, 0, sizeof(PathDesiredData
));
613 FlightModeSettingsPositionHoldOffsetData offset
;
614 FlightModeSettingsPositionHoldOffsetGet(&offset
);
616 // initialization is flight in direction of the nose.
617 // the velocity is not relevant, as it will be reset by the run function even during first call
619 AttitudeStateYawGet(&angle
);
621 cos_lookup_deg(angle
),
622 sin_lookup_deg(angle
)
624 hold_position
[0] = positionState
.North
;
625 hold_position
[1] = positionState
.East
;
626 hold_position
[2] = positionState
.Down
;
627 pathDesired
.End
.North
= hold_position
[0] + vector
[0];
628 pathDesired
.End
.East
= hold_position
[1] + vector
[1];
629 pathDesired
.End
.Down
= hold_position
[2];
630 // start position has the same offset as in position hold
631 pathDesired
.Start
.North
= pathDesired
.End
.North
+ offset
.Horizontal
; // in FlyEndPoint the direction of this vector does not matter
632 pathDesired
.Start
.East
= pathDesired
.End
.East
;
633 pathDesired
.Start
.Down
= pathDesired
.End
.Down
;
634 pathDesired
.StartingVelocity
= 0.0f
;
635 pathDesired
.EndingVelocity
= 0.0f
;
636 pathDesired
.Mode
= PATHDESIRED_MODE_GOTOENDPOINT
;
638 PathDesiredSet(&pathDesired
);
640 // re-iniztializing deltatime is valid and also good practice here since
641 // getAverageSeconds() has not been called/updated in a long time if we were in a different flightmode.
642 PIOS_DELTATIME_Init(&actimeval
, UPDATE_EXPECTED
, UPDATE_MIN
, UPDATE_MAX
, UPDATE_ALPHA
);
646 * @brief execute autocruise
648 void plan_run_AutoCruise()
650 PositionStateData positionState
;
652 PositionStateGet(&positionState
);
653 PathDesiredData pathDesired
;
654 // re-use pathdesired that was setup correctly in setup stage.
655 PathDesiredGet(&pathDesired
);
657 FlightModeSettingsPositionHoldOffsetData offset
;
658 FlightModeSettingsPositionHoldOffsetGet(&offset
);
660 float controlVector
[4];
661 ManualControlCommandRollGet(&controlVector
[0]);
662 ManualControlCommandPitchGet(&controlVector
[1]);
663 ManualControlCommandYawGet(&controlVector
[2]);
664 controlVector
[3] = 0.5f
; // dummy, thrust is normalized separately
665 normalizeDeadband(controlVector
); // return value ignored
666 ManualControlCommandThrustGet(&controlVector
[3]); // no deadband as we are using thrust for velocity
667 controlVector
[3] = boundf(controlVector
[3], 1e-6f
, 1.0f
); // bound to above zero, to prevent loss of vector direction
669 // normalize old desired movement vector
670 float vector
[3] = { pathDesired
.End
.North
- hold_position
[0],
671 pathDesired
.End
.East
- hold_position
[1],
672 pathDesired
.End
.Down
- hold_position
[2] };
673 float length
= sqrtf(vector
[0] * vector
[0] + vector
[1] * vector
[1] + vector
[2] * vector
[2]);
674 if (length
< 1e-9f
) {
675 length
= 1.0f
; // should not happen since initialized properly in setup()
681 // start position is advanced according to actual movement - in the direction of desired vector only
682 // projection using scalar product
683 float kp
= (positionState
.North
- hold_position
[0]) * vector
[0]
684 + (positionState
.East
- hold_position
[1]) * vector
[1]
685 + (positionState
.Down
- hold_position
[2]) * vector
[2];
687 hold_position
[0] += kp
* vector
[0];
688 hold_position
[1] += kp
* vector
[1];
689 hold_position
[2] += kp
* vector
[2];
692 // new angle is equal to old angle plus offset depending on yaw input and time
693 // (controlVector is normalized with a deadband, change is zero within deadband)
694 float angle
= RAD2DEG(atan2f(vector
[1], vector
[0]));
695 float dT
= PIOS_DELTATIME_GetAverageSeconds(&actimeval
);
696 angle
+= 10.0f
* controlVector
[2] * dT
; // TODO magic value could eventually end up in a to be created settings
698 // resulting movement vector is scaled by velocity demand in controlvector[3] [0.0-1.0]
699 vector
[0] = cosf(DEG2RAD(angle
)) * offset
.Horizontal
* controlVector
[3];
700 vector
[1] = sinf(DEG2RAD(angle
)) * offset
.Horizontal
* controlVector
[3];
701 vector
[2] = -controlVector
[1] * offset
.Vertical
* controlVector
[3];
703 pathDesired
.End
.North
= hold_position
[0] + vector
[0];
704 pathDesired
.End
.East
= hold_position
[1] + vector
[1];
705 pathDesired
.End
.Down
= hold_position
[2] + vector
[2];
706 // start position has the same offset as in position hold
707 pathDesired
.Start
.North
= pathDesired
.End
.North
+ offset
.Horizontal
; // in FlyEndPoint the direction of this vector does not matter
708 pathDesired
.Start
.East
= pathDesired
.End
.East
;
709 pathDesired
.Start
.Down
= pathDesired
.End
.Down
;
710 PathDesiredSet(&pathDesired
);
714 * @brief setup pathplanner/pathfollower for braking in positionroam
715 * timeout_occurred = false: Attempt to enter flyvector for braking
716 * timeout_occurred = true: Revert to position hold
718 #define ASSISTEDCONTROL_BRAKERATE_MINIMUM 0.2f // m/s2
719 #define ASSISTEDCONTROL_TIMETOSTOP_MINIMUM 0.2f // seconds
720 #define ASSISTEDCONTROL_TIMETOSTOP_MAXIMUM 9.0f // seconds
721 #define ASSISTEDCONTROL_DELAY_TO_BRAKE 1.0f // seconds
722 #define ASSISTEDCONTROL_TIMEOUT_MULTIPLIER 4.0f // actual deceleration rate can be 50% of desired...timeouts need to cater for this
723 void plan_setup_assistedcontrol()
725 PositionStateData positionState
;
727 PositionStateGet(&positionState
);
728 PathDesiredData pathDesired
;
729 // setup function, avoid carry over from previous mode
730 memset(&pathDesired
, 0, sizeof(PathDesiredData
));
732 FlightStatusAssistedControlStateOptions assistedControlFlightMode
;
734 VelocityStateData velocityState
;
735 VelocityStateGet(&velocityState
);
737 VtolPathFollowerSettingsBrakeRateGet(&brakeRate
);
738 if (brakeRate
< ASSISTEDCONTROL_BRAKERATE_MINIMUM
) {
739 brakeRate
= ASSISTEDCONTROL_BRAKERATE_MINIMUM
; // set a minimum to avoid a divide by zero potential below
741 // Calculate the velocity
742 float velocity
= velocityState
.North
* velocityState
.North
+ velocityState
.East
* velocityState
.East
+ velocityState
.Down
* velocityState
.Down
;
743 velocity
= sqrtf(velocity
);
745 // Calculate the desired time to zero velocity.
746 float time_to_stopped
= ASSISTEDCONTROL_DELAY_TO_BRAKE
; // we allow at least 0.5 seconds to rotate to a brake angle.
747 time_to_stopped
+= velocity
/ brakeRate
;
749 // Sanity check the brake rate by ensuring that the time to stop is within a range.
750 if (time_to_stopped
< ASSISTEDCONTROL_TIMETOSTOP_MINIMUM
) {
751 time_to_stopped
= ASSISTEDCONTROL_TIMETOSTOP_MINIMUM
;
752 } else if (time_to_stopped
> ASSISTEDCONTROL_TIMETOSTOP_MAXIMUM
) {
753 time_to_stopped
= ASSISTEDCONTROL_TIMETOSTOP_MAXIMUM
;
756 // calculate the distance we will travel
757 float north_delta
= velocityState
.North
* ASSISTEDCONTROL_DELAY_TO_BRAKE
; // we allow at least 0.5s to rotate to brake angle
758 north_delta
+= (time_to_stopped
- ASSISTEDCONTROL_DELAY_TO_BRAKE
) * 0.5f
* velocityState
.North
; // area under the linear deceleration plot
759 float east_delta
= velocityState
.East
* ASSISTEDCONTROL_DELAY_TO_BRAKE
; // we allow at least 0.5s to rotate to brake angle
760 east_delta
+= (time_to_stopped
- ASSISTEDCONTROL_DELAY_TO_BRAKE
) * 0.5f
* velocityState
.East
; // area under the linear deceleration plot
761 float down_delta
= velocityState
.Down
* ASSISTEDCONTROL_DELAY_TO_BRAKE
;
762 down_delta
+= (time_to_stopped
- ASSISTEDCONTROL_DELAY_TO_BRAKE
) * 0.5f
* velocityState
.Down
; // area under the linear deceleration plot
763 float net_delta
= east_delta
* east_delta
+ north_delta
* north_delta
+ down_delta
* down_delta
;
764 net_delta
= sqrtf(net_delta
);
766 pathDesired
.Start
.North
= positionState
.North
;
767 pathDesired
.Start
.East
= positionState
.East
;
768 pathDesired
.Start
.Down
= positionState
.Down
;
769 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_BRAKE_STARTVELOCITYVECTOR_NORTH
] = velocityState
.North
;
770 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_BRAKE_STARTVELOCITYVECTOR_EAST
] = velocityState
.East
;
771 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_BRAKE_STARTVELOCITYVECTOR_DOWN
] = velocityState
.Down
;
773 pathDesired
.End
.North
= positionState
.North
+ north_delta
;
774 pathDesired
.End
.East
= positionState
.East
+ east_delta
;
775 pathDesired
.End
.Down
= positionState
.Down
+ down_delta
;
777 pathDesired
.StartingVelocity
= velocity
;
778 pathDesired
.EndingVelocity
= 0.0f
;
779 pathDesired
.Mode
= PATHDESIRED_MODE_BRAKE
;
780 pathDesired
.ModeParameters
[PATHDESIRED_MODEPARAMETER_BRAKE_TIMEOUT
] = time_to_stopped
* ASSISTEDCONTROL_TIMEOUT_MULTIPLIER
;
781 assistedControlFlightMode
= FLIGHTSTATUS_ASSISTEDCONTROLSTATE_BRAKE
;
782 FlightStatusAssistedControlStateSet(&assistedControlFlightMode
);
783 PathDesiredSet(&pathDesired
);