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
129#else
131#endif
132
133#ifdef ONELOOP_NB_FILT_CUTOFF_ACC
135#else
137#endif
138
139#ifdef 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
148#else
150#endif
151
152#ifdef ONELOOP_NB_FILT_CUTOFF_Q
153#define ONELOOP_NB_FILTER_PITCH_RATE TRUE
155#else
157#endif
158
159#ifdef ONELOOP_NB_FILT_CUTOFF_R
160#define ONELOOP_NB_FILTER_YAW_RATE TRUE
162#else
164#endif
165
166PRINT_CONFIG_MSG("============================================================")
174PRINT_CONFIG_MSG("============================================================")
175PRINT_CONFIG_MSG("============================================================")
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
201#endif
202
203#ifdef ONELOOP_NB_ACT_IS_SERVO // Unused but kept for future developments
205#else
207#endif
208
209#ifdef ONELOOP_NB_ACT_DYN // Actuator dynamics (first order lag) corner frequency [rad/s]
212#else
213#error "You must specify the actuator dynamics"
216#endif
217
218#ifdef ONELOOP_NB_ACT_MAX // Maximum Paparazzi actuator command
220#else
222#endif
223
224#ifdef ONELOOP_NB_ACT_MIN // Minimum Paparazzi actuator command
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
232#else
234#endif
235
236#ifdef ONELOOP_NB_ACT_MIN_NORM // Minimum normalized actuator command
238#else
240#endif
241
242#ifdef ONELOOP_NB_NU_NORM_MAX // Maximum norm of the normalized pseudo control vector
244#else
245float nu_norm_max = 1.0;
246#endif
247
248#ifdef ONELOOP_NB_U_PREF // Preferred Paparazzi actuator command
250#else
251static float u_pref[ANDI_NUM_ACT_TOT] = {0.0};
252#endif
253
254PRINT_CONFIG_MSG("============================================================")
259PRINT_CONFIG_MSG("============================================================")
260
261#ifdef ONELOOP_NB_MAX_BANK
263#else
265#endif
266
267#ifdef ONELOOP_NB_MAX_PHI
269#else
271#endif
272
273#ifdef ONELOOP_NB_MAX_THETA
275#else
277#endif
278
279#ifndef ONELOOP_THETA_PREF_MAX // Max preferred pitch angles
281#else
283#endif
284
285PRINT_CONFIG_MSG("============================================================")
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
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
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
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
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
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
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]
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
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
444#endif
445
446struct WLS_t WLS_one_p = {
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}
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
523#else
524float delta_fault = 1000.0;
525#endif
526PRINT_CONFIG_MSG("%%% 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
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
671#else
672float slow_pole = 22.0;
673#endif
674PRINT_CONFIG_MSG("%%% 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
777#else
783#endif
784}
786{
787 // Vertical (thrust) row of the effectiveness, x and y are not used
788 float zero = 0.0;
789#ifdef STREAM_BWLS
791 1, &zero,
792 1, &zero,
794#else
796 1, &zero,
797 1, &zero,
799#endif
800}
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{
889 &xi,
892}
893#endif
894static void debug_vect(struct transport_tx *trans, struct link_device *dev, char *name, float *data, int datasize)
895{
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
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
976static void spin_man_reset(void)
977{
979 spin_man_up = false;
980 spin_man_down = false;
981 spin_man_alpha = 1.0;
982}
992static void spin_man_start_blend(void)
993{
997 spin_man_alpha = 0.0;
998}
1000static void spin_man_ramp_ref(float target)
1001{
1002 float step = target - spin_man_r_ref;
1005}
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 }
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 }
1097 {
1099 }
1100 break;
1101 }
1102 if (spin_man_alpha < 1.0)
1103 {
1105 Bound(spin_man_alpha, 0.0, 1.0);
1106 }
1107}
1109static float positive_non_zero(float input)
1110{
1111 if (input < FLT_EPSILON)
1112 {
1113 input = 0.00001;
1114 }
1115 return input;
1116}
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}
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}
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}
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}
1154void vect_bound_nd(float vect[], float bound, int n)
1155{
1156 float norm = float_vect_norm(vect, n);
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
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
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)
1319
1320 // Apply ARW (decide whether to accept the integral update)
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)
1384
1385 // Apply ARW (decide whether to accept the integral update)
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);
1415 {
1417 }
1419 BoundAbs(phi_des, max_phi); // Limit to 30 deg
1420 BoundAbs(theta_des, max_theta); // Limit to 30 deg
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]);
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];
1504 v[1] = sqrtf(acc_b_y_2);
1505 }
1506 vect->x = sign_v0 * v[0];
1507 vect->y = sign_v1 * v[1];
1508}
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}
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]);
1581 // Angular Rate error ----------------------------------------------------------------------------------------------
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 -----------------------------------------
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 ---------------------------------------------
1593 if (ow_psi)
1594 {
1595 x_3d_ref[2] = psi_overwrite[3];
1596 }
1597 // Angular Acceleration Reference -------------------------------------
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 ------------------------------------------------
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);
1643 err_nd(e_x_d, e_x, x_d_ref, k2_rm, 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];
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];
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];
1721 err_sum_nd(e_x_d, x_ref, x, k1_e, x_d_ref, 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
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);
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{
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;
1832
1833 p_roll_e.omega_n = slow_pole / 3.0;
1834 p_roll_e.zeta = 1.0;
1836
1838 p_att_rm.zeta = 1.0;
1840
1841 p_head_e.omega_n = slow_pole / 3.0;
1842 p_head_e.zeta = 1.0;
1844
1846 p_head_rm.zeta = 1.0;
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;
1854
1856 p_pos_rm.zeta = 0.5;
1858
1859 p_alt_e.omega_n = 1.19; // slow_pole/3.0*2.0;
1860 p_alt_e.zeta = 0.5;
1862
1864 p_alt_rm.zeta = 0.5;
1866}
1867
1873{
1874 /*Register a variable from nav_hybrid. Should be improved when nav hybrid is final.*/
1875 float max_wind = 20.0;
1878 /*Some calculations in case new poles have been specified*/
1879 // init_poles_att();
1880 // init_poles_pos();
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
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*/
1907
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;//
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
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*/
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
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;
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;
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}
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}
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}
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);
2146 bool reinit_other = ((LP.p_dot.freq != LP.p_dot.freq_set) || 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 {
2162 }
2163 for (int i = 0; i < 3; i++)
2164 {
2167 }
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");
2187 for (int i = 0; i < 3; i++)
2188 {
2191 }
2196 for (int i = 0; i < ANDI_NUM_ACT_TOT; i++)
2197 {
2199 }
2200 for (int i = 0; i < 3; i++)
2201 {
2204 }
2207}
2208
2211{
2212 reinit_all_LP(false);
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 }
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;
2248 // Update Filters of Feedbacks
2261 // Propagate filter for sideslip correction
2265 Bound(airspeed_meas, 0.0, 30.0);
2267}
2268//------------------------------------------------------------------------------------------
2292{
2293 oneloop_nB.half_loop = true;
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
2304 // Initialize filters and other variables
2305 init_all_LP();
2306 init_filter();
2320 eulers_zxy_des.phi = 0.0;
2321 eulers_zxy_des.theta = 0.0;
2322 eulers_zxy_des.psi = 0.0;
2323 // nB controller
2326 oneloop_nB.sta_nB_state.nI.z = -1.0;
2327// Start telemetry
2328#if PERIODIC_TELEMETRY
2335#ifdef PPRZ_MSG_ID_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{
2355 oneloop_nB.ctrl_type = 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];
2389 // =======================================================================================================================================================
2390 // Some Pusher control definitions
2391 oneloop_nB.push_nB.n = 2;
2393 oneloop_nB.push_nB.varepsilon = 25.0; // 10.0;
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
2420#ifdef ROTWING_EFF_SCHED_MP_dFdu
2421 if (use_push_PID)
2422 {
2423 // Desired Velocity ==============================================================
2425 {
2428 }
2429 else
2430 {
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;
2450 x_dot_des[0] = x_dot_des_NE.x;
2451 x_dot_des[1] = x_dot_des_NE.y;
2452 }
2459 }
2460 else
2461 {
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;
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
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
2492 // ======================================================================================================================================================
2493 // THRUST Create commands adhoc to get actuators to the wanted level
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 {
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
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];
2528 {
2535 }
2536 else
2537 {
2539 };
2543 // Update desired Heading (psi_des_rad) based on previous loop or changed setting
2544 if (heading_manual)
2545 {
2548 {
2550 }
2551 }
2552 else
2553 {
2555 }
2557#ifdef ROTWING_EFF_SCHED_MP_dFdu
2558 if (use_push_PID)
2559 {
2560 // Desired Velocity from Position Set Point ==============================================================
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 ==============================================================
2577 // Current Velocity ==============================================================
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);
2590 // Allocation on Integral Solution ===============================================
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;
2601 }
2602 else
2603 {
2604 // Pusher off when not used (nothing else commands it, otherwise it would keep its last value)
2607 }
2608#endif
2609 // ======================================================================================================================================================
2610 if (!in_flight_oneloop)
2611 {
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
2618 {
2621 }
2623 // ======================================================================================================================================================
2624 // Set and Save the desired attitude and run the attitude RM
2626#define OVERRIDE_ATT_RM
2627#ifdef OVERRIDE_ATT_RM
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
2638#endif
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
2677 oneloop_nB_propagate_filters(); // needs to be after update of attitude vector
2684 // (2) Position related
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
2717 // ======================================================================================================================================================
2718 // Run the Reference Model (RM)
2720 // ======================================================================================================================================================
2721 // Calculate new nB states based on updated RM for nI
2723 // ======================================================================================================================================================
2724 // Update Effectiveness matrix based on the control type
2726 // ======================================================================================================================================================
2727 // Attitude EC
2728 float att_jerk_des[3];
2729 float nu_stab[3] = {0.0, 0.0, 0.0};
2734
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:
2747 nu_stab[0] = att_jerk_des[0];
2748 nu_stab[1] = att_jerk_des[1];
2749 nu_stab[2] = att_jerk_des[2];
2751 break;
2752 case CTRL_INDI:
2754 nu_stab[0] = att_jerk_des[0];
2755 nu_stab[1] = att_jerk_des[1];
2756 nu_stab[2] = att_jerk_des[2];
2758 break;
2759 case CTRL_NB_ANDI:
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);
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];
2767 break;
2768 case CTRL_NB_INDI:
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);
2772 nu_stab[0] = nB_jerk_des[0];
2773 nu_stab[1] = nB_jerk_des[1];
2774 nu_stab[2] = att_jerk_des[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
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;
2826 if (auto_fault_cmd)
2827 {
2831 {
2832 counter_afc = 0;
2833 auto_fault_cmd = false;
2834 }
2835 }
2836 else
2837 {
2839 counter_afc = 0;
2840 }
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).
2851 {
2852 // Spin manoeuvre slowing down: open loop trim increase, no bleed
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 {
2861 }
2862 else if (abs_r < spin_trim_release_rate)
2863 {
2865 }
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)
2878 {
2881 }
2883 {
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
2930 if (heading_manual)
2931 {
2933 }
2937}
2938
2939//=========================================================================================================================================================
2941//==========================================================================================================================================================
2943{
2944 int8_t i;
2946 for (i = 0; i < ANDI_NUM_ACT_TOT; i++)
2947 {
2948 if (i < ANDI_NUM_ACT)
2949 {
2953 {
2954 actuator_state_1l[i] = 0.0;
2955 }
2957 }
2958 else
2959 {
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];
3008 }
3009 //=========================================================================================================================================================
3010 // Only a single faulted pair is supported, both pairs faulted is treated as no fault
3012 {
3015 for (int i = 0; i < ANDI_OUTPUTS; i++)
3016 {
3018 EFF_MAT_G[i][COMMAND_MOTOR_BACK] = 0.0;
3019 }
3020 }
3022 {
3025 for (int i = 0; i < ANDI_OUTPUTS; i++)
3026 {
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
3063 ratio_denominator = positive_non_zero(ratio_denominator); // make sure denominator is non-zero
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 {
3070 float ratio_denominator = 1.0;
3071 switch (i)
3072 {
3073 case (IDX_aD):
3076 break;
3077 case (IDX_ap):
3080 break;
3081 case (IDX_aq):
3084 break;
3085 case (IDX_ar):
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 {
3113 }
3114 struct FloatVect3 PSA_des;
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 {
3126 // rm_order_h = 3;
3127 break;
3131 // rm_order_h = 2;
3132 break;
3133 }
3134 switch (nav.vertical_mode)
3135 {
3138 // rm_order_v = 3;
3139 break;
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.
3159 // Prevent flipping
3160 if ((eulers_zxy.theta > 0.0f) && (fabs(eulers_zxy.phi) < eulers_zxy.theta))
3161 {
3162 // printf("Preventing flipping\n");
3164 }
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;
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
3200 // Check if some minimum airspeed is desired (e.g. to prevent stall)
3201 if (norm_des_as < min_as)
3202 {
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;
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 }
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
3234 {
3235 float delta_psi = atan2f(des_as_NE.y, des_as_NE.x) - 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 {
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 {
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
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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{
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
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
3511 // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3512
3513 // nB = LBI * nI
3515
3516 // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3517 // nB_d= -Omega_B * nB + LBI * nI_dot
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 {
3533 nB_2d_inited = true;
3534 }
3541#else
3545 float_rmat_vmult(&C, &Omega_B, &temp);
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 {
3564 nB_3d_inited = true;
3565 }
3572#else
3573 // t1 = Omega_B_ddot * nB
3575
3576 // t2 = 2 * Omega_B * Omega_B_dot * 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
3585 float_rmat_vmult(&temp2, &Omega_B, &temp);
3586 float_rmat_vmult(&t3, &Omega_B, &temp2);
3587
3588 // t4 = LBI * nI_3d
3590
3591 // t5 = 3 * Omega_B * 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
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
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
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);
3632 state_term[0] += upsilon_1;
3633 state_term[1] += upsilon_2;
3634 state_term[2] += upsilon_3;
3635
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 {
3763 Bound(SQ_r, 0.0, 40.0);
3764 }
3765
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
3786
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{
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;
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:49
bool autopilot_get_motors_on(void)
get motors status
Definition autopilot.c:295
pprz_t throttle
throttle level as will be displayed in GCS
Definition autopilot.h:66
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
struct F_M_Body mP
struct RW_skew skew
#define Min(x, y)
Definition esc_dshot.c:110
float phi
in radians
float theta
in radians
float m[3 *3]
float psi
in radians
#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:1203
static struct FloatRMat * stateGetNedToBodyRMat_f(void)
Get vehicle body attitude rotation matrix (float).
Definition state.h:1308
static struct FloatQuat * stateGetNedToBodyQuat_f(void)
Get vehicle body attitude quaternion (float).
Definition state.h:1302
static struct NedCoor_f * stateGetPositionNed_f(void)
Get position in local NED coordinates (float).
Definition state.h:839
static struct FloatRates * stateGetBodyRates_f(void)
Get vehicle body angular rate (float).
Definition state.h:1381
static struct NedCoor_f * stateGetSpeedNed_f(void)
Get ground speed in local NED coordinates (float).
Definition state.h:1049
static struct Int32Vect3 * stateGetAccelBody_i(void)
Get acceleration in Body coordinates (int).
Definition state.h:1094
static float stateGetAirspeed_f(void)
Get airspeed (float).
Definition state.h:1604
int32_t max_airspeed
bool force_forward
forward flight for hybrid nav
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.
float o[2]
output history
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.
Second order low pass filter structure.
uint16_t foo
Definition main_demo5.c:58
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
float p_ref_0[3]
float t_chirp
bool chirp_on
static float psi_vec[4]
float t_0_chirp
bool chirp_first_call
#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
struct PolePlacement p_pos_e
Definition oneloop_nB.c:681
float spin_prot_min_gap
Definition oneloop_nB.c:567
float k2_NE_tune
Definition oneloop_nB.c:698
float max_j_lin
Definition oneloop_nB.c:413
#define ONELOOP_NB_SPIN_MAN_TRIM_RATE
Definition oneloop_nB.c:592
float k_D
Definition oneloop_nB.c:703
static float Wv_backup[ANDI_OUTPUTS]
Definition oneloop_nB.c:477
static void reinit_LP(struct LP_t *LP, bool reinit)
#define ONELOOP_NB_DEBUG_MODE
Definition oneloop_nB.c:111
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.
static float spin_man_dir
Definition oneloop_nB.c:661
static Butterworth2LowPass accely_filt
Definition oneloop_nB.c:188
float act_dynamics[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:214
#define ONELOOP_NB_SPIN_MAN_RAMP_RATE
Definition oneloop_nB.c:586
float ratio_u_un[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:489
bool drop_pitch
Definition oneloop_nB.c:504
static Butterworth2LowPass nB_filt[3]
Definition oneloop_nB.c:191
static float Wu_backup[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:471
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)
struct PolePlacement p_head_rm
Definition oneloop_nB.c:688
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 Butterworth2LowPass airspeed_filt
Definition oneloop_nB.c:189
static void eul_of_acc(float a[3], float psi)
float n_array[ANDI_OUTPUTS]
Definition oneloop_nB.c:486
static void init_all_LP(void)
Initialize all Low Pass Filters.
float act_max_norm[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:233
struct WLS_t WLS_one_p
Definition oneloop_nB.c:446
struct Gains3rdOrder k_att_rm
Definition oneloop_nB.c:691
float max_a_nav
Definition oneloop_nB.c:407
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.
float k_I
Definition oneloop_nB.c:702
static Butterworth2LowPass u_filt[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:190
void oneloop_nB_propagate_filters(void)
Propagate the filters.
bool SpinQuad
Definition oneloop_nB.c:495
float act_dyn_ctrl[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:215
float delta_fault
Definition oneloop_nB.c:524
struct FloatEulers eulers_zxy_des
Definition oneloop_nB.c:387
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
struct PolePlacement p_att_rm
Definition oneloop_nB.c:679
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 max_as
Definition oneloop_nB.c:430
float xi_fun(float r, float w, float aN_des, float aE_des)
struct Gains3rdOrder k_att_e
Definition oneloop_nB.c:690
float psi_des_rad
Definition oneloop_nB.c:389
#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 EFF_MAT_G[ANDI_OUTPUTS][ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:485
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.
float min_as
Definition oneloop_nB.c:431
void guidance_set_max_climb_speed(float max_climb_speed_quad, float max_climb_speed_fwd)
bool ctrl_off
Definition oneloop_nB.c:482
struct Gains3rdOrder k_pos_e
Definition oneloop_nB.c:692
bool use_push_Position
Definition oneloop_nB.c:508
float spin_prot_max_cmd
Definition oneloop_nB.c:541
float nu[ANDI_OUTPUTS]
Definition oneloop_nB.c:303
float nu_norm_max
Definition oneloop_nB.c:245
float temp_P_error[3]
Definition oneloop_nB.c:704
bool actuator_is_servo[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:206
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
Definition oneloop_nB.c:198
float ec_headroom
Definition oneloop_nB.c:433
static float act_dynamics_d[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:305
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
static float andi_u_n[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:302
float act_min_norm[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:239
#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.
bool drop_yaw
Definition oneloop_nB.c:502
static float ec_poles(float p_rm, float slow_pole, float k)
Calculate EC poles given RM poles.
static float g2_ff
Definition oneloop_nB.c:481
float k_P
Definition oneloop_nB.c:701
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
struct PolePlacement p_alt_rm
Definition oneloop_nB.c:685
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 andi_u[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:300
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
float fwd_sideslip_gain
Definition oneloop_nB.c:399
static void send_oneloop_nB(struct transport_tx *trans, struct link_device *dev)
Definition oneloop_nB.c:808
struct Gains3rdOrder k_pos_e_indi
Definition oneloop_nB.c:696
float temp_I_error[3]
Definition oneloop_nB.c:706
struct PolePlacement p_att_e
Definition oneloop_nB.c:677
static void debug_vect(struct transport_tx *trans, struct link_device *dev, char *name, float *data, int datasize)
Definition oneloop_nB.c:894
struct PolePlacement p_alt_e
Definition oneloop_nB.c:684
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
static float g
Definition oneloop_nB.c:116
void get_act_state_oneloop(void)
Function to reconstruct actuator state using first order dynamics.
struct PolePlacement p_roll_e
Definition oneloop_nB.c:678
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
struct PolePlacement p_head_e
Definition oneloop_nB.c:687
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
float xdot_lim_sf
Definition oneloop_nB.c:432
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
float andi_du[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:301
float max_v_nav_v
Definition oneloop_nB.c:425
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 max_v_nav
Definition oneloop_nB.c:419
bool heading_manual
Definition oneloop_nB.c:333
float spin_trim_bleed_rate
Definition oneloop_nB.c:561
bool drop_roll
Definition oneloop_nB.c:503
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
static float nav_target[3]
Definition oneloop_nB.c:434
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
float k1_NE_tune
Definition oneloop_nB.c:697
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.
struct Gains3rdOrder k_pos_rm
Definition oneloop_nB.c:693
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
float m_array[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:487
bool state_compensation_on
Definition oneloop_nB.c:506
static Butterworth2LowPass push_PID_vel[2]
Definition oneloop_nB.c:186
float Wu_quad_motors_fwd
Definition oneloop_nB.c:441
float temp_acc_des[3]
Definition oneloop_nB.c:515
bool drop_aD
Definition oneloop_nB.c:505
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
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[])
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
float theta_pref_max
Definition oneloop_nB.c:280
float act_max[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:221
#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.
float psi_des_deg
Definition oneloop_nB.c:390
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.
struct FloatEulers eulers_zxy
Definition oneloop_nB.c:388
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.
float gi_unbounded_airspeed_sp
Definition oneloop_nB.c:436
PRINT_CONFIG_VAR(ONELOOP_NB_FILT_CUTOFF)
struct OneloopStabilizationRef sta_bounds
Definition oneloop_nB.c:342
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.
struct PolePlacement p_pos_rm
Definition oneloop_nB.c:682
float ratio_vn_v[ANDI_OUTPUTS]
Definition oneloop_nB.c:490
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 nu_n[ANDI_OUTPUTS]
Definition oneloop_nB.c:304
bool yaw_stick_in_auto
Definition oneloop_nB.c:339
float actuator_state_1l[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:306
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 temp_D_error[3]
Definition oneloop_nB.c:705
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 float dt_1l
Definition oneloop_nB.c:115
struct Gains3rdOrder k_att_e_indi
Definition oneloop_nB.c:695
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
float act_min[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:227
static float a_thrust
Definition oneloop_nB.c:480
static void send_guidance_oneloop_nB(struct transport_tx *trans, struct link_device *dev)
Definition oneloop_nB.c:846
float max_r
Definition oneloop_nB.c:319
struct Oneloop_LP_t LP
Definition oneloop_nB.c:182
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.
float * bwls_1l[ANDI_OUTPUTS]
Definition oneloop_nB.c:484
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
static float nav_target_new[3]
Definition oneloop_nB.c:435
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
static float u_pref[ANDI_NUM_ACT_TOT]
Definition oneloop_nB.c:251
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])
struct OneloopGuidanceState gui_state
struct OneloopStabilizationState sta_state
struct FloatVect3 nI_3d
Definition oneloop_nB.h:180
float max_push_cmd
Definition oneloop_nB.h:199
struct FloatVect3 mu_B
Definition oneloop_nB.h:181
#define CTRL_NB_ANDI
Definition oneloop_nB.h:62
union LP_t::@275 meas_filt
struct FloatVect3 nB_2d
Definition oneloop_nB.h:174
float meas
struct FloatVect3 nB_3d
Definition oneloop_nB.h:175
float bandwidth
struct LP_t q_ddot
Definition oneloop_nB.h:282
float meas_prev
float tau
struct OneloopGuidanceRef gui_ref
struct FloatVect3 nI_des
Definition oneloop_nB.h:176
struct LP_t ax
struct OneloopStabilizationRef sta_ref
struct OneloopStabilizationnBState sta_nB_state
Definition oneloop_nB.h:211
struct FloatVect3 nB_d
Definition oneloop_nB.h:173
float freq
struct LP_t r_dot
struct LP_t p_dot
float freq_set
struct LP_t p
float out
struct FloatVect3 nI_d
Definition oneloop_nB.h:178
struct LP_t az
struct LP_t q
enum FilterType filter_type
struct LP_t p_ddot
Definition oneloop_nB.h:281
struct OneloopPushnB push_nB
Definition oneloop_nB.h:212
#define CTRL_NB_INDI
Definition oneloop_nB.h:63
struct LP_t ay
struct LP_t q_dot
struct LP_t r
struct FloatVect3 nI_2d
Definition oneloop_nB.h:179
struct LP_t r_ddot
Definition oneloop_nB.h:283
#define MAX_PPRZ
Definition paparazzi.h:8
Paparazzi floating point algebra.
float y
in meters
float x
in meters
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.
pprz_t values[RADIO_CONTROL_NB_CHANNEL]
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.
struct EnuCoor_f speed
speed setpoint (in m/s)
Definition navigation.h:128
float climb
climb setpoint (in m/s)
Definition navigation.h:137
#define NAV_SETPOINT_MODE_SPEED
Definition navigation.h:101
#define NAV_VERTICAL_MODE_CLIMB
Definition navigation.h:93
float nav_altitude
current altitude setpoint (in meters): might differ from fp_altitude depending on altitude shift from...
Definition navigation.h:139
#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
struct EnuCoor_f target
final target position (in meters)
Definition navigation.h:126
#define MAX(x, y)
Definition sdLog.c:42
static const ShellCommand commands[]
Definition shell_arch.c:77
struct Stabilization stabilization
int32_t cmd[COMMANDS_NB]
output command vector, range from [-MAX_PPRZ:MAX_PPRZ] (store for messages)
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
float u[WLS_N_U_MAX]
Definition wls_alloc.h:71
#define WLS_N_V_MAX
Definition wls_alloc.h:64
float u_min[WLS_N_U_MAX]
Definition wls_alloc.h:75
float Wu[WLS_N_U_MAX]
Definition wls_alloc.h:73
float u_max[WLS_N_U_MAX]
Definition wls_alloc.h:76
float u_pref[WLS_N_U_MAX]
Definition wls_alloc.h:74
float Wv[WLS_N_V_MAX]
Definition wls_alloc.h:72
float v[WLS_N_V_MAX]
Definition wls_alloc.h:70
int nu
Definition wls_alloc.h:67