Paparazzi UAS v7.1_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
oneloop_nB.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2023 Tomaso De Ponti <tmldeponti@tudelft.nl>
3 *
4 * This file is part of paparazzi
5 *
6 * paparazzi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * paparazzi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with paparazzi; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
25//====================================================================================================================================
32//====================================================================================================================================
33// Enter functions change the state of the oneloop controller
46// Example of execution of the oneloop controller for two different states in the state machine
78//====================================================================================================================================
79/* Include necessary header files */
82#include "state.h"
83#include "generated/airframe.h"
86#include "modules/core/abi.h"
89#include "math/wls/wls_alloc.h"
92#ifndef ONELOOP_NB_SIMPLE_QUAD
94#endif
96// #include "modules/ctrl/eff_scheduling_rotwing_V2.h"
98#include <stdio.h>
99#if INS_EXT_POSE
101#endif
102//====================================================================================================================================
103//====================================================================================================================================
104// Define configuration variables with default values if not defined in the airframe file
105//====================================================================================================================================
106//====================================================================================================================================
107// GENERAL VARIABLES
108//====================================================================================================================================
109
110#ifndef ONELOOP_NB_DEBUG_MODE // Debug mode, sets in_flight to FALSE
111#define ONELOOP_NB_DEBUG_MODE FALSE
112#endif
114struct OneloopGeneral oneloop_nB; // Define general struct of the Oneloop ANDI controller
115static float dt_1l = 1. / PERIODIC_FREQUENCY; // Time step of the oneloop controller [s]
116static float g = 9.81; // [m/s^2] Gravitational Acceleration
117
118#define IDX_aD RW_aD - 2 // Down axis (linear acceleration)
119#define IDX_ap RW_ap - 2 // // X body axis (angular acceleration)
120#define IDX_aq RW_aq - 2 // // Y body axis (angular acceleration)
121#define IDX_ar RW_ar - 2 // // Z body axis (angular acceleration)
122//====================================================================================================================================
123// FILTERING VARIABLES
124//====================================================================================================================================
125#define USE_BW2
126
127#ifdef ONELOOP_NB_FILT_CUTOFF
128float oneloop_nB_filt_cutoff = ONELOOP_NB_FILT_CUTOFF;
129#else
131#endif
132
133#ifdef ONELOOP_NB_FILT_CUTOFF_ACC
134float oneloop_nB_filt_cutoff_a = ONELOOP_NB_FILT_CUTOFF_ACC;
135#else
137#endif
138
139#ifdef ONELOOP_NB_FILT_CUTOFF_VEL
140float oneloop_nB_filt_cutoff_v = ONELOOP_NB_FILT_CUTOFF_VEL;
141#else
143#endif
144
145#ifdef ONELOOP_NB_FILT_CUTOFF_P
146#define ONELOOP_NB_FILTER_ROLL_RATE TRUE
147float oneloop_nB_filt_cutoff_p = ONELOOP_NB_FILT_CUTOFF_P;
148#else
150#endif
151
152#ifdef ONELOOP_NB_FILT_CUTOFF_Q
153#define ONELOOP_NB_FILTER_PITCH_RATE TRUE
154float oneloop_nB_filt_cutoff_q = ONELOOP_NB_FILT_CUTOFF_Q;
155#else
157#endif
158
159#ifdef ONELOOP_NB_FILT_CUTOFF_R
160#define ONELOOP_NB_FILTER_YAW_RATE TRUE
161float oneloop_nB_filt_cutoff_r = ONELOOP_NB_FILT_CUTOFF_R;
162#else
164#endif
165
166PRINT_CONFIG_MSG("============================================================")
167PRINT_CONFIG_MSG("%%% ONELOOP FILTERING VARIABLES %%%")
168PRINT_CONFIG_VAR(ONELOOP_NB_FILT_CUTOFF_ACC)
169PRINT_CONFIG_VAR(ONELOOP_NB_FILT_CUTOFF_VEL)
170PRINT_CONFIG_VAR(ONELOOP_NB_FILT_CUTOFF);
171PRINT_CONFIG_VAR(ONELOOP_NB_FILT_CUTOFF_Q);
172PRINT_CONFIG_VAR(ONELOOP_NB_FILT_CUTOFF_P);
173PRINT_CONFIG_VAR(ONELOOP_NB_FILT_CUTOFF_R);
174PRINT_CONFIG_MSG("============================================================")
175PRINT_CONFIG_MSG("============================================================")
176PRINT_CONFIG_MSG("%%% ONELOOP GENERAL VARIABLES %%%")
181PRINT_CONFIG_MSG("============================================================")
183
188static Butterworth2LowPass accely_filt; // FIXME (check if condenseable) Low pass filter for acceleration in y direction
189static Butterworth2LowPass airspeed_filt; // FIXME (check if condenseable) Low pass filter for airspeed
190static Butterworth2LowPass u_filt[ANDI_NUM_ACT_TOT]; // FIXME (check if condenseable) Low pass filter for actuators for synchronous filtering
194//====================================================================================================================================
195// ACTUATOR VARIABLES
196//====================================================================================================================================
197#ifndef ONELOOP_NB_NUM_THRUSTERS // Number of motors used for thrust
199#else
200float num_thrusters_oneloop = ONELOOP_NB_NUM_THRUSTERS;
201#endif
202
203#ifdef ONELOOP_NB_ACT_IS_SERVO // Unused but kept for future developments
204bool actuator_is_servo[ANDI_NUM_ACT_TOT] = ONELOOP_NB_ACT_IS_SERVO;
205#else
207#endif
208
209#ifdef ONELOOP_NB_ACT_DYN // Actuator dynamics (first order lag) corner frequency [rad/s]
210float act_dynamics[ANDI_NUM_ACT_TOT] = ONELOOP_NB_ACT_DYN;
211float act_dyn_ctrl[ANDI_NUM_ACT_TOT] = ONELOOP_NB_ACT_DYN;
212#else
213#error "You must specify the actuator dynamics"
216#endif
217
218#ifdef ONELOOP_NB_ACT_MAX // Maximum Paparazzi actuator command
219float act_max[ANDI_NUM_ACT_TOT] = ONELOOP_NB_ACT_MAX;
220#else
222#endif
223
224#ifdef ONELOOP_NB_ACT_MIN // Minimum Paparazzi actuator command
225float act_min[ANDI_NUM_ACT_TOT] = ONELOOP_NB_ACT_MIN;
226#else
227float act_min[ANDI_NUM_ACT_TOT] = = {0.0};
228#endif
229
230#ifdef ONELOOP_NB_ACT_MAX_NORM // Maximum normalized actuator command
231float act_max_norm[ANDI_NUM_ACT_TOT] = ONELOOP_NB_ACT_MAX_NORM;
232#else
234#endif
235
236#ifdef ONELOOP_NB_ACT_MIN_NORM // Minimum normalized actuator command
237float act_min_norm[ANDI_NUM_ACT_TOT] = ONELOOP_NB_ACT_MIN_NORM;
238#else
240#endif
241
242#ifdef ONELOOP_NB_NU_NORM_MAX // Maximum norm of the normalized pseudo control vector
243float nu_norm_max = ONELOOP_NB_NU_NORM_MAX;
244#else
245float nu_norm_max = 1.0;
246#endif
247
248#ifdef ONELOOP_NB_U_PREF // Preferred Paparazzi actuator command
249static float u_pref[ANDI_NUM_ACT_TOT] = ONELOOP_NB_U_PREF;
250#else
251static float u_pref[ANDI_NUM_ACT_TOT] = {0.0};
252#endif
253
254PRINT_CONFIG_MSG("============================================================")
255PRINT_CONFIG_MSG("%%% ONELOOP MAX ANGLES %%%")
256PRINT_CONFIG_VAR(ONELOOP_NB_MAX_BANK)
257PRINT_CONFIG_VAR(ONELOOP_NB_MAX_PHI)
258PRINT_CONFIG_VAR(ONELOOP_NB_MAX_THETA);
259PRINT_CONFIG_MSG("============================================================")
260
261#ifdef ONELOOP_NB_MAX_BANK
262float max_bank = ONELOOP_NB_MAX_BANK;
263#else
264float max_bank = M_PI_6;
265#endif
266
267#ifdef ONELOOP_NB_MAX_PHI
268float max_phi = ONELOOP_NB_MAX_PHI;
269#else
270float max_phi = M_PI_6;
271#endif
272
273#ifdef ONELOOP_NB_MAX_THETA
274float max_theta = ONELOOP_NB_MAX_THETA;
275#else
276float max_theta = M_PI_6;
277#endif
278
279#ifndef ONELOOP_THETA_PREF_MAX // Max preferred pitch angles
280float theta_pref_max = RadOfDeg(20.0);
281#else
282float theta_pref_max = RadOfDeg(ONELOOP_THETA_PREF_MAX);
283#endif
284
285PRINT_CONFIG_MSG("============================================================")
286PRINT_CONFIG_MSG("%%% ONELOOP WLS %%%")
289PRINT_CONFIG_MSG("============================================================")
290
291#if ANDI_NUM_ACT_TOT != WLS_N_U_MAX
292#error Matrix-WLS_N_U_MAX is not equal to the number of actuators: define WLS_N_U_MAX == ANDI_NUM_ACT_TOT in airframe file
293#define WLS_N_U_MAX == ANDI_NUM_ACT_TOT
294#endif
295#if ANDI_OUTPUTS != WLS_N_V_MAX
296#error Matrix-WLS_N_V_MAX is not equal to the number of controlled axis: define WLS_N_V_MAX == ANDI_OUTPUTS in airframe file
297#define WLS_N_V_MAX == ANDI_OUTPUTS
298#endif
299
300float andi_u[ANDI_NUM_ACT_TOT]; // Control command vector
301float andi_du[ANDI_NUM_ACT_TOT]; // Control command increment vector
302static float andi_u_n[ANDI_NUM_ACT_TOT]; // Control command vector (normalized)
303float nu[ANDI_OUTPUTS]; // Pseudo control vector
304float nu_n[ANDI_OUTPUTS]; // Pseudo control vector (normalized)
305static float act_dynamics_d[ANDI_NUM_ACT_TOT]; // Actuator dynamics (first order lag) corner frequency [rad/s]
306float actuator_state_1l[ANDI_NUM_ACT_TOT]; // Actuator state vector (including virtual actuators)
307float nB_jerk_des[3];
308float SQ_r = 0.0;
309#ifndef ONELOOP_NB_MAX_FAULT_MOT // Max static command to the faulted motors (throttle - delta_fault is cut to it) [pprz]
310#define ONELOOP_NB_MAX_FAULT_MOT 3000.0
311#endif
312_Static_assert(ONELOOP_NB_MAX_FAULT_MOT >= 0.0 && ONELOOP_NB_MAX_FAULT_MOT <= 9600.0,
313 "ONELOOP_NB_MAX_FAULT_MOT must be in [0, 9600] pprz");
315//====================================================================================================================================
316// STABILIZATION VARIABLES
317//====================================================================================================================================
318#ifndef MAX_R // Max Yaw rate with the sticks
319float max_r = RadOfDeg(180.0); // RadOfDeg(120.0);
320#else
321float max_r = RadOfDeg(MAX_R);
322#endif
323
324#ifdef ONELOOP_NB_YAW_DISTURBANCE_LIMIT // Yaw disturbance rejection limit
325float oneloop_nB_yaw_dist_limit = ONELOOP_NB_YAW_DISTURBANCE_LIMIT;
326#else
327float oneloop_nB_yaw_dist_limit = 99999.f; // High value to disable the feature
328#endif
329
330#if ONELOOP_NB_HEADING_MANUAL // Specify heading in NAV with a slider
331bool heading_manual = true;
332#else
333bool heading_manual = false;
334#endif
335
336#if ONELOOP_NB_YAW_STICK_IN_AUTO // Specify heading in NAV with the yaw stick
337bool yaw_stick_in_auto = true;
338#else
339bool yaw_stick_in_auto = false;
340#endif
341
343 // Stabilization bounds specified per axis
344#ifdef ONELOOP_NB_MAX_ANGULAR_JERK
345 .att_3d[0] = ONELOOP_NB_MAX_ANGULAR_JERK,
346 .att_3d[1] = ONELOOP_NB_MAX_ANGULAR_JERK,
347#else
348 .att_3d[0] = RadOfDeg(100000.0),
349 .att_3d[1] = RadOfDeg(100000.0),
350#endif
351
352#ifdef ONELOOP_NB_MAX_ANGULAR_JERK_YAW
353 .att_3d[2] = ONELOOP_NB_MAX_ANGULAR_JERK_YAW,
354#else
355 .att_3d[2] = RadOfDeg(100000.0),
356#endif
357
358#ifdef ONELOOP_NB_MAX_ANGULAR_ACCEL
359 .att_2d[0] = ONELOOP_NB_MAX_ANGULAR_ACCEL,
360 .att_2d[1] = ONELOOP_NB_MAX_ANGULAR_ACCEL,
361#else
362 .att_2d[0] = RadOfDeg(700.0),
363 .att_2d[1] = RadOfDeg(480.0),
364#endif
365
366#ifdef ONELOOP_NB_MAX_ANGULAR_ACCEL_YAW
367 .att_2d[2] = ONELOOP_NB_MAX_ANGULAR_ACCEL_YAW,
368#else
369 .att_2d[2] = RadOfDeg(480.0),
370#endif
371
372#ifdef ONELOOP_NB_MAX_ANGULAR_VEL
373 .att_d[0] = ONELOOP_NB_MAX_ANGULAR_VEL,
374 .att_d[1] = ONELOOP_NB_MAX_ANGULAR_VEL,
375#else
376 .att_d[0] = RadOfDeg(10000.0),
377 .att_d[1] = RadOfDeg(10000.0),
378#endif
379
380#ifdef ONELOOP_NB_MAX_ANGULAR_VEL_YAW
381 .att_d[2] = ONELOOP_NB_MAX_ANGULAR_VEL_YAW,
382#else
383 .att_d[2] = RadOfDeg(10000.0),
384#endif
385};
386
387struct FloatEulers eulers_zxy_des; // Desired Euler angles in ZXY sequence
388struct FloatEulers eulers_zxy; // Actual Euler angles in ZXY sequence
389float psi_des_rad = 0.0; // Desired Yaw angle [rad]
390float psi_des_deg = 0.0; // Desired Yaw angle [deg]
391//====================================================================================================================================
392// GUIDANCE VARIABLES
393//====================================================================================================================================
394#ifndef ONELOOP_NB_AIRSPEED_SWITCH_THRESHOLD // Airspeed threshold to switch to coordinated turn behavior
395#define ONELOOP_NB_AIRSPEED_SWITCH_THRESHOLD 10.0
396#endif
397
398#ifndef FWD_SIDESLIP_GAIN // Gain to reduce sideslip when flying forward
400#else
401float fwd_sideslip_gain = FWD_SIDESLIP_GAIN;
402#endif
403
404#ifdef NAV_HYBRID_MAX_DECELERATION // Max (ac)/(de)celeration. Can be overwritte nby NAV HYBRID
406#else
407float max_a_nav = 4.0;
408#endif
409
410#ifdef ONELOOP_NB_MAX_LINEAR_JERK // Max linear jerk [m/s^3]
411float max_j_lin = ONELOOP_NB_MAX_LINEAR_JERK;
412#else
413float max_j_lin = 500.0;
414#endif
415
416#ifdef NAV_HYBRID_MAX_AIRSPEED
417float max_v_nav = NAV_HYBRID_MAX_AIRSPEED; // Max horizontal speed. Can be overwritten by NAV HYBRID
418#else
419float max_v_nav = 5.0;
420#endif
421
422#ifdef NAV_HYBRID_MAX_SPEED_V // Max vertical speed
423float max_v_nav_v = NAV_HYBRID_MAX_SPEED_V;
424#else
425float max_v_nav_v = 1.5;
426#endif
427
428#define USE_ND_VELOCITIES // Use NumDiff of velocities instead of Accelerometer.
429
430float max_as = 19.0f; // Max airspeed [m/s]
431float min_as = 0.0f; // Min airspeed [m/s]
432float xdot_lim_sf = 0.8; // Safety Factor on SUVAT velocity limit
433float ec_headroom = 1.5; // Extra headroom for the EC wrt the RM
434static float nav_target[3]; // Can be a position, speed or acceleration depending on the guidance H mode
435static float nav_target_new[3]; // Wind triangle reshaped NAV target
436float gi_unbounded_airspeed_sp = 0.0; // Unbounded airspeed setpoint [m/s] (mimics guidance_indi_hybrid)
437//====================================================================================================================================
438// CONTROL ALLOCATION VARIABLES
439//====================================================================================================================================
440#ifndef ONELOOP_NB_WU_QUAD_MOTORS_FWD
442#else
443float Wu_quad_motors_fwd = ONELOOP_NB_WU_QUAD_MOTORS_FWD;
444#endif
445
446struct WLS_t WLS_one_p = {
447 .nu = ANDI_NUM_ACT_TOT,
448 .nv = ANDI_OUTPUTS,
449 .gamma_sq = 1000.0,
450 .v = {0.0},
451#ifdef ONELOOP_NB_WV // {ax_dot,ay_dot,az_dot,p_ddot,q_ddot,r_ddot}
452 .Wv = ONELOOP_NB_WV,
453#else
454 .Wv = {1.0},
455#endif
456#ifdef ONELOOP_NB_WU // {de,dr,daL,daR,mF,mB,mL,mR,mP,phi,theta}
457 .Wu = ONELOOP_NB_WU,
458#else
459 .Wu = {1.0},
460#endif
461 .u_pref = {0.0},
462 .u_min = {0.0},
463 .u_max = {0.0},
464 .PC = 0.0,
465 .SC = 0.0,
466 .iter = 0};
467
468#ifdef ONELOOP_NB_WU // {mF,mR,mB,mL,mP,de,dr,da,df,phi,theta}
469static float Wu_backup[ANDI_NUM_ACT_TOT] = ONELOOP_NB_WU;
470#else
471static float Wu_backup[ANDI_NUM_ACT_TOT] = {1.0};
472#endif
473
474#ifdef ONELOOP_NB_WV // {mF,mR,mB,mL,mP,de,dr,da,df,phi,theta}
475static float Wv_backup[ANDI_OUTPUTS] = ONELOOP_NB_WV;
476#else
477static float Wv_backup[ANDI_OUTPUTS] = {1.0};
478#endif
479
480static float a_thrust = 0.0; // Virtual z-Acceleration to command a Thrust level[m/s^2]
481static float g2_ff = 0.0; // Feedforward G2 term for Yaw control
482bool ctrl_off = false; // Preferred pitch angle for the control allocation
483
484float *bwls_1l[ANDI_OUTPUTS]; // Pointer to the WLS Effectiveness matrix
485float EFF_MAT_G[ANDI_OUTPUTS][ANDI_NUM_ACT_TOT]; // Intermidiate variable to save Effectiveness matrix
491//====================================================================================================================================
492// CONTROL LAW VARIABLES
493//====================================================================================================================================
494float SpinQuadRate = 0.0;
495bool SpinQuad = false; // Quadrotor spinning configuration
496bool fault_pitch_motors = false; // Fault pitch motors
497bool fault_roll_motors = false; // Fault roll motors
498#ifndef ONELOOP_NB_FAULT_AILERONS // Fault ailerons at boot (FALSE on airframes with ailerons to use them in nB modes)
499#define ONELOOP_NB_FAULT_AILERONS TRUE
500#endif
502bool drop_yaw = false; // Drop the control of the Yaw axis
503bool drop_roll = false; // Drop the control of the Roll axis
504bool drop_pitch = false; // Drop the control of the aE axis
505bool drop_aD = false; // Drop the control of the aD axis
506bool state_compensation_on = false; // State compensation for rotating bodies
507bool use_push_PID = false; // Use PID to cmd the pusher
508bool use_push_Position = false; // Use position loop to cmd the pusher
509bool radio_body_ctrl = false; // Control nI in body axes
510bool oneloop_nB_Z_hold = false; // Hold only the altitude when in NAV
511bool vel_ctrl_in_manual = true; // Use velocity control in manual mode (instead of direct stick to acceleration mapping)
512bool use_safety_killer = false; // !!DANGER!! never turn on by default.
514bool auto_fault_cmd = false; //
516float safety_killer_cutoff = 7500.0;
517float xi = 0.0;
518float max_pusher_cmd = 7500;
519float debug_state[3];
520float state_term[3];
521#ifdef ONELOOP_NB_DELTA_FAULT
522float delta_fault = ONELOOP_NB_DELTA_FAULT;
523#else
524float delta_fault = 1000.0;
525#endif
526PRINT_CONFIG_MSG("%%% DELTA FAULT %%%")
527PRINT_CONFIG_VAR(ONELOOP_NB_DELTA_FAULT)
528// Yaw spin envelope protection (faulted motors): blend the static fault command towards
529// spin_prot_max_cmd as |r| grows from spin_prot_start_rate to spin_prot_max_rate
530#ifndef ONELOOP_NB_SPIN_PROT_MAX_RATE // Absolute max yaw rate, fully protected [rad/s]
531#define ONELOOP_NB_SPIN_PROT_MAX_RATE 34.0
532#endif
533#ifndef ONELOOP_NB_SPIN_PROT_START_RATE // Yaw rate where protection starts to blend in [rad/s]
534#define ONELOOP_NB_SPIN_PROT_START_RATE 28.0
535#endif
536#ifndef ONELOOP_NB_SPIN_PROT_MAX_CMD // Max command to the faulted motors, reached at max yaw rate [pprz]
537#define ONELOOP_NB_SPIN_PROT_MAX_CMD 4800.0
538#endif
542float spin_prot_ratio = 0.0; // 0 = normal static command, 1 = fully protected
543// 0 ──── bleed ──── 24 ── hold ── 28 ── envelope + trim rising ── 34 ── fully protected ──▶
544// release start max
545// Spin trim: slow integrator that raises the static fault command while the envelope is active,
546// so that the equilibrium spin rate is pushed back below spin_prot_start_rate (e.g. battery drop)
547#ifndef ONELOOP_NB_SPIN_TRIM_ON // Enable the spin trim integrator
548#define ONELOOP_NB_SPIN_TRIM_ON TRUE
549#endif
550#ifndef ONELOOP_NB_SPIN_TRIM_RATE // Trim increase rate at spin_prot_ratio = 1 [pprz/s]
551#define ONELOOP_NB_SPIN_TRIM_RATE 1000.0
552#endif
553#ifndef ONELOOP_NB_SPIN_TRIM_BLEED_RATE // Trim decrease rate below release rate [pprz/s] (0 = only increase)
554#define ONELOOP_NB_SPIN_TRIM_BLEED_RATE 1000.0
555#endif
556#ifndef ONELOOP_NB_SPIN_TRIM_RELEASE_RATE // Yaw rate below which the trim bleeds off [rad/s]
557#define ONELOOP_NB_SPIN_TRIM_RELEASE_RATE 24.0
558#endif
563float spin_trim = 0.0; // Current trim [pprz]
564#ifndef ONELOOP_NB_SPIN_PROT_MIN_GAP // Min gap enforced between release < start < max rates [rad/s]
565#define ONELOOP_NB_SPIN_PROT_MIN_GAP 1.0
566#endif
568// Compile time checks of the airframe values (same limits are enforced at runtime, see spin_prot_bound_params)
569_Static_assert(ONELOOP_NB_SPIN_PROT_MIN_GAP >= 0.1 && ONELOOP_NB_SPIN_PROT_MIN_GAP <= 10.0,
570 "ONELOOP_NB_SPIN_PROT_MIN_GAP must be in [0.1, 10] rad/s");
571_Static_assert(ONELOOP_NB_SPIN_PROT_MAX_RATE <= 60.0,
572 "ONELOOP_NB_SPIN_PROT_MAX_RATE must be <= 60 rad/s");
574 "ONELOOP_NB_SPIN_PROT_START_RATE must be at least SPIN_PROT_MIN_GAP below SPIN_PROT_MAX_RATE");
575_Static_assert(ONELOOP_NB_SPIN_TRIM_RELEASE_RATE >= 0.0 &&
577 "ONELOOP_NB_SPIN_TRIM_RELEASE_RATE must be >= 0 and at least SPIN_PROT_MIN_GAP below SPIN_PROT_START_RATE");
579 "ONELOOP_NB_SPIN_PROT_MAX_CMD must be in [0, MAX_PPRZ]");
580_Static_assert(ONELOOP_NB_SPIN_TRIM_RATE >= 0.0 && ONELOOP_NB_SPIN_TRIM_RATE <= 1000.0,
581 "ONELOOP_NB_SPIN_TRIM_RATE must be in [0, 1000] pprz/s");
583 "ONELOOP_NB_SPIN_TRIM_BLEED_RATE must be in [0, 1000] pprz/s");
584// Spin transition manoeuvre: nominal <-> pitch motors faulted, triggered from the GCS
585#ifndef ONELOOP_NB_SPIN_MAN_RAMP_RATE // Yaw rate reference ramp [rad/s^2]
586#define ONELOOP_NB_SPIN_MAN_RAMP_RATE 2.0
587#endif
588#ifndef ONELOOP_NB_SPIN_MAN_BLEND_TIME // Blend time of the pitch motors between allocator and static cmd [s]
589#define ONELOOP_NB_SPIN_MAN_BLEND_TIME 1.0
590#endif
591#ifndef ONELOOP_NB_SPIN_MAN_TRIM_RATE // Open loop trim increase while slowing down [pprz/s]
592#define ONELOOP_NB_SPIN_MAN_TRIM_RATE 300.0
593#endif
594#ifndef ONELOOP_NB_SPIN_MAN_DONE_RATE // |r| below which the spin is considered stopped [rad/s]
595#define ONELOOP_NB_SPIN_MAN_DONE_RATE 0.5
596#endif
597#define SPIN_MAN_PAIR_PITCH 0
598#define SPIN_MAN_PAIR_ROLL 1
599#ifndef ONELOOP_NB_SPIN_MAN_PAIR // Pair faulted by the spin up: 0 = pitch (FRONT/BACK), 1 = roll (RIGHT/LEFT)
600#define ONELOOP_NB_SPIN_MAN_PAIR SPIN_MAN_PAIR_PITCH
601#endif
602#ifndef ONELOOP_NB_SPIN_MAN_PITCH_DIR // Sign of r when the pitch motors are faulted (+1/-1), roll fault spins opposite
603#define ONELOOP_NB_SPIN_MAN_PITCH_DIR 1.0
604#endif
606 "ONELOOP_NB_SPIN_MAN_PAIR must be 0 (pitch) or 1 (roll)");
607_Static_assert(ONELOOP_NB_SPIN_MAN_PITCH_DIR == 1.0 || ONELOOP_NB_SPIN_MAN_PITCH_DIR == -1.0,
608 "ONELOOP_NB_SPIN_MAN_PITCH_DIR must be 1 or -1");
609_Static_assert(ONELOOP_NB_SPIN_MAN_RAMP_RATE >= 0.1 && ONELOOP_NB_SPIN_MAN_RAMP_RATE <= 10.0,
610 "ONELOOP_NB_SPIN_MAN_RAMP_RATE must be in [0.1, 10] rad/s^2");
612 "ONELOOP_NB_SPIN_MAN_BLEND_TIME must be in [0.1, 5] s");
613_Static_assert(ONELOOP_NB_SPIN_MAN_TRIM_RATE >= 0.0 && ONELOOP_NB_SPIN_MAN_TRIM_RATE <= 1000.0,
614 "ONELOOP_NB_SPIN_MAN_TRIM_RATE must be in [0, 1000] pprz/s");
616 "ONELOOP_NB_SPIN_MAN_DONE_RATE must be in [0.1, 5] rad/s");
617// Third gain of the ANDI error controller (roll/pitch and vertical), equal to the hover motors actuator dynamics
618#ifndef ONELOOP_NB_EC_K3 // [rad/s], 22 on the RW3C, 29 on the PlusQuad
619#define ONELOOP_NB_EC_K3 22.0
620#endif
621_Static_assert(ONELOOP_NB_EC_K3 >= 1.0 && ONELOOP_NB_EC_K3 <= 100.0, "ONELOOP_NB_EC_K3 must be in [1, 100] rad/s");
623// Velocity PID limits (manual and NAV): max acceleration setpoint (sets the max tilt of the thrust vector in nB modes,
624// max_phi/max_theta do not limit it there) and max velocity setpoint. RW3C: conservative, PlusQuad: relaxed.
625#ifndef ONELOOP_NB_PID_A_MAX // Max acceleration setpoint [g] (0.12 g ~ 7 deg tilt, 0.6 g ~ 31 deg tilt)
626#define ONELOOP_NB_PID_A_MAX 0.6
627#endif
628#ifndef ONELOOP_NB_PID_V_MAX_MANUAL // Max velocity setpoint in manual, also the full stick velocity [m/s]
629#define ONELOOP_NB_PID_V_MAX_MANUAL 3.0
630#endif
631#ifndef ONELOOP_NB_PID_V_MAX_NAV // Max velocity setpoint in NAV [m/s]
632#define ONELOOP_NB_PID_V_MAX_NAV 3.0
633#endif
634_Static_assert(ONELOOP_NB_PID_A_MAX >= 0.05 && ONELOOP_NB_PID_A_MAX <= 1.0, "ONELOOP_NB_PID_A_MAX must be in [0.05, 1] g");
635_Static_assert(ONELOOP_NB_PID_V_MAX_MANUAL >= 0.1 && ONELOOP_NB_PID_V_MAX_MANUAL <= 10.0,
636 "ONELOOP_NB_PID_V_MAX_MANUAL must be in [0.1, 10] m/s");
637_Static_assert(ONELOOP_NB_PID_V_MAX_NAV >= 0.1 && ONELOOP_NB_PID_V_MAX_NAV <= 10.0,
638 "ONELOOP_NB_PID_V_MAX_NAV must be in [0.1, 10] m/s");
643{
645 SPIN_MAN_UP_RAMP, // no fault, yaw rate ref ramps up until |r| >= release rate, then fault spin_man_pair
646 SPIN_MAN_UP_BLEND, // pair faulted, blend from allocator cmd to static cmd
647 SPIN_MAN_DOWN_SLOW, // single pair faulted, open loop trim increase until |r| < release - gap
648 SPIN_MAN_DOWN_BLEND, // no fault, blend from static cmd to allocator cmd, yaw rate ref ramps to 0
649 SPIN_MAN_DOWN_RAMP // no fault, yaw rate ref ramps to 0 until the spin is stopped
650};
651bool spin_man_up = false; // GCS trigger: spin up, then fault spin_man_pair (clears itself)
652bool spin_man_down = false; // GCS trigger: slow down, unfault the faulted pair, stop the spin (clears itself)
660float spin_man_r_ref = 0.0; // Yaw rate reference [rad/s]
661static float spin_man_dir = 1.0; // Spin direction (sign of r once the pair is faulted)
662static float spin_man_alpha = 1.0; // Blend factor: 0 = held cmd, 1 = new source
663static uint8_t spin_man_mot[2] = {COMMAND_MOTOR_FRONT, COMMAND_MOTOR_BACK}; // Motors of the pair being blended
664static float spin_man_u_hold[2] = {0.0, 0.0}; // Cmd of spin_man_mot captured at the transition
665static float spin_man_u_last[ANDI_NUM_ACT] = {0.0}; // Cmd of all motors applied in the previous loop
666//====================================================================================================================================
667// Error Controller and Reference Model VARIABLES
668//====================================================================================================================================
669#ifdef ONELOOP_NB_SLOW_POLE
670float slow_pole = ONELOOP_NB_SLOW_POLE;
671#else
672float slow_pole = 22.0;
673#endif
674PRINT_CONFIG_MSG("%%% SLOW POLE %%%")
675PRINT_CONFIG_VAR(ONELOOP_NB_SLOW_POLE)
676/*Declaration of Reference Model and Error Controller Gains*/
680/*Position Loop*/
683/*Altitude Loop*/
686/*Heading Loop*/
689/*Gains of EC and RM ANDI*/
694/*Gains of EC and RM INDI*/
697float k1_NE_tune = 0.6;
698float k2_NE_tune = 1.85;
699/* PID */
700float k_K = 0.6; // 1.33; //2.4/1.8=1.33
701float k_P = 1.8; //
702float k_I = 0.4;
703float k_D = 0.2;
707//====================================================================================================================================
708// Function Declaration Section
709//====================================================================================================================================
710void init_poles(void);
711void init_poles_att(void); // FIXME check if still needed
712void init_poles_pos(void); // FIXME check if still needed
713void calc_normalization(void);
714void normalize_nu(void);
715void G1G2_oneloop(int ctrl_type);
716void get_act_state_oneloop(void);
718void init_filter(void);
719void init_controller_gains(void);
720void reinit_controller(void);
721void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3]);
722void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3]);
723void err_nd(float err[], float a[], float b[], float k[], int n);
724void err_sum_nd(float err[], float a[], float b[], float k[], float c[], int n);
725void float_vect_diff_euler(float err[3], float a[3], float b[3]);
726void integrate_nd(float dt, float a[], float a_dot[], int n);
727void vect_bound_nd(float vect[], float bound, int n);
728void acc_body_bound(struct FloatVect2* vect, float bound);
729float bound_v_from_a_vect(float e_x[], float v_bound, float a_bound, int n);
730float bound_v_from_a(float e_x, float v_bound, float a_bound);
731void rm_3rd_attitude(float dt, float x_ref[3], float x_d_ref[3], float x_2d_ref[3], float x_3d_ref[3], float x_des[3], bool ow_psi, float psi_overwrite[4], float k1_rm[3], float k2_rm[3], float k3_rm[3], struct OneloopStabilizationRef bounds);
732void rm_3rd_pos(float dt, float x_ref[], float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x_des[], float k1_rm[], float k2_rm[], float k3_rm[], float x_d_bound, float x_2d_bound, float x_3d_bound, int n);
733void rm_2nd_pos(float dt, float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x_d_des[], float k2_rm[], float k3_rm[], float x_2d_bound, float x_3d_bound, int n);
734void rm_1st_pos(float dt, float x_2d_ref[], float x_3d_ref[], float x_2d_des[], float k3_rm[], float x_3d_bound, int n);
735void rm_3rd_nI(float dt, struct FloatVect3 *x_ref, struct FloatVect3 *x_d_ref, struct FloatVect3 *x_2d_ref, struct FloatVect3 *x_3d_ref, const struct FloatVect3 *x_des, const float k1_rm[3], const float k2_rm[3], const float k3_rm[3]);
736void ec_3rd_att(float y_4d[3], float x_des[3], float x_ref[3], float x_d_ref[3], float x_2d_ref[3], float x_3d_ref[3], float x[3], float x_d[3], float x_2d[3], float k1_e[3], float k2_e[3], float k3_e[3], struct OneloopStabilizationRef bounds, float fb[3]);
737void ec_3rd_pos(float y_4d[], float x_des[], float x_ref[], float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x[], float x_d[], float x_2d[], float k1_e[], float k2_e[], float k3_e[], float x_d_bound, float x_2d_bound, float fb[], int n);
738float oneloop_nB_sideslip(void);
739void reshape_wind(void);
740void chirp_pos(float time_elapsed, float f0, float f1, float t_chirp, float A, int8_t n, float psi, float p_ref[], float v_ref[], float a_ref[], float j_ref[], float p_ref_0[]);
741void chirp_call(bool* chirp_on, bool* chirp_first_call, float* t_0_chirp, float* time_elapsed, float f0, float f1, float t_chirp, float A, int8_t n, float psi, float p_ref[], float v_ref[], float a_ref[], float j_ref[], float p_ref_0[]);
742void oneloop_calc_model_disturbance(bool in_flight);
744void set_WLS_settings(void);
745void drop_axis(void);
746void skew_symmetric(struct FloatRMat *out, const struct FloatVect3 *in);
748void nB_EC(struct FloatVect3 nB, struct FloatVect3 nB_d, struct FloatVect3 nB_2d, struct FloatVect3 mu_B, float k1_e[3], float k2_e[3], float k3_e[3], float dist[3], float nB_nu[3]);
749void calc_HB_matrix(float HB[3][3], struct FloatVect3 nB);
750void SpinQuad_overwrite(float gain, float ce_model, float *nu_stab_2);
751float cos_2n(float psi, float xi, int n);
752float phase_first_order(float r, float w);
753float xi_fun(float r, float w, float aN_des, float aE_des);
754float pusher_cmd_fun(float aN_des, float aE_des, float r, float psi, float w, int n);
755//====================================================================================================================================
756// Telemetry Section
757//====================================================================================================================================
758#if PERIODIC_TELEMETRY
760static void send_wls_v_oneloop(struct transport_tx *trans, struct link_device *dev)
761{
762 send_wls_v("one", &WLS_one_p, trans, dev);
763}
764static void send_wls_u_oneloop(struct transport_tx *trans, struct link_device *dev)
765{
766 send_wls_u("one", &WLS_one_p, trans, dev);
767}
768static void send_eff_mat_stab_oneloop_nB(struct transport_tx *trans, struct link_device *dev)
769{
770#define STREAM_BWLS
771#ifdef STREAM_BWLS
772 pprz_msg_send_EFF_MAT_STAB(trans, dev, AC_ID,
777#else
778 pprz_msg_send_EFF_MAT_STAB(trans, dev, AC_ID,
783#endif
784}
785static void send_eff_mat_stab_thrust_oneloop_nB(struct transport_tx *trans, struct link_device *dev)
786{
787 // Vertical (thrust) row of the effectiveness, x and y are not used
788 float zero = 0.0;
789#ifdef STREAM_BWLS
790 pprz_msg_send_EFF_MAT_STAB_THRUST(trans, dev, AC_ID,
791 1, &zero,
792 1, &zero,
794#else
795 pprz_msg_send_EFF_MAT_STAB_THRUST(trans, dev, AC_ID,
796 1, &zero,
797 1, &zero,
799#endif
800}
801static void send_eff_mat_guid_oneloop_nB(struct transport_tx *trans, struct link_device *dev)
802{
803 pprz_msg_send_EFF_MAT_GUID(trans, dev, AC_ID,
807}
808static void send_oneloop_nB(struct transport_tx *trans, struct link_device *dev)
809{
810 float temp_eulers_zxy_des[3] = {eulers_zxy_des.phi, eulers_zxy_des.theta, eulers_zxy_des.psi};
811 pprz_msg_send_STAB_ATTITUDE(trans, dev, AC_ID,
812 3, temp_eulers_zxy_des,
813 3, oneloop_nB.sta_state.att,
814 3, oneloop_nB.sta_ref.att,
815 3, oneloop_nB.sta_state.att_d,
816 3, oneloop_nB.sta_ref.att_d,
817 3, oneloop_nB.sta_state.att_2d,
818 3, oneloop_nB.sta_ref.att_2d,
819 3, oneloop_nB.sta_ref.att_3d,
821}
822static void send_oneloop_nB_ctrl(struct transport_tx *trans, struct link_device *dev)
823{
824 float nI_des[3] = {oneloop_nB.sta_nB_state.nI_des.x, oneloop_nB.sta_nB_state.nI_des.y, oneloop_nB.sta_nB_state.nI_des.z};
825 float nI[3] = {oneloop_nB.sta_nB_state.nI.x, oneloop_nB.sta_nB_state.nI.y, oneloop_nB.sta_nB_state.nI.z};
826 float nI_d[3] = {oneloop_nB.sta_nB_state.nI_d.x, oneloop_nB.sta_nB_state.nI_d.y, oneloop_nB.sta_nB_state.nI_d.z};
827 float nI_2d[3] = {oneloop_nB.sta_nB_state.nI_2d.x, oneloop_nB.sta_nB_state.nI_2d.y, oneloop_nB.sta_nB_state.nI_2d.z};
828 float nI_3d[3] = {oneloop_nB.sta_nB_state.nI_3d.x, oneloop_nB.sta_nB_state.nI_3d.y, oneloop_nB.sta_nB_state.nI_3d.z};
829 float nB[3] = {oneloop_nB.sta_nB_state.nB.x, oneloop_nB.sta_nB_state.nB.y, oneloop_nB.sta_nB_state.nB.z};
830 float nB_d[3] = {oneloop_nB.sta_nB_state.nB_d.x, oneloop_nB.sta_nB_state.nB_d.y, oneloop_nB.sta_nB_state.nB_d.z};
831 float nB_2d[3] = {oneloop_nB.sta_nB_state.nB_2d.x, oneloop_nB.sta_nB_state.nB_2d.y, oneloop_nB.sta_nB_state.nB_2d.z};
832 float nB_3d[3] = {oneloop_nB.sta_nB_state.nB_3d.x, oneloop_nB.sta_nB_state.nB_3d.y, oneloop_nB.sta_nB_state.nB_3d.z};
833 float mu_B[3] = {oneloop_nB.sta_nB_state.mu_B.x, oneloop_nB.sta_nB_state.mu_B.y, oneloop_nB.sta_nB_state.mu_B.z};
834 pprz_msg_send_NB_CTRL(trans, dev, AC_ID,
835 3, nI_des,
836 3, nI,
837 3, nI_d,
838 3, nI_2d,
839 3, nI_3d,
840 3, nB,
841 3, nB_d,
842 3, nB_2d,
843 3, nB_3d,
844 3, mu_B);
845}
846static void send_guidance_oneloop_nB(struct transport_tx *trans, struct link_device *dev)
847{
848 pprz_msg_send_GUIDANCE(trans, dev, AC_ID,
849 &oneloop_nB.gui_ref.pos[0],
850 &oneloop_nB.gui_ref.pos[1],
851 &oneloop_nB.gui_ref.pos[2],
852 &oneloop_nB.gui_state.pos[0],
853 &oneloop_nB.gui_state.pos[1],
854 &oneloop_nB.gui_state.pos[2],
855 &oneloop_nB.gui_ref.vel[0],
856 &oneloop_nB.gui_ref.vel[1],
857 &oneloop_nB.gui_ref.vel[2],
858 &oneloop_nB.gui_state.vel[0],
859 &oneloop_nB.gui_state.vel[1],
860 &oneloop_nB.gui_state.vel[2],
861 &oneloop_nB.gui_ref.acc[0],
862 &oneloop_nB.gui_ref.acc[1],
863 &oneloop_nB.gui_ref.acc[2],
864 &oneloop_nB.gui_state.acc[0],
865 &oneloop_nB.gui_state.acc[1],
866 &oneloop_nB.gui_state.acc[2],
867 &oneloop_nB.gui_ref.jer[0],
868 &oneloop_nB.gui_ref.jer[1],
869 &oneloop_nB.gui_ref.jer[2]);
870}
871
872#ifdef PPRZ_MSG_ID_PUSH_NB // message not in pprzlink, only sent with a local message definition
873static void send_PUSH_NB(struct transport_tx *trans, struct link_device *dev)
874{
875 float xi = oneloop_nB.push_nB.xi - oneloop_nB.push_nB.xi_0;
876 pprz_msg_send_PUSH_NB(trans, dev, AC_ID,
877 &oneloop_nB.push_nB.pN_d,
878 &oneloop_nB.push_nB.pE_d,
879 &oneloop_nB.push_nB.pN,
880 &oneloop_nB.push_nB.pE,
881 &oneloop_nB.push_nB.vN_d,
882 &oneloop_nB.push_nB.vE_d,
883 &oneloop_nB.push_nB.vN_d_filt,
884 &oneloop_nB.push_nB.vE_d_filt,
885 &oneloop_nB.push_nB.vN,
886 &oneloop_nB.push_nB.vE,
887 &oneloop_nB.push_nB.vN_filt,
888 &oneloop_nB.push_nB.vE_filt,
889 &xi,
890 &oneloop_nB.push_nB.xi_0,
891 &oneloop_nB.push_nB.push_cmd);
892}
893#endif
894static void debug_vect(struct transport_tx *trans, struct link_device *dev, char *name, float *data, int datasize)
895{
896 pprz_msg_send_DEBUG_VECT(trans, dev, AC_ID,
897 strlen(name), name,
898 datasize, data);
899}
900static void send_oneloop_debug(struct transport_tx *trans, struct link_device *dev)
901{
902 // Spin transition manoeuvre debug vector
903 float temp_debug_vect[20];
904 temp_debug_vect[0] = (float)spin_man_state; // 0 IDLE, 1 UP_RAMP, 2 UP_BLEND, 3 DOWN_SLOW, 4 DOWN_BLEND, 5 DOWN_RAMP
905 temp_debug_vect[1] = spin_man_r_ref; // Yaw rate reference of the manoeuvre [rad/s]
906 temp_debug_vect[2] = oneloop_nB.sta_state.att_d[2]; // Filtered yaw rate (used by manoeuvre and spin protection) [rad/s]
907 temp_debug_vect[3] = LP.r.meas; // Raw yaw rate [rad/s]
908 temp_debug_vect[4] = SQ_r; // Yaw rate reference actually tracked [rad/s]
909 temp_debug_vect[5] = nu[IDX_ar]; // Yaw pseudo control
910 temp_debug_vect[6] = spin_man_alpha; // Blend factor (0 = held cmd, 1 = new source)
911 temp_debug_vect[7] = spin_man_u_hold[0]; // Held cmd at the transition, first motor of the pair
912 temp_debug_vect[8] = spin_man_u_hold[1]; // Held cmd at the transition, second motor of the pair
913 temp_debug_vect[9] = andi_u[COMMAND_MOTOR_FRONT]; // Motor commands after fault override and blend
914 temp_debug_vect[10] = andi_u[COMMAND_MOTOR_RIGHT];
915 temp_debug_vect[11] = andi_u[COMMAND_MOTOR_BACK];
916 temp_debug_vect[12] = andi_u[COMMAND_MOTOR_LEFT];
917 temp_debug_vect[13] = spin_trim; // Spin trim [pprz]
918 temp_debug_vect[14] = spin_prot_ratio; // Spin envelope ratio [0, 1]
919 temp_debug_vect[15] = (float)fault_pitch_motors + 2.0 * (float)fault_roll_motors; // 0 none, 1 pitch, 2 roll, 3 both
920 temp_debug_vect[16] = (float)spin_man_up + 2.0 * (float)spin_man_down; // Triggers: 1 up, 2 down
921 temp_debug_vect[17] = eulers_zxy.psi; // Actual heading [rad]
922 temp_debug_vect[18] = psi_des_rad; // Desired heading [rad]
923 temp_debug_vect[19] = (float)radio_control_get(RADIO_THROTTLE); // Throttle stick (static cmd = throttle - delta_fault)
924 debug_vect(trans, dev, "APF", temp_debug_vect, 20);
925 /* Previous debug vector ("APF"), kept for reference
926 float temp_debug_vect[20];
927 temp_debug_vect[0] = temp_acc_des[0]; // LP.p.meas;
928 temp_debug_vect[1] = temp_acc_des[1]; // LP.q.meas;
929 temp_debug_vect[2] = temp_acc_des[2]; // LP.r.meas;
930 temp_debug_vect[3] = LP.p_dot.meas;
931 temp_debug_vect[4] = LP.q_dot.meas;
932 temp_debug_vect[5] = LP.r_dot.meas;
933 temp_debug_vect[6] = LP.p_ddot.meas;
934 temp_debug_vect[7] = LP.q_ddot.meas;
935 temp_debug_vect[8] = LP.r_ddot.meas;
936 temp_debug_vect[9] = nB_jerk_des[0];
937 temp_debug_vect[10] = nB_jerk_des[1];
938 temp_debug_vect[11] = nB_jerk_des[2];
939 temp_debug_vect[12] = ctrl_effort_model[IDX_aD];
940 temp_debug_vect[13] = ctrl_effort_model[IDX_ap];
941 temp_debug_vect[14] = ctrl_effort_model[IDX_aq];
942 temp_debug_vect[15] = ctrl_effort_model[IDX_ar];
943 temp_debug_vect[16] = debug_state[0];
944 temp_debug_vect[17] = debug_state[1];
945 temp_debug_vect[18] = debug_state[2];
946 temp_debug_vect[19] = auto_fault_cmd;
947 debug_vect(trans, dev, "APF", temp_debug_vect, 20);
948 */
949}
950#endif
951//====================================================================================================================================
952// Functions Definition Section
953//====================================================================================================================================
954// General Mathematical Functions
959static void spin_prot_bound_params(void)
960{
961 Bound(spin_prot_min_gap, 0.1, 10.0);
962 Bound(spin_prot_max_rate, 2.0 * spin_prot_min_gap, 60.0);
965 Bound(spin_prot_max_cmd, 0.0, MAX_PPRZ);
966 Bound(spin_trim_rate, 0.0, 1000.0);
967 Bound(spin_trim_bleed_rate, 0.0, 1000.0);
968 Bound(spin_man_ramp_rate, 0.1, 10.0);
969 Bound(spin_man_blend_time, 0.1, 5.0);
970 Bound(spin_man_trim_rate, 0.0, 1000.0);
971 Bound(spin_man_done_rate, 0.1, 5.0);
973 spin_man_pitch_dir = (spin_man_pitch_dir >= 0.0) ? 1.0 : -1.0;
974}
975
976static void spin_man_reset(void)
977{
979 spin_man_up = false;
980 spin_man_down = false;
981 spin_man_alpha = 1.0;
982}
983
984static void spin_man_set_pair(uint8_t pair)
985{
986 spin_man_mot[0] = (pair == SPIN_MAN_PAIR_ROLL) ? COMMAND_MOTOR_RIGHT : COMMAND_MOTOR_FRONT;
987 spin_man_mot[1] = (pair == SPIN_MAN_PAIR_ROLL) ? COMMAND_MOTOR_LEFT : COMMAND_MOTOR_BACK;
988}
989
992static void spin_man_start_blend(void)
993{
994 float u_avg = 0.5 * (spin_man_u_last[spin_man_mot[0]] + spin_man_u_last[spin_man_mot[1]]);
995 spin_man_u_hold[0] = u_avg;
996 spin_man_u_hold[1] = u_avg;
997 spin_man_alpha = 0.0;
998}
999
1000static void spin_man_ramp_ref(float target)
1001{
1002 float step = target - spin_man_r_ref;
1003 BoundAbs(step, spin_man_ramp_rate * dt_1l);
1005}
1006
1012
1016static void spin_man_update(bool in_flight, bool nb_ctrl)
1017{
1018 if (!in_flight || !nb_ctrl)
1019 {
1021 return;
1022 }
1023 float r = oneloop_nB.sta_state.att_d[2]; // filtered yaw rate, same as the spin protection
1024 float abs_r = fabsf(r);
1025 switch (spin_man_state)
1026 {
1027 case SPIN_MAN_IDLE:
1029 {
1030 // Spin in the direction the drone naturally spins once the pair is faulted (the pairs spin opposite)
1033 spin_man_r_ref = r;
1035 }
1037 {
1040 }
1041 else
1042 {
1043 spin_man_up = false; // reject a trigger whose precondition is not met
1044 spin_man_down = false;
1045 }
1046 break;
1047 case SPIN_MAN_UP_RAMP:
1048 if (!spin_man_up)
1049 {
1050 spin_man_state = SPIN_MAN_DOWN_RAMP; // abort: bring the spin back to zero, no fault
1051 break;
1052 }
1054 if (abs_r >= spin_trim_release_rate)
1055 {
1057 {
1058 fault_roll_motors = true;
1059 }
1060 else
1061 {
1062 fault_pitch_motors = true;
1063 }
1066 }
1067 break;
1068 case SPIN_MAN_UP_BLEND:
1069 if (spin_man_alpha >= 1.0)
1070 {
1072 }
1073 break;
1074 case SPIN_MAN_DOWN_SLOW:
1076 {
1077 spin_man_reset(); // abort (or fault flags changed by hand): stay as is, the normal trim logic takes over
1078 break;
1079 }
1081 {
1082 fault_pitch_motors = false;
1083 fault_roll_motors = false;
1084 spin_man_r_ref = r; // yaw control resumes with zero rate error
1087 }
1088 break;
1090 case SPIN_MAN_DOWN_RAMP:
1091 spin_man_ramp_ref(0.0);
1093 {
1095 }
1096 else if (spin_man_state == SPIN_MAN_DOWN_RAMP && spin_man_r_ref == 0.0 && abs_r < spin_man_done_rate)
1097 {
1099 }
1100 break;
1101 }
1102 if (spin_man_alpha < 1.0)
1103 {
1105 Bound(spin_man_alpha, 0.0, 1.0);
1106 }
1107}
1108
1109static float positive_non_zero(float input)
1110{
1111 if (input < FLT_EPSILON)
1112 {
1113 input = 0.00001;
1114 }
1115 return input;
1116}
1117
1118void err_nd(float err[], float a[], float b[], float k[], int n)
1119{
1120 int8_t i;
1121 for (i = 0; i < n; i++)
1122 {
1123 err[i] = k[i] * (a[i] - b[i]);
1124 }
1125}
1126
1127void err_sum_nd(float err[], float a[], float b[], float k[], float c[], int n)
1128{
1129 int8_t i;
1130 for (i = 0; i < n; i++)
1131 {
1132 err[i] = k[i] * (a[i] - b[i]);
1133 err[i] += c[i];
1134 }
1135}
1136
1137void float_vect_diff_euler(float err[3], float a[3], float b[3])
1138{
1139 err[0] = (a[0] - b[0]);
1140 err[1] = (a[1] - b[1]);
1141 err[2] = (a[2] - b[2]);
1142 NormRadAngle(err[2]);
1143}
1144
1145void integrate_nd(float dt, float a[], float a_dot[], int n)
1146{
1147 int8_t i;
1148 for (i = 0; i < n; i++)
1149 {
1150 a[i] = a[i] + dt * a_dot[i];
1151 }
1152}
1153
1154void vect_bound_nd(float vect[], float bound, int n)
1155{
1156 float norm = float_vect_norm(vect, n);
1157 norm = positive_non_zero(norm);
1158 if ((norm - bound) > FLT_EPSILON)
1159 {
1160 float scale = bound / norm;
1161 int8_t i;
1162 for (i = 0; i < n; i++)
1163 {
1164 vect[i] *= scale;
1165 }
1166 }
1167}
1168//====================================================================================================================================
1169// Reference Model Gain Design Functions
1171static float k_rm_1_3_f(float omega_n, float zeta, float p1)
1172{
1173 omega_n = positive_non_zero(omega_n);
1174 zeta = positive_non_zero(zeta);
1175 p1 = positive_non_zero(p1);
1176 return (omega_n * omega_n * p1) / (omega_n * omega_n + omega_n * p1 * zeta * 2.0);
1177}
1178static float k_rm_2_3_f(float omega_n, float zeta, float p1)
1179{
1180 omega_n = positive_non_zero(omega_n);
1181 zeta = positive_non_zero(zeta);
1182 p1 = positive_non_zero(p1);
1183 return (omega_n * omega_n + omega_n * p1 * zeta * 2.0) / (p1 + omega_n * zeta * 2.0);
1184}
1185static float k_rm_3_3_f(float omega_n, float zeta, float p1)
1186{
1187 omega_n = positive_non_zero(omega_n);
1188 zeta = positive_non_zero(zeta);
1189 p1 = positive_non_zero(p1);
1190 return p1 + omega_n * zeta * 2.0;
1191}
1192
1193// 3-axis position PID controller
1194// static void Pos_PID(float x_des[3], float x[3],float x_dot[3], float k_P, float k_I, float k_D,float a[3])
1195// {
1196// static float prev_pos[3] = {0.0f, 0.0f, 0.0f};
1197// static float integral[3] = {0.0f, 0.0f, 0.0f};
1198// for (int i = 0; i < 3; i++)
1199// {
1200// float err = x_des[i] - x[i];
1201// integral[i] += err * dt_1l;
1202// // Optional anti-windup
1203// const float I_MAX = 0.4f;
1204// if (integral[i] > I_MAX) integral[i] = I_MAX;
1205// if (integral[i] < -I_MAX) integral[i] = -I_MAX;
1206// #ifdef USE_PID_NUMDIFF_DERIVATIVE
1207// (void) x_dot;
1208// // Numerical derivative
1209// //static float prev_err[3] = {0.0f, 0.0f, 0.0f};
1210// //float derivative = (err - prev_err[i]) / dt_1l;
1211// //prev_err[i] = err;
1212// float derivative_nd = (x[i] - prev_pos[i]) / dt_1l;
1213// prev_pos[i] = x[i];
1214// update_butterworth_2_low_pass(&KPID_vel_filt[i], derivative_nd);
1215// float derivative = -KPID_vel_filt[i].o[0];
1216// #else
1217// float derivative = -x_dot[i];
1218// #endif
1219
1220// // Temp debug
1221// temp_P_error[i] = k_P * err;
1222// temp_D_error[i] = k_D * derivative;
1223// temp_I_error[i] = k_I * integral[i];
1224// a[i] = k_P * err+ k_I * integral[i]+ k_D * derivative;
1225// }
1226// vect_bound_nd(a,0.5*9.81,3);
1227// }
1228
1229static inline bool vec3_saturated(const float u_unsat[3], const float u_sat[3], float eps)
1230{
1231 return (fabsf(u_sat[0] - u_unsat[0]) > eps) ||
1232 (fabsf(u_sat[1] - u_unsat[1]) > eps) ||
1233 (fabsf(u_sat[2] - u_unsat[2]) > eps);
1234}
1235
1236// Standalone clamping / conditional-integration ARW for a 3D command with vector saturation. [web:32][web:33]
1237static void ARW_ClampVec3(const float err[3],
1238 const float u_unsat[3],
1239 const float u_sat[3],
1240 const float I_prev[3],
1241 const float I_cand[3],
1242 float I_next[3])
1243{
1244 const float eps = 1e-6f;
1245
1246 if (!vec3_saturated(u_unsat, u_sat, eps))
1247 {
1248 I_next[0] = I_cand[0];
1249 I_next[1] = I_cand[1];
1250 I_next[2] = I_cand[2];
1251 return;
1252 }
1253
1254 const float ds0 = u_unsat[0] - u_sat[0];
1255 const float ds1 = u_unsat[1] - u_sat[1];
1256 const float ds2 = u_unsat[2] - u_sat[2];
1257
1258 // If integrating would push further into saturation, clamp (freeze). [web:32]
1259 const float dot_err_ds = err[0] * ds0 + err[1] * ds1 + err[2] * ds2;
1260
1261 if (dot_err_ds < 0.0f)
1262 {
1263 I_next[0] = I_cand[0];
1264 I_next[1] = I_cand[1];
1265 I_next[2] = I_cand[2];
1266 }
1267 else
1268 {
1269 I_next[0] = I_prev[0];
1270 I_next[1] = I_prev[1];
1271 I_next[2] = I_prev[2];
1272 }
1273}
1274
1275static void Vel_PID_ARW(float x_dot_des[3],
1276 const float x_dot[3],
1277 float k_P, float k_I, float k_D,
1278 float a_sp[3], float a_max, float v_max)
1279{
1280 static float prev_vel[3] = {0.f, 0.f, 0.f};
1281 static float integral[3] = {0.f, 0.f, 0.f};
1282
1283 // const float a_max = 0.12f * 9.81f;
1284 // const float v_max = 3.0f;//0.5f;
1285 const float I_MAX = 0.4f;
1286
1287 float err[3];
1288
1289 float I_cand[3];
1290 float I_next[3];
1291
1292 float a_unsat[3];
1293 float a_sat[3];
1294
1295 vect_bound_nd(x_dot_des, v_max, 3);
1296 // Build candidate integral and unsaturated acceleration command
1297 for (int i = 0; i < 3; i++)
1298 {
1300 err[i] = x_dot_des[i] - KPID_vel_filt[i].o[0];
1301
1302 I_cand[i] = integral[i] + err[i] * dt_1l;
1303 BoundAbs(I_cand[i], I_MAX);
1304
1305 // derivative on measurement (measured acceleration ~= d/dt(x_dot))
1306 const float vel_dot_nd = (x_dot[i] - prev_vel[i]) / dt_1l;
1308 prev_vel[i] = x_dot[i];
1309
1310 const float vel_dot_filt = KPID_filt[i].o[0];
1311
1312 // PX4-like sign: ... - D * vel_dot
1313 a_unsat[i] = k_P * err[i] + k_I * I_cand[i] - k_D * vel_dot_filt;
1314 a_sat[i] = a_unsat[i];
1315 }
1316
1317 // Apply the real saturation (vector magnitude)
1318 vect_bound_nd(a_sat, a_max, 3);
1319
1320 // Apply ARW (decide whether to accept the integral update)
1321 ARW_ClampVec3(err, a_unsat, a_sat, integral, I_cand, I_next);
1322
1323 // Commit I state and output saturated acceleration setpoint
1324 integral[0] = I_next[0];
1325 integral[1] = I_next[1];
1326 integral[2] = I_next[2];
1327
1328 a_sp[0] = a_sat[0];
1329 a_sp[1] = a_sat[1];
1330 a_sp[2] = a_sat[2];
1331}
1332
1333static void Pos_KPID_ARW(const float x_des[3],
1334 const float x[3],
1335 const float x_dot[3],
1336 float k_K, float k_P, float k_I, float k_D,
1337 float a_sp[3], float a_max, float v_max)
1338{
1339 static float prev_vel[3] = {0.f, 0.f, 0.f};
1340 static float integral[3] = {0.f, 0.f, 0.f};
1341
1342 // const float a_max = 0.12f * 9.81f;//0.05f * 9.81f;//0.12f * 9.81f; //0.5f * 9.81f;
1343 // const float v_max = 0.5f;
1344 const float I_MAX = 0.4f;
1345
1346 float v_d[3];
1347 float err[3];
1348
1349 float I_cand[3];
1350 float I_next[3];
1351
1352 float a_unsat[3];
1353 float a_sat[3];
1354
1355 // Position P -> velocity setpoint
1356 for (int i = 0; i < 3; i++)
1357 {
1358 v_d[i] = (x_des[i] - x[i]) * k_K;
1359 }
1360 vect_bound_nd(v_d, v_max, 3);
1361 // Build candidate integral and unsaturated acceleration command
1362 for (int i = 0; i < 3; i++)
1363 {
1365 err[i] = v_d[i] - KPID_vel_filt[i].o[0];
1366
1367 I_cand[i] = integral[i] + err[i] * dt_1l;
1368 BoundAbs(I_cand[i], I_MAX);
1369
1370 // derivative on measurement (measured acceleration ~= d/dt(x_dot))
1371 const float vel_dot_nd = (x_dot[i] - prev_vel[i]) / dt_1l;
1373 prev_vel[i] = x_dot[i];
1374
1375 const float vel_dot_filt = KPID_filt[i].o[0];
1376
1377 // PX4-like sign: ... - D * vel_dot
1378 a_unsat[i] = k_P * err[i] + k_I * I_cand[i] - k_D * vel_dot_filt;
1379 a_sat[i] = a_unsat[i];
1380 }
1381
1382 // Apply the real saturation (vector magnitude)
1383 vect_bound_nd(a_sat, a_max, 3);
1384
1385 // Apply ARW (decide whether to accept the integral update)
1386 ARW_ClampVec3(err, a_unsat, a_sat, integral, I_cand, I_next);
1387
1388 // Commit I state and output saturated acceleration setpoint
1389 integral[0] = I_next[0];
1390 integral[1] = I_next[1];
1391 integral[2] = I_next[2];
1392
1393 a_sp[0] = a_sat[0];
1394 a_sp[1] = a_sat[1];
1395 a_sp[2] = a_sat[2];
1396}
1397
1398static void shape_vector(float a[3])
1399{
1400 a[2] += -9.81;
1401 vect_bound_nd(a, 1.0, 3);
1402}
1403static void eul_of_acc(float a[3], float psi)
1404{
1405 float phi_des;
1406 float theta_des;
1407
1408 float spsi = sinf(psi);
1409 float cpsi = cosf(psi);
1410 float aX = cpsi * a[0] + spsi * a[1];
1411 float aY = -spsi * a[0] + cpsi * a[1];
1412 theta_des = asinf(-aX);
1413 float ctheta_des = cosf(theta_des);
1414 if (fabs(ctheta_des) < FLT_EPSILON)
1415 {
1416 ctheta_des = FLT_EPSILON;
1417 }
1418 phi_des = asinf(aY / ctheta_des);
1419 BoundAbs(phi_des, max_phi); // Limit to 30 deg
1420 BoundAbs(theta_des, max_theta); // Limit to 30 deg
1421 eulers_zxy_des.phi = phi_des;
1422 eulers_zxy_des.theta = theta_des;
1423}
1424//====================================================================================================================================
1425// Attitude Conversion Functions
1427// void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3])
1428// {
1429// float sphi = sinf(e[0]);
1430// float cphi = cosf(e[0]);
1431// float stheta = sinf(e[1]);
1432// float ctheta = cosf(e[1]);
1433// r[0] = edot[0] - stheta * edot[2];
1434// r[1] = cphi * edot[1] + sphi * ctheta * edot[2];
1435// r[2] = -sphi * edot[1] + cphi * ctheta * edot[2];
1436// }
1437
1439void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3])
1440{
1441 float sphi = sinf(e[0]);
1442 float cphi = cosf(e[0]);
1443 float stheta = sinf(e[1]);
1444 float ctheta = cosf(e[1]);
1445 r[0] = ctheta * edot[0] - stheta * cphi * edot[2];
1446 r[1] = edot[1] + sphi * edot[2];
1447 r[2] = stheta * edot[0] + ctheta * cphi * edot[2];
1448}
1449
1451// void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3])
1452// {
1453// float sphi = sinf(e[0]);
1454// float cphi = cosf(e[0]);
1455// float stheta = sinf(e[1]);
1456// float ctheta = cosf(e[1]);
1457// if (fabs(ctheta) < FLT_EPSILON)
1458// {
1459// ctheta = FLT_EPSILON;
1460// }
1461// edot[0] = r[0] + sphi * stheta / ctheta * r[1] + cphi * stheta / ctheta * r[2];
1462// edot[1] = cphi * r[1] - sphi * r[2];
1463// edot[2] = sphi / ctheta * r[1] + cphi / ctheta * r[2];
1464// }
1465
1467void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3])
1468{
1469 float sphi = sinf(e[0]);
1470 float cphi = cosf(e[0]);
1471 float stheta = sinf(e[1]);
1472 float ctheta = cosf(e[1]);
1473 float spsi = sinf(e[2]);
1474 float cpsi = cosf(e[2]);
1475
1476 if (fabs(ctheta) < FLT_EPSILON)
1477 {
1478 ctheta = FLT_EPSILON;
1479 }
1480 edot[0] = r[0] + spsi * stheta / ctheta * r[1] + cpsi * stheta / ctheta * r[2];
1481 edot[1] = cphi * r[1] - sphi * r[2];
1482 edot[2] = sphi * r[1] + cphi * r[2];
1483}
1484//====================================================================================================================================
1485// Bounding Functions
1487void acc_body_bound(struct FloatVect2 *vect, float bound)
1488{
1489 int n = 2;
1490 float v[2] = {vect->x, vect->y};
1491 float sign_v0 = (v[0] > 0.f) ? 1.f : (v[0] < 0.f) ? -1.f
1492 : 0.f;
1493 float sign_v1 = (v[1] > 0.f) ? 1.f : (v[1] < 0.f) ? -1.f
1494 : 0.f;
1495 float norm = float_vect_norm(v, n);
1496 v[0] = fabsf(v[0]);
1497 v[1] = fabsf(v[1]);
1498 norm = positive_non_zero(norm);
1499 if ((norm - bound) > FLT_EPSILON)
1500 {
1501 v[0] = Min(v[0], bound);
1502 float acc_b_y_2 = bound * bound - v[0] * v[0];
1503 acc_b_y_2 = positive_non_zero(acc_b_y_2);
1504 v[1] = sqrtf(acc_b_y_2);
1505 }
1506 vect->x = sign_v0 * v[0];
1507 vect->y = sign_v1 * v[1];
1508}
1509
1518float bound_v_from_a_vect(float e_x[], float v_bound, float a_bound, int n)
1519{
1520 float norm = float_vect_norm(e_x, n);
1521 norm = fmaxf(norm, 1.0);
1522 float v_bound_a = sqrtf(fabs(2.0 * a_bound * norm * xdot_lim_sf));
1523 return fminf(v_bound, v_bound_a);
1524}
1525
1534float bound_v_from_a(float e_x, float v_bound, float a_bound)
1535{
1536 float norm;
1537 norm = fabsf(e_x);
1538 // norm = fmaxf(norm, 1.0);
1539 float v_bound_a = sqrtf(fabs(2.0 * a_bound * norm * xdot_lim_sf));
1540 return fminf(v_bound, v_bound_a);
1541}
1542//====================================================================================================================================
1543// Reference Model Functions
1559void rm_3rd_attitude(float dt, float x_ref[3], float x_d_ref[3], float x_2d_ref[3], float x_3d_ref[3], float x_des[3], bool ow_psi, float psi_overwrite[4], float k1_rm[3], float k2_rm[3], float k3_rm[3], struct OneloopStabilizationRef bounds)
1560{
1561
1562 float e_x[3]; // Attitude Error
1563 float x_d_fw[3]; // Forward Signal Euler Dot
1564 float x_d_fw_rates[3]; // Forward Signal Angular Rates
1565 float x_2d_fw[3]; // Forward Signal Angular Acceleration
1566 float x_3d_fw[3]; // Forward Signal Angular Jerk
1567 float bounds_att_d[3]; // Bounds on Angular Rate (SUVAT based)
1568 float x_d_eul_ref[3]; // Euler angle Reference
1569 // Attitude error --------------------------------------------------------------------------------------------------
1570 float_vect_diff_euler(e_x, x_des, x_ref); // Calculate Attitude Error
1571 x_d_fw[0] = e_x[0] * k1_rm[0]; // Calculate Forward Signal Euler Dot
1572 x_d_fw[1] = e_x[1] * k1_rm[1]; // Calculate Forward Signal Euler Dot
1573 x_d_fw[2] = e_x[2] * k1_rm[2]; // Calculate Forward Signal Euler Dot
1574 float_rates_of_euler_dot_vec(x_d_fw_rates, x_ref, x_d_fw); // Convert Euler Dot to Angular Rates
1575 bounds_att_d[0] = bound_v_from_a(e_x[0], bounds.att_d[0], bounds.att_2d[0]);
1576 bounds_att_d[1] = bound_v_from_a(e_x[1], bounds.att_d[1], bounds.att_2d[1]);
1577 bounds_att_d[2] = bound_v_from_a(e_x[2], bounds.att_d[2], bounds.att_2d[2]);
1578 BoundAbs(x_d_fw_rates[0], bounds_att_d[0]);
1579 BoundAbs(x_d_fw_rates[1], bounds_att_d[1]);
1580 BoundAbs(x_d_fw_rates[2], bounds_att_d[2]);
1581 // Angular Rate error ----------------------------------------------------------------------------------------------
1582 err_nd(x_2d_fw, x_d_fw_rates, x_d_ref, k2_rm, 3);
1583 BoundAbs(x_2d_fw[0], bounds.att_2d[0]);
1584 BoundAbs(x_2d_fw[1], bounds.att_2d[1]);
1585 BoundAbs(x_2d_fw[2], bounds.att_2d[2]);
1586 // Angular Acceleration error -----------------------------------------
1587 err_nd(x_3d_fw, x_2d_fw, x_2d_ref, k3_rm, 3);
1588 BoundAbs(x_3d_fw[0], bounds.att_3d[0]);
1589 BoundAbs(x_3d_fw[1], bounds.att_3d[1]);
1590 BoundAbs(x_3d_fw[2], bounds.att_3d[2]);
1591 // Angular Jerk Reference ---------------------------------------------
1592 float_vect_copy(x_3d_ref, x_3d_fw, 3);
1593 if (ow_psi)
1594 {
1595 x_3d_ref[2] = psi_overwrite[3];
1596 }
1597 // Angular Acceleration Reference -------------------------------------
1598 integrate_nd(dt, x_2d_ref, x_3d_ref, 3);
1599 if (ow_psi)
1600 {
1601 x_2d_ref[2] = psi_overwrite[2];
1602 }
1603 // Angular Rate Reference ---------------------------------------------
1604 integrate_nd(dt, x_d_ref, x_2d_ref, 3);
1605 if (ow_psi)
1606 {
1607 x_d_ref[2] = psi_overwrite[1];
1608 }
1609 // Attitude Reference ------------------------------------------------
1610 float_euler_dot_of_rates_vec(x_d_ref, x_ref, x_d_eul_ref);
1611 integrate_nd(dt, x_ref, x_d_eul_ref, 3);
1612 if (ow_psi)
1613 {
1614 x_ref[2] = psi_overwrite[0];
1615 }
1616 NormRadAngle(x_ref[2]);
1617}
1618
1635void rm_3rd_pos(float dt, float x_ref[], float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x_des[], float k1_rm[], float k2_rm[], float k3_rm[], float x_d_bound, float x_2d_bound, float x_3d_bound, int n)
1636{
1637 float e_x[n];
1638 float e_x_d[n];
1639 float e_x_2d[n];
1640 err_nd(e_x, x_des, x_ref, k1_rm, n);
1641 float max_x_d = bound_v_from_a_vect(e_x, x_d_bound, x_2d_bound, n);
1642 vect_bound_nd(e_x, max_x_d, n);
1643 err_nd(e_x_d, e_x, x_d_ref, k2_rm, n);
1644 vect_bound_nd(e_x_d, x_2d_bound, n);
1645 err_nd(e_x_2d, e_x_d, x_2d_ref, k3_rm, n);
1646 float_vect_copy(x_3d_ref, e_x_2d, n);
1647 vect_bound_nd(x_3d_ref, x_3d_bound, n);
1648 integrate_nd(dt, x_2d_ref, x_3d_ref, n);
1649 integrate_nd(dt, x_d_ref, x_2d_ref, n);
1650 integrate_nd(dt, x_ref, x_d_ref, n);
1651}
1652
1666void rm_2nd_pos(float dt, float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x_d_des[], float k2_rm[], float k3_rm[], float x_2d_bound, float x_3d_bound, int n)
1667{
1668 float e_x_d[n];
1669 float e_x_2d[n];
1670 err_nd(e_x_d, x_d_des, x_d_ref, k2_rm, n);
1671 vect_bound_nd(e_x_d, x_2d_bound, n);
1672 err_nd(e_x_2d, e_x_d, x_2d_ref, k3_rm, n);
1673 float_vect_copy(x_3d_ref, e_x_2d, n);
1674 vect_bound_nd(x_3d_ref, x_3d_bound, n);
1675 integrate_nd(dt, x_2d_ref, x_3d_ref, n);
1676 integrate_nd(dt, x_d_ref, x_2d_ref, n);
1677}
1678
1689void rm_1st_pos(float dt, float x_2d_ref[], float x_3d_ref[], float x_2d_des[], float k3_rm[], float x_3d_bound, int n)
1690{
1691 float e_x_2d[n];
1692 err_nd(e_x_2d, x_2d_des, x_2d_ref, k3_rm, n);
1693 float_vect_copy(x_3d_ref, e_x_2d, n);
1694 vect_bound_nd(x_3d_ref, x_3d_bound, n);
1695 integrate_nd(dt, x_2d_ref, x_3d_ref, n);
1696}
1697//====================================================================================================================================
1698// Error Controller Functions
1714void ec_3rd_pos(float y_4d[], float x_des[], float x_ref[], float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x[], float x_d[], float x_2d[], float k1_e[], float k2_e[], float k3_e[], float x_d_bound, float x_2d_bound, float fb[], int n)
1715{
1716 float e_x_d[n];
1717 float e_x_2d[n];
1718 float e_x_des[n];
1719 float_vect_diff(e_x_des, x_des, x, n);
1720 float max_x_d = bound_v_from_a_vect(e_x_des, x_d_bound * ec_headroom, x_2d_bound * ec_headroom, n);
1721 err_sum_nd(e_x_d, x_ref, x, k1_e, x_d_ref, n);
1722 vect_bound_nd(e_x_d, max_x_d, n);
1723 err_sum_nd(e_x_2d, e_x_d, x_d, k2_e, x_2d_ref, n);
1724 vect_bound_nd(e_x_2d, x_2d_bound * ec_headroom, n);
1725 // Calculate and bound distrubance --------------------
1726 float dist[3];
1727 float_vect_diff(dist, x_2d, fb, 3);
1728 err_sum_nd(y_4d, e_x_2d, dist, k3_e, x_3d_ref, n);
1729}
1730
1746void ec_3rd_att(float y_4d[3], float x_des[3], float x_ref[3], float x_d_ref[3], float x_2d_ref[3], float x_3d_ref[3], float x[3], float x_d[3], float x_2d[3], float k1_e[3], float k2_e[3], float k3_e[3], struct OneloopStabilizationRef bounds, float fb[3])
1747{
1748 float e_x[3]; // Attitude Error on Reference
1749 float e_x_des[3]; // Attitude Error on Desired
1750 float x_d_fw[3]; // Forward Signal Euler Dot
1751 float x_d_fw_rates[3]; // Forward Signal Angular Rates
1752 float x_d_fw_rates_rm[3]; // Forward Signal Angular Rates plus RM
1753 float x_2d_fw[3]; // Forward Signal Angular Acceleration
1754 float bounds_att_d[3];
1755 // Attitude Error and Heading conversion --------------------------------
1756 float_vect_diff_euler(e_x, x_ref, x); // Calculate the Attitude Error
1757 x_d_fw[0] = e_x[0] * k1_e[0]; // Calculate Forward Signal Euler Dot
1758 x_d_fw[1] = e_x[1] * k1_e[1]; // Calculate Forward Signal Euler Dot
1759 x_d_fw[2] = e_x[2] * k1_e[2]; // Calculate Forward Signal Euler Dot
1760 float_rates_of_euler_dot_vec(x_d_fw_rates, x, x_d_fw); // Euler dot to rates conversion
1761 float_vect_sum(x_d_fw_rates_rm, x_d_ref, x_d_fw_rates, 3); // Add body rates reference signal
1762 float_vect_diff_euler(e_x_des, x_des, x);
1763 bounds_att_d[0] = bound_v_from_a(e_x_des[0], bounds.att_d[0] * ec_headroom, bounds.att_2d[0] * ec_headroom);
1764 bounds_att_d[1] = bound_v_from_a(e_x_des[1], bounds.att_d[1] * ec_headroom, bounds.att_2d[1] * ec_headroom);
1765 bounds_att_d[2] = bound_v_from_a(e_x_des[2], bounds.att_d[2] * ec_headroom, bounds.att_2d[2] * ec_headroom);
1766 BoundAbs(x_d_fw_rates_rm[0], bounds_att_d[0]);
1767 BoundAbs(x_d_fw_rates_rm[1], bounds_att_d[1]);
1768 BoundAbs(x_d_fw_rates_rm[2], bounds_att_d[2]);
1769 // Angular Rate Error ---------------------------------------------------
1770 x_2d_fw[0] = (x_d_fw_rates_rm[0] - x_d[0]) * k2_e[0] + x_2d_ref[0];
1771 x_2d_fw[1] = (x_d_fw_rates_rm[1] - x_d[1]) * k2_e[1] + x_2d_ref[1];
1772 x_2d_fw[2] = (x_d_fw_rates_rm[2] - x_d[2]) * k2_e[2] + x_2d_ref[2];
1773 BoundAbs(x_2d_fw[0], bounds.att_2d[0] * ec_headroom);
1774 BoundAbs(x_2d_fw[1], bounds.att_2d[1] * ec_headroom);
1775 BoundAbs(x_2d_fw[2], bounds.att_2d[2] * ec_headroom);
1776 // Calculate and bound distrubance --------------------------------------
1777 float dist[3];
1778 float fb_k3[3]; // local copy: fb is an input and is reused by the caller (nB_EC), do not modify it
1779 fb_k3[0] = fb[0] / k3_e[0];
1780 fb_k3[1] = fb[1] / k3_e[1];
1781 fb_k3[2] = fb[2] / k3_e[2];
1782 float_vect_diff(dist, x_2d, fb_k3, 3); // The Disturbance is THe difference between the measurment and the Model
1783 // Here we can bound the disturbance to avoid too large control efforts
1784 // Example MAX YAW CONTROL EFFORT: BoundAbs(dist[2], oneloop_nB_yaw_dist_limit);
1785 // Angular Acceleration Error -------------------------------------------
1786 err_sum_nd(y_4d, x_2d_fw, dist, k3_e, x_3d_ref, 3);
1787}
1788
1796static float ec_poles(float p_rm, float slow_pole, float k)
1797{
1798 p_rm = positive_non_zero(p_rm);
1800 k = positive_non_zero(k);
1801 // float omega_n = (2*p_rm*slow_pole*k)/(3*slow_pole-p_rm);
1802 float omega_n = (2 * k * p_rm * slow_pole) / (3 * slow_pole - k * p_rm);
1803 return omega_n;
1804}
1805
1811{
1812 p_att_e.omega_n = ec_poles(p_att_rm.omega_n, slow_pole, 1.28); // k = 1.28;
1813 p_head_e.omega_n = ec_poles(p_head_rm.omega_n, slow_pole, 1.28); // k = 1.28;
1814}
1816{
1817 p_pos_e.omega_n = ec_poles(p_pos_rm.omega_n, slow_pole / 3.0, 1.28); // k = 1.28; 1.0;
1818 p_alt_e.omega_n = ec_poles(p_alt_rm.omega_n, slow_pole / 3.0, 1.28); // k = 1.28; 1.0;// 3.0
1819}
1820
1825void init_poles(void)
1826{
1827
1828 // Attitude Controller Poles----------------------------------------------------------
1829 p_att_e.omega_n = slow_pole / 3.0;
1830 p_att_e.zeta = 1.0;
1831 p_att_e.p3 = p_att_e.omega_n;
1832
1833 p_roll_e.omega_n = slow_pole / 3.0;
1834 p_roll_e.zeta = 1.0;
1835 p_roll_e.p3 = p_roll_e.omega_n;
1836
1837 p_att_rm.omega_n = p_att_e.omega_n * 0.8;
1838 p_att_rm.zeta = 1.0;
1839 p_att_rm.p3 = p_att_rm.omega_n;
1840
1841 p_head_e.omega_n = slow_pole / 3.0;
1842 p_head_e.zeta = 1.0;
1843 p_head_e.p3 = p_head_e.omega_n;
1844
1845 p_head_rm.omega_n = p_head_e.omega_n * 0.8;
1846 p_head_rm.zeta = 1.0;
1847 p_head_rm.p3 = p_head_rm.omega_n;
1848
1849 // Position Controller Poles----------------------------------------------------------
1850
1851 p_pos_e.omega_n = 1.19; // slow_pole/3.0;
1852 p_pos_e.zeta = 0.5;
1853 p_pos_e.p3 = p_pos_e.omega_n;
1854
1855 p_pos_rm.omega_n = p_pos_e.omega_n * 0.8;
1856 p_pos_rm.zeta = 0.5;
1857 p_pos_rm.p3 = p_pos_rm.omega_n;
1858
1859 p_alt_e.omega_n = 1.19; // slow_pole/3.0*2.0;
1860 p_alt_e.zeta = 0.5;
1861 p_alt_e.p3 = p_alt_e.omega_n;
1862
1863 p_alt_rm.omega_n = p_alt_e.omega_n * 0.8;
1864 p_alt_rm.zeta = 0.5;
1865 p_alt_rm.p3 = p_alt_rm.omega_n;
1866}
1867
1873{
1874 /*Register a variable from nav_hybrid. Should be improved when nav hybrid is final.*/
1875 float max_wind = 20.0;
1876 max_v_nav = nav_max_speed + max_wind;
1878 /*Some calculations in case new poles have been specified*/
1879 // init_poles_att();
1880 // init_poles_pos();
1881 p_att_rm.p3 = p_att_rm.omega_n * p_att_rm.zeta;
1882 p_pos_rm.p3 = p_pos_rm.omega_n * p_pos_rm.zeta;
1883 p_alt_rm.p3 = p_alt_rm.omega_n * p_alt_rm.zeta;
1884 p_head_rm.p3 = p_head_rm.omega_n * p_head_rm.zeta;
1885
1886 //--ANDI Controller gains --------------------------------------------------------------------------------
1887 /*Attitude Loop*/
1888 k_att_e.k1[0] = k_rm_1_3_f(p_roll_e.omega_n, p_roll_e.zeta, p_roll_e.p3); // k_rm_1_3_f(p_att_e.omega_n, p_att_e.zeta, p_att_e.p3);
1889 k_att_e.k2[0] = k_rm_2_3_f(p_roll_e.omega_n, p_roll_e.zeta, p_roll_e.p3); // k_rm_2_3_f(p_att_e.omega_n, p_att_e.zeta, p_att_e.p3);
1890 k_att_e.k3[0] = k_rm_3_3_f(p_roll_e.omega_n, p_roll_e.zeta, p_roll_e.p3); // k_rm_3_3_f(p_att_e.omega_n, p_att_e.zeta, p_att_e.p3);
1891
1892 k_att_e.k1[1] = k_rm_1_3_f(p_att_e.omega_n, p_att_e.zeta, p_att_e.p3); // k_att_e.k1[0];
1893 k_att_e.k2[1] = k_rm_2_3_f(p_att_e.omega_n, p_att_e.zeta, p_att_e.p3); // k_att_e.k2[0];
1894 k_att_e.k3[1] = k_rm_3_3_f(p_att_e.omega_n, p_att_e.zeta, p_att_e.p3); // k_att_e.k3[0];
1895
1896 k_att_rm.k1[0] = k_rm_1_3_f(p_att_rm.omega_n, p_att_rm.zeta, p_att_rm.p3);
1897 k_att_rm.k2[0] = k_rm_2_3_f(p_att_rm.omega_n, p_att_rm.zeta, p_att_rm.p3);
1898 k_att_rm.k3[0] = k_rm_3_3_f(p_att_rm.omega_n, p_att_rm.zeta, p_att_rm.p3);
1899 k_att_rm.k1[1] = k_att_rm.k1[0];
1900 k_att_rm.k2[1] = k_att_rm.k2[0];
1901 k_att_rm.k3[1] = k_att_rm.k3[0];
1902
1903 /*Heading Loop NAV*/
1904 k_att_e.k1[2] = k_rm_1_3_f(p_head_e.omega_n, p_head_e.zeta, p_head_e.p3);
1905 k_att_e.k2[2] = k_rm_2_3_f(p_head_e.omega_n, p_head_e.zeta, p_head_e.p3);
1906 k_att_e.k3[2] = k_rm_3_3_f(p_head_e.omega_n, p_head_e.zeta, p_head_e.p3);
1907
1908 k_att_rm.k1[2] = k_rm_1_3_f(p_head_rm.omega_n, p_head_rm.zeta, p_head_rm.p3);
1909 k_att_rm.k2[2] = k_rm_2_3_f(p_head_rm.omega_n, p_head_rm.zeta, p_head_rm.p3);
1910 k_att_rm.k3[2] = k_rm_3_3_f(p_head_rm.omega_n, p_head_rm.zeta, p_head_rm.p3);
1911
1912 // Temporary overrirde of gains
1913 // The third gain equals the actuator dynamics of the hover motors, set per airframe (ONELOOP_NB_EC_K3)
1914 Bound(ec_k3, 1.0, 100.0);
1915 k_att_e.k1[0] = 4.19;
1916 k_att_e.k2[0] = 10.01;
1917 k_att_e.k3[0] = ec_k3;
1918 k_att_e.k1[1] = k_att_e.k1[0];
1919 k_att_e.k2[1] = k_att_e.k2[0];
1920 k_att_e.k3[1] = k_att_e.k3[0];
1921
1922 // k_att_rm.k1[0] = 4.19;
1923 // k_att_rm.k2[0] = 10.01;
1924 // k_att_rm.k3[0] = 22.0;
1925 //
1926 // k_pos_e.k1[0] = 0.6539;
1927 // k_pos_e.k2[0] = 1.795;
1928 // k_pos_e.k3[0] = XXX;
1929
1930 // Print INNERLOOP ANDI controller gains
1931 // printf("Attitude RM poles, omega_n: %f, zeta: %f, p3: %f\n", p_att_rm.omega_n, p_att_rm.zeta, p_att_rm.p3);
1932 // printf("Attitude EC poles, omega_n: %f, zeta: %f, p3: %f\n", p_att_e.omega_n, p_att_e.zeta, p_att_e.p3);
1933 // printf("Heading RM poles, omega_n: %f, zeta: %f, p3: %f\n", p_head_rm.omega_n, p_head_rm.zeta, p_head_rm.p3);
1934 // printf("Heading EC poles, omega_n: %f, zeta: %f, p3: %f\n", p_head_e.omega_n, p_head_e.zeta, p_head_e.p3);
1935 // printf("ANDI Attitude RM Gains: %f %f %f\n", k_att_rm.k1[0], k_att_rm.k2[0], k_att_rm.k3[0]);
1936 // printf("ANDI Attitude EC Gains: %f %f %f\n", k_att_e.k1[0], k_att_e.k2[0], k_att_e.k3[0]);
1937 // printf("ANDI Heading RM Gains: %f %f %f\n", k_att_rm.k1[2], k_att_rm.k2[2], k_att_rm.k3[2]);
1938 // printf("ANDI Heading EC Gains: %f %f %f\n", k_att_e.k1[2], k_att_e.k2[2], k_att_e.k3[2]);
1939
1940 /*Position Loop*/
1941 k_pos_e.k1[0] = k1_NE_tune; // k_rm_1_3_f(p_pos_e.omega_n, p_pos_e.zeta, p_pos_e.p3); // 0.595;//
1942 k_pos_e.k2[0] = k2_NE_tune; // k_rm_2_3_f(p_pos_e.omega_n, p_pos_e.zeta, p_pos_e.p3); // 1.190;//
1943 k_pos_e.k3[0] = k_rm_3_3_f(p_pos_e.omega_n, p_pos_e.zeta, p_pos_e.p3); // 2.380;//
1944 k_pos_e.k1[1] = k_pos_e.k1[0];
1945 k_pos_e.k2[1] = k_pos_e.k2[0];
1946 k_pos_e.k3[1] = k_pos_e.k3[0];
1947
1948 k_pos_rm.k1[0] = k_rm_1_3_f(p_pos_rm.omega_n, p_pos_rm.zeta, p_pos_rm.p3); // 0.595;
1949 k_pos_rm.k2[0] = k_rm_2_3_f(p_pos_rm.omega_n, p_pos_rm.zeta, p_pos_rm.p3); // 1.190;
1950 k_pos_rm.k3[0] = k_rm_3_3_f(p_pos_rm.omega_n, p_pos_rm.zeta, p_pos_rm.p3); // 2.380;
1951 k_pos_rm.k1[1] = k_pos_rm.k1[0];
1952 k_pos_rm.k2[1] = k_pos_rm.k2[0];
1953 k_pos_rm.k3[1] = k_pos_rm.k3[0];
1956
1957 /*Altitude Loop*/
1958 k_pos_e.k1[2] = k_rm_1_3_f(p_alt_e.omega_n, p_alt_e.zeta, p_alt_e.p3); // 0.595;
1959 k_pos_e.k2[2] = k_rm_2_3_f(p_alt_e.omega_n, p_alt_e.zeta, p_alt_e.p3); // 1.190;
1960 k_pos_e.k3[2] = ec_k3; // k_rm_3_3_f(p_alt_e.omega_n, p_alt_e.zeta, p_alt_e.p3); //2.380;
1961
1962 k_pos_rm.k1[2] = k_rm_1_3_f(p_alt_rm.omega_n, p_alt_rm.zeta, p_alt_rm.p3); // 0.595;
1963 k_pos_rm.k2[2] = k_rm_2_3_f(p_alt_rm.omega_n, p_alt_rm.zeta, p_alt_rm.p3); // 1.190;
1964 k_pos_rm.k3[2] = k_rm_3_3_f(p_alt_rm.omega_n, p_alt_rm.zeta, p_alt_rm.p3); // 2.380;
1965
1966 // Print OUTERLOOP ANDI controller gains
1967 // printf("Position NE RM poles, omega_n: %f, zeta: %f, p3: %f\n", p_pos_rm.omega_n, p_pos_rm.zeta, p_pos_rm.p3);
1968 // printf("Position NE EC poles, omega_n: %f, zeta: %f, p3: %f\n", p_pos_e.omega_n, p_pos_e.zeta, p_pos_e.p3);
1969 // printf("Position D RM poles, omega_n: %f, zeta: %f, p3: %f\n", p_alt_rm.omega_n, p_alt_rm.zeta, p_alt_rm.p3);
1970 // printf("Position D EC poles, omega_n: %f, zeta: %f, p3: %f\n", p_alt_e.omega_n, p_alt_e.zeta, p_alt_e.p3);
1971 // printf("Position N RM Gains: %f %f %f\n", k_pos_rm.k1[0], k_pos_rm.k2[0], k_pos_rm.k3[0]);
1972 // printf("Position N EC Gains: %f %f %f\n", k_pos_e.k1[0], k_pos_e.k2[0], k_pos_e.k3[0]);
1973 // printf("Position D RM Gains: %f %f %f\n", k_pos_rm.k1[2], k_pos_rm.k2[2], k_pos_rm.k3[2]);
1974 // printf("Position D EC Gains: %f %f %f\n", k_pos_e.k1[2], k_pos_e.k2[2], k_pos_e.k3[2]);
1975 //--INDI Controller gains --------------------------------------------------------------------------------
1976 /*Attitude Loop*/
1977 k_att_e_indi.k1[0] = k_att_e.k1[0];
1978 k_att_e_indi.k2[0] = k_att_e.k2[0];
1979 k_att_e_indi.k3[0] = 1.0;
1980 k_att_e_indi.k1[1] = k_att_e_indi.k1[0];
1981 k_att_e_indi.k2[1] = k_att_e_indi.k2[0];
1982 k_att_e_indi.k3[1] = k_att_e_indi.k3[0];
1983
1984 /*Heading Loop NAV*/
1985 k_att_e_indi.k1[2] = k_att_e.k1[2];
1986 k_att_e_indi.k2[2] = k_att_e.k2[2];
1987 k_att_e_indi.k3[2] = 1.0;
1988
1989 // Print INDI INNERLOOP controller gains
1990 // printf("INDI Attitude EC gains: %f %f %f\n", k_att_e_indi.k1[0], k_att_e_indi.k2[0], k_att_e_indi.k3[0]);
1991 // printf("INDI Heading EC gains: %f %f %f\n", k_att_e_indi.k1[2], k_att_e_indi.k2[2], k_att_e_indi.k3[2]);
1992
1993 /*Position Loop*/
1994 k_pos_e_indi.k1[0] = k_pos_e.k1[0];
1995 k_pos_e_indi.k2[0] = k_pos_e.k2[0];
1996 k_pos_e_indi.k3[0] = 1.0;
1997 k_pos_e_indi.k1[1] = k_pos_e_indi.k1[0];
1998 k_pos_e_indi.k2[1] = k_pos_e_indi.k2[0];
1999 k_pos_e_indi.k3[1] = k_pos_e_indi.k3[0];
2000
2001 /*Altitude Loop*/
2002 k_pos_e_indi.k1[2] = k_pos_e.k1[2];
2003 k_pos_e_indi.k2[2] = k_pos_e.k2[2];
2004 k_pos_e_indi.k3[2] = 1.0;
2005
2006 // Print INDI OUTERLOOP controller gains
2007 // printf("INDI Position NE EC gains: %f %f %f\n", k_pos_e_indi.k1[0], k_pos_e_indi.k2[0], k_pos_e_indi.k3[0]);
2008 // printf("INDI Position D EC gains: %f %f %f\n", k_pos_e_indi.k1[2], k_pos_e_indi.k2[2], k_pos_e_indi.k3[2]);
2009
2010 //------------------------------------------------------------------------------------------
2011}
2012// -----------------------------------------------------------------------------------------
2013// Filter Functions ------------------------------------------------------------------------
2014// -----------------------------------------------------------------------------------------
2015
2017static inline void init_filter_on_type(struct LP_t *filter, float x0)
2018{
2019 switch (filter->filter_type)
2020 {
2021 case LOWPASS_1:
2022 init_first_order_low_pass(&filter->meas_filt.lp1, filter->tau, 1.0 / PERIODIC_FREQUENCY, x0);
2023 break;
2024 case BUTTERWORTH_2:
2025 init_butterworth_2_low_pass(&filter->meas_filt.bw2, filter->tau, 1.0 / PERIODIC_FREQUENCY, x0);
2026 break;
2027 case BUTTERWORTH_4:
2028 init_butterworth_4_low_pass(&filter->meas_filt.bw4, filter->tau, 1.0 / PERIODIC_FREQUENCY, x0);
2029 break;
2030 case NOTCH:
2031 notch_filter_init(&filter->meas_filt.notch, filter->freq, filter->bandwidth, PERIODIC_FREQUENCY);
2032 break;
2033 default:
2034 // Handle unexpected filter type
2035 break;
2036 }
2037}
2038
2039static inline void update_filter_on_type(struct LP_t *filter, float input)
2040{
2041 // filter->meas_prev = filter->meas;
2042 // filter->meas = input;
2043 switch (filter->filter_type)
2044 {
2045 case LOWPASS_1:
2046 update_first_order_low_pass(&filter->meas_filt.lp1, input);
2047 filter->out = filter->meas_filt.lp1.last_out;
2048 break;
2049 case BUTTERWORTH_2:
2050 update_butterworth_2_low_pass(&filter->meas_filt.bw2, input);
2051 filter->out = filter->meas_filt.bw2.o[0];
2052 break;
2053 case BUTTERWORTH_4:
2054 update_butterworth_4_low_pass(&filter->meas_filt.bw4, input);
2055 filter->out = filter->meas_filt.bw4.lp2.o[0];
2056 break;
2057 case NOTCH:
2058 {
2059 notch_filter_update(&filter->meas_filt.notch, &input, &filter->out);
2060 break;
2061 }
2062 default:
2063 filter->out = 0.0;
2064 break;
2065 // Handle unexpected filter type
2066 }
2067}
2068
2069static inline void init_LP(struct LP_t *LP, float fc)
2070{
2071 LP->freq = fc;
2072 LP->freq_set = fc;
2073 LP->tau = 1 / (2 * M_PI * LP->freq);
2074#ifdef USE_LP1
2075 LP->filter_type = LOWPASS_1;
2076#elif defined(USE_BW2)
2077 LP->filter_type = BUTTERWORTH_2;
2078#elif defined(USE_YAW_LP4)
2079 LP->filter_type = BUTTERWORTH_4;
2080#endif
2081 init_filter_on_type(LP, 0.0);
2082 // init_first_order_low_pass(&LP->meas_filt, LP->tau, 1.0 / PERIODIC_FREQUENCY, 0.0);
2083 LP->meas = 0.0;
2084 LP->meas_prev = 0.0;
2085 LP->out = 0.0;
2086}
2087
2088static inline void reinit_LP_synchronous(struct LP_t *LP, struct LP_t *f, bool reinit)
2089{
2090 if (LP->freq != LP->freq_set || reinit)
2091 {
2092 LP->freq = LP->freq_set;
2093 LP->tau = 1 / (2 * M_PI * LP->freq);
2094 init_filter_on_type(LP, LP->out);
2095 init_filter_on_type(f, f->out);
2096 }
2097}
2098static inline void reinit_LP(struct LP_t *LP, bool reinit)
2099{
2100 if (LP->freq != LP->freq_set || reinit)
2101 {
2102 LP->freq = LP->freq_set;
2103 LP->tau = 1 / (2 * M_PI * LP->freq);
2104 init_filter_on_type(LP, LP->out);
2105 }
2106}
2107
2109static inline void init_all_LP(void)
2110{
2120 init_LP(&LP.p, 15.0); // oneloop_nB_filt_cutoff_p
2121 init_LP(&LP.q, 15.0); // oneloop_nB_filt_cutoff_q
2122 init_LP(&LP.r, 15.0); // oneloop_nB_filt_cutoff_r
2123}
2124
2126static inline void reinit_all_LP(bool reinit)
2127{
2128 // reinit_LP_synchronous(&LP.ax, &ctrl_effort_model_filt.ax, reinit);
2129 // reinit_LP_synchronous(&LP.ay, &ctrl_effort_model_filt.ay, reinit);
2130 // reinit_LP_synchronous(&LP.az, &ctrl_effort_model_filt.az, reinit);
2131 // reinit_LP_synchronous(&LP.p_dot, &ctrl_effort_model_filt.p_dot, reinit);
2132 // reinit_LP_synchronous(&LP.q_dot, &ctrl_effort_model_filt.q_dot, reinit);
2133 // reinit_LP_synchronous(&LP.r_dot, &ctrl_effort_model_filt.r_dot, reinit);
2134 reinit_LP(&LP.p, reinit);
2135 reinit_LP(&LP.q, reinit);
2136 reinit_LP(&LP.r, reinit);
2137 LP.p_dot.freq_set = oneloop_nB_filt_cutoff;
2138 LP.q_dot.freq_set = oneloop_nB_filt_cutoff;
2139 LP.r_dot.freq_set = oneloop_nB_filt_cutoff;
2140 LP.p_ddot.freq_set = oneloop_nB_filt_cutoff;
2141 LP.q_ddot.freq_set = oneloop_nB_filt_cutoff;
2142 LP.r_ddot.freq_set = oneloop_nB_filt_cutoff;
2143 LP.ax.freq_set = oneloop_nB_filt_cutoff;
2144 LP.ay.freq_set = oneloop_nB_filt_cutoff;
2145 LP.az.freq_set = oneloop_nB_filt_cutoff;
2146 bool reinit_other = ((LP.p_dot.freq != LP.p_dot.freq_set) || reinit);
2147 reinit_LP(&LP.p_dot, reinit);
2148 reinit_LP(&LP.q_dot, reinit);
2149 reinit_LP(&LP.r_dot, reinit);
2150 reinit_LP(&LP.p_ddot, reinit);
2151 reinit_LP(&LP.q_ddot, reinit);
2152 reinit_LP(&LP.r_ddot, reinit);
2153 reinit_LP(&LP.ax, reinit);
2154 reinit_LP(&LP.ay, reinit);
2155 reinit_LP(&LP.az, reinit);
2156 if (reinit_other)
2157 {
2158 float tau = 1.0 / (2.0 * M_PI * oneloop_nB_filt_cutoff);
2159 for (int i = 0; i < ANDI_NUM_ACT_TOT; i++)
2160 {
2161 init_butterworth_2_low_pass(&u_filt[i], tau, 1.0 / PERIODIC_FREQUENCY, u_filt[i].o[0]);
2162 }
2163 for (int i = 0; i < 3; i++)
2164 {
2165 init_butterworth_2_low_pass(&nB_filt[i], tau, 1.0 / PERIODIC_FREQUENCY, nB_filt[i].o[0]);
2166 init_butterworth_2_low_pass(&nB_2d_filt[i], tau, 1.0 / PERIODIC_FREQUENCY, nB_2d_filt[i].o[0]);
2167 }
2168 init_butterworth_2_low_pass(&nB_3d_state_filt[0], tau, 1.0 / PERIODIC_FREQUENCY, state_term[0]);
2169 init_butterworth_2_low_pass(&nB_3d_state_filt[1], tau, 1.0 / PERIODIC_FREQUENCY, state_term[1]);
2170 }
2171}
2172
2173//------------------------------------------------------------------------------------------
2174
2176void init_filter(void)
2177{
2178 // Filtering of the velocities
2179 float tau = 1.0 / (2.0 * M_PI * oneloop_nB_filt_cutoff);
2180 float tau_v = 1.0 / (2.0 * M_PI * oneloop_nB_filt_cutoff_v);
2181 // float tau_2 = 1.0 / (2.0 * M_PI * 2.0);
2182 float tau_r = 1.0 / (5.0);
2183 // printf("tau: %f tau_v: %f\n", tau, tau_v);
2184 // printf("initializing filters\n");
2185 init_butterworth_2_low_pass(&accely_filt, tau, 1.0 / PERIODIC_FREQUENCY, accely_filt.o[0]);
2186 init_butterworth_2_low_pass(&airspeed_filt, tau, 1.0 / PERIODIC_FREQUENCY, airspeed_filt.o[0]);
2187 for (int i = 0; i < 3; i++)
2188 {
2189 init_butterworth_2_low_pass(&KPID_vel_filt[i], tau_v, 1.0 / PERIODIC_FREQUENCY, KPID_vel_filt[i].o[0]);
2190 init_butterworth_2_low_pass(&KPID_filt[i], tau_v, 1.0 / PERIODIC_FREQUENCY, 0.0);
2191 }
2192 init_butterworth_2_low_pass(&push_PID_vel[0], tau_r, 1.0 / PERIODIC_FREQUENCY, push_PID_vel[0].o[0]);
2193 init_butterworth_2_low_pass(&push_PID_vel[1], tau_r, 1.0 / PERIODIC_FREQUENCY, push_PID_vel[1].o[0]);
2194 init_butterworth_2_low_pass(&push_PID_vel_d[0], tau_r, 1.0 / PERIODIC_FREQUENCY, push_PID_vel_d[0].o[0]);
2195 init_butterworth_2_low_pass(&push_PID_vel_d[1], tau_r, 1.0 / PERIODIC_FREQUENCY, push_PID_vel_d[1].o[0]);
2196 for (int i = 0; i < ANDI_NUM_ACT_TOT; i++)
2197 {
2198 init_butterworth_2_low_pass(&u_filt[i], tau, 1.0 / PERIODIC_FREQUENCY, 0.0);
2199 }
2200 for (int i = 0; i < 3; i++)
2201 {
2202 init_butterworth_2_low_pass(&nB_filt[i], tau, 1.0 / PERIODIC_FREQUENCY, 0.0);
2203 init_butterworth_2_low_pass(&nB_2d_filt[i], tau, 1.0 / PERIODIC_FREQUENCY, 0.0);
2204 }
2205 init_butterworth_2_low_pass(&nB_3d_state_filt[0], tau, 1.0 / PERIODIC_FREQUENCY, 0.0);
2206 init_butterworth_2_low_pass(&nB_3d_state_filt[1], tau, 1.0 / PERIODIC_FREQUENCY, 0.0);
2207}
2208
2211{
2212 reinit_all_LP(false);
2213 struct NedCoor_f *veloc = stateGetSpeedNed_f();
2214 struct FloatRates *body_rates = stateGetBodyRates_f();
2215#ifdef USE_ND_VELOCITIES
2216 static bool vel_inited = false;
2217 static struct NedCoor_f veloc_prev;
2218 if (!vel_inited)
2219 {
2220 veloc_prev = *veloc;
2221 vel_inited = true;
2222 }
2223 LP.ax.meas = (veloc->x - veloc_prev.x) * PERIODIC_FREQUENCY;
2224 LP.ay.meas = (veloc->y - veloc_prev.y) * PERIODIC_FREQUENCY;
2225 LP.az.meas = (veloc->z - veloc_prev.z) * PERIODIC_FREQUENCY;
2226 veloc_prev = *veloc;
2227#else
2228 struct NedCoor_f *accel = stateGetAccelNed_f();
2229 LP.ax.meas = accel->x;
2230 LP.ay.meas = accel->y;
2231 LP.az.meas = accel->z;
2232#endif
2233 LP.p.meas_prev = LP.p.meas;
2234 LP.q.meas_prev = LP.q.meas;
2235 LP.r.meas_prev = LP.r.meas;
2236 LP.p.meas = body_rates->p;
2237 LP.q.meas = body_rates->q;
2238 LP.r.meas = body_rates->r;
2239 LP.p_dot.meas_prev = LP.p_dot.meas;
2240 LP.q_dot.meas_prev = LP.q_dot.meas;
2241 LP.r_dot.meas_prev = LP.r_dot.meas;
2242 LP.p_dot.meas = (LP.p.meas - LP.p.meas_prev) * PERIODIC_FREQUENCY;
2243 LP.q_dot.meas = (LP.q.meas - LP.q.meas_prev) * PERIODIC_FREQUENCY;
2244 LP.r_dot.meas = (LP.r.meas - LP.r.meas_prev) * PERIODIC_FREQUENCY;
2245 LP.p_ddot.meas = (LP.p_dot.meas - LP.p_dot.meas_prev) * PERIODIC_FREQUENCY;
2246 LP.q_ddot.meas = (LP.q_dot.meas - LP.q_dot.meas_prev) * PERIODIC_FREQUENCY;
2247 LP.r_ddot.meas = (LP.r_dot.meas - LP.r_dot.meas_prev) * PERIODIC_FREQUENCY;
2248 // Update Filters of Feedbacks
2249 update_filter_on_type(&LP.ax, LP.ax.meas);
2250 update_filter_on_type(&LP.ay, LP.ay.meas);
2251 update_filter_on_type(&LP.az, LP.az.meas);
2252 update_filter_on_type(&LP.p_ddot, LP.p_ddot.meas);
2253 update_filter_on_type(&LP.q_ddot, LP.q_ddot.meas);
2254 update_filter_on_type(&LP.r_ddot, LP.r_ddot.meas);
2255 update_filter_on_type(&LP.p_dot, LP.p_dot.meas);
2256 update_filter_on_type(&LP.q_dot, LP.q_dot.meas);
2257 update_filter_on_type(&LP.r_dot, LP.r_dot.meas);
2258 update_filter_on_type(&LP.p, LP.p.meas);
2259 update_filter_on_type(&LP.q, LP.q.meas);
2260 update_filter_on_type(&LP.r, LP.r.meas);
2261 // Propagate filter for sideslip correction
2262 float accely = ACCEL_FLOAT_OF_BFP(stateGetAccelBody_i()->y);
2264 float airspeed_meas = stateGetAirspeed_f();
2265 Bound(airspeed_meas, 0.0, 30.0);
2267}
2268//------------------------------------------------------------------------------------------
2271{
2272 // Stabilization
2273 float_vect_copy(oneloop_nB.sta_ref.att, oneloop_nB.sta_state.att, 3);
2274 float_vect_copy(oneloop_nB.sta_ref.att_d, oneloop_nB.sta_state.att_d, 3);
2275 float_vect_copy(oneloop_nB.sta_ref.att_2d, oneloop_nB.sta_state.att_2d, 3);
2276 float_vect_zero(oneloop_nB.sta_ref.att_3d, 3);
2277 eulers_zxy_des.phi = oneloop_nB.sta_state.att[0];
2278 eulers_zxy_des.theta = oneloop_nB.sta_state.att[1];
2279 eulers_zxy_des.psi = oneloop_nB.sta_state.att[2];
2280 // Guidance
2281 float_vect_copy(oneloop_nB.gui_ref.pos, oneloop_nB.gui_state.pos, 3);
2282 float_vect_copy(oneloop_nB.gui_ref.vel, oneloop_nB.gui_state.vel, 3);
2283 float_vect_copy(oneloop_nB.gui_ref.acc, oneloop_nB.gui_state.acc, 3);
2284 float_vect_zero(oneloop_nB.gui_ref.jer, 3);
2285 // nB controller
2286 oneloop_nB.sta_nB_state.nI.x = 0.0;
2287 oneloop_nB.sta_nB_state.nI.y = 0.0;
2288 oneloop_nB.sta_nB_state.nI.z = -1.0;
2289}
2290
2292{
2293 oneloop_nB.half_loop = true;
2294 oneloop_nB.ctrl_type = CTRL_ANDI;
2295 init_poles();
2296 // Make sure that the dynamics are positive and non-zero
2297 for (int8_t i = 0; i < ANDI_NUM_ACT_TOT; i++)
2298 {
2300 }
2301 // Initialize Effectiveness matrix
2303 G1G2_oneloop(oneloop_nB.ctrl_type);
2304 // Initialize filters and other variables
2305 init_all_LP();
2306 init_filter();
2312 float_vect_zero(oneloop_nB.sta_ref.att, 3);
2313 float_vect_zero(oneloop_nB.sta_ref.att_d, 3);
2314 float_vect_zero(oneloop_nB.sta_ref.att_2d, 3);
2315 float_vect_zero(oneloop_nB.sta_ref.att_3d, 3);
2320 eulers_zxy_des.phi = 0.0;
2321 eulers_zxy_des.theta = 0.0;
2322 eulers_zxy_des.psi = 0.0;
2323 // nB controller
2324 oneloop_nB.sta_nB_state.nI.x = 0.0;
2325 oneloop_nB.sta_nB_state.nI.y = 0.0;
2326 oneloop_nB.sta_nB_state.nI.z = -1.0;
2327// Start telemetry
2328#if PERIODIC_TELEMETRY
2329 register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_STAB_ATTITUDE, send_oneloop_nB);
2335#ifdef PPRZ_MSG_ID_PUSH_NB
2336 register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_PUSH_NB, send_PUSH_NB);
2337#endif
2341#endif
2342 safety_killer_trigger = false;
2343 // Log pointer to effectiveness matrix (can do only once after init)
2344}
2345
2352void oneloop_nB_enter(bool half_loop_sp, int ctrl_type)
2353{
2354 oneloop_nB.half_loop = half_loop_sp;
2355 oneloop_nB.ctrl_type = ctrl_type;
2356 psi_des_rad = eulers_zxy.psi;
2357 psi_des_deg = DegOfRad(eulers_zxy.psi);
2359 G1G2_oneloop(oneloop_nB.ctrl_type);
2362 safety_killer_trigger = false;
2363 spin_man_reset(); // any mode change aborts the spin manoeuvre
2364}
2365
2371void oneloop_nB_RM(bool half_loop, struct FloatVect3 PSA_des, bool in_flight_oneloop)
2372{
2373 // printf("Starting Oneloop ANDI RM\n");
2374 // Initialize some variables
2375 a_thrust = 0.0;
2376 nav_target[0] = PSA_des.x;
2377 nav_target[1] = PSA_des.y;
2378 nav_target[2] = PSA_des.z;
2379 float radio_thrust_cmd = 0.0;
2380 float radio_roll_cmd = 0.0;
2381 float radio_pitch_cmd = 0.0;
2382 float des_r = 0.0;
2383 // ======================================================================================================================================================
2384 // Need to save and convert desired position for bounding. Not sure NAV always updates this correctly.
2385 float pos_des[3];
2386 pos_des[0] = POS_FLOAT_OF_BFP(POS_BFP_OF_REAL(nav.target.y));
2387 pos_des[1] = POS_FLOAT_OF_BFP(POS_BFP_OF_REAL(nav.target.x));
2388 pos_des[2] = POS_FLOAT_OF_BFP(-POS_BFP_OF_REAL(nav.nav_altitude));
2389 // =======================================================================================================================================================
2390 // Some Pusher control definitions
2391 oneloop_nB.push_nB.n = 2;
2392 oneloop_nB.push_nB.max_push_cmd = max_pusher_cmd;
2393 oneloop_nB.push_nB.varepsilon = 25.0; // 10.0;
2394 oneloop_nB.push_nB.max_v_d = 1.0;
2395 oneloop_nB.push_nB.pN_d = pos_des[0];
2396 oneloop_nB.push_nB.pE_d = pos_des[1];
2397 oneloop_nB.push_nB.pN = oneloop_nB.gui_state.pos[0];
2398 oneloop_nB.push_nB.pE = oneloop_nB.gui_state.pos[1];
2399 Bound(pid_a_max, 0.05, 1.0);
2400 Bound(pid_v_max_manual, 0.1, 10.0);
2401 Bound(pid_v_max_nav, 0.1, 10.0);
2402 float PID_a_max = pid_a_max * 9.81;
2403 float acc_des[3];
2404 // Generate reference signals with reference model
2405 if (half_loop)
2406 {
2407 // printf("Half loop mode RM enabled\n");
2408 // ======================================================================================================================================================
2409 // PHI & THETA Set desired attitude with stick input
2410 radio_roll_cmd = (float)(radio_control_get(RADIO_ROLL));
2411 radio_pitch_cmd = (float)(radio_control_get(RADIO_PITCH));
2412 Bound(radio_roll_cmd, -MAX_PPRZ, MAX_PPRZ);
2413 Bound(radio_pitch_cmd, -MAX_PPRZ, MAX_PPRZ);
2414 eulers_zxy_des.phi = radio_roll_cmd / MAX_PPRZ * max_phi;
2415 eulers_zxy_des.theta = radio_pitch_cmd / MAX_PPRZ * max_theta;
2416 float sphi_des = sinf(eulers_zxy_des.phi);
2417 float cphi_des = cosf(eulers_zxy_des.phi);
2418 float stheta_des = sinf(eulers_zxy_des.theta);
2419 float ctheta_des = cosf(eulers_zxy_des.theta);
2420#ifdef ROTWING_EFF_SCHED_MP_dFdu
2421 if (use_push_PID)
2422 {
2423 // Desired Velocity ==============================================================
2425 {
2426 oneloop_nB.push_nB.vN_d = (oneloop_nB.push_nB.pN_d - oneloop_nB.push_nB.pN) * k_K; //
2427 oneloop_nB.push_nB.vE_d = (oneloop_nB.push_nB.pE_d - oneloop_nB.push_nB.pE) * k_K; //
2428 }
2429 else
2430 {
2431 oneloop_nB.push_nB.vN_d = -radio_pitch_cmd / MAX_PPRZ * oneloop_nB.push_nB.max_v_d; //
2432 oneloop_nB.push_nB.vE_d = radio_roll_cmd / MAX_PPRZ * oneloop_nB.push_nB.max_v_d; //
2433 }
2434 }
2435#endif
2436 radio_body_ctrl = (fault_pitch_motors == fault_roll_motors) && (spin_man_state == SPIN_MAN_IDLE); // N/E sticks while spinning (single faulted pair)
2438 {
2439 float x_dot_des[3];
2440 x_dot_des[0] = -radio_pitch_cmd / MAX_PPRZ * pid_v_max_manual; // oneloop_nB.push_nB.max_v_d;
2441 x_dot_des[1] = radio_roll_cmd / MAX_PPRZ * pid_v_max_manual; // oneloop_nB.push_nB.max_v_d;
2442 x_dot_des[2] = 0.0;
2443 if (radio_body_ctrl)
2444 {
2445 float sin_psi = sinf(eulers_zxy.psi);
2446 float cos_psi = cosf(eulers_zxy.psi);
2447 struct FloatVect3 x_dot_des_NE;
2448 x_dot_des_NE.x = x_dot_des[0] * cos_psi - x_dot_des[1] * sin_psi;
2449 x_dot_des_NE.y = x_dot_des[0] * sin_psi + x_dot_des[1] * cos_psi;
2450 x_dot_des[0] = x_dot_des_NE.x;
2451 x_dot_des[1] = x_dot_des_NE.y;
2452 }
2453 Vel_PID_ARW(x_dot_des, oneloop_nB.gui_state.vel, k_P, k_I, k_D, acc_des, PID_a_max, pid_v_max_manual);
2454 shape_vector(acc_des);
2455 eul_of_acc(acc_des, eulers_zxy.psi);
2456 oneloop_nB.sta_nB_state.nI_des.x = acc_des[0];
2457 oneloop_nB.sta_nB_state.nI_des.y = acc_des[1];
2458 oneloop_nB.sta_nB_state.nI_des.z = acc_des[2];
2459 }
2460 else
2461 {
2462 oneloop_nB.sta_nB_state.nI_des.x = -stheta_des;
2463 oneloop_nB.sta_nB_state.nI_des.y = sphi_des * ctheta_des;
2464 oneloop_nB.sta_nB_state.nI_des.z = -cphi_des * ctheta_des;
2465 if (radio_body_ctrl)
2466 {
2467 float sin_psi = sinf(eulers_zxy.psi);
2468 float cos_psi = cosf(eulers_zxy.psi);
2469 struct FloatVect3 nI_des_NED;
2470 nI_des_NED.x = oneloop_nB.sta_nB_state.nI_des.x * cos_psi - oneloop_nB.sta_nB_state.nI_des.y * sin_psi;
2471 nI_des_NED.y = oneloop_nB.sta_nB_state.nI_des.x * sin_psi + oneloop_nB.sta_nB_state.nI_des.y * cos_psi;
2472 oneloop_nB.sta_nB_state.nI_des.x = nI_des_NED.x;
2473 oneloop_nB.sta_nB_state.nI_des.y = nI_des_NED.y;
2474 }
2475 }
2476 // ======================================================================================================================================================
2477 // PSI Set desired Yaw rate with stick input
2478 if (!SpinQuad && spin_man_state == SPIN_MAN_IDLE) // yaw stick ignored during the spin manoeuvre
2479 {
2480 des_r = (float)(radio_control_get(RADIO_YAW)) / MAX_PPRZ * max_r; // Get yaw rate from stick
2481 BoundAbs(des_r, max_r);
2482 } // Bound yaw rate
2483 float delta_psi_des_rad = des_r * dt_1l; // Integrate desired Yaw rate to get desired change in yaw
2484 float delta_psi_rad = eulers_zxy_des.psi - eulers_zxy.psi; // Calculate current yaw difference between des and actual
2485 NormRadAngle(delta_psi_rad); // Normalize the difference
2486 if (fabs(delta_psi_rad) > RadOfDeg(30.0)) // If difference is bigger than 10 deg do not further increment desired
2487 {
2488 delta_psi_des_rad = 0.0;
2489 }
2490 psi_des_rad += delta_psi_des_rad; // Incrementdesired yaw
2491 NormRadAngle(psi_des_rad);
2492 // ======================================================================================================================================================
2493 // THRUST Create commands adhoc to get actuators to the wanted level
2494 radio_thrust_cmd = (float)radio_control_get(RADIO_THROTTLE);
2495 Bound(radio_thrust_cmd, 0.0, MAX_PPRZ);
2496 int8_t i;
2497 // To calculate the nu corrsponding to the Thrust command, plug it in the control law.
2498 for (i = 0; i < ANDI_NUM_ACT; i++)
2499 {
2500 float den = positive_non_zero(ratio_u_un[i] * ratio_vn_v[IDX_aD]);
2501 a_thrust += (radio_thrust_cmd)*EFF_MAT_G[IDX_aD][i] / den;
2502 }
2503 a_thrust = a_thrust - ctrl_effort_model[IDX_aD]; // Subtract model disturbance
2504 ctrl_off = false; // Make sure all control on for manual takeover
2505 nu[IDX_aD] = a_thrust;
2506 }
2507 else
2508 {
2509 // ======================================================================================================================================================
2510 // PID Guidance
2511 Pos_KPID_ARW(pos_des, oneloop_nB.gui_state.pos, oneloop_nB.gui_state.vel, k_K, k_P, k_I, k_D, acc_des, PID_a_max, pid_v_max_nav);
2512 switch (oneloop_nB.ctrl_type)
2513 {
2514 case CTRL_ANDI:
2515 case CTRL_NB_ANDI:
2516 nu[IDX_aD] = (acc_des[2] - oneloop_nB.gui_state.acc[2]) * k_pos_e.k3[2];
2517 break;
2518 case CTRL_INDI:
2519 case CTRL_NB_INDI:
2520 nu[IDX_aD] = (acc_des[2] - oneloop_nB.gui_state.acc[2]);
2521 break;
2522 }
2523 temp_acc_des[0] = acc_des[0];
2524 temp_acc_des[1] = acc_des[1];
2525 temp_acc_des[2] = acc_des[2];
2526 shape_vector(acc_des);
2528 {
2529 radio_roll_cmd = (float)(radio_control_get(RADIO_ROLL));
2530 radio_pitch_cmd = (float)(radio_control_get(RADIO_PITCH));
2531 Bound(radio_roll_cmd, -MAX_PPRZ, MAX_PPRZ);
2532 Bound(radio_pitch_cmd, -MAX_PPRZ, MAX_PPRZ);
2533 eulers_zxy_des.phi = radio_roll_cmd / MAX_PPRZ * max_phi;
2534 eulers_zxy_des.theta = radio_pitch_cmd / MAX_PPRZ * max_theta;
2535 }
2536 else
2537 {
2538 eul_of_acc(acc_des, eulers_zxy.psi);
2539 };
2540 oneloop_nB.sta_nB_state.nI_des.x = acc_des[0];
2541 oneloop_nB.sta_nB_state.nI_des.y = acc_des[1];
2542 oneloop_nB.sta_nB_state.nI_des.z = acc_des[2];
2543 // Update desired Heading (psi_des_rad) based on previous loop or changed setting
2544 if (heading_manual)
2545 {
2546 psi_des_rad = RadOfDeg(psi_des_deg);
2548 {
2550 }
2551 }
2552 else
2553 {
2555 }
2556 NormRadAngle(psi_des_rad);
2557#ifdef ROTWING_EFF_SCHED_MP_dFdu
2558 if (use_push_PID)
2559 {
2560 // Desired Velocity from Position Set Point ==============================================================
2561 oneloop_nB.push_nB.vN_d = (oneloop_nB.push_nB.pN_d - oneloop_nB.push_nB.pN) * k_K; //
2562 oneloop_nB.push_nB.vE_d = (oneloop_nB.push_nB.pE_d - oneloop_nB.push_nB.pE) * k_K; //
2563 }
2564#endif
2565 }
2566 // ============================================================================================================
2567 // Pusher Control in Either NAV or ATT
2568 // ============================================================================================================
2569#ifdef ROTWING_EFF_SCHED_MP_dFdu
2570 if (use_push_PID)
2571 {
2572 // Desired Velocity ==============================================================
2575 oneloop_nB.push_nB.vN_d_filt = push_PID_vel_d[0].o[0];
2576 oneloop_nB.push_nB.vE_d_filt = push_PID_vel_d[1].o[0];
2577 // Current Velocity ==============================================================
2578 oneloop_nB.push_nB.vN = stateGetSpeedNed_f()->x;
2579 oneloop_nB.push_nB.vE = stateGetSpeedNed_f()->y;
2582 oneloop_nB.push_nB.vN_filt = push_PID_vel[0].o[0];
2583 oneloop_nB.push_nB.vE_filt = push_PID_vel[1].o[0];
2584 // Calculate Amplitude ===========================================================
2585 float push_delta_v[2];
2586 // push_delta_v[0] = (oneloop_nB.push_nB.vN_d_filt-oneloop_nB.push_nB.vN_filt);
2587 // push_delta_v[1] = (oneloop_nB.push_nB.vE_d_filt-oneloop_nB.push_nB.vE_filt);
2588 push_delta_v[0] = (oneloop_nB.push_nB.vN_d - oneloop_nB.push_nB.vN) * k_P;
2589 push_delta_v[1] = (oneloop_nB.push_nB.vE_d - oneloop_nB.push_nB.vE) * k_P;
2590 // Allocation on Integral Solution ===============================================
2591 float push_delta_v_norm = sqrtf(push_delta_v[0] * push_delta_v[0] + push_delta_v[1] * push_delta_v[1]);
2592 float r_int_sol = oneloop_nB.sta_state.att_d[2];
2593 BoundAbs(r_int_sol, 5.0);
2594 float push_cmd_A = fabs(r_int_sol) * sqrtf((float)oneloop_nB.push_nB.n) / (2.0 * sqrtf((float)M_PI) * RW.mP.dFdu / RW.m) * push_delta_v_norm;
2595 Bound(push_cmd_A, 0.0f, oneloop_nB.push_nB.max_push_cmd);
2596 oneloop_nB.push_nB.push_cmd = push_cmd_A * pusher_cmd_fun(push_delta_v[0], push_delta_v[1], oneloop_nB.sta_state.att_d[2], oneloop_nB.sta_state.att[2], oneloop_nB.push_nB.varepsilon, oneloop_nB.push_nB.n);
2597 commands[COMMAND_MOTOR_PUSHER] = (int16_t)oneloop_nB.push_nB.push_cmd;
2598 oneloop_nB.sta_nB_state.nI_des.x = 0.0;
2599 oneloop_nB.sta_nB_state.nI_des.y = 0.0;
2600 oneloop_nB.sta_nB_state.nI_des.z = -1.0;
2601 }
2602 else
2603 {
2604 // Pusher off when not used (nothing else commands it, otherwise it would keep its last value)
2605 oneloop_nB.push_nB.push_cmd = 0.0;
2606 commands[COMMAND_MOTOR_PUSHER] = 0;
2607 }
2608#endif
2609 // ======================================================================================================================================================
2610 if (!in_flight_oneloop)
2611 {
2612 psi_des_rad = eulers_zxy.psi;
2613 } // Reset if not flying
2614 // Heading is not controlled while spinning (manoeuvre or motor fault in nB): keep the desired heading on the
2615 // actual one, so that heading control resumes without a jump (up to 180 deg) when the fault is removed
2616 bool nb_ctrl_rm = (oneloop_nB.ctrl_type == CTRL_NB_INDI || oneloop_nB.ctrl_type == CTRL_NB_ANDI);
2618 {
2619 psi_des_rad = eulers_zxy.psi;
2620 psi_des_deg = DegOfRad(psi_des_rad);
2621 }
2623 // ======================================================================================================================================================
2624 // Set and Save the desired attitude and run the attitude RM
2625 float att_des[3] = {eulers_zxy_des.phi, eulers_zxy_des.theta, eulers_zxy_des.psi};
2626#define OVERRIDE_ATT_RM
2627#ifdef OVERRIDE_ATT_RM
2628 float_vect_zero(oneloop_nB.sta_ref.att, 3);
2629 float_vect_zero(oneloop_nB.sta_ref.att_d, 3);
2630 float_vect_zero(oneloop_nB.sta_ref.att_2d, 3);
2631 float_vect_zero(oneloop_nB.sta_ref.att_3d, 3);
2632 oneloop_nB.sta_ref.att[0] = att_des[0];
2633 oneloop_nB.sta_ref.att[1] = att_des[1];
2634 oneloop_nB.sta_ref.att[2] = att_des[2];
2635#else
2636 static float psi_vec[4] = {0.0, 0.0, 0.0, 0.0}; // Vector to overwrite the Yaw reference in the attitude controller
2637 rm_3rd_attitude(dt_1l, oneloop_nB.sta_ref.att, oneloop_nB.sta_ref.att_d, oneloop_nB.sta_ref.att_2d, oneloop_nB.sta_ref.att_3d, att_des, false, psi_vec, k_att_rm.k1, k_att_rm.k2, k_att_rm.k3, sta_bounds);
2638#endif
2639 rm_3rd_nI(dt_1l, &oneloop_nB.sta_nB_state.nI, &oneloop_nB.sta_nB_state.nI_d, &oneloop_nB.sta_nB_state.nI_2d, &oneloop_nB.sta_nB_state.nI_3d, &oneloop_nB.sta_nB_state.nI_des, k_att_rm.k1, k_att_rm.k2, k_att_rm.k3);
2640 // ======================================================================================================================================================
2641}
2642
2649void oneloop_nB_run(bool in_flight, bool half_loop, struct FloatVect3 PSA_des)
2650{
2651 // ======================================================================================================================================================
2652 // At beginnig of the loop: (1) Register Attitude, (2) Initialize gains of RM and EC, (3) Calculate Normalization of Actuators Signals, (4) Propagate Actuator Model, (5) Update effectiveness matrix
2657 // ======================================================================================================================================================
2658 // If drone is not on the ground use incremental law
2659 bool in_flight_oneloop = false;
2660 if (in_flight)
2661 {
2662 in_flight_oneloop = true;
2663 }
2665 {
2666 in_flight_oneloop = true;
2667 }
2668 // ======================================================================================================================================================
2669 // Calculate disturbance (model control effort) based on the model
2671 // ======================================================================================================================================================
2672 // Register the state of the drone in the variables used in RM and EC
2673 // (1) Attitude related
2674 oneloop_nB.sta_state.att[0] = eulers_zxy.phi;
2675 oneloop_nB.sta_state.att[1] = eulers_zxy.theta;
2676 oneloop_nB.sta_state.att[2] = eulers_zxy.psi;
2677 oneloop_nB_propagate_filters(); // needs to be after update of attitude vector
2678 oneloop_nB.sta_state.att_d[0] = LP.p.out;
2679 oneloop_nB.sta_state.att_d[1] = LP.q.out;
2680 oneloop_nB.sta_state.att_d[2] = LP.r.out;
2681 oneloop_nB.sta_state.att_2d[0] = LP.p_dot.out;
2682 oneloop_nB.sta_state.att_2d[1] = LP.q_dot.out;
2683 oneloop_nB.sta_state.att_2d[2] = LP.r_dot.out;
2684 // (2) Position related
2685 oneloop_nB.gui_state.pos[0] = stateGetPositionNed_f()->x;
2686 oneloop_nB.gui_state.pos[1] = stateGetPositionNed_f()->y;
2687 oneloop_nB.gui_state.pos[2] = stateGetPositionNed_f()->z;
2688 oneloop_nB.gui_state.vel[0] = stateGetSpeedNed_f()->x;
2689 oneloop_nB.gui_state.vel[1] = stateGetSpeedNed_f()->y;
2690 oneloop_nB.gui_state.vel[2] = stateGetSpeedNed_f()->z;
2691 oneloop_nB.gui_state.acc[0] = LP.ax.out;
2692 oneloop_nB.gui_state.acc[1] = LP.ay.out;
2693 oneloop_nB.gui_state.acc[2] = LP.az.out;
2694 // ======================================================================================================================================================
2695 // Calculated feedforward signal for yaw control
2696 g2_ff = 0.0;
2697 for (int i = 0; i < ANDI_NUM_ACT; i++)
2698 {
2699 switch (oneloop_nB.ctrl_type)
2700 {
2701 case (CTRL_ANDI):
2702 case (CTRL_NB_ANDI):
2703 g2_ff += G2_RW[i] * act_dyn_ctrl[i] * (andi_u[i] - u_filt[i].o[0]);
2704 break;
2705 case (CTRL_INDI):
2706 case (CTRL_NB_INDI):
2707 g2_ff += G2_RW[i] * (andi_u[i] - u_filt[i].o[0]);
2708 break;
2709 default:
2710 break;
2711 }
2712 }
2713 // ======================================================================================================================================================
2714 // Spin protection / manoeuvre: validate parameters, then run the manoeuvre (it sets fault_pitch_motors)
2715 spin_prot_bound_params(); // guarantees spin_prot_max_rate - spin_prot_start_rate >= spin_prot_min_gap > 0
2716 spin_man_update(in_flight, (oneloop_nB.ctrl_type == CTRL_NB_INDI || oneloop_nB.ctrl_type == CTRL_NB_ANDI));
2717 // ======================================================================================================================================================
2718 // Run the Reference Model (RM)
2719 oneloop_nB_RM(half_loop, PSA_des, in_flight_oneloop);
2720 // ======================================================================================================================================================
2721 // Calculate new nB states based on updated RM for nI
2723 // ======================================================================================================================================================
2724 // Update Effectiveness matrix based on the control type
2725 G1G2_oneloop(oneloop_nB.ctrl_type);
2726 // ======================================================================================================================================================
2727 // Attitude EC
2728 float att_jerk_des[3];
2729 float nu_stab[3] = {0.0, 0.0, 0.0};
2730 float att_des[3] = {eulers_zxy_des.phi, eulers_zxy_des.theta, eulers_zxy_des.psi};
2731 oneloop_nB.sta_nB_state.mu_B.x = 0.0;
2732 oneloop_nB.sta_nB_state.mu_B.y = 0.0;
2733 oneloop_nB.sta_nB_state.mu_B.z = -1.0;
2734
2735 float ctrl_effort_model_att[3] = {ctrl_effort_model[IDX_ap], ctrl_effort_model[IDX_aq], ctrl_effort_model[IDX_ar]};
2736 float dummy1[3] = {1.0, 1.0, 1.0};
2737 float dummy0[3] = {0.0, 0.0, 0.0};
2738 struct FloatVect3 nB_2d_FV3;
2739 nB_2d_FV3.x = nB_2d_filt[0].o[0];
2740 nB_2d_FV3.y = nB_2d_filt[1].o[0];
2741 nB_2d_FV3.z = nB_2d_filt[2].o[0];
2742 switch (oneloop_nB.ctrl_type)
2743 {
2744 case CTRL_ANDI:
2745 ec_3rd_att(att_jerk_des, att_des, oneloop_nB.sta_ref.att, oneloop_nB.sta_ref.att_d, oneloop_nB.sta_ref.att_2d, oneloop_nB.sta_ref.att_3d, oneloop_nB.sta_state.att, oneloop_nB.sta_state.att_d, oneloop_nB.sta_state.att_2d, k_att_e.k1, k_att_e.k2, k_att_e.k3, sta_bounds, ctrl_effort_model_att);
2746 nB_EC(oneloop_nB.sta_nB_state.nB, oneloop_nB.sta_nB_state.nB_d, oneloop_nB.sta_nB_state.nB_2d, oneloop_nB.sta_nB_state.mu_B, k_att_e.k1, k_att_e.k2, dummy1, ctrl_effort_model_att, nB_jerk_des);
2747 nu_stab[0] = att_jerk_des[0];
2748 nu_stab[1] = att_jerk_des[1];
2749 nu_stab[2] = att_jerk_des[2];
2750 SpinQuad_overwrite(k_att_e.k3[2], ctrl_effort_model[IDX_ar], &nu_stab[2]);
2751 break;
2752 case CTRL_INDI:
2753 ec_3rd_att(att_jerk_des, att_des, oneloop_nB.sta_ref.att, oneloop_nB.sta_ref.att_d, oneloop_nB.sta_ref.att_2d, dummy0, oneloop_nB.sta_state.att, oneloop_nB.sta_state.att_d, oneloop_nB.sta_state.att_2d, k_att_e.k1, k_att_e.k2, dummy1, sta_bounds, ctrl_effort_model_att);
2754 nu_stab[0] = att_jerk_des[0];
2755 nu_stab[1] = att_jerk_des[1];
2756 nu_stab[2] = att_jerk_des[2];
2757 SpinQuad_overwrite(1.0, ctrl_effort_model[IDX_ar], &nu_stab[2]);
2758 break;
2759 case CTRL_NB_ANDI:
2760 ec_3rd_att(att_jerk_des, att_des, oneloop_nB.sta_ref.att, oneloop_nB.sta_ref.att_d, oneloop_nB.sta_ref.att_2d, oneloop_nB.sta_ref.att_3d, oneloop_nB.sta_state.att, oneloop_nB.sta_state.att_d, oneloop_nB.sta_state.att_2d, k_att_e.k1, k_att_e.k2, k_att_e.k3, sta_bounds, ctrl_effort_model_att);
2761 // nB_EC(oneloop_nB.sta_nB_state.nB, oneloop_nB.sta_nB_state.nB_d, oneloop_nB.sta_nB_state.nB_2d, oneloop_nB.sta_nB_state.mu_B, k_att_e.k1, k_att_e.k2, k_att_e.k3, ctrl_effort_model_att, nB_jerk_des);
2762 nB_EC(oneloop_nB.sta_nB_state.nB, oneloop_nB.sta_nB_state.nB_d, nB_2d_FV3, oneloop_nB.sta_nB_state.mu_B, k_att_e.k1, k_att_e.k2, k_att_e.k3, ctrl_effort_model_att, nB_jerk_des);
2763 nu_stab[0] = nB_jerk_des[0] - nB_3d_state_filt[0].o[0]; // state_term[0];
2764 nu_stab[1] = nB_jerk_des[1] - nB_3d_state_filt[1].o[0]; // state_term[1];
2765 nu_stab[2] = att_jerk_des[2];
2766 SpinQuad_overwrite(k_att_e.k3[2], ctrl_effort_model[IDX_ar], &nu_stab[2]);
2767 break;
2768 case CTRL_NB_INDI:
2769 ec_3rd_att(att_jerk_des, att_des, oneloop_nB.sta_ref.att, oneloop_nB.sta_ref.att_d, oneloop_nB.sta_ref.att_2d, dummy0, oneloop_nB.sta_state.att, oneloop_nB.sta_state.att_d, oneloop_nB.sta_state.att_2d, k_att_e.k1, k_att_e.k2, dummy1, sta_bounds, ctrl_effort_model_att);
2770 // nB_EC(oneloop_nB.sta_nB_state.nB, oneloop_nB.sta_nB_state.nB_d, oneloop_nB.sta_nB_state.nB_2d, oneloop_nB.sta_nB_state.mu_B, k_att_e.k1, k_att_e.k2, dummy1, ctrl_effort_model_att, nB_jerk_des);
2771 nB_EC(oneloop_nB.sta_nB_state.nB, oneloop_nB.sta_nB_state.nB_d, nB_2d_FV3, oneloop_nB.sta_nB_state.mu_B, k_att_e.k1, k_att_e.k2, dummy1, ctrl_effort_model_att, nB_jerk_des);
2772 nu_stab[0] = nB_jerk_des[0];
2773 nu_stab[1] = nB_jerk_des[1];
2774 nu_stab[2] = att_jerk_des[2];
2775 SpinQuad_overwrite(1.0, ctrl_effort_model[IDX_ar], &nu_stab[2]);
2776 break;
2777 }
2778 // ======================================================================================================================================================
2779 // Set Pseudo-control inputs nu based on EC outputs
2780 if (half_loop && radio_control_get(RADIO_THROTTLE) < 200)
2781 {
2782 nu[IDX_ap] = 0.0;
2783 nu[IDX_aq] = 0.0;
2784 nu[IDX_ar] = 0.0;
2785 }
2786 else
2787 {
2788 nu[IDX_ap] = nu_stab[0];
2789 nu[IDX_aq] = nu_stab[1];
2790 nu[IDX_ar] = nu_stab[2] + g2_ff;
2791 }
2793 // ======================================================================================================================================================
2794 // Manipulate Pseudo control vecotors for state compensation and axis dropping
2795 // BoundAbs(nu[5], n_array[5]*coupling_factor[5]); //FIXME UNCOMMENT ME
2796 drop_axis();
2798 // ======================================================================================================================================================
2799 // Set the WLS settings
2801 // ======================================================================================================================================================
2802 // WLS Control Allocator
2803 normalize_nu();
2804 wls_alloc(&WLS_one_p, bwls_1l, 0, 0, 10);
2805 // ======================================================================================================================================================
2806 // Save the commands to the actuators
2807 for (int i = 0; i < ANDI_NUM_ACT_TOT; i++)
2808 {
2809 andi_u_n[i] = WLS_one_p.u[i];
2810 andi_u[i] = (float)(andi_u_n[i] * ratio_u_un[i]);
2811 Bound(andi_u[i], act_min[i], act_max[i]);
2813 {
2814 safety_killer_trigger = true;
2815 }
2816 }
2817 // ======================================================================================================================================================
2818 // Handle fault static commands
2819 // The static fault commands (and the spin trim) are only used by the nB controllers
2820 bool nb_ctrl = (oneloop_nB.ctrl_type == CTRL_NB_INDI || oneloop_nB.ctrl_type == CTRL_NB_ANDI);
2821 float temp_thrust = 0.0;
2822 static int counter_afc = 0;
2823 float min_fault_mot = 0.0;
2824 float time_afc = 30.0;
2825 float m_afc = (min_fault_mot - max_fault_mot) / (time_afc * PERIODIC_FREQUENCY);
2826 if (auto_fault_cmd)
2827 {
2828 temp_thrust = m_afc * (float)counter_afc + max_fault_mot;
2829 counter_afc = counter_afc + 1;
2830 if (counter_afc > time_afc * PERIODIC_FREQUENCY)
2831 {
2832 counter_afc = 0;
2833 auto_fault_cmd = false;
2834 }
2835 }
2836 else
2837 {
2838 temp_thrust = (float)radio_control_get(RADIO_THROTTLE) - delta_fault;
2839 counter_afc = 0;
2840 }
2841 Bound(temp_thrust, 0.0, max_fault_mot);
2842 // Yaw spin envelope protection: linearly mix the static command with the max command
2843 // depending on how close the (filtered) yaw rate is to the max allowed yaw rate
2844 float abs_r = fabsf(oneloop_nB.sta_state.att_d[2]); // parameters bounded at the start of oneloop_nB_run
2846 Bound(spin_prot_ratio, 0.0, 1.0);
2847 // Spin trim: integrate up while the envelope is active, bleed off below the release rate, hold in between.
2848 // Only active with a single faulted pair in flight, reset otherwise (and during the auto fault ramp).
2849 bool single_fault = nb_ctrl && (fault_pitch_motors != fault_roll_motors);
2851 {
2852 // Spin manoeuvre slowing down: open loop trim increase, no bleed
2853 spin_trim += spin_man_trim_rate / PERIODIC_FREQUENCY;
2854 Bound(spin_trim, 0.0, spin_prot_max_cmd);
2855 }
2856 else if (spin_trim_on && single_fault && in_flight && !auto_fault_cmd)
2857 {
2858 if (spin_prot_ratio > 0.0 && (temp_thrust + spin_trim) < spin_prot_max_cmd) // anti-windup
2859 {
2860 spin_trim += spin_trim_rate * spin_prot_ratio / PERIODIC_FREQUENCY;
2861 }
2862 else if (abs_r < spin_trim_release_rate)
2863 {
2864 spin_trim -= spin_trim_bleed_rate / PERIODIC_FREQUENCY;
2865 }
2866 Bound(spin_trim, 0.0, spin_prot_max_cmd);
2867 }
2868 else
2869 {
2870 spin_trim = 0.0;
2871 }
2872 // spin_prot_max_cmd is the single ceiling for the faulted motors: base + trim is cut to it,
2873 // and the envelope blends towards it (so the blend can only raise the command)
2874 temp_thrust += spin_trim;
2875 Bound(temp_thrust, 0.0, spin_prot_max_cmd);
2876 temp_thrust = (1.0 - spin_prot_ratio) * temp_thrust + spin_prot_ratio * spin_prot_max_cmd;
2877 if (fault_pitch_motors && !fault_roll_motors && nb_ctrl)
2878 {
2879 andi_u[COMMAND_MOTOR_FRONT] = temp_thrust;
2880 andi_u[COMMAND_MOTOR_BACK] = temp_thrust;
2881 }
2882 else if (fault_roll_motors && !fault_pitch_motors && nb_ctrl)
2883 {
2884 andi_u[COMMAND_MOTOR_RIGHT] = temp_thrust;
2885 andi_u[COMMAND_MOTOR_LEFT] = temp_thrust;
2886 }
2887 // Both pairs faulted is not a supported case: it is treated as no fault (normal operation)
2888 // ======================================================================================================================================================
2889 // Spin manoeuvre: bumpless transfer of the selected pair. andi_u already holds the new source
2890 // (static fault cmd when faulted, allocator output when not), blend it from the cmd held at the transition
2891 if (spin_man_alpha < 1.0)
2892 {
2893 for (int k = 0; k < 2; k++)
2894 {
2896 }
2897 }
2898 for (int i = 0; i < ANDI_NUM_ACT; i++)
2899 {
2900 spin_man_u_last[i] = andi_u[i];
2901 }
2902 // ======================================================================================================================================================
2903 /*Commit the actuator command*/
2904 for (int i = 0; i < ANDI_NUM_ACT; i++)
2905 {
2906#if ONELOOP_NB_DEBUG_MODE
2907 if (i == TestMotorIDX)
2908 {
2910 }
2911 else
2912 {
2913 commands[i] = (int16_t)(0.0);
2914 }
2915#else
2917 {
2918 commands[i] = (int16_t)0.0;
2919 }
2920 else
2921 {
2922 commands[i] = (int16_t)andi_u[i];
2923 }
2924#endif
2925 }
2926
2927 commands[COMMAND_THRUST] = (commands[COMMAND_MOTOR_FRONT] + commands[COMMAND_MOTOR_RIGHT] + commands[COMMAND_MOTOR_BACK] + commands[COMMAND_MOTOR_LEFT]) / num_thrusters_oneloop;
2928 autopilot.throttle = commands[COMMAND_THRUST];
2929 stabilization.cmd[COMMAND_THRUST] = commands[COMMAND_THRUST];
2930 if (heading_manual)
2931 {
2932 psi_des_deg = DegOfRad(psi_des_rad);
2933 }
2934 stabilization.cmd[COMMAND_ROLL] = (int16_t)(DegOfRad(eulers_zxy_des.phi) * MAX_PPRZ / DegOfRad(max_phi));
2935 stabilization.cmd[COMMAND_PITCH] = (int16_t)(DegOfRad(eulers_zxy_des.theta) * MAX_PPRZ / DegOfRad(max_theta));
2936 stabilization.cmd[COMMAND_YAW] = (int16_t)(psi_des_deg * MAX_PPRZ / 180.0);
2937}
2938
2939//=========================================================================================================================================================
2941//==========================================================================================================================================================
2943{
2944 int8_t i;
2945 float prev_actuator_state_1l;
2946 for (i = 0; i < ANDI_NUM_ACT_TOT; i++)
2947 {
2948 if (i < ANDI_NUM_ACT)
2949 {
2950 prev_actuator_state_1l = actuator_state_1l[i];
2951 actuator_state_1l[i] = prev_actuator_state_1l + act_dynamics_d[i] * (andi_u[i] - prev_actuator_state_1l);
2953 {
2954 actuator_state_1l[i] = 0.0;
2955 }
2956 Bound(actuator_state_1l[i], act_min[i], act_max[i]);
2957 }
2958 else
2959 {
2960 actuator_state_1l[i] = oneloop_nB.sta_state.att[i - ANDI_NUM_ACT];
2961 }
2962 }
2963}
2964//=========================================================================================================================================================
2969//=========================================================================================================================================================
2970void G1G2_oneloop(int ctrl_type)
2971{
2972 for (int i = 0; i < ANDI_OUTPUTS; i++)
2973 {
2974 bwls_1l[i] = EFF_MAT_G[i];
2975 }
2976 float scaler = 1.0;
2977 for (int i = 0; i < ANDI_NUM_ACT_TOT; i++)
2978 {
2979 switch (ctrl_type)
2980 {
2981 case (CTRL_ANDI):
2982 case (CTRL_NB_ANDI):
2983 scaler = act_dyn_ctrl[i] * ratio_u_un[i];
2984 break;
2985 case (CTRL_INDI):
2986 case (CTRL_NB_INDI):
2987 scaler = ratio_u_un[i];
2988 break;
2989 }
2990 for (int j = 0; j < ANDI_OUTPUTS; j++)
2991 {
2992 EFF_MAT_G[j][i] = EFF_MAT_RW[2 + j][i] * scaler * ratio_vn_v[j]; // EFF_MAT_RW has extra entries for North and EAST
2993 }
2994 }
2995 //=========================================================================================================================================================
2996 // If using an nB controller, convert the Eff matrix to the nB axes
2997 switch (ctrl_type)
2998 {
2999 case (CTRL_NB_ANDI):
3000 case (CTRL_NB_INDI):
3001 {
3002 for (int j = 0; j < ANDI_NUM_ACT_TOT; j++)
3003 {
3004 float temp_ap_j = -EFF_MAT_G[IDX_aq][j] * nB_filt[2].o[0]; //+ EFF_MAT_G[IDX_ar][j]*nB_filt[1].o[0] ;
3005 float temp_aq_j = EFF_MAT_G[IDX_ap][j] * nB_filt[2].o[0]; //- EFF_MAT_G[IDX_ar][j]*nB_filt[0].o[0];
3006 EFF_MAT_G[IDX_ap][j] = temp_ap_j;
3007 EFF_MAT_G[IDX_aq][j] = temp_aq_j;
3008 }
3009 //=========================================================================================================================================================
3010 // Only a single faulted pair is supported, both pairs faulted is treated as no fault
3012 {
3013 EFF_MAT_G[IDX_ar][COMMAND_MOTOR_RIGHT] = 0.0;
3014 EFF_MAT_G[IDX_ar][COMMAND_MOTOR_LEFT] = 0.0;
3015 for (int i = 0; i < ANDI_OUTPUTS; i++)
3016 {
3017 EFF_MAT_G[i][COMMAND_MOTOR_FRONT] = 0.0;
3018 EFF_MAT_G[i][COMMAND_MOTOR_BACK] = 0.0;
3019 }
3020 }
3022 {
3023 EFF_MAT_G[IDX_ar][COMMAND_MOTOR_FRONT] = 0.0;
3024 EFF_MAT_G[IDX_ar][COMMAND_MOTOR_BACK] = 0.0;
3025 for (int i = 0; i < ANDI_OUTPUTS; i++)
3026 {
3027 EFF_MAT_G[i][COMMAND_MOTOR_RIGHT] = 0.0;
3028 EFF_MAT_G[i][COMMAND_MOTOR_LEFT] = 0.0;
3029 }
3030 }
3031#ifdef COMMAND_AILERONS
3032 if (fault_ailerons)
3033 {
3034 for (int i = 0; i < ANDI_OUTPUTS; i++)
3035 {
3036 EFF_MAT_G[i][COMMAND_AILERONS] = 0.0;
3037 }
3038 }
3039#endif
3040 }
3041 break;
3042 }
3043 for (int i = 0; i < ANDI_NUM_ACT_TOT; i++)
3044 {
3045 act_dyn_ctrl[i] = act_dynamics[i];
3046 }
3047}
3048//=========================================================================================================================================================
3050//=========================================================================================================================================================
3052{
3053 int8_t i;
3054 for (i = 0; i < ANDI_NUM_ACT_TOT; i++)
3055 {
3056 act_dynamics_d[i] = 1.0 - exp(-act_dynamics[i] * dt_1l);
3057 Bound(act_dynamics_d[i], 0.00001, 1.0);
3058 Bound(act_max[i], 0, MAX_PPRZ);
3059 Bound(act_min[i], -MAX_PPRZ, 0);
3060 float ratio_numerator = act_max[i] - act_min[i];
3061 ratio_numerator = positive_non_zero(ratio_numerator); // make sure numerator is non-zero
3062 float ratio_denominator = act_max_norm[i] - act_min_norm[i];
3063 ratio_denominator = positive_non_zero(ratio_denominator); // make sure denominator is non-zero
3064 ratio_u_un[i] = ratio_numerator / ratio_denominator;
3065 ratio_u_un[i] = positive_non_zero(ratio_u_un[i]); // make sure ratio is not zero
3066 }
3067 for (i = 0; i < ANDI_OUTPUTS; i++)
3068 {
3069 float ratio_numerator = positive_non_zero(nu_norm_max);
3070 float ratio_denominator = 1.0;
3071 switch (i)
3072 {
3073 case (IDX_aD):
3074 ratio_denominator = positive_non_zero(max_j_lin);
3075 ratio_vn_v[i] = ratio_numerator / ratio_denominator;
3076 break;
3077 case (IDX_ap):
3078 ratio_denominator = positive_non_zero(sta_bounds.att_3d[0]);
3079 ratio_vn_v[i] = ratio_numerator / ratio_denominator;
3080 break;
3081 case (IDX_aq):
3082 ratio_denominator = positive_non_zero(sta_bounds.att_3d[1]);
3083 ratio_vn_v[i] = ratio_numerator / ratio_denominator;
3084 break;
3085 case (IDX_ar):
3086 ratio_denominator = positive_non_zero(sta_bounds.att_3d[2]);
3087 ratio_vn_v[i] = ratio_numerator / ratio_denominator;
3088 break;
3089 }
3090 }
3091}
3092//=========================================================================================================================================================
3094//=========================================================================================================================================================
3096{
3097 int8_t i;
3098 for (i = 0; i < ANDI_OUTPUTS; i++)
3099 {
3100 // printf("ratio_vn_v[%d] = %f \n",i,ratio_vn_v[i]);
3101 nu_n[i] = nu[i] * ratio_vn_v[i];
3102 WLS_one_p.v[i] = nu_n[i];
3103 }
3104}
3105//=========================================================================================================================================================
3107//=========================================================================================================================================================
3108void oneloop_from_nav(bool in_flight)
3109{
3110 if (!in_flight)
3111 {
3112 oneloop_nB_enter(false, oneloop_nB.ctrl_type);
3113 }
3114 struct FloatVect3 PSA_des;
3115 PSA_des.x = stateGetPositionNed_f()->x;
3116 PSA_des.y = stateGetPositionNed_f()->y;
3117 PSA_des.z = stateGetPositionNed_f()->z;
3118 // int rm_order_h = 3;
3119 // int rm_order_v = 3;
3120 // Oneloop controller wants desired targets and handles reference generation internally
3121 switch (nav.setpoint_mode)
3122 {
3124 PSA_des.x = POS_FLOAT_OF_BFP(POS_BFP_OF_REAL(nav.target.y));
3125 PSA_des.y = POS_FLOAT_OF_BFP(POS_BFP_OF_REAL(nav.target.x));
3126 // rm_order_h = 3;
3127 break;
3129 PSA_des.x = SPEED_FLOAT_OF_BFP(SPEED_BFP_OF_REAL(nav.speed.y));
3130 PSA_des.y = SPEED_FLOAT_OF_BFP(SPEED_BFP_OF_REAL(nav.speed.x));
3131 // rm_order_h = 2;
3132 break;
3133 }
3134 switch (nav.vertical_mode)
3135 {
3137 PSA_des.z = POS_FLOAT_OF_BFP(-POS_BFP_OF_REAL(nav.nav_altitude));
3138 // rm_order_v = 3;
3139 break;
3141 PSA_des.z = SPEED_FLOAT_OF_BFP(-SPEED_BFP_OF_REAL(nav.climb));
3142 // rm_order_v = 2;
3143 break;
3144 }
3145 oneloop_nB_run(in_flight, false, PSA_des);
3146}
3147//=========================================================================================================================================================
3149//=========================================================================================================================================================
3151{
3152 // Coordinated turn
3153 // feedforward estimate angular rotation omega = g*tan(phi)/v
3154 float omega = 0.0;
3155 float airspeed_turn = airspeed_filt.o[0];
3156 Bound(airspeed_turn, 1.0f, 30.0f);
3157 // Use the current roll angle to determine the corresponding heading rate of change.
3158 float coordinated_turn_roll = eulers_zxy.phi;
3159 // Prevent flipping
3160 if ((eulers_zxy.theta > 0.0f) && (fabs(eulers_zxy.phi) < eulers_zxy.theta))
3161 {
3162 // printf("Preventing flipping\n");
3163 coordinated_turn_roll = ((eulers_zxy.phi > 0.0f) - (eulers_zxy.phi < 0.0f)) * eulers_zxy.theta;
3164 }
3165 BoundAbs(coordinated_turn_roll, max_phi);
3166 omega = g / airspeed_turn * tanf(coordinated_turn_roll);
3167#ifdef FWD_SIDESLIP_GAIN
3168 // Add sideslip correction
3169 omega -= accely_filt.o[0] * fwd_sideslip_gain;
3170#endif
3171 return omega;
3172}
3173//=========================================================================================================================================================
3175//=========================================================================================================================================================
3177{
3178 return !motors_on;
3179}
3180//=========================================================================================================================================================
3181// Some functions for Airspeed Control DEPRECIATED
3182//=========================================================================================================================================================
3184{
3185 float psi = eulers_zxy.psi;
3186 float cpsi = cosf(psi);
3187 float spsi = sinf(psi);
3188 float airspeed = airspeed_filt.o[0];
3189 struct FloatVect2 NT_v_NE = {nav_target[0], nav_target[1]}; // Nav target in North and East frame
3190 struct FloatVect2 airspeed_v = {cpsi * airspeed, spsi * airspeed};
3191 struct FloatVect2 windspeed;
3192 struct FloatVect2 groundspeed = {oneloop_nB.gui_state.vel[0], oneloop_nB.gui_state.vel[1]};
3193 struct FloatVect2 des_as_NE;
3194 struct FloatVect2 des_as_B;
3195 struct FloatVect2 des_acc_B;
3196 VECT2_DIFF(windspeed, groundspeed, airspeed_v); // Wind speed in North and East frame
3197 VECT2_DIFF(des_as_NE, NT_v_NE, windspeed); // Desired airspeed in North and East frame
3198 float norm_des_as = FLOAT_VECT2_NORM(des_as_NE);
3199 gi_unbounded_airspeed_sp = norm_des_as;
3200 // Check if some minimum airspeed is desired (e.g. to prevent stall)
3201 if (norm_des_as < min_as)
3202 {
3203 norm_des_as = min_as;
3204 }
3205 nav_target_new[0] = NT_v_NE.x;
3206 nav_target_new[1] = NT_v_NE.y;
3207 // if the desired airspeed is larger than the max airspeed or we are in force forward reshape gs des to cancel wind and fly at max airspeed
3208 if ((norm_des_as > max_as) || (force_forward))
3209 {
3210 float groundspeed_factor = 0.0f;
3211 if (FLOAT_VECT2_NORM(windspeed) < max_as)
3212 {
3213 float av = NT_v_NE.x * NT_v_NE.x + NT_v_NE.y * NT_v_NE.y; // norm squared of nav target
3214 float bv = -2.f * (windspeed.x * NT_v_NE.x + windspeed.y * NT_v_NE.y);
3215 float cv = windspeed.x * windspeed.x + windspeed.y * windspeed.y - max_as * max_as;
3216 float dv = bv * bv - 4.0f * av * cv;
3217 // dv can only be positive, but just in case
3218 if (dv < 0.0f)
3219 {
3220 dv = fabsf(dv);
3221 }
3222 float d_sqrt = sqrtf(dv);
3223 groundspeed_factor = (-bv + d_sqrt) / (2.0f * av);
3224 }
3225 des_as_NE.x = groundspeed_factor * NT_v_NE.x - windspeed.x;
3226 des_as_NE.y = groundspeed_factor * NT_v_NE.y - windspeed.y;
3227 NT_v_NE.x = groundspeed_factor * NT_v_NE.x;
3228 NT_v_NE.y = groundspeed_factor * NT_v_NE.y;
3229 norm_des_as = max_as;
3230 }
3231 des_as_B.x = norm_des_as; // Desired airspeed in body x frame
3232 des_as_B.y = 0.0; // Desired airspeed in body y frame
3233 if (((airspeed > ONELOOP_NB_AIRSPEED_SWITCH_THRESHOLD) && (norm_des_as > (ONELOOP_NB_AIRSPEED_SWITCH_THRESHOLD + 2.0f))) || (force_forward))
3234 {
3235 float delta_psi = atan2f(des_as_NE.y, des_as_NE.x) - psi;
3236 FLOAT_ANGLE_NORMALIZE(delta_psi);
3237 des_acc_B.y = delta_psi * 5.0; // gih_params.heading_bank_gain;
3238 des_acc_B.x = (des_as_B.x - airspeed) * k_pos_rm.k2[0]; // gih_params.speed_gain;
3239 acc_body_bound(&des_acc_B, max_a_nav); // Scale down side acceleration if norm is too large
3240 nav_target_new[0] = cpsi * des_acc_B.x - spsi * des_acc_B.y;
3241 nav_target_new[1] = spsi * des_acc_B.x + cpsi * des_acc_B.y;
3242 }
3243 else
3244 {
3245 nav_target_new[0] = (NT_v_NE.x - groundspeed.x) * k_pos_rm.k2[0];
3246 nav_target_new[1] = (NT_v_NE.y - groundspeed.y) * k_pos_rm.k2[1];
3247 }
3249}
3250
3251void guidance_set_min_max_airspeed(float min_airspeed, float max_airspeed)
3252{
3253 min_as = min_airspeed;
3255}
3256//=========================================================================================================================================================
3262//=========================================================================================================================================================
3264{
3265 for (int8_t i = 0; i < ANDI_NUM_ACT; i++)
3266 {
3268 }
3269 // Store the distrubance
3270 // float k3;
3271 if (in_flight)
3272 {
3273 for (int8_t i = 0; i < ANDI_OUTPUTS; i++)
3274 { // For loop for prediction of acceleration
3275 ctrl_effort_model[i] = 0.0;
3276 // switch (i)
3277 // {
3278 // case (IDX_aD):
3279 // k3 = 1.0; // k_pos_e.k3[2];
3280 // break;
3281 // case (IDX_ap):
3282 // k3 = k_att_e.k3[0];
3283 // break;
3284 // case (IDX_aq):
3285 // k3 = k_att_e.k3[1];
3286 // break;
3287 // case (IDX_ar):
3288 // k3 = k_att_e.k3[2];
3289 // break;
3290 // }
3291 // k3 = positive_non_zero(k3);
3292 for (int8_t j = 0; j < ANDI_NUM_ACT_TOT; j++)
3293 {
3294 float den = positive_non_zero(ratio_u_un[j] * ratio_vn_v[i]);
3295 float num = u_filt[j].o[0] * EFF_MAT_G[i][j];
3296 ctrl_effort_model[i] += num / den;
3297 }
3298 // ctrl_effort_model[i] = ctrl_effort_model[i] / k3;
3299 }
3300 }
3301 else
3302 {
3304 }
3305}
3306//=========================================================================================================================================================
3308//=========================================================================================================================================================
3310{
3311 float p = oneloop_nB.sta_state.att_d[0];
3312 float q = oneloop_nB.sta_state.att_d[1];
3313 float r = oneloop_nB.sta_state.att_d[2];
3314 float p_dot = oneloop_nB.sta_state.att_2d[0];
3315 float q_dot = oneloop_nB.sta_state.att_2d[1];
3316 float r_dot = oneloop_nB.sta_state.att_2d[2];
3318 {
3319 nu[IDX_ap] -= (r * q_dot + q * r_dot) * (RW.I.yy - RW.I.zz) / RW.I.xx; // Roll
3320 nu[IDX_aq] -= (r * p_dot + p * r_dot) * (RW.I.zz - RW.I.xx) / RW.I.yy; // Pitch
3321 }
3322}
3323//=========================================================================================================================================================
3325//=========================================================================================================================================================
3326void drop_axis(void)
3327{
3328 if (drop_yaw)
3329 {
3331 }
3332 if (drop_roll)
3333 {
3335 }
3336 if (drop_pitch)
3337 {
3339 }
3340 if (drop_aD)
3341 {
3343 }
3344}
3345//=========================================================================================================================================================
3347//=========================================================================================================================================================
3349{
3350 for (int i = 0; i < ANDI_NUM_ACT_TOT; i++)
3351 {
3352 switch (i)
3353 {
3354 case COMMAND_MOTOR_FRONT:
3355 case COMMAND_MOTOR_RIGHT:
3356 case COMMAND_MOTOR_BACK:
3357 case COMMAND_MOTOR_LEFT:
3358#ifdef COMMAND_AILERONS
3359 case COMMAND_AILERONS:
3360#endif
3361 WLS_one_p.Wu[i] = Wu_backup[i];
3362 WLS_one_p.u_min[i] = (act_min[i]) / ratio_u_un[i];
3363 WLS_one_p.u_pref[i] = (u_pref[i]) / ratio_u_un[i];
3364 WLS_one_p.u_max[i] = (act_max[i]) / ratio_u_un[i];
3365 break;
3366 }
3367 }
3368 bool IN_QUAD = true;
3369#ifdef COMMAND_ROT_MECH
3370 if (RW.skew.deg > 70.0)
3371 {
3372 IN_QUAD = false;
3373 }
3374#endif
3375 // Start from the nominal weights every loop, the single fault cases below only override what they change.
3376 // This way no weight or drop flag is carried over when switching from one faulted pair to the other.
3381 drop_roll = false;
3382 drop_pitch = false;
3383 drop_yaw = false;
3384 drop_aD = false;
3385 // Only a single faulted pair is supported, both pairs faulted (or no fault) keeps the nominal weights
3386 if (fault_pitch_motors && !fault_roll_motors && fault_ailerons && IN_QUAD && (oneloop_nB.ctrl_type == CTRL_NB_INDI || oneloop_nB.ctrl_type == CTRL_NB_ANDI))
3387 {
3388 /* TRUE FALSE TRUE, QUAD → 0 1 0, 1 0 1 */
3389 WLS_one_p.Wv[IDX_ap] = 0.0;
3391 WLS_one_p.Wv[IDX_ar] = 0.0;
3392 drop_roll = true;
3393 drop_pitch = false;
3394 drop_yaw = true;
3395 }
3396 else if (fault_pitch_motors && !fault_roll_motors && fault_ailerons && !IN_QUAD && (oneloop_nB.ctrl_type == CTRL_NB_INDI || oneloop_nB.ctrl_type == CTRL_NB_ANDI))
3397 {
3398 /* TRUE FALSE TRUE, skew90 → 1 0 0, 0 1 1 */
3400 WLS_one_p.Wv[IDX_aq] = 0.0;
3401 WLS_one_p.Wv[IDX_ar] = 0.0;
3402 drop_roll = false;
3403 drop_pitch = true;
3404 drop_yaw = true;
3405 }
3406 else if (!fault_pitch_motors && fault_roll_motors && fault_ailerons && IN_QUAD && (oneloop_nB.ctrl_type == CTRL_NB_INDI || oneloop_nB.ctrl_type == CTRL_NB_ANDI))
3407 {
3408 /* FALSE TRUE TRUE, QUAD → 1 0 0, 0 1 1 */
3409 // Only FRONT/BACK remain and they give pitch moment, which in nB is the IDX_ap row: keep ap, drop aq
3410 // (same as the FALSE TRUE FALSE, QUAD case: the ailerons have no effect in quad)
3412 WLS_one_p.Wv[IDX_aq] = 0.0;
3413 WLS_one_p.Wv[IDX_ar] = 0.0;
3414 drop_roll = false;
3415 drop_pitch = true;
3416 drop_yaw = true;
3417 }
3418 else if (!fault_pitch_motors && fault_roll_motors && fault_ailerons && !IN_QUAD && (oneloop_nB.ctrl_type == CTRL_NB_INDI || oneloop_nB.ctrl_type == CTRL_NB_ANDI))
3419 {
3420 /* FALSE TRUE TRUE, skew90 → 1 0 0, 0 1 1 */
3422 WLS_one_p.Wv[IDX_aq] = 0.0;
3423 WLS_one_p.Wv[IDX_ar] = 0.0;
3424 drop_roll = false;
3425 drop_pitch = true;
3426 drop_yaw = true;
3427 }
3428 else if (fault_pitch_motors && !fault_roll_motors && !fault_ailerons && IN_QUAD && (oneloop_nB.ctrl_type == CTRL_NB_INDI || oneloop_nB.ctrl_type == CTRL_NB_ANDI))
3429 {
3430 /* TRUE FALSE FALSE, QUAD → 0 1 0, 1 0 1 */
3431 WLS_one_p.Wv[IDX_ap] = 0.0;
3433 WLS_one_p.Wv[IDX_ar] = 0.0;
3434 drop_roll = true;
3435 drop_pitch = false;
3436 drop_yaw = true;
3437 }
3438 else if (fault_pitch_motors && !fault_roll_motors && !fault_ailerons && !IN_QUAD && (oneloop_nB.ctrl_type == CTRL_NB_INDI || oneloop_nB.ctrl_type == CTRL_NB_ANDI))
3439 {
3440 /* TRUE FALSE FALSE, skew90 → 1 1 0, 0 0 1 */
3443 WLS_one_p.Wv[IDX_ar] = 0.0;
3444 drop_roll = false;
3445 drop_pitch = false;
3446 drop_yaw = true;
3447 }
3448 else if (!fault_pitch_motors && fault_roll_motors && !fault_ailerons && IN_QUAD && (oneloop_nB.ctrl_type == CTRL_NB_INDI || oneloop_nB.ctrl_type == CTRL_NB_ANDI))
3449 {
3450 /* FALSE TRUE FALSE, QUAD → 0 1 0, 1 0 1 */
3452 WLS_one_p.Wv[IDX_aq] = 0.0;
3453 WLS_one_p.Wv[IDX_ar] = 0.0;
3454 drop_roll = false;
3455 drop_pitch = true;
3456 drop_yaw = true;
3457 }
3458 else if (!fault_pitch_motors && fault_roll_motors && !fault_ailerons && !IN_QUAD && (oneloop_nB.ctrl_type == CTRL_NB_INDI || oneloop_nB.ctrl_type == CTRL_NB_ANDI))
3459 {
3460 /* FALSE TRUE FALSE, skew90 → 1 1 0, 0 0 1 */
3463 WLS_one_p.Wv[IDX_ar] = 0.0;
3464 drop_roll = false;
3465 drop_pitch = false;
3466 drop_yaw = true;
3467 }
3468}
3469//=========================================================================================================================================================
3472{
3473 struct FloatRMat *LBI = stateGetNedToBodyRMat_f();
3474 struct FloatRMat Omega_B;
3475 struct FloatRMat Omega_B_dot;
3476 struct FloatRMat Omega_B_ddot;
3477
3478 struct FloatVect3 pqr;
3479 struct FloatVect3 pqr_dot;
3480 struct FloatVect3 pqr_ddot;
3481
3482 struct FloatVect3 A;
3483 struct FloatVect3 B;
3484 struct FloatVect3 C;
3485 struct FloatVect3 D;
3486 struct FloatVect3 temp;
3487 struct FloatVect3 temp2;
3488
3489 // Variables for the 3rd derivative components
3490 struct FloatVect3 t1, t2, t3, t4, t5, t6, t7;
3491
3492 FLOAT_VECT3_ZERO(oneloop_nB.sta_nB_state.nB);
3493 FLOAT_VECT3_ZERO(oneloop_nB.sta_nB_state.nB_d);
3494 FLOAT_VECT3_ZERO(oneloop_nB.sta_nB_state.nB_2d);
3495 FLOAT_VECT3_ZERO(oneloop_nB.sta_nB_state.nB_3d);
3496
3497 // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3498 pqr.x = LP.p.meas;
3499 pqr.y = LP.q.meas;
3500 pqr.z = LP.r.meas;
3501 pqr_dot.x = LP.p_dot.meas;
3502 pqr_dot.y = LP.q_dot.meas;
3503 pqr_dot.z = LP.r_dot.meas;
3504 pqr_ddot.x = LP.p_ddot.meas;
3505 pqr_ddot.y = LP.q_ddot.meas;
3506 pqr_ddot.z = LP.r_ddot.meas;
3507
3508 skew_symmetric(&Omega_B, &pqr);
3509 skew_symmetric(&Omega_B_dot, &pqr_dot);
3510 skew_symmetric(&Omega_B_ddot, &pqr_ddot);
3511 // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3512
3513 // nB = LBI * nI
3514 float_rmat_vmult(&oneloop_nB.sta_nB_state.nB, LBI, &oneloop_nB.sta_nB_state.nI);
3515
3516 // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3517 // nB_d= -Omega_B * nB + LBI * nI_dot
3518 float_rmat_vmult(&A, &Omega_B, &oneloop_nB.sta_nB_state.nB);
3519 float_rmat_vmult(&B, LBI, &oneloop_nB.sta_nB_state.nI_d);
3520 VECT3_SUB(oneloop_nB.sta_nB_state.nB_d, A);
3521 VECT3_ADD(oneloop_nB.sta_nB_state.nB_d, B);
3522
3523 // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3524 // nB_2d= -Omega_B_dot * nB - Omega_B * nB_dot - Omega_B * LBI * nI_dot + LBI * nI_2dot
3525#ifdef USE_ND_NB_2D
3526 static bool nB_2d_inited = false;
3527 static struct FloatVect3 nB_d_prev;
3528 if (!nB_2d_inited)
3529 {
3530 nB_d_prev.x = oneloop_nB.sta_nB_state.nB_d.x;
3531 nB_d_prev.y = oneloop_nB.sta_nB_state.nB_d.y;
3532 nB_d_prev.z = oneloop_nB.sta_nB_state.nB_d.z;
3533 nB_2d_inited = true;
3534 }
3535 oneloop_nB.sta_nB_state.nB_2d.x = (oneloop_nB.sta_nB_state.nB_d.x - nB_d_prev.x) * PERIODIC_FREQUENCY;
3536 oneloop_nB.sta_nB_state.nB_2d.y = (oneloop_nB.sta_nB_state.nB_d.y - nB_d_prev.y) * PERIODIC_FREQUENCY;
3537 oneloop_nB.sta_nB_state.nB_2d.z = (oneloop_nB.sta_nB_state.nB_d.z - nB_d_prev.z) * PERIODIC_FREQUENCY;
3538 nB_d_prev.x = oneloop_nB.sta_nB_state.nB_d.x;
3539 nB_d_prev.y = oneloop_nB.sta_nB_state.nB_d.y;
3540 nB_d_prev.z = oneloop_nB.sta_nB_state.nB_d.z;
3541#else
3542 float_rmat_vmult(&A, &Omega_B_dot, &oneloop_nB.sta_nB_state.nB);
3543 float_rmat_vmult(&B, &Omega_B, &oneloop_nB.sta_nB_state.nB_d);
3544 float_rmat_vmult(&temp, LBI, &oneloop_nB.sta_nB_state.nI_d);
3545 float_rmat_vmult(&C, &Omega_B, &temp);
3546 float_rmat_vmult(&D, LBI, &oneloop_nB.sta_nB_state.nI_2d);
3547 VECT3_SUB(oneloop_nB.sta_nB_state.nB_2d, A);
3548 VECT3_SUB(oneloop_nB.sta_nB_state.nB_2d, B);
3549 VECT3_SUB(oneloop_nB.sta_nB_state.nB_2d, C);
3550 VECT3_ADD(oneloop_nB.sta_nB_state.nB_2d, D);
3551#endif
3552
3553 // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3554 // nB_3d = -Omega_B_ddot*nB - 2*Omega_B*Omega_B_dot*nB - Omega_B*Omega_B*Omega_B*nB
3555 // + LBI*nI_3d - 3*Omega_B*nB_2d - 3*Omega_B_dot*nB_d - 3*Omega_B*Omega_B*nB_d
3556#ifdef USE_ND_NB_3D
3557 static bool nB_3d_inited = false;
3558 static struct FloatVect3 nB_2d_prev;
3559 if (!nB_3d_inited)
3560 {
3561 nB_2d_prev.x = oneloop_nB.sta_nB_state.nB_2d.x;
3562 nB_2d_prev.y = oneloop_nB.sta_nB_state.nB_2d.y;
3563 nB_2d_prev.z = oneloop_nB.sta_nB_state.nB_2d.z;
3564 nB_3d_inited = true;
3565 }
3566 oneloop_nB.sta_nB_state.nB_3d.x = (oneloop_nB.sta_nB_state.nB_2d.x - nB_2d_prev.x) * PERIODIC_FREQUENCY;
3567 oneloop_nB.sta_nB_state.nB_3d.y = (oneloop_nB.sta_nB_state.nB_2d.y - nB_2d_prev.y) * PERIODIC_FREQUENCY;
3568 oneloop_nB.sta_nB_state.nB_3d.z = (oneloop_nB.sta_nB_state.nB_2d.z - nB_2d_prev.z) * PERIODIC_FREQUENCY;
3569 nB_2d_prev.x = oneloop_nB.sta_nB_state.nB_2d.x;
3570 nB_2d_prev.y = oneloop_nB.sta_nB_state.nB_2d.y;
3571 nB_2d_prev.z = oneloop_nB.sta_nB_state.nB_2d.z;
3572#else
3573 // t1 = Omega_B_ddot * nB
3574 float_rmat_vmult(&t1, &Omega_B_ddot, &oneloop_nB.sta_nB_state.nB);
3575
3576 // t2 = 2 * Omega_B * Omega_B_dot * nB
3577 float_rmat_vmult(&temp, &Omega_B_dot, &oneloop_nB.sta_nB_state.nB);
3578 float_rmat_vmult(&t2, &Omega_B, &temp);
3579 t2.x *= 2.0f;
3580 t2.y *= 2.0f;
3581 t2.z *= 2.0f;
3582
3583 // t3 = Omega_B * Omega_B * Omega_B * nB
3584 float_rmat_vmult(&temp, &Omega_B, &oneloop_nB.sta_nB_state.nB);
3585 float_rmat_vmult(&temp2, &Omega_B, &temp);
3586 float_rmat_vmult(&t3, &Omega_B, &temp2);
3587
3588 // t4 = LBI * nI_3d
3589 float_rmat_vmult(&t4, LBI, &oneloop_nB.sta_nB_state.nI_3d);
3590
3591 // t5 = 3 * Omega_B * nB_2d
3592 float_rmat_vmult(&t5, &Omega_B, &oneloop_nB.sta_nB_state.nB_2d);
3593 t5.x *= 3.0f;
3594 t5.y *= 3.0f;
3595 t5.z *= 3.0f;
3596
3597 // t6 = 3 * Omega_B_dot * nB_d
3598 float_rmat_vmult(&t6, &Omega_B_dot, &oneloop_nB.sta_nB_state.nB_d);
3599 t6.x *= 3.0f;
3600 t6.y *= 3.0f;
3601 t6.z *= 3.0f;
3602
3603 // t7 = 3 * Omega_B * Omega_B * nB_d
3604 float_rmat_vmult(&temp, &Omega_B, &oneloop_nB.sta_nB_state.nB_d);
3605 float_rmat_vmult(&t7, &Omega_B, &temp);
3606 t7.x *= 3.0f;
3607 t7.y *= 3.0f;
3608 t7.z *= 3.0f;
3609
3610 // Combine components into nB_3d state
3611
3612 VECT3_SUB(oneloop_nB.sta_nB_state.nB_3d, t2);
3613 VECT3_SUB(oneloop_nB.sta_nB_state.nB_3d, t3);
3614 VECT3_ADD(oneloop_nB.sta_nB_state.nB_3d, t4);
3615 VECT3_SUB(oneloop_nB.sta_nB_state.nB_3d, t5);
3616 VECT3_SUB(oneloop_nB.sta_nB_state.nB_3d, t6);
3617 VECT3_SUB(oneloop_nB.sta_nB_state.nB_3d, t7);
3618 debug_state[0] = oneloop_nB.sta_nB_state.nB_3d.x;
3619 debug_state[1] = oneloop_nB.sta_nB_state.nB_3d.y;
3620 debug_state[2] = oneloop_nB.sta_nB_state.nB_3d.z;
3621 state_term[0] = oneloop_nB.sta_nB_state.nB_3d.x;
3622 state_term[1] = oneloop_nB.sta_nB_state.nB_3d.y;
3623 state_term[2] = oneloop_nB.sta_nB_state.nB_3d.z;
3624 VECT3_SUB(oneloop_nB.sta_nB_state.nB_3d, t1);
3625
3626 float sigma_1 = RW.I.yy * (pqr.y * pqr_dot.z + pqr_dot.y * pqr.z) - RW.I.zz * (pqr.y * pqr_dot.z + pqr_dot.y * pqr.z);
3627 float sigma_2 = RW.I.xx * (pqr.x * pqr_dot.z + pqr_dot.x * pqr.z) - RW.I.zz * (pqr.x * pqr_dot.z + pqr_dot.x * pqr.z);
3628 float sigma_3 = RW.I.xx * (pqr.x * pqr_dot.y + pqr_dot.x * pqr.y) - RW.I.yy * (pqr.x * pqr_dot.y + pqr_dot.x * pqr.y);
3629 float upsilon_1 = oneloop_nB.sta_nB_state.nB.y * sigma_3 / RW.I.zz + oneloop_nB.sta_nB_state.nB.z * sigma_2 / RW.I.yy;
3630 float upsilon_2 = oneloop_nB.sta_nB_state.nB.z * sigma_1 / RW.I.xx - oneloop_nB.sta_nB_state.nB.x * sigma_3 / RW.I.zz;
3631 float upsilon_3 = -oneloop_nB.sta_nB_state.nB.x * sigma_2 / RW.I.yy - oneloop_nB.sta_nB_state.nB.y * sigma_1 / RW.I.xx;
3632 state_term[0] += upsilon_1;
3633 state_term[1] += upsilon_2;
3634 state_term[2] += upsilon_3;
3635
3636 update_butterworth_2_low_pass(&nB_filt[0], oneloop_nB.sta_nB_state.nB.x);
3637 update_butterworth_2_low_pass(&nB_filt[1], oneloop_nB.sta_nB_state.nB.y);
3638 update_butterworth_2_low_pass(&nB_filt[2], oneloop_nB.sta_nB_state.nB.z);
3639 update_butterworth_2_low_pass(&nB_2d_filt[0], oneloop_nB.sta_nB_state.nB_2d.x);
3640 update_butterworth_2_low_pass(&nB_2d_filt[1], oneloop_nB.sta_nB_state.nB_2d.y);
3641 update_butterworth_2_low_pass(&nB_2d_filt[2], oneloop_nB.sta_nB_state.nB_2d.z);
3644
3645#endif
3646}
3647
3648void nB_EC(struct FloatVect3 nB, struct FloatVect3 nB_d, struct FloatVect3 nB_2d, struct FloatVect3 mu_B, float k1_e[3], float k2_e[3], float k3_e[3], float dist[3], float nB_nu[3])
3649{
3650 float nB_d_des[3];
3651 nB_d_des[0] = k1_e[0] * (mu_B.x - nB.x);
3652 nB_d_des[1] = k1_e[1] * (mu_B.y - nB.y);
3653 nB_d_des[2] = k1_e[2] * (mu_B.z - nB.z);
3654 float nB_2d_des[3];
3655 nB_2d_des[0] = k2_e[0] * (nB_d_des[0] - nB_d.x);
3656 nB_2d_des[1] = k2_e[1] * (nB_d_des[1] - nB_d.y);
3657 nB_2d_des[2] = k2_e[2] * (nB_d_des[2] - nB_d.z);
3658
3659 nB_nu[0] = k3_e[0] * (nB_2d_des[0] - nB_2d.x) + dist[0];
3660 nB_nu[1] = k3_e[1] * (nB_2d_des[1] - nB_2d.y) + dist[1];
3661 nB_nu[2] = 0.0; // k3_e[2]*(nB_2d_des[2]-nB_2d.z) + dist[2];
3662 // printf("nB_nu function: %f, %f, %f\n", nB_nu[0], nB_nu[1], nB_nu[2]);
3663}
3664
3665void skew_symmetric(struct FloatRMat *out, const struct FloatVect3 *in)
3666{
3667 // Row 0
3668 out->m[0] = 0.0f; // (0,0)
3669 out->m[1] = -in->z; // (0,1)
3670 out->m[2] = in->y; // (0,2)
3671 // Row 1
3672 out->m[3] = in->z; // (1,0)
3673 out->m[4] = 0.0f; // (1,1)
3674 out->m[5] = -in->x; // (1,2)
3675 // Row 2
3676 out->m[6] = -in->y; // (2,0)
3677 out->m[7] = in->x; // (2,1)
3678 out->m[8] = 0.0f; // (2,2)
3679}
3680
3681void rm_3rd_nI(float dt, struct FloatVect3 *x_ref, struct FloatVect3 *x_d_ref, struct FloatVect3 *x_2d_ref, struct FloatVect3 *x_3d_ref, const struct FloatVect3 *x_des, const float k1_rm[3], const float k2_rm[3], const float k3_rm[3])
3682{
3683 // printf("RM 3rd nI\n");
3684 // printf("x_ref: %f, %f, %f\n", x_ref->x, x_ref->y, x_ref->z);
3685 // printf("x_d_ref: %f, %f, %f\n", x_d_ref->x, x_d_ref->y, x_d_ref->z);
3686 // printf("x_2d_ref: %f, %f, %f\n", x_2d_ref->x, x_2d_ref->y, x_2d_ref->z);
3687 // printf("x_3d_ref: %f, %f, %f\n", x_3d_ref->x, x_3d_ref->y, x_3d_ref->z);
3688 // printf("x_des: %f, %f, %f\n", x_des->x, x_des->y, x_des->z);
3689
3690 float e_x[3];
3691 float e_x_d[3];
3692 float e_x_2d[3];
3693
3694 e_x[0] = k1_rm[0] * (x_des->x - x_ref->x);
3695 e_x[1] = k1_rm[1] * (x_des->y - x_ref->y);
3696 e_x[2] = k1_rm[2] * (x_des->z - x_ref->z);
3697
3698 e_x_d[0] = k2_rm[0] * (e_x[0] - x_d_ref->x);
3699 e_x_d[1] = k2_rm[1] * (e_x[1] - x_d_ref->y);
3700 e_x_d[2] = k2_rm[2] * (e_x[2] - x_d_ref->z);
3701
3702 e_x_2d[0] = k3_rm[0] * (e_x_d[0] - x_2d_ref->x);
3703 e_x_2d[1] = k3_rm[1] * (e_x_d[1] - x_2d_ref->y);
3704 e_x_2d[2] = k3_rm[2] * (e_x_d[2] - x_2d_ref->z);
3705
3706 // printf("e_x : %f, %f, %f\n", e_x[0], e_x[1], e_x[2]);
3707 // printf("e_x_d : %f, %f, %f\n", e_x_d[0], e_x_d[1], e_x_d[2]);
3708 // printf("e_x_2d: %f, %f, %f\n", e_x_2d[0], e_x_2d[1], e_x_2d[2]);
3709
3710 // 3rd derivative
3711 x_3d_ref->x = e_x_2d[0];
3712 x_3d_ref->y = e_x_2d[1];
3713 x_3d_ref->z = e_x_2d[2];
3714
3715 // integrate jerk -> acceleration
3716 x_2d_ref->x += dt * x_3d_ref->x;
3717 x_2d_ref->y += dt * x_3d_ref->y;
3718 x_2d_ref->z += dt * x_3d_ref->z;
3719
3720 // integrate acceleration -> velocity
3721 x_d_ref->x += dt * x_2d_ref->x;
3722 x_d_ref->y += dt * x_2d_ref->y;
3723 x_d_ref->z += dt * x_2d_ref->z;
3724
3725 // integrate velocity -> position
3726 x_ref->x += dt * x_d_ref->x;
3727 x_ref->y += dt * x_d_ref->y;
3728 x_ref->z += dt * x_d_ref->z;
3729
3730 // printf("Updated x_ref : %f, %f, %f\n", x_ref->x, x_ref->y, x_ref->z);
3731 // printf("Updated x_d_ref : %f, %f, %f\n", x_d_ref->x, x_d_ref->y, x_d_ref->z);
3732 // printf("Updated x_2d_ref: %f, %f, %f\n", x_2d_ref->x, x_2d_ref->y, x_2d_ref->z);
3733 // printf("Updated x_3d_ref: %f, %f, %f\n", x_3d_ref->x, x_3d_ref->y, x_3d_ref->z);
3734}
3735
3736void calc_HB_matrix(float HB[3][3], struct FloatVect3 nB)
3737{
3738 HB[0][0] = 0.0;
3739 HB[0][1] = -nB.z;
3740 HB[0][2] = nB.y;
3741 HB[1][0] = nB.z;
3742 HB[1][1] = 0.0;
3743 HB[1][2] = -nB.x;
3744 HB[2][0] = -nB.y;
3745 HB[2][1] = nB.x;
3746 HB[2][2] = 0.0;
3747}
3748
3749void SpinQuad_overwrite(float gain, float ce_model, float *nu_stab_2)
3750{
3751 SQ_r = 0.0;
3752
3754 {
3755 if (spin_man_rate_ctrl())
3756 {
3757 SQ_r = spin_man_r_ref; // signed yaw rate reference of the spin manoeuvre
3758 BoundAbs(SQ_r, 40.0);
3759 }
3760 else
3761 {
3762 SQ_r = (float)radio_control.values[RADIO_AUX4] / MAX_PPRZ * 40.0;
3763 Bound(SQ_r, 0.0, 40.0);
3764 }
3765
3766 *nu_stab_2 = (SQ_r - oneloop_nB.sta_state.att_d[2]) * k_att_e.k2[2];
3767 BoundAbs(*nu_stab_2, sta_bounds.att_2d[2]);
3768
3769 *nu_stab_2 = (*nu_stab_2 - oneloop_nB.sta_state.att_2d[2]) * gain;
3770 *nu_stab_2 += ce_model;
3771 }
3772}
3773
3775{
3776 (void)max_bank;
3777 return;
3778}
3779
3780void guidance_set_max_climb_speed(float max_climb_speed_quad, float max_climb_speed_fwd)
3781{
3782 (void)max_climb_speed_quad;
3783 (void)max_climb_speed_fwd;
3784 return;
3785}
3786
3787void guidance_set_max_descend_speed(float max_descend_speed_quad, float max_descend_speed_fwd)
3788{
3789 (void)max_descend_speed_quad;
3790 (void)max_descend_speed_fwd;
3791 return;
3792}
3793
3794// Calculate cos^{2n}((psi-xi)/2)
3795float cos_2n(float psi, float xi, int n)
3796{
3797 float c = cosf((psi - xi) / 2.0f); // cos((psi-xi)/2)
3798 float c2 = c * c; // cos^2((psi-xi)/2)
3799 float y = 1.0f;
3800 for (int i = 0; i < n; i++)
3801 {
3802 y *= c2; // y = (cos^2(x))^n
3803 }
3804
3805 return y;
3806}
3807
3808float phase_first_order(float r, float w)
3809{
3810 float out = -atan2f(r, w);
3811 NormRadAngle(out);
3812 return out;
3813}
3814
3815float xi_fun(float r, float w, float aN_des, float aE_des)
3816{
3817 oneloop_nB.push_nB.xi_0 = phase_first_order(r, w);
3818 oneloop_nB.push_nB.xi = atan2f(aE_des, aN_des) + oneloop_nB.push_nB.xi_0;
3819 NormRadAngle(oneloop_nB.push_nB.xi);
3820 return oneloop_nB.push_nB.xi;
3821}
3822
3823float pusher_cmd_fun(float aN_des, float aE_des, float r, float psi, float w, int n)
3824{
3825 float a_des_norm = sqrtf(aN_des * aN_des + aE_des * aE_des);
3826 float xi;
3827 if (a_des_norm > 0.1)
3828 {
3829 xi = xi_fun(r, w, aN_des, aE_des);
3830 }
3831 else
3832 {
3833 xi = psi + M_PI;
3834 NormRadAngle(xi);
3835 }
3836 // float pusher_cmd = a_des_norm * cos_2n(psi, xi, n);
3837 float pusher_cmd = cos_2n(psi, xi, n);
3838 Bound(pusher_cmd, 0.0f, 1.0f);
3839 return pusher_cmd;
3840}
3841
3842// float pusher_cmd_fun(float aN_des, float aE_des, float r, float psi, float w, int n){
3843// (void) n;
3844// float a_des_norm = sqrtf(aN_des * aN_des + aE_des * aE_des);
3845// float xi;
3846// if (a_des_norm > 0.1){
3847// xi = xi_fun(r, w, aN_des, aE_des);
3848// }else{
3849// xi = psi + M_PI;
3850// NormRadAngle(xi);
3851// }
3852//
3853// // compute smallest signed angle difference between psi and xi
3854// float d = psi - xi;
3855// NormRadAngle(d);
3856//
3857// // if psi is within +/- pi/2 of xi, command 1.0, else 0.0
3858// float pusher_cmd;
3859// if (fabsf(d) <= (M_PI * 0.5f)){
3860// pusher_cmd = 1.0f;
3861// } else {
3862// pusher_cmd = 0.0f;
3863// }
3864//
3865// Bound(pusher_cmd, 0.0f, 1.0f);
3866// return pusher_cmd;
3867// }
3868
3869// float pusher_pre_cmd_fun(float vN_d, float vE_d, float r, float psi, float w, int n){
3870
3871// }
Main include for ABI (AirBorneInterface).
#define B
struct pprz_autopilot autopilot
Global autopilot structure.
Definition autopilot.c:50
bool autopilot_get_motors_on(void)
get motors status
Definition autopilot.c:302
static uint16_t c2
#define UNUSED(x)
Hardware independent code for commands handling.
static struct uart_periph * dev
float G2_RW[EFF_MAT_COLS_NB]
struct RW_Model RW
float EFF_MAT_RW[EFF_MAT_ROWS_NB][EFF_MAT_COLS_NB]
#define COMMAND_PITCH
#define COMMAND_ROLL
#define Min(x, y)
Definition esc_dshot.c:110
float q
in rad/s
float p
in rad/s
float r
in rad/s
float m[3 *3]
#define FLOAT_ANGLE_NORMALIZE(_a)
static void float_vect_sum(float *o, const float *a, const float *b, const int n)
o = a + b
static void float_vect_zero(float *a, const int n)
a = 0
void float_eulers_of_quat_zxy(struct FloatEulers *e, const struct FloatQuat *q)
euler rotation 'ZXY' This rotation order is useful if you need 90 deg pitch
#define FLOAT_VECT3_ZERO(_v)
void float_rmat_vmult(struct FloatVect3 *vb, const struct FloatRMat *m_a2b, const struct FloatVect3 *va)
rotate 3D vector by rotation matrix.
static void float_vect_copy(float *a, const float *b, const int n)
a = b
static void float_vect_diff(float *o, const float *a, const float *b, const int n)
o = a - b
static float float_vect_norm(const float *a, const int n)
||a||
#define FLOAT_VECT2_NORM(_v)
euler angles
rotation matrix
angular rates
#define VECT2_DIFF(_c, _a, _b)
#define VECT3_SUB(_a, _b)
#define VECT3_ADD(_a, _b)
#define POS_FLOAT_OF_BFP(_ai)
#define SPEED_FLOAT_OF_BFP(_ai)
#define POS_BFP_OF_REAL(_af)
#define ACCEL_FLOAT_OF_BFP(_ai)
#define SPEED_BFP_OF_REAL(_af)
#define A
static struct NedCoor_f * stateGetAccelNed_f(void)
Get acceleration in NED coordinates (float).
Definition state.h:1214
static struct FloatRMat * stateGetNedToBodyRMat_f(void)
Get vehicle body attitude rotation matrix (float).
Definition state.h:1319
static struct FloatQuat * stateGetNedToBodyQuat_f(void)
Get vehicle body attitude quaternion (float).
Definition state.h:1313
static struct NedCoor_f * stateGetPositionNed_f(void)
Get position in local NED coordinates (float).
Definition state.h:850
static struct FloatRates * stateGetBodyRates_f(void)
Get vehicle body angular rate (float).
Definition state.h:1392
static struct NedCoor_f * stateGetSpeedNed_f(void)
Get ground speed in local NED coordinates (float).
Definition state.h:1060
static struct Int32Vect3 * stateGetAccelBody_i(void)
Get acceleration in Body coordinates (int).
Definition state.h:1105
static float stateGetAirspeed_f(void)
Get airspeed (float).
Definition state.h:1615
int32_t max_airspeed
bool force_forward
forward flight for hybrid nav
Butterworth2LowPass accely_filt
struct FloatEulers eulers_zxy
state eulers in zxy order
float gi_unbounded_airspeed_sp
static float p[2][2]
static float t1
Integrated Navigation System interface.
PRINT_CONFIG_MSG("USE_INS_NAV_INIT defaulting to TRUE")
Simple first order low pass filter with bilinear transform.
struct SecondOrderLowPass Butterworth2LowPass
Second order Butterworth low pass filter.
static void init_first_order_low_pass(struct FirstOrderLowPass *filter, float tau, const float sample_time, float value)
Init first order low pass filter.
static float update_first_order_low_pass(struct FirstOrderLowPass *filter, const float value)
Update first order low pass filter state with a new value.
static void init_butterworth_2_low_pass(Butterworth2LowPass *filter, const float tau, const float sample_time, const float value)
Init a second order Butterworth filter.
static float update_butterworth_2_low_pass(Butterworth2LowPass *filter, const float value)
Update second order Butterworth low pass filter state with a new value.
static float update_butterworth_4_low_pass(Butterworth4LowPass *filter, const float value)
Update fourth order Butterworth low pass filter state with a new value.
static void init_butterworth_4_low_pass(Butterworth4LowPass *filter, const float tau, const float sample_time, const float value)
Init a fourth order Butterworth filter.
uint8_t step
Definition max7456.c:140
Hardware independent API for actuators (servos, motor controllers).
#define NAV_HYBRID_MAX_AIRSPEED
float nav_max_speed
float nav_hybrid_max_bank
float nav_max_acceleration_sp
float nav_hybrid_pos_gain
#define NAV_HYBRID_MAX_DECELERATION
Specific navigation functions for hybrid aircraft.
static void notch_filter_update(struct SecondOrderNotchFilter *filter, int32_t *input_signal, int32_t *output_signal)
Notch filter propagate.
static void notch_filter_init(struct SecondOrderNotchFilter *filter, float cutoff_frequency, float bandwidth, uint16_t sample_frequency)
Initialize second order notch filter.
float v_max
void init_poles(void)
Initialize Position of Poles.
struct PolePlacement p_pos_e
float k2_NE_tune
float max_j_lin
float k_D
static float Wv_backup[ANDI_OUTPUTS]
void chirp_pos(float time_elapsed, float f0, float f1, float t_chirp, float A, int8_t n, float psi, float p_ref[], float v_ref[], float a_ref[], float j_ref[], float p_ref_0[])
Reference Model Definition for 3rd order system specific to positioning with bounds.
float act_dynamics[ANDI_NUM_ACT_TOT]
float ratio_u_un[ANDI_NUM_ACT_TOT]
bool drop_pitch
static float Wu_backup[ANDI_NUM_ACT_TOT]
void init_filter(void)
Initialize the filters.
void reinit_controller(void)
Re-Init function of controller variables.
struct PolePlacement p_head_rm
void oneloop_calc_model_disturbance(bool in_flight)
Function that calculates the model disturbance (Control Effort) The control effort is equalt to : EFF...
static Butterworth2LowPass airspeed_filt
float n_array[ANDI_OUTPUTS]
float act_max_norm[ANDI_NUM_ACT_TOT]
struct WLS_t WLS_one_p
struct Gains3rdOrder k_att_rm
float max_a_nav
void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3])
Attitude Euler to Rates Conversion Function ZYX.
float k_I
static Butterworth2LowPass u_filt[ANDI_NUM_ACT_TOT]
float act_dyn_ctrl[ANDI_NUM_ACT_TOT]
struct FloatEulers eulers_zxy_des
float p_ref_0[3]
struct PolePlacement p_att_rm
float max_as
struct Gains3rdOrder k_att_e
float psi_des_rad
float EFF_MAT_G[ANDI_OUTPUTS][ANDI_NUM_ACT_TOT]
void rm_1st_pos(float dt, float x_2d_ref[], float x_3d_ref[], float x_2d_des[], float k3_rm[], float x_3d_bound, int n)
Reference Model Definition for 3rd order system specific to positioning with bounds.
float min_as
bool ctrl_off
struct Gains3rdOrder k_pos_e
float nu[ANDI_OUTPUTS]
float nu_norm_max
float temp_P_error[3]
bool actuator_is_servo[ANDI_NUM_ACT_TOT]
void float_vect_diff_euler(float err[3], float a[3], float b[3])
Calculate Error between two 3D euler arrays with the psi normalized.
float num_thrusters_oneloop
float ec_headroom
static float act_dynamics_d[ANDI_NUM_ACT_TOT]
float t_chirp
static float andi_u_n[ANDI_NUM_ACT_TOT]
float act_min_norm[ANDI_NUM_ACT_TOT]
void rm_3rd_attitude(float dt, float x_ref[3], float x_d_ref[3], float x_2d_ref[3], float x_3d_ref[3], float x_des[3], bool ow_psi, float psi_overwrite[4], float k1_rm[3], float k2_rm[3], float k3_rm[3], struct OneloopStabilizationRef bounds)
Reference Model Definition for 3rd order system with attitude conversion functions.
bool drop_yaw
static float g2_ff
float k_P
static void send_wls_u_oneloop(struct transport_tx *trans, struct link_device *dev)
float bound_v_from_a(float e_x, float v_bound, float a_bound)
Calculate velocity limit based on acceleration limit for a float From SUVAT we have that v^2 = u^2 + ...
struct PolePlacement p_alt_rm
void init_controller_gains(void)
Initialize Controller Gains FIXME: Calculate the gains dynamically for transition.
bool chirp_on
float andi_u[ANDI_NUM_ACT_TOT]
static float psi_vec[4]
void calc_normalization(void)
Calculate Normalization of actuators and discrete actuator dynamics.
float fwd_sideslip_gain
struct Gains3rdOrder k_pos_e_indi
float temp_I_error[3]
struct PolePlacement p_att_e
struct PolePlacement p_alt_e
float bound_v_from_a_vect(float e_x[], float v_bound, float a_bound, int n)
Calculate velocity limit based on acceleration limit for a vector From SUVAT we have that v^2 = u^2 +...
void rm_2nd_pos(float dt, float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x_d_des[], float k2_rm[], float k3_rm[], float x_2d_bound, float x_3d_bound, int n)
Reference Model Definition for 3rd order system specific to positioning with bounds.
void reshape_wind(void)
static float g
void get_act_state_oneloop(void)
Function to reconstruct actuator state using first order dynamics.
struct PolePlacement p_roll_e
void ec_3rd_pos(float y_4d[], float x_des[], float x_ref[], float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x[], float x_d[], float x_2d[], float k1_e[], float k2_e[], float k3_e[], float x_d_bound, float x_2d_bound, float fb[], int n)
Error Controller Definition for 3rd order system.
struct PolePlacement p_head_e
float xdot_lim_sf
float andi_du[ANDI_NUM_ACT_TOT]
float max_v_nav_v
float max_v_nav
bool heading_manual
bool drop_roll
float t_0_chirp
static void send_wls_v_oneloop(struct transport_tx *trans, struct link_device *dev)
static float nav_target[3]
void err_nd(float err[], float a[], float b[], float k[], int n)
Calculate Scaled Error between two 3D arrays.
float k1_NE_tune
struct Gains3rdOrder k_pos_rm
float m_array[ANDI_NUM_ACT_TOT]
float Wu_quad_motors_fwd
bool drop_aD
void chirp_call(bool *chirp_on, bool *chirp_first_call, float *t_0_chirp, float *time_elapsed, float f0, float f1, float t_chirp, float A, int8_t n, float psi, float p_ref[], float v_ref[], float a_ref[], float j_ref[], float p_ref_0[])
void G1G2_oneloop(int ctrl_type)
Function that samples and scales the effectiveness matrix FIXME: make this function into a for loop t...
float theta_pref_max
float act_max[ANDI_NUM_ACT_TOT]
bool chirp_first_call
void normalize_nu(void)
Function to normalize the pseudo control vector.
float psi_des_deg
void rm_3rd_pos(float dt, float x_ref[], float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x_des[], float k1_rm[], float k2_rm[], float k3_rm[], float x_d_bound, float x_2d_bound, float x_3d_bound, int n)
Reference Model Definition for 3rd order system specific to positioning with bounds.
void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3])
Attitude Rates to Euler Conversion Function ZYX.
struct OneloopStabilizationRef sta_bounds
struct PolePlacement p_pos_rm
float ratio_vn_v[ANDI_OUTPUTS]
float nu_n[ANDI_OUTPUTS]
bool yaw_stick_in_auto
float actuator_state_1l[ANDI_NUM_ACT_TOT]
void vect_bound_nd(float vect[], float bound, int n)
Scale a 3D array to within a 3D bound.
void err_sum_nd(float err[], float a[], float b[], float k[], float c[], int n)
Calculate Scaled Error between two 3D arrays.
float temp_D_error[3]
PRINT_CONFIG_VAR(ONELOOP_ANDI_FILT_CUTOFF)
void integrate_nd(float dt, float a[], float a_dot[], int n)
Integrate in time 3D array.
static float dt_1l
struct Gains3rdOrder k_att_e_indi
static void send_oneloop_debug(struct transport_tx *trans, struct link_device *dev)
float act_min[ANDI_NUM_ACT_TOT]
static float a_thrust
float max_r
struct Oneloop_LP_t LP
void acc_body_bound(struct FloatVect2 *vect, float bound)
Scale a 3D array to within a 3D bound.
float * bwls_1l[ANDI_OUTPUTS]
static float nav_target_new[3]
void ec_3rd_att(float y_4d[3], float x_des[3], float x_ref[3], float x_d_ref[3], float x_2d_ref[3], float x_3d_ref[3], float x[3], float x_d[3], float x_2d[3], float k1_e[3], float k2_e[3], float k3_e[3], struct OneloopStabilizationRef bounds, float fb[3])
Error Controller Definition for 3rd order system specific to attitude.
static float u_pref[ANDI_NUM_ACT_TOT]
#define CTRL_INDI
#define ANDI_NUM_VIRTUAL_ACT
#define ANDI_NUM_ACT
#define CTRL_ANDI
Control types.
@ BUTTERWORTH_2
@ BUTTERWORTH_4
@ LOWPASS_1
@ NOTCH
#define ANDI_NUM_ACT_TOT
#define ANDI_OUTPUTS
void init_poles(void)
Initialize Position of Poles.
static void send_oneloop_nB_ctrl(struct transport_tx *trans, struct link_device *dev)
Definition oneloop_nB.c:822
#define ONELOOP_NB_PID_V_MAX_NAV
Definition oneloop_nB.c:632
bool fault_ailerons
Definition oneloop_nB.c:501
float oneloop_nB_filt_cutoff
Definition oneloop_nB.c:130
float spin_prot_min_gap
Definition oneloop_nB.c:567
#define ONELOOP_NB_SPIN_MAN_TRIM_RATE
Definition oneloop_nB.c:592
static void reinit_LP(struct LP_t *LP, bool reinit)
#define ONELOOP_NB_DEBUG_MODE
Definition oneloop_nB.c:111
static float spin_man_dir
Definition oneloop_nB.c:661
#define ONELOOP_NB_SPIN_MAN_RAMP_RATE
Definition oneloop_nB.c:586
static Butterworth2LowPass nB_filt[3]
Definition oneloop_nB.c:191
void init_filter(void)
Initialize the filters.
float spin_man_blend_time
Definition oneloop_nB.c:656
float ctrl_effort_model[ANDI_OUTPUTS]
Definition oneloop_nB.c:488
void reinit_controller(void)
Re-Init function of controller variables.
static bool vec3_saturated(const float u_unsat[3], const float u_sat[3], float eps)
void oneloop_calc_model_disturbance(bool in_flight)
Function that calculates the model disturbance (Control Effort) The control effort is equalt to : EFF...
static void update_filter_on_type(struct LP_t *filter, float input)
Update a filter based on its type.
static void eul_of_acc(float a[3], float psi)
static void init_all_LP(void)
Initialize all Low Pass Filters.
static void send_eff_mat_stab_oneloop_nB(struct transport_tx *trans, struct link_device *dev)
Definition oneloop_nB.c:768
void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3])
Attitude Euler to Rates Conversion Function ZYX.
void oneloop_nB_propagate_filters(void)
Propagate the filters.
bool SpinQuad
Definition oneloop_nB.c:495
float delta_fault
Definition oneloop_nB.c:524
bool use_safety_killer
Definition oneloop_nB.c:512
float spin_prot_ratio
Definition oneloop_nB.c:542
#define IDX_aD
Definition oneloop_nB.c:118
float pusher_cmd_fun(float aN_des, float aE_des, float r, float psi, float w, int n)
static void ARW_ClampVec3(const float err[3], const float u_unsat[3], const float u_sat[3], const float I_prev[3], const float I_cand[3], float I_next[3])
static float k_rm_3_3_f(float omega_n, float zeta, float p1)
uint8_t spin_man_pair
Definition oneloop_nB.c:653
static Butterworth2LowPass nB_2d_filt[3]
Definition oneloop_nB.c:192
#define ONELOOP_NB_PID_V_MAX_MANUAL
Definition oneloop_nB.c:629
bool safety_killer_trigger
Definition oneloop_nB.c:513
float xi
Definition oneloop_nB.c:517
void guidance_set_max_bank_angle(float max_bank)
Guidance limit setters called by rotwing_state (also implemented by guidance_indi_hybrid).
float xi_fun(float r, float w, float aN_des, float aE_des)
#define ONELOOP_NB_SPIN_TRIM_BLEED_RATE
Definition oneloop_nB.c:554
static float spin_man_u_last[ANDI_NUM_ACT]
Definition oneloop_nB.c:665
float oneloop_nB_sideslip(void)
Function to calculate corrections for sideslip DEPRECIATED.
bool vel_ctrl_in_manual
Definition oneloop_nB.c:511
void rm_1st_pos(float dt, float x_2d_ref[], float x_3d_ref[], float x_2d_des[], float k3_rm[], float x_3d_bound, int n)
Reference Model Definition for 3rd order system specific to positioning with bounds.
void guidance_set_max_climb_speed(float max_climb_speed_quad, float max_climb_speed_fwd)
bool use_push_Position
Definition oneloop_nB.c:508
float spin_prot_max_cmd
Definition oneloop_nB.c:541
void float_vect_diff_euler(float err[3], float a[3], float b[3])
Calculate Error between two 3D euler arrays with the psi normalized.
static void Vel_PID_ARW(float x_dot_des[3], const float x_dot[3], float k_P, float k_I, float k_D, float a_sp[3], float a_max, float v_max)
static void spin_man_set_pair(uint8_t pair)
Select the motors of a pair (pitch: FRONT/BACK, roll: RIGHT/LEFT) for the blend.
Definition oneloop_nB.c:984
#define ONELOOP_NB_SPIN_MAN_PITCH_DIR
Definition oneloop_nB.c:603
#define ONELOOP_NB_SPIN_PROT_START_RATE
Definition oneloop_nB.c:534
void rm_3rd_attitude(float dt, float x_ref[3], float x_d_ref[3], float x_2d_ref[3], float x_3d_ref[3], float x_des[3], bool ow_psi, float psi_overwrite[4], float k1_rm[3], float k2_rm[3], float k3_rm[3], struct OneloopStabilizationRef bounds)
Reference Model Definition for 3rd order system with attitude conversion functions.
static float ec_poles(float p_rm, float slow_pole, float k)
Calculate EC poles given RM poles.
bool radio_body_ctrl
Definition oneloop_nB.c:509
static void send_wls_u_oneloop(struct transport_tx *trans, struct link_device *dev)
Definition oneloop_nB.c:764
#define ONELOOP_NB_SPIN_PROT_MAX_RATE
Definition oneloop_nB.c:531
float spin_trim_release_rate
Definition oneloop_nB.c:562
static bool spin_man_rate_ctrl(void)
Yaw rate tracking is used by the manoeuvre (no fault active).
void nB_EC(struct FloatVect3 nB, struct FloatVect3 nB_d, struct FloatVect3 nB_2d, struct FloatVect3 mu_B, float k1_e[3], float k2_e[3], float k3_e[3], float dist[3], float nB_nu[3])
void oneloop_from_nav(bool in_flight)
Function that maps navigation inputs to the oneloop controller for the generated autopilot.
#define IDX_ar
Definition oneloop_nB.c:121
float phase_first_order(float r, float w)
float spin_trim_rate
Definition oneloop_nB.c:560
float bound_v_from_a(float e_x, float v_bound, float a_bound)
Calculate velocity limit based on acceleration limit for a float From SUVAT we have that v^2 = u^2 + ...
float debug_state[3]
Definition oneloop_nB.c:519
static Butterworth2LowPass KPID_filt[3]
Definition oneloop_nB.c:185
float cos_2n(float psi, float xi, int n)
void init_controller_gains(void)
Initialize Controller Gains FIXME: Calculate the gains dynamically for transition.
float nB_jerk_des[3]
Definition oneloop_nB.c:307
static uint8_t spin_man_mot[2]
Definition oneloop_nB.c:663
static void reinit_all_LP(bool reinit)
Reinitialize all the Low Pass Filters.
static float positive_non_zero(float input)
Function to make sure that inputs are positive non zero vaues.
#define ONELOOP_NB_SPIN_MAN_DONE_RATE
Definition oneloop_nB.c:595
float safety_killer_cutoff
Definition oneloop_nB.c:516
#define ONELOOP_NB_SPIN_PROT_MIN_GAP
Definition oneloop_nB.c:565
#define SPIN_MAN_PAIR_PITCH
Definition oneloop_nB.c:597
bool fault_roll_motors
Definition oneloop_nB.c:497
void guidance_set_min_max_airspeed(float min_airspeed, float max_airspeed)
float oneloop_nB_filt_cutoff_q
Definition oneloop_nB.c:156
void calc_normalization(void)
Calculate Normalization of actuators and discrete actuator dynamics.
static void send_eff_mat_guid_oneloop_nB(struct transport_tx *trans, struct link_device *dev)
Definition oneloop_nB.c:801
bool oneloop_nB_Z_hold
Definition oneloop_nB.c:510
static void spin_man_update(bool in_flight, bool nb_ctrl)
Spin transition manoeuvre state machine.
void drop_axis(void)
Function that drops control along selected axes.
static void spin_man_start_blend(void)
Start a bumpless transfer of the selected pair from the average of its last applied commands,...
Definition oneloop_nB.c:992
static void send_oneloop_nB(struct transport_tx *trans, struct link_device *dev)
Definition oneloop_nB.c:808
static void debug_vect(struct transport_tx *trans, struct link_device *dev, char *name, float *data, int datasize)
Definition oneloop_nB.c:894
float SQ_r
Definition oneloop_nB.c:308
float max_bank
Definition oneloop_nB.c:264
float bound_v_from_a_vect(float e_x[], float v_bound, float a_bound, int n)
Calculate velocity limit based on acceleration limit for a vector From SUVAT we have that v^2 = u^2 +...
void rm_2nd_pos(float dt, float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x_d_des[], float k2_rm[], float k3_rm[], float x_2d_bound, float x_3d_bound, int n)
Reference Model Definition for 3rd order system specific to positioning with bounds.
float spin_man_r_ref
Definition oneloop_nB.c:660
void reshape_wind(void)
float max_pusher_cmd
Definition oneloop_nB.c:518
void get_act_state_oneloop(void)
Function to reconstruct actuator state using first order dynamics.
void ec_3rd_pos(float y_4d[], float x_des[], float x_ref[], float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x[], float x_d[], float x_2d[], float k1_e[], float k2_e[], float k3_e[], float x_d_bound, float x_2d_bound, float fb[], int n)
Error Controller Definition for 3rd order system.
float pid_v_max_nav
Definition oneloop_nB.c:641
bool use_push_PID
Definition oneloop_nB.c:507
#define SPIN_MAN_PAIR_ROLL
Definition oneloop_nB.c:598
static void spin_prot_bound_params(void)
Enforce valid spin protection / spin trim parameters (they can be changed in flight from the settings...
Definition oneloop_nB.c:959
static Butterworth2LowPass nB_3d_state_filt[2]
Definition oneloop_nB.c:193
static void init_LP(struct LP_t *LP, float fc)
Initialize the Low Pass Filter Struct.
float ec_k3
Definition oneloop_nB.c:622
static float spin_man_alpha
Definition oneloop_nB.c:662
float oneloop_nB_filt_cutoff_v
Definition oneloop_nB.c:142
#define ONELOOP_NB_EC_K3
Definition oneloop_nB.c:619
float spin_trim_bleed_rate
Definition oneloop_nB.c:561
struct OneloopGeneral oneloop_nB
Definition oneloop_nB.c:114
float spin_man_pitch_dir
Definition oneloop_nB.c:654
static void send_wls_v_oneloop(struct transport_tx *trans, struct link_device *dev)
Definition oneloop_nB.c:760
float k_K
Definition oneloop_nB.c:700
uint8_t spin_man_state
Definition oneloop_nB.c:659
float pid_a_max
Definition oneloop_nB.c:639
float state_term[3]
Definition oneloop_nB.c:520
float SpinQuadRate
Definition oneloop_nB.c:494
bool spin_man_up
Definition oneloop_nB.c:651
void err_nd(float err[], float a[], float b[], float k[], int n)
Calculate Scaled Error between two 3D arrays.
spin_man_state_t
Definition oneloop_nB.c:643
@ SPIN_MAN_UP_RAMP
Definition oneloop_nB.c:645
@ SPIN_MAN_UP_BLEND
Definition oneloop_nB.c:646
@ SPIN_MAN_IDLE
Definition oneloop_nB.c:644
@ SPIN_MAN_DOWN_BLEND
Definition oneloop_nB.c:648
@ SPIN_MAN_DOWN_RAMP
Definition oneloop_nB.c:649
@ SPIN_MAN_DOWN_SLOW
Definition oneloop_nB.c:647
void oneloop_nB_state_compensation(bool state_compensation_on)
Function that performs state compensation for gyroscopic effects.
bool spin_man_down
Definition oneloop_nB.c:652
#define ONELOOP_NB_FAULT_AILERONS
Definition oneloop_nB.c:499
float spin_trim
Definition oneloop_nB.c:563
float oneloop_nB_yaw_dist_limit
Definition oneloop_nB.c:327
static void init_filter_on_type(struct LP_t *filter, float x0)
Initialize a filter based on its type.
bool autopilot_in_flight_end_detection(bool motors_on UNUSED)
Quadplanes can still be in-flight with COMMAND_THRUST==0 and can even soar not descending in updrafts...
void guidance_set_max_descend_speed(float max_descend_speed_quad, float max_descend_speed_fwd)
#define ONELOOP_NB_SPIN_PROT_MAX_CMD
Definition oneloop_nB.c:537
static void reinit_LP_synchronous(struct LP_t *LP, struct LP_t *f, bool reinit)
Reinitialize Low Pass filter if new frequency setting or if forced.
static void spin_man_reset(void)
Stop the spin manoeuvre and clear its GCS triggers (fault flags are left as they are).
Definition oneloop_nB.c:976
bool state_compensation_on
Definition oneloop_nB.c:506
static Butterworth2LowPass push_PID_vel[2]
Definition oneloop_nB.c:186
float temp_acc_des[3]
Definition oneloop_nB.c:515
float pid_v_max_manual
Definition oneloop_nB.c:640
void oneloop_nB_enter(bool half_loop_sp, int ctrl_type)
Function that resets important values upon engaging Oneloop ANDI.
static void Pos_KPID_ARW(const float x_des[3], const float x[3], const float x_dot[3], float k_K, float k_P, float k_I, float k_D, float a_sp[3], float a_max, float v_max)
float spin_man_done_rate
Definition oneloop_nB.c:658
float spin_man_ramp_rate
Definition oneloop_nB.c:655
void G1G2_oneloop(int ctrl_type)
Function that samples and scales the effectiveness matrix FIXME: make this function into a for loop t...
float slow_pole
Definition oneloop_nB.c:672
#define ONELOOP_NB_SPIN_TRIM_RELEASE_RATE
Definition oneloop_nB.c:557
#define ONELOOP_NB_SPIN_MAN_BLEND_TIME
Definition oneloop_nB.c:589
float max_theta
Definition oneloop_nB.c:276
bool auto_fault_cmd
Definition oneloop_nB.c:514
static void spin_man_ramp_ref(float target)
Move the yaw rate reference towards target at spin_man_ramp_rate.
void set_WLS_settings(void)
Function that sets the WLS settings for oneloop controller.
void normalize_nu(void)
Function to normalize the pseudo control vector.
void rm_3rd_pos(float dt, float x_ref[], float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x_des[], float k1_rm[], float k2_rm[], float k3_rm[], float x_d_bound, float x_2d_bound, float x_3d_bound, int n)
Reference Model Definition for 3rd order system specific to positioning with bounds.
void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3])
Attitude Rates to Euler Conversion Function ZYX.
int8_t TestMotorIDX
Definition oneloop_nB.c:113
void SpinQuad_overwrite(float gain, float ce_model, float *nu_stab_2)
static void send_eff_mat_stab_thrust_oneloop_nB(struct transport_tx *trans, struct link_device *dev)
Definition oneloop_nB.c:785
#define IDX_aq
Definition oneloop_nB.c:120
#define ONELOOP_NB_SPIN_TRIM_ON
Definition oneloop_nB.c:548
static Butterworth2LowPass push_PID_vel_d[2]
Definition oneloop_nB.c:187
static float k_rm_1_3_f(float omega_n, float zeta, float p1)
Reference Model Gain Design.
void init_poles_att(void)
Initialize Position of Poles.
#define ONELOOP_NB_MAX_FAULT_MOT
Definition oneloop_nB.c:310
void oneloop_nB_calc_nB_states(void)
Function which estimates the nB states.
void oneloop_nB_run(bool in_flight, bool half_loop, struct FloatVect3 PSA_des)
Main function that runs the controller and performs control allocation.
float oneloop_nB_filt_cutoff_a
Definition oneloop_nB.c:136
void vect_bound_nd(float vect[], float bound, int n)
Scale a 3D array to within a 3D bound.
void err_sum_nd(float err[], float a[], float b[], float k[], float c[], int n)
Calculate Scaled Error between two 3D arrays.
float spin_man_trim_rate
Definition oneloop_nB.c:657
#define ONELOOP_NB_AIRSPEED_SWITCH_THRESHOLD
Definition oneloop_nB.c:395
void integrate_nd(float dt, float a[], float a_dot[], int n)
Integrate in time 3D array.
void rm_3rd_nI(float dt, struct FloatVect3 *x_ref, struct FloatVect3 *x_d_ref, struct FloatVect3 *x_2d_ref, struct FloatVect3 *x_3d_ref, const struct FloatVect3 *x_des, const float k1_rm[3], const float k2_rm[3], const float k3_rm[3])
static Butterworth2LowPass KPID_vel_filt[3]
Definition oneloop_nB.c:184
static void send_oneloop_debug(struct transport_tx *trans, struct link_device *dev)
Definition oneloop_nB.c:900
static void send_guidance_oneloop_nB(struct transport_tx *trans, struct link_device *dev)
Definition oneloop_nB.c:846
float oneloop_nB_filt_cutoff_p
Definition oneloop_nB.c:149
void oneloop_nB_RM(bool half_loop, struct FloatVect3 PSA_des, bool in_flight_oneloop)
Function to generate the reference signals for the oneloop controller.
float oneloop_nB_filt_cutoff_r
Definition oneloop_nB.c:163
float max_fault_mot
Definition oneloop_nB.c:314
#define IDX_ap
Definition oneloop_nB.c:119
static float spin_man_u_hold[2]
Definition oneloop_nB.c:664
bool spin_trim_on
Definition oneloop_nB.c:559
void acc_body_bound(struct FloatVect2 *vect, float bound)
Scale a 3D array to within a 3D bound.
void init_poles_pos(void)
#define ONELOOP_NB_SPIN_TRIM_RATE
Definition oneloop_nB.c:551
void skew_symmetric(struct FloatRMat *out, const struct FloatVect3 *in)
#define ONELOOP_NB_PID_A_MAX
Definition oneloop_nB.c:626
static float k_rm_2_3_f(float omega_n, float zeta, float p1)
float max_phi
Definition oneloop_nB.c:270
void ec_3rd_att(float y_4d[3], float x_des[3], float x_ref[3], float x_d_ref[3], float x_2d_ref[3], float x_3d_ref[3], float x[3], float x_d[3], float x_2d[3], float k1_e[3], float k2_e[3], float k3_e[3], struct OneloopStabilizationRef bounds, float fb[3])
Error Controller Definition for 3rd order system specific to attitude.
#define ONELOOP_NB_SPIN_MAN_PAIR
Definition oneloop_nB.c:600
void calc_HB_matrix(float HB[3][3], struct FloatVect3 nB)
float spin_prot_max_rate
Definition oneloop_nB.c:539
float spin_prot_start_rate
Definition oneloop_nB.c:540
void oneloop_nB_init(void)
Init function of Oneloop ANDI controller.
bool fault_pitch_motors
Definition oneloop_nB.c:496
static void shape_vector(float a[3])
#define CTRL_NB_ANDI
Definition oneloop_nB.h:62
float bandwidth
union LP_t::@324202153354356061211053020005360346147215120230 meas_filt
float tau
float freq
float out
enum FilterType filter_type
#define CTRL_NB_INDI
Definition oneloop_nB.h:63
#define MAX_PPRZ
Definition paparazzi.h:8
Paparazzi floating point algebra.
float z
in meters
float x
in meters
float y
in meters
vector in North East Down coordinates Units: meters
struct RadioControl radio_control
Generic interface for radio control modules.
static pprz_t radio_control_get(uint8_t idx)
Get a radio control channel value.
struct RotorcraftNavigation nav
Definition navigation.c:51
Rotorcraft navigation functions.
#define NAV_SETPOINT_MODE_SPEED
Definition navigation.h:101
#define NAV_VERTICAL_MODE_CLIMB
Definition navigation.h:93
#define NAV_VERTICAL_MODE_ALT
Definition navigation.h:94
#define NAV_SETPOINT_MODE_POS
Nav setpoint modes these modes correspond to submodes defined by navigation routines to tell which se...
Definition navigation.h:100
static const ShellCommand commands[]
Definition shell_arch.c:77
struct Stabilization stabilization
API to get/set the generic vehicle states.
struct target_t target
Definition target_pos.c:65
int16_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint16_t _id, telemetry_cb _cb)
Register a telemetry callback function.
Definition telemetry.c:51
Periodic telemetry system header (includes downlink utility and generated code).
#define DefaultPeriodic
Set default periodic telemetry.
Definition telemetry.h:66
static float D
static const float scale[]
short int16_t
Typedef defining 16 bit short type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
signed char int8_t
Typedef defining 8 bit char type.
uint16_t f
Camera baseline, in meters (i.e. horizontal distance between the two cameras of the stereo setup).
Definition wedgebug.c:204
float b
Definition wedgebug.c:202
void send_wls_v(char *name, struct WLS_t *WLS_p, struct transport_tx *trans, struct link_device *dev)
Definition wls_alloc.c:61
void wls_alloc(struct WLS_t *WLS_p, float **B, float *u_guess, float *W_init, int imax)
active set algorithm for control allocation
Definition wls_alloc.c:119
void send_wls_u(char *name, struct WLS_t *WLS_p, struct transport_tx *trans, struct link_device *dev)
Definition wls_alloc.c:71
#define WLS_N_V_MAX
Definition wls_alloc.h:64
float v[WLS_N_V_MAX]
Definition wls_alloc.h:70