Paparazzi UAS v7.1_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
oneloop_andi.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_ANDI_SIMPLE_QUAD
94#endif
96// #include "modules/ctrl/eff_scheduling_rotwing_V2.h"
97#include "generated/modules.h"
98#ifdef MODULE_SYS_ID_DOUBLET_ID
100#endif
101#include <stdio.h>
102#if INS_EXT_POSE
104#endif
105
106#ifdef ONELOOP_ANDI_CONSTANT_EFFECTIVENESS
107/* Quadrotor without an effectiveness scheduling module: the effectiveness matrix is built here
108 * from the airframe rows ONELOOP_ANDI_G1_THRUST/ROLL/PITCH/YAW and ONELOOP_ANDI_G2 (scaled by ANDI_G_SCALING).
109 * Do not combine with an effectiveness scheduling module, those provide EFF_MAT_RW themselves.
110 */
111#define RW_aN 0 // North axis (linear acceleration)
112#define RW_aE 1 // East axis (linear acceleration)
113#define RW_aD 2 // Down axis (linear acceleration)
114#define RW_ap 3 // X body axis (angular acceleration)
115#define RW_aq 4 // Y body axis (angular acceleration)
116#define RW_ar 5 // Z body axis (angular acceleration)
119static void oneloop_andi_constant_eff(void);
120#endif
121//====================================================================================================================================
122//====================================================================================================================================
123// Define configuration variables with default values if not defined in the airframe file
124//====================================================================================================================================
125//====================================================================================================================================
126// GENERAL VARIABLES
127//====================================================================================================================================
128#ifndef ONELOOP_ANDI_DEBUG_MODE // Debug mode, sets in_flight to FALSE
129#define ONELOOP_ANDI_DEBUG_MODE FALSE
130#endif
131
132struct OneloopGeneral oneloop_andi; // Define general struct of the Oneloop ANDI controller
133static float dt_1l = 1./PERIODIC_FREQUENCY; // Time step of the oneloop controller [s]
134static float g = 9.81; // [m/s^2] Gravitational Acceleration
135//====================================================================================================================================
136// FILTERING VARIABLES
137//====================================================================================================================================
138#define USE_BW2
139
140#ifdef ONELOOP_ANDI_FILT_CUTOFF
142#else
144#endif
145
146#ifdef ONELOOP_ANDI_FILT_CUTOFF_ACC
148#else
150#endif
151
152#ifdef ONELOOP_ANDI_FILT_CUTOFF_VEL
154#else
156#endif
157
158#ifdef ONELOOP_ANDI_FILT_CUTOFF_P
159#define ONELOOP_ANDI_FILTER_ROLL_RATE TRUE
161#else
163#endif
164
165#ifdef ONELOOP_ANDI_FILT_CUTOFF_Q
166#define ONELOOP_ANDI_FILTER_PITCH_RATE TRUE
168#else
170#endif
171
172#ifdef ONELOOP_ANDI_FILT_CUTOFF_R
173#define ONELOOP_ANDI_FILTER_YAW_RATE TRUE
175#else
177#endif
178
179PRINT_CONFIG_MSG("============================================================")
187PRINT_CONFIG_MSG("============================================================")
188
197
198#define USE_PID_NUMDIFF_DERIVATIVE
199#ifdef USE_PID_NUMDIFF_DERIVATIVE
201#endif
202static Butterworth2LowPass accely_filt; // FIXME (check if condenseable) Low pass filter for acceleration in y direction
203static Butterworth2LowPass airspeed_filt; // FIXME (check if condenseable) Low pass filter for airspeed
204static Butterworth2LowPass u_filt[ANDI_NUM_ACT_TOT]; // FIXME (check if condenseable) Low pass filter for actuators for synchronous filtering
205//====================================================================================================================================
206// ACTUATOR VARIABLES
207//====================================================================================================================================
208#ifndef ONELOOP_ANDI_NUM_THRUSTERS // Number of motors used for thrust
210#else
212#endif
213
214#ifdef ONELOOP_ANDI_ACT_IS_SERVO // Unused but kept for future developments
216#else
218#endif
219
220#ifdef ONELOOP_ANDI_ACT_DYN // Actuator dynamics (first order lag) corner frequency [rad/s]
223#else
224#error "You must specify the actuator dynamics"
227#endif
228
229#ifdef ONELOOP_ANDI_ACT_MAX // Maximum Paparazzi actuator command
231#else
233#endif
234
235#ifdef ONELOOP_ANDI_ACT_MIN // Minimum Paparazzi actuator command
237#else
238float act_min[ANDI_NUM_ACT_TOT] = = {0.0};
239#endif
240
241#ifdef ONELOOP_ANDI_ACT_MAX_NORM // Maximum normalized actuator command
243#else
245#endif
246
247#ifdef ONELOOP_ANDI_ACT_MIN_NORM // Minimum normalized actuator command
249#else
251#endif
252
253#ifdef ONELOOP_ANDI_NU_NORM_MAX // Maximum norm of the normalized pseudo control vector
255#else
256float nu_norm_max = 1.0;
257#endif
258
259#ifdef ONELOOP_ANDI_U_PREF // Preferred Paparazzi actuator command
261#else
262static float u_pref[ANDI_NUM_ACT_TOT] = {0.0};
263#endif
264
265#define ONELOOP_ANDI_MAX_BANK act_max[COMMAND_ROLL] // Max Bank (can be different from Max Roll) assuming abs of max and min is the same
266#define ONELOOP_ANDI_MAX_PHI act_max[COMMAND_ROLL] // Max Roll assuming abs of max and min is the same
267#define ONELOOP_ANDI_MAX_THETA act_max[COMMAND_PITCH] // Max Pitch assuming abs of max and min is the same
268
269#ifndef ONELOOP_THETA_PREF_MAX // Max preferred pitch angles
271#else
273#endif
274
275#if ANDI_NUM_ACT_TOT != WLS_N_U_MAX
276#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
277#define WLS_N_U_MAX == ANDI_NUM_ACT_TOT
278#endif
279#if ANDI_OUTPUTS != WLS_N_V_MAX
280#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
281#define WLS_N_V_MAX == ANDI_OUTPUTS
282#endif
283
284float andi_u[ANDI_NUM_ACT_TOT]; // Control command vector
285float andi_du[ANDI_NUM_ACT_TOT]; // Control command increment vector
286static float andi_u_n[ANDI_NUM_ACT_TOT]; // Control command vector (normalized)
287float nu[ANDI_OUTPUTS]; // Pseudo control vector
288float nu_n[ANDI_OUTPUTS]; // Pseudo control vector (normalized)
289static float act_dynamics_d[ANDI_NUM_ACT_TOT]; // Actuator dynamics (first order lag) corner frequency [rad/s]
290float actuator_state_1l[ANDI_NUM_ACT_TOT]; // Actuator state vector (including virtual actuators)
291//====================================================================================================================================
292// STABILIZATION VARIABLES
293//====================================================================================================================================
294#ifndef MAX_R // Max Yaw rate with the sticks
295float max_r = RadOfDeg(120.0);
296#else
297float max_r = RadOfDeg(MAX_R);
298#endif
299
300#ifdef ONELOOP_ANDI_YAW_DISTURBANCE_LIMIT // Yaw disturbance rejection limit
302#else
303float oneloop_andi_yaw_dist_limit = 99999.f; // High value to disable the feature
304#endif
305
306#if ONELOOP_ANDI_HEADING_MANUAL // Specify heading in NAV with a slider
307bool heading_manual = true;
308#else
309bool heading_manual = false;
310#endif
311
312#if ONELOOP_ANDI_YAW_STICK_IN_AUTO // Specify heading in NAV with the yaw stick
313bool yaw_stick_in_auto = true;
314#else
315bool yaw_stick_in_auto = false;
316#endif
317
318struct OneloopStabilizationRef sta_bounds = { // Stabilization bounds specified per axis
319 #ifdef ONELOOP_ANDI_MAX_ANGULAR_JERK
322 #else
323 .att_3d[0] = RadOfDeg(100000.0),
324 .att_3d[1] = RadOfDeg(100000.0),
325 #endif
326
327#ifdef ONELOOP_ANDI_MAX_ANGULAR_JERK_YAW
329#else
330 .att_3d[2] = RadOfDeg(1520.0),
331#endif
332
333 #ifdef ONELOOP_ANDI_MAX_ANGULAR_ACCEL
336 #else
337 .att_2d[0] = RadOfDeg(700.0),
338 .att_2d[1] = RadOfDeg(480.0),
339 #endif
340
341#ifdef ONELOOP_ANDI_MAX_ANGULAR_ACCEL_YAW
343#else
344 .att_2d[2] = RadOfDeg(130.0),
345#endif
346
347#ifdef ONELOOP_ANDI_MAX_ANGULAR_VEL
350#else
351 .att_d[0] = RadOfDeg(10000.0),
352 .att_d[1] = RadOfDeg(10000.0),
353#endif
354
355#ifdef ONELOOP_ANDI_MAX_ANGULAR_VEL_YAW
357#else
358 .att_d[2] = RadOfDeg(30.0),
359#endif
360};
361
362struct FloatEulers eulers_zxy_des; // Desired Euler angles in ZXY sequence
363struct FloatEulers eulers_zxy; // Actual Euler angles in ZXY sequence
364float psi_des_rad = 0.0; // Desired Yaw angle [rad]
365float psi_des_deg = 0.0; // Desired Yaw angle [deg]
366static float psi_vec[4] = {0.0, 0.0, 0.0, 0.0}; // Vector to overwrite the Yaw reference in the attitude controller
367static float phi_vec[4] = {0.0, 0.0, 0.0, 0.0}; // Vector to overwrite the Roll reference in the attitude controller
368//====================================================================================================================================
369// GUIDANCE VARIABLES
370//====================================================================================================================================
371#ifndef ONELOOP_ANDI_AIRSPEED_SWITCH_THRESHOLD // Airspeed threshold to switch to coordinated turn behavior
372#define ONELOOP_ANDI_AIRSPEED_SWITCH_THRESHOLD 10.0
373#endif
374
375#ifndef FWD_SIDESLIP_GAIN // Gain to reduce sideslip when flying forward
377#else
379#endif
380
381#ifdef NAV_HYBRID_MAX_DECELERATION // Max (ac)/(de)celeration. Can be overwritte nby NAV HYBRID
383#else
384float max_a_nav = 4.0;
385#endif
386
387#ifdef ONELOOP_ANDI_MAX_LINEAR_JERK // Max linear jerk [m/s^3]
389#else
390float max_j_lin = 500.0;
391#endif
392
393#ifdef NAV_HYBRID_MAX_AIRSPEED
394float max_v_nav = NAV_HYBRID_MAX_AIRSPEED; // Max horizontal speed. Can be overwritten by NAV HYBRID
395#else
396float max_v_nav = 5.0;
397#endif
398
399#ifdef NAV_HYBRID_MAX_SPEED_V // Max vertical speed
401#else
402float max_v_nav_v = 1.5;
403#endif
404
405#define USE_ND_VELOCITIES // Use NumDiff of velocities instead of Accelerometer.
406
407float max_as = 19.0f; // Max airspeed [m/s]
408float min_as = 0.0f; // Min airspeed [m/s]
409float xdot_lim_sf = 0.8; // Safety Factor on SUVAT velocity limit
410float ec_headroom = 1.5; // Extra headroom for the EC wrt the RM
411static float nav_target[3]; // Can be a position, speed or acceleration depending on the guidance H mode
412static float nav_target_new[3]; // Wind triangle reshaped NAV target
413float gi_unbounded_airspeed_sp = 0.0; // Unbounded airspeed setpoint [m/s] (mimics guidance_indi_hybrid)
414//====================================================================================================================================
415// CONTROL ALLOCATION VARIABLES
416//====================================================================================================================================
417#ifndef ONELOOP_ANDI_WU_QUAD_MOTORS_FWD
419#else
421#endif
422
423struct WLS_t WLS_one_p = {
425 .nv = ANDI_OUTPUTS,
426 .gamma_sq = 1000.0,
427 .v = {0.0},
428#ifdef ONELOOP_ANDI_WV // {ax_dot,ay_dot,az_dot,p_ddot,q_ddot,r_ddot}
429 .Wv = ONELOOP_ANDI_WV,
430#else
431 .Wv = {1.0},
432#endif
433#ifdef ONELOOP_ANDI_WU // {de,dr,daL,daR,mF,mB,mL,mR,mP,phi,theta}
434 .Wu = ONELOOP_ANDI_WU,
435#else
436 .Wu = {1.0},
437#endif
438 .u_pref = {0.0},
439 .u_min = {0.0},
440 .u_max = {0.0},
441 .PC = 0.0,
442 .SC = 0.0,
443 .iter = 0
444};
445
446#ifdef ONELOOP_ANDI_WV // {ax_dot,ay_dot,az_dot,p_ddot,q_ddot,r_ddot}
448#else
449static float Wv_backup[ANDI_OUTPUTS] = {1.0};
450#endif
451
452#ifdef ONELOOP_ANDI_WU // {mF,mR,mB,mL,mP,de,dr,da,df,phi,theta}
454#else
455static float Wu_backup[ANDI_NUM_ACT_TOT] = {1.0};
456#endif
457
458static float a_thrust = 0.0; // Virtual z-Acceleration to command a Thrust level[m/s^2]
459static float g2_ff = 0.0; // Feedforward G2 term for Yaw control
460bool ctrl_off = false; // Turn off stabilization with the quad motors
461static float pitch_pref = 0; // Preferred pitch angle for the control allocation
462
463float *bwls_1l[ANDI_OUTPUTS]; // Pointer to the WLS Effectiveness matrix
464float EFF_MAT_G[ANDI_OUTPUTS][ANDI_NUM_ACT_TOT]; // Intermidiate variable to save Effectiveness matrix
472//====================================================================================================================================
473// CONTROL LAW VARIABLES
474//====================================================================================================================================
475bool drop_yaw = false; // Drop the control of the Yaw axis
476bool drop_roll = false; // Drop the control of the Roll axis
477bool drop_pitch = false; // Drop the control of the Pitch axis
478bool drop_aN = false; // Drop the control of the aN axis
479bool drop_aE = false; // Drop the control of the aE axis
480bool drop_aD = false; // Drop the control of the aD axis
481//====================================================================================================================================
482// Error Controller and Reference Model VARIABLES
483//====================================================================================================================================
484/*Declaration of Reference Model and Error Controller Gains*/
488/*Position Loop*/
491/*Altitude Loop*/
494/*Heading Loop*/
497/*Gains of EC and RM ANDI*/
502/*Gains of EC and RM INDI*/
505float k1_NE_tune = 0.6;
506float k2_NE_tune = 1.85;
507/* PID */
508float k_P = 0.6;
509float k_D = 1.2;
510float k_I = 9.0e-4;
514//====================================================================================================================================
515// System Identification VARIABLES
516//====================================================================================================================================
517bool chirp_on = false;
520float t_0_chirp = 0.0;
521float f0_chirp = 0.2; // Start Frequency [Hz]
522float f1_chirp = 0.2; // End Frequency [Hz]
523float t_chirp = 0.65 ; // Time length of the chirp [s]
524float A_chirp = 250.0; // Amplitude of the chirp
525int8_t chirp_axis = 6 ; // Axis on which the chirp is applied
526float p_ref_0[3] = {0.0, 0.0, 0.0};
532//====================================================================================================================================
533// Function Declaration Section
534//====================================================================================================================================
535void init_poles(void);
536void calc_normalization(void);
537void normalize_nu(void);
538void G1G2_oneloop(int ctrl_type);
539void get_act_state_oneloop(void);
541void init_filter(void);
542void init_controller_gains(void);
543void reinit_controller(void);
544void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3]);
545void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3]);
546void err_nd(float err[], float a[], float b[], float k[], int n);
547void err_sum_nd(float err[], float a[], float b[], float k[], float c[], int n);
548void float_vect_diff_euler(float err[3], float a[3], float b[3]);
549void integrate_nd(float dt, float a[], float a_dot[], int n);
550void vect_bound_nd(float vect[], float bound, int n);
551void acc_body_bound(struct FloatVect2* vect, float bound);
552float bound_v_from_a_vect(float e_x[], float v_bound, float a_bound, int n);
553float bound_v_from_a(float e_x, float v_bound, float a_bound);
554void 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);
555void 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);
556void 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);
557void 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);
558void 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]);
559void 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);
560float oneloop_andi_sideslip(void);
561void reshape_wind(void);
562void 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[]);
563void 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[]);
564void oneloop_axis_effectiveness_calc(void); // FIXME check if used
565void oneloop_andi_bound_disturbance(void); // FIXME add flag to turn on and off
566void oneloop_calc_model_disturbance(bool in_flight);
567void dynFilter_init(struct Oneloop_DynFilt_t *mu, float varepsilon, float sigma);
568void dynFilter_run(struct Oneloop_DynFilt_t *mu, float u_c, float sigma);
569//====================================================================================================================================
570// Telemetry Section
571//====================================================================================================================================
572#if PERIODIC_TELEMETRY
574// static void send_cf_oneloop(struct transport_tx *trans, struct link_device *dev)
575// {
576// float temp_cf_p[5] = {cf.p.model,cf.p.model_filt.o[0],cf.p.feedback,cf.p.feedback_filt.o[0],cf.p.out};
577// float temp_cf_q[5] = {cf.q.model,cf.q.model_filt.o[0],cf.q.feedback,cf.q.feedback_filt.o[0],cf.q.out};
578// float temp_cf_r[5] = {cf.r.model,cf.r.model_filt.o[0],cf.r.feedback,cf.r.feedback_filt.o[0],cf.r.out};
579// float temp_cf_p_dot[5] = {cf.p_dot.model,cf.p_dot.model_filt.lp2.o[0],cf.p_dot.feedback,cf.p_dot.feedback_filt.lp2.o[0],cf.p_dot.out};
580// float temp_cf_q_dot[5] = {cf.q_dot.model,cf.q_dot.model_filt.lp2.o[0],cf.q_dot.feedback,cf.q_dot.feedback_filt.lp2.o[0],cf.q_dot.out};
581// float temp_cf_r_dot[5] = {cf.r_dot.model,cf.r_dot.model_filt.o[0],cf.r_dot.feedback,cf.r_dot.feedback_filt.o[0],cf.r_dot.out};
582// //float temp_cf_ax[5] = {cf.ax.model,cf.ax.model_filt.o[0],cf.ax.feedback,cf.ax.feedback_filt.o[0],cf.ax.out};
583// //float temp_cf_ay[5] = {cf.ay.model,cf.ay.model_filt.o[0],cf.ay.feedback,cf.ay.feedback_filt.o[0],cf.ay.out};
584// float temp_cf_az[5] = {cf.az.model,cf.az.model_filt.o[0],cf.az.feedback,cf.az.feedback_filt.o[0],cf.az.out};
585// pprz_msg_send_COMPLEMENTARY_FILTER(trans, dev, AC_ID,
586// 5, temp_cf_p,
587// 5, temp_cf_q,
588// 5, temp_cf_r,
589// 5, temp_cf_p_dot,
590// 5, temp_cf_q_dot,
591// 5, temp_cf_r_dot,
592// 5, temp_cf_az);
593// }
594static void send_wls_v_oneloop(struct transport_tx *trans, struct link_device *dev)
595{
596 send_wls_v("one", &WLS_one_p, trans, dev);
597}
598static void send_wls_u_oneloop(struct transport_tx *trans, struct link_device *dev)
599{
600 send_wls_u("one", &WLS_one_p, trans, dev);
601}
603{
604 float zero = 0.0;
610}
657static void debug_vect(struct transport_tx *trans, struct link_device *dev, char *name, float *data, int datasize)
658{
660 strlen(name), name,
661 datasize, data);
662}
663static void send_oneloop_debug(struct transport_tx *trans, struct link_device *dev)
664{
665 float temp_debug_vect[9];
666 //temp_debug_vect[0] = oneloop_andi_model[0];
667 //temp_debug_vect[1] = oneloop_andi_model[1];
668 //temp_debug_vect[2] = oneloop_andi_model[2];
669 //temp_debug_vect[3] = oneloop_andi_model[3];
670 //temp_debug_vect[4] = oneloop_andi_model[4];
671 //temp_debug_vect[5] = oneloop_andi_model[5];
681 debug_vect(trans, dev, "APF", temp_debug_vect, 9);
682}
683#endif
684//====================================================================================================================================
685// Functions Definition Section
686//====================================================================================================================================
687// General Mathematical Functions
689static float positive_non_zero(float input)
690{
691 if (input < FLT_EPSILON)
692 {
693 input = 0.00001;
694 }
695 return input;
696}
698void err_nd(float err[], float a[], float b[], float k[], int n)
699{
700 int8_t i;
701 for (i = 0; i < n; i++) {
702 err[i] = k[i] * (a[i] - b[i]);
703 }
704}
706void err_sum_nd(float err[], float a[], float b[], float k[], float c[], int n)
707{
708 int8_t i;
709 for (i = 0; i < n; i++) {
710 err[i] = k[i] * (a[i] - b[i]);
711 err[i] += c[i];
712 }
713}
715void float_vect_diff_euler(float err[3], float a[3], float b[3])
716{
717 err[0] = (a[0] - b[0]);
718 err[1] = (a[1] - b[1]);
719 err[2] = (a[2] - b[2]);
720 NormRadAngle(err[2]);
721}
723void integrate_nd(float dt, float a[], float a_dot[], int n)
724{
725 int8_t i;
726 for (i = 0; i < n; i++) {
727 a[i] = a[i] + dt * a_dot[i];
728 }
729}
731void vect_bound_nd(float vect[], float bound, int n) {
732 float norm = float_vect_norm(vect,n);
734 if((norm-bound) > FLT_EPSILON) {
735 float scale = bound/norm;
736 int8_t i;
737 for(i = 0; i < n; i++) {
738 vect[i] *= scale;
739 }
740 }
741}
742//====================================================================================================================================
743// Reference Model Gain Design Functions
745static float k_rm_1_3_f(float omega_n, float zeta, float p1) {
746 omega_n = positive_non_zero(omega_n);
747 zeta = positive_non_zero(zeta);
748 p1 = positive_non_zero(p1);
749 return (omega_n * omega_n * p1) / (omega_n * omega_n + omega_n * p1 * zeta * 2.0);
750}
751static float k_rm_2_3_f(float omega_n, float zeta, float p1) {
752 omega_n = positive_non_zero(omega_n);
753 zeta = positive_non_zero(zeta);
754 p1 = positive_non_zero(p1);
755 return (omega_n * omega_n + omega_n * p1 * zeta * 2.0) / (p1 + omega_n * zeta * 2.0);
756}
757static float k_rm_3_3_f(float omega_n, float zeta, float p1) {
758 omega_n = positive_non_zero(omega_n);
759 zeta = positive_non_zero(zeta);
760 p1 = positive_non_zero(p1);
761 return p1 + omega_n * zeta * 2.0;
762}
763
764// 3-axis position PID controller
765
766static 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])
767{
768 static float prev_pos[3] = {0.0f, 0.0f, 0.0f};
769 static float integral[3] = {0.0f, 0.0f, 0.0f};
770 for (int i = 0; i < 3; i++)
771 {
772 float err = x_des[i] - x[i];
773 integral[i] += err * dt_1l;
774 // Optional anti-windup
775 const float I_MAX = 0.4f;
776 if (integral[i] > I_MAX) integral[i] = I_MAX;
777 if (integral[i] < -I_MAX) integral[i] = -I_MAX;
778#ifdef USE_PID_NUMDIFF_DERIVATIVE
779 // Numerical derivative
780 //static float prev_err[3] = {0.0f, 0.0f, 0.0f};
781 //float derivative = (err - prev_err[i]) / dt_1l;
782 //prev_err[i] = err;
783 float derivative_nd = (x[i] - prev_pos[i]) / dt_1l;
784 prev_pos[i] = x[i];
786 float derivative = -filt_veloc[i].o[0];
787#else
788 float derivative = -x_dot[i];
789#endif
790
791 // Temp debug
792 temp_P_error[i] = k_P * err;
794 temp_I_error[i] = k_I * integral[i];
795 a[i] = k_P * err+ k_I * integral[i]+ k_D * derivative;
796 }
797 vect_bound_nd(a,0.5*9.81,3);
798}
799static void shape_vector(float a[3]){
800 a[2] += -9.81;
801 vect_bound_nd(a,1.0,3);
802}
803static void eul_of_acc(float a[3], float psi){
804 float phi_des;
805 float theta_des;
806
807 float spsi = sinf(psi);
808 float cpsi = cosf(psi);
809 //printf("psi:%f \n",DegOfRad(psi));
810 float aX = cpsi*a[0]+spsi*a[1];
811 float aY =-spsi*a[0]+cpsi*a[1];
812 //printf("[aX,aY]=[%f,%f] \n",aX,aY);
813 theta_des = asinf(-aX);
814 float ctheta_des = cosf(theta_des);
817 //printf("[phi_des,theta_des]=[%f,%f] \n",DegOfRad(phi_des),DegOfRad(theta_des));
818 BoundAbs(phi_des, M_PI_6); // Limit to 30 deg
819 BoundAbs(theta_des, M_PI_6); // Limit to 30 deg
822}
823//====================================================================================================================================
824// Attitude Conversion Functions
826// void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3])
827// {
828// float sphi = sinf(e[0]);
829// float cphi = cosf(e[0]);
830// float stheta = sinf(e[1]);
831// float ctheta = cosf(e[1]);
832// r[0] = edot[0] - stheta * edot[2];
833// r[1] = cphi * edot[1] + sphi * ctheta * edot[2];
834// r[2] = -sphi * edot[1] + cphi * ctheta * edot[2];
835// }
836
838void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3])
839{
840 float sphi = sinf(e[0]);
841 float cphi = cosf(e[0]);
842 float stheta = sinf(e[1]);
843 float ctheta = cosf(e[1]);
844 r[0] = ctheta * edot[0] - stheta * cphi * edot[2];
845 r[1] = edot[1] + sphi * edot[2];
846 r[2] = stheta * edot[0] + ctheta *cphi * edot[2];
847}
848
850// void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3])
851// {
852// float sphi = sinf(e[0]);
853// float cphi = cosf(e[0]);
854// float stheta = sinf(e[1]);
855// float ctheta = cosf(e[1]);
856// if (fabs(ctheta) < FLT_EPSILON)
857// {
858// ctheta = FLT_EPSILON;
859// }
860// edot[0] = r[0] + sphi * stheta / ctheta * r[1] + cphi * stheta / ctheta * r[2];
861// edot[1] = cphi * r[1] - sphi * r[2];
862// edot[2] = sphi / ctheta * r[1] + cphi / ctheta * r[2];
863// }
864
866void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3])
867{
868 float sphi = sinf(e[0]);
869 float cphi = cosf(e[0]);
870 float stheta = sinf(e[1]);
871 float ctheta = cosf(e[1]);
872 float spsi = sinf(e[2]);
873 float cpsi = cosf(e[2]);
874
875 if (fabs(ctheta) < FLT_EPSILON)
876 {
877 ctheta = FLT_EPSILON;
878 }
879 edot[0] = r[0] + spsi * stheta / ctheta * r[1] + cpsi * stheta / ctheta * r[2];
880 edot[1] = cphi * r[1] - sphi * r[2];
881 edot[2] = sphi * r[1] + cphi * r[2];
882}
883//====================================================================================================================================
884// Bounding Functions
886void acc_body_bound(struct FloatVect2 *vect, float bound)
887{
888 int n = 2;
889 float v[2] = {vect->x, vect->y};
890 float sign_v0 = (v[0] > 0.f) ? 1.f : (v[0] < 0.f) ? -1.f : 0.f;
891 float sign_v1 = (v[1] > 0.f) ? 1.f : (v[1] < 0.f) ? -1.f : 0.f;
892 float norm = float_vect_norm(v, n);
893 v[0] = fabsf(v[0]);
894 v[1] = fabsf(v[1]);
896 if ((norm - bound) > FLT_EPSILON)
897 {
898 v[0] = Min(v[0], bound);
899 float acc_b_y_2 = bound * bound - v[0] * v[0];
901 v[1] = sqrtf(acc_b_y_2);
902 }
903 vect->x = sign_v0 * v[0];
904 vect->y = sign_v1 * v[1];
905}
915float bound_v_from_a_vect(float e_x[], float v_bound, float a_bound, int n)
916{
917 float norm = float_vect_norm(e_x, n);
918 norm = fmaxf(norm, 1.0);
919 float v_bound_a = sqrtf(fabs(2.0 * a_bound * norm * xdot_lim_sf));
920 return fminf(v_bound, v_bound_a);
921}
931float bound_v_from_a(float e_x, float v_bound, float a_bound)
932{
933 float norm;
934 norm = fabsf(e_x);
935 //norm = fmaxf(norm, 1.0);
936 float v_bound_a = sqrtf(fabs(2.0 * a_bound * norm * xdot_lim_sf));
937 return fminf(v_bound, v_bound_a);
938}
939//====================================================================================================================================
940// Reference Model Functions
956void 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){
957
958 float e_x[3]; // Attitude Error
959 float x_d_fw[3]; // Forward Signal Euler Dot
960 float x_d_fw_rates[3]; // Forward Signal Angular Rates
961 float x_2d_fw[3]; // Forward Signal Angular Acceleration
962 float x_3d_fw[3]; // Forward Signal Angular Jerk
963 float bounds_att_d[3]; // Bounds on Angular Rate (SUVAT based)
964 float x_d_eul_ref[3]; // Euler angle Reference
965 // Attitude error --------------------------------------------------------------------------------------------------
966 float_vect_diff_euler(e_x, x_des, x_ref); // Calculate Attitude Error
967 x_d_fw[0] = e_x[0] * k1_rm[0]; // Calculate Forward Signal Euler Dot
968 x_d_fw[1] = e_x[1] * k1_rm[1]; // Calculate Forward Signal Euler Dot
969 x_d_fw[2] = e_x[2] * k1_rm[2]; // Calculate Forward Signal Euler Dot
970 float_rates_of_euler_dot_vec(x_d_fw_rates, x_ref, x_d_fw); // Convert Euler Dot to Angular Rates
971 bounds_att_d[0] = bound_v_from_a(e_x[0], bounds.att_d[0], bounds.att_2d[0]);
972 bounds_att_d[1] = bound_v_from_a(e_x[1], bounds.att_d[1], bounds.att_2d[1]);
973 bounds_att_d[2] = bound_v_from_a(e_x[2], bounds.att_d[2], bounds.att_2d[2]);
977 // Angular Rate error ----------------------------------------------------------------------------------------------
979 BoundAbs(x_2d_fw[0], bounds.att_2d[0]);
980 BoundAbs(x_2d_fw[1], bounds.att_2d[1]);
981 BoundAbs(x_2d_fw[2], bounds.att_2d[2]);
982 // Angular Acceleration error -----------------------------------------
984 BoundAbs(x_3d_fw[0], bounds.att_3d[0]);
985 BoundAbs(x_3d_fw[1], bounds.att_3d[1]);
986 BoundAbs(x_3d_fw[2], bounds.att_3d[2]);
987 // Angular Jerk Reference ---------------------------------------------
989 if (ow_psi){x_3d_ref[2] = psi_overwrite[3];}
990 // Angular Acceleration Reference -------------------------------------
992 if (ow_psi){x_2d_ref[2] = psi_overwrite[2];}
993 // Angular Rate Reference ---------------------------------------------
995 if (ow_psi){x_d_ref[2] = psi_overwrite[1];}
996 // Attitude Reference ------------------------------------------------
999 if (ow_psi){x_ref[2] = psi_overwrite[0];}
1000 NormRadAngle(x_ref[2]);
1001}
1002
1003
1020void 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)
1021{
1022 float e_x[n];
1023 float e_x_d[n];
1024 float e_x_2d[n];
1025 err_nd(e_x, x_des, x_ref, k1_rm, n);
1028 err_nd(e_x_d, e_x, x_d_ref, k2_rm, n);
1034 integrate_nd(dt, x_d_ref, x_2d_ref, n);
1035 integrate_nd(dt, x_ref, x_d_ref, n);
1036}
1037
1051void 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)
1052{
1053 float e_x_d[n];
1054 float e_x_2d[n];
1061 integrate_nd(dt, x_d_ref, x_2d_ref, n);
1062}
1063
1074void 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)
1075{
1076 float e_x_2d[n];
1081}
1082//====================================================================================================================================
1083// Error Controller Functions
1099void 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)
1100{
1101 float e_x_d[n];
1102 float e_x_2d[n];
1103 float e_x_des[n];
1106 err_sum_nd(e_x_d, x_ref, x, k1_e, x_d_ref, n);
1110 // Calculate and bound distrubance --------------------
1111 float dist[3];
1112 float_vect_diff(dist, x_2d, fb, 3);
1113 err_sum_nd(y_4d, e_x_2d, dist, k3_e, x_3d_ref, n);
1114}
1115
1131void 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])
1132{
1133 float e_x[3]; // Attitude Error on Reference
1134 float e_x_des[3]; // Attitude Error on Desired
1135 float x_d_fw[3]; // Forward Signal Euler Dot
1136 float x_d_fw_rates[3]; // Forward Signal Angular Rates
1137 float x_d_fw_rates_rm[3]; // Forward Signal Angular Rates plus RM
1138 float x_2d_fw[3]; // Forward Signal Angular Acceleration
1139 float bounds_att_d[3];
1140 // Attitude Error and Heading conversion --------------------------------
1141 float_vect_diff_euler(e_x,x_ref,x); // Calculate the Attitude Error
1142 x_d_fw[0] = e_x[0]*k1_e[0]; // Calculate Forward Signal Euler Dot
1143 x_d_fw[1] = e_x[1]*k1_e[1]; // Calculate Forward Signal Euler Dot
1144 x_d_fw[2] = e_x[2]*k1_e[2]; // Calculate Forward Signal Euler Dot
1145 float_rates_of_euler_dot_vec(x_d_fw_rates, x, x_d_fw); // Euler dot to rates conversion
1146 float_vect_sum(x_d_fw_rates_rm, x_d_ref, x_d_fw_rates, 3);// Add body rates reference signal
1148 bounds_att_d[0] = bound_v_from_a(e_x_des[0], bounds.att_d[0] * ec_headroom, bounds.att_2d[0] * ec_headroom);
1149 bounds_att_d[1] = bound_v_from_a(e_x_des[1], bounds.att_d[1] * ec_headroom, bounds.att_2d[1] * ec_headroom);
1150 bounds_att_d[2] = bound_v_from_a(e_x_des[2], bounds.att_d[2] * ec_headroom, bounds.att_2d[2] * ec_headroom);
1154 // Angular Rate Error ---------------------------------------------------
1155 x_2d_fw[0] = (x_d_fw_rates_rm[0] - x_d[0]) * k2_e[0] + x_2d_ref[0];
1156 x_2d_fw[1] = (x_d_fw_rates_rm[1] - x_d[1]) * k2_e[1] + x_2d_ref[1];
1157 x_2d_fw[2] = (x_d_fw_rates_rm[2] - x_d[2]) * k2_e[2] + x_2d_ref[2];
1158 BoundAbs(x_2d_fw[0], bounds.att_2d[0] * ec_headroom);
1159 BoundAbs(x_2d_fw[1], bounds.att_2d[1] * ec_headroom);
1160 BoundAbs(x_2d_fw[2], bounds.att_2d[2] * ec_headroom);
1161 // Calculate and bound distrubance --------------------------------------
1162 float dist[3];
1163 float_vect_diff(dist, x_2d, fb, 3); // The Disturbance is THe difference between the measurment and the Model
1164 //BoundAbs(dist[2], oneloop_andi_yaw_dist_limit); //FIXME UNCOMMENT ME TO HAVE MAX YAW CONTROL EFFORT
1165 // Angular Acceleration Error -------------------------------------------
1166 err_sum_nd(y_4d, x_2d_fw, dist, k3_e, x_3d_ref, 3);
1167}
1168
1176static float w_approx(float p1, float p2, float p3, float rm_k)
1177{
1178 p1 = positive_non_zero(p1);
1179 p2 = positive_non_zero(p2);
1180 p3 = positive_non_zero(p3);
1182 float tao = (p1 * p2 + p1 * p3 + p2 * p3) / (p1 * p2 * p3) / (rm_k);
1184 return 1.0 / tao;
1185}
1186
1191void init_poles(void)
1192{
1193
1194 // Attitude Controller Poles----------------------------------------------------------
1195 float slow_pole = 22.0; // Pole of the slowest dynamics used in the attitude controller
1196
1197 p_att_e.omega_n = slow_pole / 3.0;
1198 p_att_e.zeta = 1.0;
1200
1202 p_roll_e.zeta = 1.0;
1204
1206 p_att_rm.zeta = 1.0;
1208
1209 p_head_e.omega_n = slow_pole / 3.0;
1210 p_head_e.zeta = 1.0;
1212
1214 p_head_rm.zeta = 1.0;
1216
1219
1220 // Position Controller Poles----------------------------------------------------------
1221 slow_pole = act_dynamics[COMMAND_ROLL]; // Pole of the slowest dynamics used in the position controller
1222
1223 p_pos_e.omega_n = 1.19; // slow_pole/3.0;
1224 p_pos_e.zeta = 0.5;
1226
1228 p_pos_rm.zeta = 0.5;
1230
1231 p_alt_e.omega_n = 1.19; // slow_pole/3.0*2.0;
1232 p_alt_e.zeta = 0.5;
1234
1236 p_alt_rm.zeta = 0.5;
1238}
1239
1245{
1246 /*Register a variable from nav_hybrid. Should be improved when nav hybrid is final.*/
1247 float max_wind = 20.0;
1250 /*Some calculations in case new poles have been specified*/
1255
1256 //--ANDI Controller gains --------------------------------------------------------------------------------
1257 /*Attitude Loop*/
1258 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);
1259 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);
1260 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);
1261
1262 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];
1263 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];
1264 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];
1265
1269 k_att_rm.k1[1] = k_att_rm.k1[0];
1270 k_att_rm.k2[1] = k_att_rm.k2[0];
1271 k_att_rm.k3[1] = k_att_rm.k3[0];
1272 /*Heading Loop NAV*/
1276
1280
1281 // Temporary overrirde of gains
1282 k_att_e.k1[0] = 4.19;
1283 k_att_e.k2[0] = 10.01;
1284 k_att_e.k3[0] = 22.0;
1285 k_att_e.k1[1] = k_att_e.k1[0];
1286 k_att_e.k2[1] = k_att_e.k2[0];
1287 k_att_e.k3[1] = k_att_e.k3[0];
1288
1289 //k_att_rm.k1[0] = 4.19;
1290 //k_att_rm.k2[0] = 10.01;
1291 //k_att_rm.k3[0] = 22.0;
1292//
1293 //k_pos_e.k1[0] = 0.6539;
1294 //k_pos_e.k2[0] = 1.795;
1295 //k_pos_e.k3[0] = XXX;
1296
1297 // Print INNERLOOP ANDI controller gains
1298 // 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);
1299 // 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);
1300 // 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);
1301 // 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);
1302 // printf("ANDI Attitude RM Gains: %f %f %f\n", k_att_rm.k1[0], k_att_rm.k2[0], k_att_rm.k3[0]);
1303 // printf("ANDI Attitude EC Gains: %f %f %f\n", k_att_e.k1[0], k_att_e.k2[0], k_att_e.k3[0]);
1304 // printf("ANDI Heading RM Gains: %f %f %f\n", k_att_rm.k1[2], k_att_rm.k2[2], k_att_rm.k3[2]);
1305 // printf("ANDI Heading EC Gains: %f %f %f\n", k_att_e.k1[2], k_att_e.k2[2], k_att_e.k3[2]);
1306
1307 /*Position Loop*/
1308 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;//
1309 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;//
1311 k_pos_e.k1[1] = k_pos_e.k1[0];
1312 k_pos_e.k2[1] = k_pos_e.k2[0];
1313 k_pos_e.k3[1] = k_pos_e.k3[0];
1314
1318 k_pos_rm.k1[1] = k_pos_rm.k1[0];
1319 k_pos_rm.k2[1] = k_pos_rm.k2[0];
1320 k_pos_rm.k3[1] = k_pos_rm.k3[0];
1323
1324 /*Altitude Loop*/
1327 k_pos_e.k3[2] = 22; // k_rm_3_3_f(p_alt_e.omega_n, p_alt_e.zeta, p_alt_e.p3); //2.380;
1328
1332
1333 // Print OUTERLOOP ANDI controller gains
1334 //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);
1335 //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);
1336 //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);
1337 //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);
1338 //printf("Position N RM Gains: %f %f %f\n", k_pos_rm.k1[0], k_pos_rm.k2[0], k_pos_rm.k3[0]);
1339 //printf("Position N EC Gains: %f %f %f\n", k_pos_e.k1[0], k_pos_e.k2[0], k_pos_e.k3[0]);
1340 //printf("Position D RM Gains: %f %f %f\n", k_pos_rm.k1[2], k_pos_rm.k2[2], k_pos_rm.k3[2]);
1341 //printf("Position D EC Gains: %f %f %f\n", k_pos_e.k1[2], k_pos_e.k2[2], k_pos_e.k3[2]);
1342 //--INDI Controller gains --------------------------------------------------------------------------------
1343 /*Attitude Loop*/
1344 k_att_e_indi.k1[0] = k_att_e.k1[0];
1345 k_att_e_indi.k2[0] = k_att_e.k2[0];
1346 k_att_e_indi.k3[0] = 1.0;
1347 k_att_e_indi.k1[1] = k_att_e_indi.k1[0];
1348 k_att_e_indi.k2[1] = k_att_e_indi.k2[0];
1349 k_att_e_indi.k3[1] = k_att_e_indi.k3[0];
1350
1351 /*Heading Loop NAV*/
1352 k_att_e_indi.k1[2] = k_att_e.k1[2];
1353 k_att_e_indi.k2[2] = k_att_e.k2[2];
1354 k_att_e_indi.k3[2] = 1.0;
1355
1356 // Print INDI INNERLOOP controller gains
1357 // 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]);
1358 // 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]);
1359
1360 /*Position Loop*/
1361 k_pos_e_indi.k1[0] = k_pos_e.k1[0];
1362 k_pos_e_indi.k2[0] = k_pos_e.k2[0];
1363 k_pos_e_indi.k3[0] = 1.0;
1364 k_pos_e_indi.k1[1] = k_pos_e_indi.k1[0];
1365 k_pos_e_indi.k2[1] = k_pos_e_indi.k2[0];
1366 k_pos_e_indi.k3[1] = k_pos_e_indi.k3[0];
1367
1368 /*Altitude Loop*/
1369 k_pos_e_indi.k1[2] = k_pos_e.k1[2];
1370 k_pos_e_indi.k2[2] = k_pos_e.k2[2];
1371 k_pos_e_indi.k3[2] = 1.0;
1372
1373 // Print INDI OUTERLOOP controller gains
1374 // 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]);
1375 // 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]);
1376
1377 //------------------------------------------------------------------------------------------
1378 /*Approximated Dynamics*/
1381 // printf("Act Dynamics: %f %f\n", act_dynamics[COMMAND_ROLL], act_dynamics[COMMAND_PITCH]);
1382}
1383// -----------------------------------------------------------------------------------------
1384// Filter Functions ------------------------------------------------------------------------
1385// -----------------------------------------------------------------------------------------
1386
1388static inline void init_filter_on_type(struct LP_t *filter, float x0)
1389{
1390 switch (filter->filter_type)
1391 {
1392 case LOWPASS_1:
1393 init_first_order_low_pass(&filter->meas_filt.lp1, filter->tau, 1.0 / PERIODIC_FREQUENCY, x0);
1394 break;
1395 case BUTTERWORTH_2:
1396 init_butterworth_2_low_pass(&filter->meas_filt.bw2, filter->tau, 1.0 / PERIODIC_FREQUENCY, x0);
1397 break;
1398 case BUTTERWORTH_4:
1399 init_butterworth_4_low_pass(&filter->meas_filt.bw4, filter->tau, 1.0 / PERIODIC_FREQUENCY, x0);
1400 break;
1401 case NOTCH:
1402 notch_filter_init(&filter->meas_filt.notch, filter->freq, filter->bandwidth, PERIODIC_FREQUENCY);
1403 break;
1404 default:
1405 // Handle unexpected filter type
1406 break;
1407 }
1408}
1410static inline void update_filter_on_type(struct LP_t *filter, float input)
1411{
1412 // filter->meas_prev = filter->meas;
1413 // filter->meas = input;
1414 switch (filter->filter_type)
1415 {
1416 case LOWPASS_1:
1417 update_first_order_low_pass(&filter->meas_filt.lp1, input);
1418 filter->out = filter->meas_filt.lp1.last_out;
1419 break;
1420 case BUTTERWORTH_2:
1421 update_butterworth_2_low_pass(&filter->meas_filt.bw2, input);
1422 filter->out = filter->meas_filt.bw2.o[0];
1423 break;
1424 case BUTTERWORTH_4:
1425 update_butterworth_4_low_pass(&filter->meas_filt.bw4, input);
1426 filter->out = filter->meas_filt.bw4.lp2.o[0];
1427 break;
1428 case NOTCH:
1429 {
1430 notch_filter_update(&filter->meas_filt.notch, &input, &filter->out);
1431 break;
1432 }
1433 default:
1434 filter->out = 0.0;
1435 break;
1436 // Handle unexpected filter type
1437 }
1438}
1440static inline void init_LP(struct LP_t *LP, float fc)
1441{
1442 LP->freq = fc;
1443 LP->freq_set = fc;
1444 LP->tau = 1 / (2 * M_PI * LP->freq);
1445#ifdef USE_LP1
1446 LP->filter_type = LOWPASS_1;
1447#elif defined(USE_BW2)
1448 LP->filter_type = BUTTERWORTH_2;
1449#elif defined(USE_YAW_LP4)
1450 LP->filter_type = BUTTERWORTH_4;
1451#endif
1452 init_filter_on_type(LP, 0.0);
1453 // init_first_order_low_pass(&LP->meas_filt, LP->tau, 1.0 / PERIODIC_FREQUENCY, 0.0);
1454 LP->meas = 0.0;
1455 LP->meas_prev = 0.0;
1456 LP->out = 0.0;
1457}
1459static inline void reinit_LP_synchronous(struct LP_t *LP, struct LP_t *f, bool reinit)
1460{
1461 if (LP->freq != LP->freq_set || reinit)
1462 {
1463 LP->freq = LP->freq_set;
1464 LP->tau = 1 / (2 * M_PI * LP->freq);
1465 init_filter_on_type(LP, LP->out);
1466 init_filter_on_type(f, f->out);
1467 }
1468}
1469static inline void reinit_LP(struct LP_t *LP, bool reinit)
1470{
1471 if (LP->freq != LP->freq_set || reinit)
1472 {
1473 LP->freq = LP->freq_set;
1474 LP->tau = 1 / (2 * M_PI * LP->freq);
1475 init_filter_on_type(LP, LP->out);
1476 }
1477}
1478
1480static inline void init_all_LP(void)
1481{
1482 init_LP(&LP.ax, 2.0); // oneloop_andi_filt_cutoff_a
1483 init_LP(&LP.ay, 2.0); // oneloop_andi_filt_cutoff_a
1484 init_LP(&LP.az, 2.0); // oneloop_andi_filt_cutoff_a
1485 init_LP(&LP.p_dot, 2.0);
1486 init_LP(&LP.q_dot, 2.0);
1487 init_LP(&LP.r_dot, 2.0);
1488 init_LP(&LP.p, 15.0); // oneloop_andi_filt_cutoff_p
1489 init_LP(&LP.q, 15.0); // oneloop_andi_filt_cutoff_q
1490 init_LP(&LP.r, 15.0); // oneloop_andi_filt_cutoff_r
1491
1492 init_LP(&oneloop_andi_model_filt.ax, 2.0); // oneloop_andi_filt_cutoff_a
1493 init_LP(&oneloop_andi_model_filt.ay, 2.0); // oneloop_andi_filt_cutoff_a
1494 init_LP(&oneloop_andi_model_filt.az, 2.0); // oneloop_andi_filt_cutoff_a
1498}
1499
1513//------------------------------------------------------------------------------------------
1514
1516void init_filter(void)
1517{
1518 // Filtering of the velocities
1519 float tau = 1.0 / (2.0 * M_PI * oneloop_andi_filt_cutoff);
1520 float tau_v = 1.0 / (2.0 * M_PI * oneloop_andi_filt_cutoff_v);
1521 float tau_2 = 1.0 / (2.0 * M_PI * 2.0);
1522 // printf("tau: %f tau_v: %f\n", tau, tau_v);
1523 // printf("initializing filters\n");
1526#ifdef USE_PID_NUMDIFF_DERIVATIVE
1527 for (int i = 0; i < 3; i++){
1529 }
1530#endif
1531 for (int i = 0; i < ANDI_NUM_ACT_TOT; i++)
1532 {
1534 }
1535}
1536
1539{
1540 reinit_all_LP(false);
1543#ifdef USE_ND_VELOCITIES
1544 static bool vel_inited = false;
1545 static struct NedCoor_f veloc_prev;
1546 if (!vel_inited) { veloc_prev = *veloc; vel_inited = true; }
1550 veloc_prev = *veloc;
1551#else
1552 struct NedCoor_f *accel = stateGetAccelNed_f();
1553 LP.ax.meas = accel->x;
1554 LP.ay.meas = accel->y;
1555 LP.az.meas = accel->z;
1556#endif
1557 LP.p.meas_prev = LP.p.meas;
1558 LP.q.meas_prev = LP.q.meas;
1559 LP.r.meas_prev = LP.r.meas;
1560 LP.p.meas = body_rates->p;
1561 LP.q.meas = body_rates->q;
1562 LP.r.meas = body_rates->r;
1566 // Update Filters of Feedbacks
1576 // Propagate filter for sideslip correction
1580 Bound(airspeed_meas, 0.0, 30.0);
1582}
1583//------------------------------------------------------------------------------------------
1586{
1587 //printf("Re-INIT \n");
1588 // store float version of commands
1589 // float commands_float[ANDI_NUM_ACT_TOT];
1590 // for (int i = 0; i < ANDI_NUM_ACT; i++) {
1591 // commands_float[i] = (float)commands[i];
1592 // }
1593 // Actuators
1594 // float_vect_copy(andi_u, commands_float, ANDI_NUM_ACT);
1597
1598 // float_vect_zero(andi_du, ANDI_NUM_ACT_TOT); // Not used
1599 // float_vect_zero(andi_u_n, ANDI_NUM_ACT_TOT); // Not used
1600 // float_vect_copy(actuator_state_1l, commands_float, ANDI_NUM_ACT);
1601 // Stabilization
1609 // Guidance
1614 // Controller Inputs
1615 // float_vect_zero(nu, ANDI_OUTPUTS); // Not used
1616 // float_vect_zero(nu_n, ANDI_OUTPUTS); // Not used
1617 // float_vect_zero(nav_target,3); // Not used
1618 // float_vect_zero(nav_target_new,3); // Not used
1619}
1622{
1623 //printf("INIT \n");
1624 oneloop_andi.half_loop = true;
1626 init_poles();
1627 // Make sure that the dynamics are positive and non-zero
1628 int8_t i;
1629 for (i = 0; i < ANDI_NUM_ACT_TOT; i++)
1630 {
1632 }
1635 // Initialize Effectiveness matrix
1638 for (i = 0; i < ANDI_OUTPUTS; i++)
1639 {
1640 bwls_1l[i] = EFF_MAT_G[i];
1641 }
1642 // Initialize filters and other variables
1643 init_all_LP();
1644 init_filter();
1658 eulers_zxy_des.phi = 0.0;
1659 eulers_zxy_des.theta = 0.0;
1660 eulers_zxy_des.psi = 0.0;
1661// Start telemetry
1662#if PERIODIC_TELEMETRY
1667 // register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_ACTUATOR_STATE, send_oneloop_actuator_state);
1671#endif
1672}
1673
1680void oneloop_andi_enter(bool half_loop_sp, int ctrl_type)
1681{
1682#ifndef ONELOOP_ANDI_SIMPLE_QUAD
1683 ele_min = 0.0;
1684#endif
1686 oneloop_andi.ctrl_type = ctrl_type;
1689 multiple_chirp_run = false;
1690 // if (oneloop_andi.half_loop){
1691 // printf("HALF LOOP\n");
1692 // } else {
1693 // printf("FULL LOOP\n");
1694 // }
1695 // if (oneloop_andi.ctrl_type == CTRL_ANDI){
1696 // printf("ANDI\n");
1697 // } else if (oneloop_andi.ctrl_type == CTRL_INDI){
1698 // printf("INDI\n");
1699 // } else {
1700 // printf("CTRL_TYPE NOT SET\n");
1701 // }
1704 int8_t i;
1705 for (i = 0; i < ANDI_OUTPUTS; i++)
1706 {
1707 bwls_1l[i] = EFF_MAT_G[i];
1708 }
1709 // reinit_all_LP(true); // Not used
1710 // init_filter();
1712 /* Stabilization Reset */
1713 /*Guidance Reset*/
1715}
1716
1724void oneloop_andi_RM(bool half_loop, struct FloatVect3 PSA_des, int rm_order_h, int rm_order_v, bool in_flight_oneloop)
1725{
1726 // Initialize some variables
1727 a_thrust = 0.0;
1728 nav_target[0] = PSA_des.x;
1729 nav_target[1] = PSA_des.y;
1730 nav_target[2] = PSA_des.z;
1731 float thrust_cmd_1l = 0.0;
1732 float des_r = 0.0;
1733 // Generate reference signals with reference model
1734 if (half_loop)
1735 {
1736 // Disregard X and Y jerk objectives
1737 WLS_one_p.Wv[0] = 0.0;
1738 WLS_one_p.Wv[1] = 0.0;
1739 if (drop_yaw)
1740 {
1741 WLS_one_p.Wv[5] = 0.0;
1742 }
1743 else
1744 {
1745 WLS_one_p.Wv[5] = Wv_backup[5];
1746 }
1747 // Overwrite references with actual signals (for consistent plotting)
1752 // Set desired attitude with stick input
1755 // Set desired Yaw rate with stick input
1756 des_r = (float)(radio_control_get(RADIO_YAW)) / MAX_PPRZ * max_r; // Get yaw rate from stick
1757 BoundAbs(des_r, max_r); // Bound yaw rate
1758 float delta_psi_des_rad = des_r * dt_1l; // Integrate desired Yaw rate to get desired change in yaw
1759 float delta_psi_rad = eulers_zxy_des.psi - eulers_zxy.psi; // Calculate current yaw difference between des and actual
1760 NormRadAngle(delta_psi_rad); // Normalize the difference
1761 if (fabs(delta_psi_rad) > RadOfDeg(30.0))
1762 { // If difference is bigger than 10 deg do not further increment desired
1763 delta_psi_des_rad = 0.0;
1764 }
1765 psi_des_rad += delta_psi_des_rad; // Incrementdesired yaw
1767 // Register Attitude Setpoints from previous loop
1768 if (!in_flight_oneloop)
1769 {
1771 }
1774 // Create commands adhoc to get actuators to the wanted level
1777 int8_t i;
1778 // To calculate the nu corrsponding to the Thrust command, plug it in the control law.
1779 for (i = 0; i < ANDI_NUM_ACT; i++)
1780 {
1782 {
1784 }
1785 else
1786 {
1788 }
1789 }
1790 a_thrust = a_thrust - oneloop_andi_model[RW_aD]; // oneloop_andi_model_filt.az.out;
1792 }
1793 else
1794 {
1795 // Make sure X and Y jerk objectives are active
1796 WLS_one_p.Wv[0] = Wv_backup[0];
1797 WLS_one_p.Wv[1] = Wv_backup[1];
1798 // Generate Reference signals for positioning using RM
1799 if (rm_order_h == 3)
1800 {
1802 }
1803 else if (rm_order_h == 2)
1804 {
1807 reshape_wind(); // returns accel sp as nav target new
1809 // rm_2nd_pos(dt_1l, oneloop_andi.gui_ref.vel, oneloop_andi.gui_ref.acc, oneloop_andi.gui_ref.jer, nav_target_new, k_pos_rm.k2, k_pos_rm.k3, max_a_nav, max_j_lin, 2);
1810 }
1811 else if (rm_order_h == 1)
1812 {
1816 }
1817 // Update desired Heading (psi_des_rad) based on previous loop or changed setting
1818 if (heading_manual)
1819 {
1822 {
1824 }
1825 }
1826 else
1827 {
1830 }
1831 // Register Attitude Setpoints from previous loop
1832 if (!in_flight_oneloop)
1833 {
1835 }
1838 // The RM functions want an array as input. Create a single entry array and write the vertical guidance entries.
1839 float single_value_ref[1] = {oneloop_andi.gui_ref.pos[2]};
1843 float single_value_nav_target[1] = {nav_target[2]};
1844 float single_value_k1_rm[1] = {k_pos_rm.k1[2]};
1845 float single_value_k2_rm[1] = {k_pos_rm.k2[2]};
1846 float single_value_k3_rm[1] = {k_pos_rm.k3[2]};
1847 if (rm_order_v == 3)
1848 {
1854 }
1855 else if (rm_order_v == 2)
1856 {
1862 }
1863 else if (rm_order_v == 1)
1864 {
1870 }
1871 // Run chirp test if turnerd on (overwrite the guidance references)
1873 {
1874 multiple_chirp_run = true;
1875 chirp_on = false;
1876 }
1878 {
1880 {
1881 delay_counter++;
1882 int16_t idx_acc = 0;
1883 float trigger_acc = 0.0;
1884 switch (chirp_axis)
1885 {
1886 case 5: // Yaw
1887 idx_acc = 2;
1888 trigger_acc = 5.0;
1889 break;
1890 case 6: // Roll
1891 idx_acc = 0;
1892 trigger_acc = 15.0;
1893 break;
1894 }
1896 {
1898 }
1899 else
1900 {
1901 firing_counter = 0;
1902 }
1903 if (firing_counter >= 250)
1904 {
1906 chirp_on = true;
1907 firing_counter = 0;
1908 delay_counter = 0;
1909 }
1910 }
1911 else
1912 {
1913 multiple_chirp_run = false;
1914 chirp_n_counter = 0;
1915 }
1916 }
1917
1919 // Generate Reference signals for attitude using RM
1920 // FIX ME ow not yet defined, will be useful in the future to have accurate psi tracking in NAV functions
1921 bool ow_psi = false;
1922 if (chirp_on && (chirp_axis == 4 || chirp_axis == 5))
1923 {
1924 ow_psi = true;
1929 att_des[0] = 0.0;
1930 att_des[1] = 0.0;
1931 eulers_zxy_des.phi = 0.0;
1932 eulers_zxy_des.theta = 0.0;
1933 }
1934 bool ow_phi = false;
1935 if (chirp_on && chirp_axis == 6)
1936 {
1937 ow_phi = true;
1942 eulers_zxy_des.theta = 1.7;
1943 }
1945 if (ow_phi)
1946 {
1951 }
1952 }
1953}
1954
1963void oneloop_andi_run(bool in_flight, bool half_loop, struct FloatVect3 PSA_des, int rm_order_h, int rm_order_v)
1964{
1965 //printf("start [phi_des,theta_des]=[%f,%f] \n",DegOfRad(eulers_zxy_des.phi),DegOfRad(eulers_zxy_des.theta));
1966 // 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
1972 int8_t i;
1973 for (i = 0; i < ANDI_OUTPUTS; i++)
1974 {
1975 bwls_1l[i] = EFF_MAT_G[i];
1976 }
1977 for (i = 0; i < ANDI_NUM_ACT_TOT; i++)
1978 {
1979 act_dyn_ctrl[i] = act_dynamics[i];
1980 }
1981
1982 // Need to save and convert desired position for bounding. Not sure NAV always updates this correctly.
1983 float pos_des[3];
1987
1988 // If drone is not on the ground use incremental law
1989 bool in_flight_oneloop = false;
1990 if(in_flight) {
1991 in_flight_oneloop = true;
1992 }
1994 {
1995 in_flight_oneloop = false;
1996 }
1998 // Register the state of the drone in the variables used in RM and EC
1999 // (1) Attitude related
2003 oneloop_andi_propagate_filters(); // needs to be after update of attitude vector
2010 // (2) Position related
2020 // Calculated feedforward signal for yaw control
2021 g2_ff = 0.0;
2022 for (i = 0; i < ANDI_NUM_ACT; i++)
2023 {
2025 {
2026 g2_ff += G2_RW[i] * act_dyn_ctrl[i] * (andi_u[i] - u_filt[i].o[0]);
2027 // printf("i: %d\n", i);
2028 // printf("andi_u: %f\n", andi_u[i]);
2029 // printf("actuator_state_1l: %f\n", actuator_state_1l[i]);
2030 // printf("act_dynamics: %f\n", act_dynamics[i]);
2031 // printf("G2_RW: %f\n", G2_RW[i]);
2032 // printf("g2_ff: %f\n", g2_ff);
2033 }
2034 else if (oneloop_andi.ctrl_type == CTRL_INDI)
2035 {
2036 g2_ff += G2_RW[i] * (andi_u[i] - u_filt[i].o[0]);
2037 }
2038 }
2039 //printf("pre rm [phi_des,theta_des]=[%f,%f] \n",DegOfRad(eulers_zxy_des.phi),DegOfRad(eulers_zxy_des.theta));
2040 // Run the Reference Model (RM)
2042 //printf("post rm [phi_des,theta_des]=[%f,%f] \n",DegOfRad(eulers_zxy_des.phi),DegOfRad(eulers_zxy_des.theta));
2043 // Run Distrubance Bounder
2044 oneloop_andi_bound_disturbance(); // Fixme, can be removed
2045 // Guidance Pseudo Control Vector (nu) based on error controller
2046 if (half_loop)
2047 {
2048 nu[0] = 0.0;
2049 nu[1] = 0.0;
2050 nu[2] = a_thrust;
2051 ctrl_off = false;
2052 }
2053 else
2054 {
2056 {
2057 // float temp_dist_bound_gui[3] = {oneloop_andi_model[0], oneloop_andi_model[1], oneloop_andi_model[2]};
2058 float temp_dist_bound_gui[3] = {0.0, 0.0, 0.0};
2060 }
2061 else if (oneloop_andi.ctrl_type == CTRL_INDI)
2062 {
2063 float dummy1[3] = {0.0, 0.0, 0.0};
2065 // nu[0] = ec_3rd(oneloop_andi.gui_ref.pos[0], oneloop_andi.gui_ref.vel[0], oneloop_andi.gui_ref.acc[0], 0.0, oneloop_andi.gui_state.pos[0], oneloop_andi.gui_state.vel[0], oneloop_andi.gui_state.acc[0], k_pos_e_indi.k1[0], k_pos_e_indi.k2[0], k_pos_e_indi.k3[0]);
2066 // nu[1] = ec_3rd(oneloop_andi.gui_ref.pos[1], oneloop_andi.gui_ref.vel[1], oneloop_andi.gui_ref.acc[1], 0.0, oneloop_andi.gui_state.pos[1], oneloop_andi.gui_state.vel[1], oneloop_andi.gui_state.acc[1], k_pos_e_indi.k1[1], k_pos_e_indi.k2[1], k_pos_e_indi.k3[1]);
2067 // nu[2] = ec_3rd(oneloop_andi.gui_ref.pos[2], oneloop_andi.gui_ref.vel[2], oneloop_andi.gui_ref.acc[2], 0.0, oneloop_andi.gui_state.pos[2], oneloop_andi.gui_state.vel[2], oneloop_andi.gui_state.acc[2], k_pos_e_indi.k1[2], k_pos_e_indi.k2[2], k_pos_e_indi.k3[2]);
2068 }
2069#define USE_PID_OUTERLOOP
2070#ifdef USE_PID_OUTERLOOP
2071 float acc_des[3];
2073 //printf("[%f,%f,%f]\n",acc_des[0],acc_des[1],acc_des[2]);
2074 nu[2] = (acc_des[2]-oneloop_andi.gui_state.acc[2])*k_pos_e.k3[2];
2077 //printf("Right after [phi_des,theta_des]=[%f,%f] \n",DegOfRad(eulers_zxy_des.phi),DegOfRad(eulers_zxy_des.theta));
2078
2079#endif
2080 }
2081 // Attitude Pseudo Control Vector (nu) based on error controller
2082 float y_4d_att[3];
2085 {
2086 // float temp_dist_bound_sta[3] = {oneloop_andi_model_filt.p_dot.out, oneloop_andi_model_filt.q_dot.out, oneloop_andi_model_filt.r_dot.out};
2089 }
2090 else if (oneloop_andi.ctrl_type == CTRL_INDI)
2091 {
2092 float dummy0[3] = {0.0, 0.0, 0.0};
2095 }
2096 if (half_loop && radio_control_get(RADIO_THROTTLE) < 200)
2097 {
2098 nu[3] = 0.0;
2099 nu[4] = 0.0;
2100 nu[5] = 0.0;
2101 }
2102 else
2103 {
2104 nu[3] = y_4d_att[0];
2105 nu[4] = y_4d_att[1];
2106 nu[5] = y_4d_att[2] + g2_ff;
2107 }
2108
2109 // temp restructuring------------------
2110 nu[0] = nu[0] + oneloop_andi_model[RW_aN]; // oneloop_andi_model_filt.ax.out;
2111 nu[1] = nu[1] + oneloop_andi_model[RW_aE]; // oneloop_andi_model_filt.ay.out;
2112 nu[2] = nu[2] + oneloop_andi_model[RW_aD]; // oneloop_andi_model_filt.az.out;
2113 // nu[3] = nu[3] + oneloop_andi_model[3];
2114 // nu[4] = nu[4] + oneloop_andi_model[4];
2115 // nu[5] = nu[5] + oneloop_andi_model[5];
2116 // BoundAbs(nu[5], n_array[5]*coupling_factor[5]); //FIXME UNCOMMENT ME
2117 if (drop_yaw)
2118 {
2119 // nu[0] = oneloop_andi_model_filt.ax.out;
2120 // nu[1] = oneloop_andi_model_filt.ay.out;
2121 // nu[2] = oneloop_andi_model_filt.az.out;
2122 // nu[3] = oneloop_andi_model_filt.p_dot.out*k_att_e.k3[0];
2123 // nu[4] = oneloop_andi_model_filt.q_dot.out*k_att_e.k3[1];
2125 }
2126 if (drop_roll)
2127 {
2129 }
2130 if (drop_pitch)
2131 {
2133 }
2134 if (drop_aN)
2135 {
2137 }
2138 if (drop_aE)
2139 {
2141 }
2142 if (drop_aD)
2143 {
2145 }
2146
2147 //------------------------------------
2148
2149 if (!chirp_on)
2150 {
2154 }
2155 u_pref[COMMAND_PITCH] = 0.0; // pitch_pref; // FIXME
2156 // Calculate the min and max increments
2157 for (i = 0; i < ANDI_NUM_ACT_TOT; i++)
2158 {
2159 // printf("Act_dyn[%d]: %f\n",i,act_dynamics[i]);
2160 switch (i)
2161 {
2164 case COMMAND_MOTOR_BACK:
2165 case COMMAND_MOTOR_LEFT:
2166 {
2167#ifndef ONELOOP_ANDI_SIMPLE_QUAD
2168 float skew_bound = RW.skew.deg;
2169 Bound(skew_bound, 70.0, 90.0);
2170 float Wu_sched = (Wu_quad_motors_fwd - Wu_backup[i]) / (90.0 - 70.0) * (skew_bound - 70) + Wu_backup[i];
2171#else
2172 float Wu_sched = Wu_backup[i];
2173#endif
2174 WLS_one_p.Wu[i] = Wu_sched;
2175 WLS_one_p.u_min[i] = (act_min[i]) / ratio_u_un[i];
2176 WLS_one_p.u_pref[i] = (u_pref[i]) / ratio_u_un[i];
2177 WLS_one_p.u_max[i] = (act_max[i]) / ratio_u_un[i];
2178#ifndef ONELOOP_ANDI_SIMPLE_QUAD
2180 {
2181#else
2182 if (true)
2183 {
2184#endif
2185 WLS_one_p.u_max[i] = (act_max[i]) / ratio_u_un[i];
2186 }
2187 else
2188 {
2189 WLS_one_p.u_max[i] = (0.0) / ratio_u_un[i];
2190 }
2191 break;
2192 }
2193#ifndef ONELOOP_ANDI_SIMPLE_QUAD
2195 case COMMAND_RUDDER:
2196 WLS_one_p.u_min[i] = (act_min[i]) / ratio_u_un[i];
2197 WLS_one_p.u_max[i] = (act_max[i]) / ratio_u_un[i];
2198 WLS_one_p.u_pref[i] = (u_pref[i]) / ratio_u_un[i];
2199 break;
2200 case COMMAND_AILERONS:
2201 if (RW.skew.deg > 25.0)
2202 {
2203 WLS_one_p.u_min[i] = (act_min[i]) / ratio_u_un[i];
2204 WLS_one_p.u_max[i] = (act_max[i]) / ratio_u_un[i];
2205 }
2206 else
2207 {
2208 WLS_one_p.u_min[i] = (0.0) / ratio_u_un[i];
2209 WLS_one_p.u_max[i] = (0.0) / ratio_u_un[i];
2210 }
2211 WLS_one_p.u_pref[i] = (u_pref[i]) / ratio_u_un[i];
2212 break;
2213 case COMMAND_FLAPS:
2214 if (RW.skew.deg > 50.0)
2215 {
2216 WLS_one_p.u_min[i] = (act_min[i]) / ratio_u_un[i];
2217 WLS_one_p.u_max[i] = (act_max[i]) / ratio_u_un[i];
2218 }
2219 else
2220 {
2221 WLS_one_p.u_min[i] = (0.0) / ratio_u_un[i];
2222 WLS_one_p.u_max[i] = (0.0) / ratio_u_un[i];
2223 }
2224 WLS_one_p.u_pref[i] = (u_pref[i]) / ratio_u_un[i];
2225 break;
2226 case COMMAND_ELEVATOR:
2227 WLS_one_p.u_min[i] = (act_min[i]) / ratio_u_un[i];
2228 WLS_one_p.u_max[i] = (act_max[i]) / ratio_u_un[i];
2229 u_pref[i] = RW.ele_pref;
2230 WLS_one_p.u_pref[i] = (u_pref[i]) / ratio_u_un[i];
2231 break;
2232#endif
2233 case COMMAND_ROLL:
2234 WLS_one_p.u_min[i] = (act_min[i]) / ratio_u_un[i];
2235 WLS_one_p.u_max[i] = (act_max[i]) / ratio_u_un[i];
2236 WLS_one_p.u_pref[i] = (u_pref[i]) / ratio_u_un[i];
2237 break;
2238 case COMMAND_PITCH:
2239#ifndef ONELOOP_ANDI_SIMPLE_QUAD
2240 if (RW.skew.deg > 50.0)
2241 {
2242#else
2243 if (false)
2244 {
2245#endif
2246 WLS_one_p.u_min[i] = (RadOfDeg(-17.0)) / ratio_u_un[i];
2247 WLS_one_p.u_max[i] = (RadOfDeg(17.0)) / ratio_u_un[i];
2248 }
2249 else
2250 {
2251 WLS_one_p.u_min[i] = (act_min[i]) / ratio_u_un[i];
2252 WLS_one_p.u_max[i] = (act_max[i]) / ratio_u_un[i];
2253 }
2254 WLS_one_p.u_pref[i] = (u_pref[i]) / ratio_u_un[i];
2255 break;
2256 }
2257 }
2258 //printf("Pre alloc [phi_des,theta_des]=[%f,%f] \n",DegOfRad(eulers_zxy_des.phi),DegOfRad(eulers_zxy_des.theta));
2259 // WLS Control Allocator
2260 normalize_nu();
2261 wls_alloc(&WLS_one_p, bwls_1l, 0, 0, 10);
2262
2263 // Keep the previous command while a doublet runs (only when the sys_id_doublet module is loaded)
2264#ifdef MODULE_SYS_ID_DOUBLET_ID
2266#else
2267 bool doublet_running = false;
2268#endif
2269 if (!doublet_running)
2270 {
2271 for (i = 0; i < ANDI_NUM_ACT_TOT; i++)
2272 {
2273 andi_u_n[i] = WLS_one_p.u[i];
2274 andi_u[i] = (float)(andi_u_n[i] * ratio_u_un[i]);
2275 }
2276 }
2277 else
2278 {
2280 }
2281#ifdef COMMAND_MOTOR_PUSHER
2282 if ((half_loop))
2283 {
2285 }
2286#endif
2287 // Run the dynamics substitution filter
2290 if (use_dyn_filter)
2291 {
2294 }
2295 // TODO : USE THE PROVIDED MAX AND MIN and change limits for phi and theta
2296 // Bound the inputs to the actuators
2297 for (i = 0; i < ANDI_NUM_ACT_TOT; i++)
2298 {
2299 Bound(andi_u[i], act_min[i], act_max[i]);
2300 }
2301 /*Commit the actuator command*/
2302 for (i = 0; i < ANDI_NUM_ACT; i++)
2303 {
2304 commands[i] = (int16_t)andi_u[i];
2305 }
2306#ifndef ONELOOP_ANDI_SIMPLE_QUAD
2308 {
2309 commands[COMMAND_MOTOR_PUSHER] = -9600; // Min(1000,andi_u[COMMAND_MOTOR_PUSHER]);
2310 }
2311#endif
2312 // if (manual_all){
2313 // for(i=0; i<4; i++){
2314 // if (i==chirp_axis){
2315 // commands[i] = radio_control_get(RADIO_THROTTLE);
2316 // }
2317 // commands[i] = 0.0;
2318 // }
2319 //&& radio_control_get(RADIO_THROTTLE)>200
2320 // commands[COMMAND_MOTOR_RIGHT] = 0.0;//radio_control_get(RADIO_THROTTLE);
2321 // commands[COMMAND_MOTOR_LEFT] = 0.0;//radio_control_get(RADIO_THROTTLE);
2322 // commands[COMMAND_MOTOR_FRONT] = 0.0;//radio_control_get(RADIO_THROTTLE);
2323 // commands[COMMAND_MOTOR_BACK] = 0.0;//radio_control_get(RADIO_THROTTLE);
2324 // }
2328#ifndef USE_PID_OUTERLOOP
2329 if (!half_loop)
2330 {
2333 }
2334#endif
2335
2336 if (heading_manual)
2337 {
2339 }
2340
2344 //printf("end run [phi_des,theta_des]=[%f,%f] \n",DegOfRad(eulers_zxy_des.phi),DegOfRad(eulers_zxy_des.theta));
2345}
2346
2349{
2350 int8_t i;
2352 for (i = 0; i < ANDI_NUM_ACT_TOT; i++)
2353 {
2354 if (i < ANDI_NUM_ACT)
2355 {
2359 {
2360 actuator_state_1l[i] = 0.0;
2361 }
2363 }
2364 else
2365 {
2367 }
2368 }
2369}
2370
2371#ifdef ONELOOP_ANDI_CONSTANT_EFFECTIVENESS
2377static void oneloop_andi_constant_eff(void)
2378{
2380 static const float g1_roll[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_G1_ROLL;
2381 static const float g1_pitch[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_G1_PITCH;
2382 static const float g1_yaw[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_G1_YAW;
2383 static const float g2[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_G2;
2385 float sphi = sinf(eul->phi), cphi = cosf(eul->phi);
2386 float stheta = sinf(eul->theta), ctheta = cosf(eul->theta);
2387 float spsi = sinf(eul->psi), cpsi = cosf(eul->psi);
2388 float T = 9.81f; // hover thrust specific force
2389 int i;
2390 for (i = 0; i < ANDI_NUM_ACT; i++) {
2391 float gz = g1_thrust[i] / ANDI_G_SCALING;
2392 G2_RW[i] = g2[i] / ANDI_G_SCALING;
2393 EFF_MAT_RW[RW_aN][i] = (cpsi * stheta + ctheta * sphi * spsi) * gz;
2394 EFF_MAT_RW[RW_aE][i] = (spsi * stheta - cpsi * ctheta * sphi) * gz;
2395 EFF_MAT_RW[RW_aD][i] = (cphi * ctheta) * gz;
2398 EFF_MAT_RW[RW_ar][i] = g1_yaw[i] / ANDI_G_SCALING + G2_RW[i];
2399 }
2400 for (i = ANDI_NUM_ACT; i < ANDI_NUM_ACT_TOT; i++) {
2401 G2_RW[i] = 0.0f;
2402 EFF_MAT_RW[RW_ap][i] = 0.0f;
2403 EFF_MAT_RW[RW_aq][i] = 0.0f;
2404 EFF_MAT_RW[RW_ar][i] = 0.0f;
2405 }
2406 EFF_MAT_RW[RW_aN][COMMAND_ROLL] = -cphi * ctheta * spsi * T;
2407 EFF_MAT_RW[RW_aE][COMMAND_ROLL] = cphi * ctheta * cpsi * T;
2408 EFF_MAT_RW[RW_aD][COMMAND_ROLL] = sphi * ctheta * T;
2409 EFF_MAT_RW[RW_aN][COMMAND_PITCH] = -(ctheta * cpsi - sphi * stheta * spsi) * T;
2410 EFF_MAT_RW[RW_aE][COMMAND_PITCH] = -(ctheta * spsi + sphi * stheta * cpsi) * T;
2411 EFF_MAT_RW[RW_aD][COMMAND_PITCH] = stheta * cphi * T;
2412}
2413#endif
2414
2419void G1G2_oneloop(int ctrl_type)
2420{
2421 int i = 0;
2422 float scaler = 1.0;
2423#ifdef ONELOOP_ANDI_CONSTANT_EFFECTIVENESS
2425#endif
2426 for (i = 0; i < ANDI_NUM_ACT_TOT; i++)
2427 {
2428 // printf("act_dyn_ctrl[%d] = %f\n", i, act_dyn_ctrl[i]);
2429 switch (i)
2430 {
2431 case (COMMAND_MOTOR_FRONT):
2432 case (COMMAND_MOTOR_RIGHT):
2433 case (COMMAND_MOTOR_BACK):
2434 case (COMMAND_MOTOR_LEFT):
2435#ifndef ONELOOP_ANDI_SIMPLE_QUAD
2436 case (COMMAND_MOTOR_PUSHER):
2437 case (COMMAND_ELEVATOR):
2438 case (COMMAND_RUDDER):
2439 case (COMMAND_AILERONS):
2440 case (COMMAND_FLAPS):
2441#endif
2442 if (ctrl_type == CTRL_ANDI)
2443 {
2444 scaler = act_dyn_ctrl[i] * ratio_u_un[i];
2445 }
2446 else if (ctrl_type == CTRL_INDI)
2447 {
2448 scaler = ratio_u_un[i];
2449 }
2450 break;
2451 case (COMMAND_ROLL):
2452 case (COMMAND_PITCH):
2453 if (ctrl_type == CTRL_ANDI)
2454 {
2455 scaler = act_dyn_ctrl[i] * ratio_u_un[i];
2456 }
2457 else if (ctrl_type == CTRL_INDI)
2458 {
2459 scaler = ratio_u_un[i];
2460 }
2461 break;
2462 default:
2463 break;
2464 }
2465 int j = 0;
2466#ifndef ONELOOP_ANDI_SIMPLE_QUAD
2468#else
2469 bool turn_quad_off = false;
2470#endif
2471 for (j = 0; j < ANDI_OUTPUTS; j++)
2472 {
2473 EFF_MAT_G[j][i] = EFF_MAT_RW[j][i] * scaler * ratio_vn_v[j];
2474 if (drop_yaw)
2475 {
2476 EFF_MAT_G[5][i] = 0.0;
2477 }
2478#ifndef ONELOOP_ANDI_SIMPLE_QUAD
2479 if (airspeed_filt.o[0] < ELE_MIN_AS && i == COMMAND_ELEVATOR)
2480 {
2481 EFF_MAT_G[j][i] = 0.0;
2482 }
2483#endif
2484 if (turn_quad_off && i < 4)
2485 {
2486 EFF_MAT_G[j][i] = 0.0;
2487 }
2488 if (ctrl_off && i < 4 && j == 5)
2489 { // hack test
2490 EFF_MAT_G[j][i] = 0.0;
2491 }
2492 if (ctrl_off && i < 4 && j == 4)
2493 { // hack test
2494 EFF_MAT_G[j][i] = 0.0;
2495 }
2496 if (ctrl_off && i < 4 && j == 3)
2497 { // hack test
2498 EFF_MAT_G[j][i] = 0.0;
2499 }
2500 // if (j < 2 && i < 4){
2501 // EFF_MAT_G[j][i] = 0.0;
2502 // }
2503 }
2504 }
2506}
2507
2510{
2511 int8_t i;
2512 for (i = 0; i < ANDI_NUM_ACT_TOT; i++)
2513 {
2514 act_dynamics_d[i] = 1.0 - exp(-act_dynamics[i] * dt_1l);
2515 Bound(act_dynamics_d[i], 0.00001, 1.0);
2516 Bound(act_max[i], 0, MAX_PPRZ);
2517 Bound(act_min[i], -MAX_PPRZ, 0);
2518 float ratio_numerator = act_max[i] - act_min[i];
2519 ratio_numerator = positive_non_zero(ratio_numerator); // make sure numerator is non-zero
2521 ratio_denominator = positive_non_zero(ratio_denominator); // make sure denominator is non-zero
2523 ratio_u_un[i] = positive_non_zero(ratio_u_un[i]); // make sure ratio is not zero
2524 // printf("ratio_u_un[%d]= %f \n",i,ratio_u_un[i]);
2525 }
2526 for (i = 0; i < ANDI_OUTPUTS; i++)
2527 {
2529 float ratio_denominator = 1.0;
2530 switch (i)
2531 {
2532 case (RW_aN):
2533 case (RW_aE):
2534 case (RW_aD):
2537 break;
2538 case (RW_ap):
2541 break;
2542 case (RW_aq):
2545 break;
2546 case (RW_ar):
2549 break;
2550 }
2551 }
2552}
2553
2556{
2557 int8_t i;
2558 for (i = 0; i < ANDI_OUTPUTS; i++)
2559 {
2560 // printf("ratio_vn_v[%d] = %f \n",i,ratio_vn_v[i]);
2561 nu_n[i] = nu[i] * ratio_vn_v[i];
2562 WLS_one_p.v[i] = nu_n[i];
2563 }
2564}
2565
2566
2568void oneloop_from_nav(bool in_flight)
2569{
2570 if (!in_flight)
2571 {
2573 }
2574 struct FloatVect3 PSA_des;
2578 int rm_order_h = 3;
2579 int rm_order_v = 3;
2580 // Oneloop controller wants desired targets and handles reference generation internally
2581 switch (nav.setpoint_mode)
2582 {
2586 rm_order_h = 3;
2587 break;
2591 rm_order_h = 2;
2592 break;
2593 }
2594 switch (nav.vertical_mode)
2595 {
2598 rm_order_v = 3;
2599 break;
2602 rm_order_v = 2;
2603 break;
2604 }
2605 oneloop_andi_run(in_flight, false, PSA_des, rm_order_h, rm_order_v);
2606}
2607
2610{
2611 // printf("Calculating the sideslip correction\n");
2612 // Coordinated turn
2613 // feedforward estimate angular rotation omega = g*tan(phi)/v
2614 float omega = 0.0;
2615 const float max_phi = ONELOOP_ANDI_MAX_BANK; // RadOfDeg(ONELOOP_ANDI_MAX_BANK);
2616 float airspeed_turn = airspeed_filt.o[0];
2617 Bound(airspeed_turn, 1.0f, 30.0f);
2618 // Use the current roll angle to determine the corresponding heading rate of change.
2620 // Prevent flipping
2621 if ((eulers_zxy.theta > 0.0f) && (fabs(eulers_zxy.phi) < eulers_zxy.theta))
2622 {
2623 // printf("Preventing flipping\n");
2625 }
2628// printf("Omega: %f\n", omega);
2629// printf("Coordinated turn roll: %f\n", DegOfRad(coordinated_turn_roll));
2630// printf("phi: %f\n", DegOfRad(eulers_zxy.phi));
2631// printf("Airspeed: %f\n", airspeed_turn);
2632#ifdef FWD_SIDESLIP_GAIN
2633 // Add sideslip correction
2634 omega -= accely_filt.o[0] * fwd_sideslip_gain;
2635// printf("Omega ay: %f\n", omega);
2636#endif
2637 return omega;
2638}
2639
2641static float chirp_pos_p_ref(float delta_t, float f0, float k, float A)
2642{
2643 float p_ref_fun = sinf(delta_t * M_PI * (f0 + k * delta_t) * 2.0);
2644 return (A * p_ref_fun);
2645}
2647static float chirp_pos_v_ref(float delta_t, float f0, float k, float A)
2648{
2649 float v_ref_fun = cosf(delta_t * M_PI * (f0 + k * delta_t) * 2.0) * (M_PI * (f0 + k * delta_t) * 2.0 + k * delta_t * M_PI * 2.0);
2650 return (A * v_ref_fun);
2651}
2653static float chirp_pos_a_ref(float delta_t, float f0, float k, float A)
2654{
2655 float a_ref_fun = -sinf(delta_t * M_PI * (f0 + k * delta_t) * 2.0) * pow((M_PI * (f0 + k * delta_t) * 2.0 + k * delta_t * M_PI * 2.0), 2) + k * M_PI * cosf(delta_t * M_PI * (f0 + k * delta_t) * 2.0) * 4.0;
2656 return (A * a_ref_fun);
2657}
2659static float chirp_pos_j_ref(float delta_t, float f0, float k, float A)
2660{
2661 float j_ref_fun = -cosf(delta_t * M_PI * (f0 + k * delta_t) * 2.0) * pow((M_PI * (f0 + k * delta_t) * 2.0 + k * delta_t * M_PI * 2.0), 3) - k * M_PI * sinf(delta_t * M_PI * (f0 + k * delta_t) * 2.0) * (M_PI * (f0 + k * delta_t) * 2.0 + k * delta_t * M_PI * 2.0) * 1.2e+1;
2662 return (A * j_ref_fun);
2663}
2664
2676void 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[])
2677{
2678 float A_backup = A;
2683 if ((f1 - f0) < -FLT_EPSILON)
2684 {
2685 f1 = f0;
2686 }
2687 // 0 body x, 1 body y, 2 body z, 3 pitch pref, 4 Yaw
2688 if (n > 6)
2689 {
2690 n = 0;
2691 }
2692 if (n < 0)
2693 {
2694 n = 0;
2695 }
2696 // I think there should not be a problem with f1 being equal to f0
2697 float k = (f1 - f0) / t_chirp;
2702
2703 float spsi = sinf(psi);
2704 float cpsi = cosf(psi);
2705 float mult_0 = 0.0;
2706 float mult_1 = 0.0;
2707 float mult_2 = 0.0;
2708 switch (n)
2709 {
2710 case 0:
2711 mult_0 = cpsi;
2712 mult_1 = spsi;
2713 mult_2 = 0.0;
2714
2715 p_ref[0] = p_ref_0[0] + p_ref_chirp * mult_0;
2716 p_ref[1] = p_ref_0[1] + p_ref_chirp * mult_1;
2717 v_ref[0] = v_ref_chirp * mult_0;
2718 v_ref[1] = v_ref_chirp * mult_1;
2719 a_ref[0] = a_ref_chirp * mult_0;
2720 a_ref[1] = a_ref_chirp * mult_1;
2721 j_ref[0] = j_ref_chirp * mult_0;
2722 j_ref[1] = j_ref_chirp * mult_1;
2723 break;
2724 case 1:
2725 mult_0 = -spsi;
2726 mult_1 = cpsi;
2727 mult_2 = 0.0;
2728
2729 p_ref[0] = p_ref_0[0] + p_ref_chirp * mult_0;
2730 p_ref[1] = p_ref_0[1] + p_ref_chirp * mult_1;
2731 v_ref[0] = v_ref_chirp * mult_0;
2732 v_ref[1] = v_ref_chirp * mult_1;
2733 a_ref[0] = a_ref_chirp * mult_0;
2734 a_ref[1] = a_ref_chirp * mult_1;
2735 j_ref[0] = j_ref_chirp * mult_0;
2736 j_ref[1] = j_ref_chirp * mult_1;
2737 break;
2738 case 2:
2739 mult_0 = 0.0;
2740 mult_1 = 0.0;
2741 mult_2 = 1.0;
2742 p_ref[2] = p_ref_0[2] + p_ref_chirp * mult_2;
2743 v_ref[2] = v_ref_chirp * mult_2;
2744 a_ref[2] = a_ref_chirp * mult_2;
2745 j_ref[2] = j_ref_chirp * mult_2;
2746 break;
2747 case 3:
2748 // Pitch preferred chirp
2750 pitch_pref = (pitch_pref / A + 1.0) * (theta_pref_max / 2.0);
2751 float pitch_offset = RadOfDeg(5.0);
2753 Bound(pitch_pref, 0.0, 25.0);
2754 break;
2755 case 4:
2756 // Do a yaw acceleration chirp
2757 oneloop_andi.sta_ref.att[2] = psi_des_rad + p_ref_chirp * M_PI / 180.0; // oneloop_andi.sta_state.att[2];
2759 oneloop_andi.sta_ref.att_d[2] = v_ref_chirp * M_PI / 180.0; // oneloop_andi.sta_state.att_d[2];
2760 oneloop_andi.sta_ref.att_2d[2] = a_ref_chirp * M_PI / 180.0; // p_ref_chirp;
2761 oneloop_andi.sta_ref.att_3d[2] = j_ref_chirp * M_PI / 180.0; // v_ref_chirp;
2762 // Include change in dynamics
2765 break;
2766 case 5:
2769 if (time_elapsed < (t_chirp / 4.0) || (time_elapsed > (3.0 * t_chirp / 4.0)))
2770 {
2771 oneloop_andi.sta_ref.att_2d[2] = 0.0;
2772 }
2773 else
2774 {
2775 oneloop_andi.sta_ref.att_2d[2] = A_backup * M_PI / 180.0;
2776 }
2777 oneloop_andi.sta_ref.att_3d[2] = 0.0;
2778 float S_psi = 0.5 * A_backup * M_PI / 180.0 * t_chirp * t_chirp;
2779 BoundAbs(S_psi, 0.9 * M_PI_2)
2782 // Set the EC to track a 0 acceleration in Z
2785 a_ref[2] = 0.0;
2786 drop_aN = true;
2787 drop_aE = true;
2788
2789 break;
2790 case 6:
2791 // Do a doublet on the roll acceleration
2794 // oneloop_andi.sta_ref.att_2d[0] = (time_elapsed < (t_chirp/2.0)) ? A*M_PI/180.0 : -A*M_PI/180.0;
2795 if (time_elapsed < (0.5))
2796 {
2797 oneloop_andi.sta_ref.att_2d[0] = 0.0;
2798 }
2799 else
2800 {
2801 oneloop_andi.sta_ref.att_2d[0] = -A * M_PI / 180.0;
2802 }
2803 oneloop_andi.sta_ref.att_3d[0] = 0.0;
2804 drop_aN = true;
2805 drop_aE = true;
2806 break;
2807 }
2808}
2809
2810void chirp_call(bool *chirp_on, bool *chirp_first_call, float *t_0, 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[])
2811{
2812 if (*chirp_on)
2813 {
2814 if (*chirp_first_call)
2815 {
2816 *time_elapsed = 0.0;
2817 *chirp_first_call = false;
2819 p_ref_0[0] = p_ref[0];
2820 p_ref_0[1] = p_ref[1];
2821 p_ref_0[2] = p_ref[2];
2822 }
2823 if (*time_elapsed < t_chirp)
2824 {
2827 }
2828 else
2829 {
2830 *chirp_on = false;
2831 *chirp_first_call = true;
2832 *time_elapsed = 0.0;
2833 *t_0 = 0.0;
2834 p_ref_0[0] = p_ref[0];
2835 p_ref_0[1] = p_ref[1];
2836 p_ref_0[2] = p_ref[2];
2840 drop_yaw = false;
2841 drop_roll = false;
2842 drop_pitch = false;
2843 drop_aN = false;
2844 drop_aE = false;
2845 drop_aD = false;
2846 // oneloop_andi_enter(false, oneloop_andi.ctrl_type);
2847 }
2848 }
2849}
2850
2853{
2854 return !motors_on;
2855}
2856
2858{
2859 float psi = eulers_zxy.psi;
2860 float cpsi = cosf(psi);
2861 float spsi = sinf(psi);
2862 float airspeed = airspeed_filt.o[0];
2863 struct FloatVect2 NT_v_NE = {nav_target[0], nav_target[1]}; // Nav target in North and East frame
2864 struct FloatVect2 airspeed_v = {cpsi * airspeed, spsi * airspeed};
2865 struct FloatVect2 windspeed;
2867 struct FloatVect2 des_as_NE;
2868 struct FloatVect2 des_as_B;
2869 struct FloatVect2 des_acc_B;
2870 VECT2_DIFF(windspeed, groundspeed, airspeed_v); // Wind speed in North and East frame
2871 VECT2_DIFF(des_as_NE, NT_v_NE, windspeed); // Desired airspeed in North and East frame
2874 // Check if some minimum airspeed is desired (e.g. to prevent stall)
2875 if (norm_des_as < min_as)
2876 {
2878 }
2879 nav_target_new[0] = NT_v_NE.x;
2880 nav_target_new[1] = NT_v_NE.y;
2881 // 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
2882 if ((norm_des_as > max_as) || (force_forward))
2883 {
2884 float groundspeed_factor = 0.0f;
2886 {
2887 float av = NT_v_NE.x * NT_v_NE.x + NT_v_NE.y * NT_v_NE.y; // norm squared of nav target
2888 float bv = -2.f * (windspeed.x * NT_v_NE.x + windspeed.y * NT_v_NE.y);
2889 float cv = windspeed.x * windspeed.x + windspeed.y * windspeed.y - max_as * max_as;
2890 float dv = bv * bv - 4.0f * av * cv;
2891 // dv can only be positive, but just in case
2892 if (dv < 0.0f)
2893 {
2894 dv = fabsf(dv);
2895 }
2896 float d_sqrt = sqrtf(dv);
2897 groundspeed_factor = (-bv + d_sqrt) / (2.0f * av);
2898 }
2904 }
2905 des_as_B.x = norm_des_as; // Desired airspeed in body x frame
2906 des_as_B.y = 0.0; // Desired airspeed in body y frame
2908 {
2909 float delta_psi = atan2f(des_as_NE.y, des_as_NE.x) - psi;
2911 des_acc_B.y = delta_psi * 5.0; // gih_params.heading_bank_gain;
2912 des_acc_B.x = (des_as_B.x - airspeed) * k_pos_rm.k2[0]; // gih_params.speed_gain;
2913 acc_body_bound(&des_acc_B, max_a_nav); // Scale down side acceleration if norm is too large
2914 nav_target_new[0] = cpsi * des_acc_B.x - spsi * des_acc_B.y;
2915 nav_target_new[1] = spsi * des_acc_B.x + cpsi * des_acc_B.y;
2916 }
2917 else
2918 {
2919 nav_target_new[0] = (NT_v_NE.x - groundspeed.x) * k_pos_rm.k2[0];
2920 nav_target_new[1] = (NT_v_NE.y - groundspeed.y) * k_pos_rm.k2[1];
2921 }
2923}
2924
2925void guidance_set_min_max_airspeed(float min_airspeed, float max_airspeed)
2926{
2927 min_as = min_airspeed;
2929}
2930
2932{
2933 // Reset the effectiveness matrix
2934 memset(n_array, 0, sizeof(n_array));
2936 memset(m_array, 0, sizeof(m_array));
2937 float u_trim[ANDI_NUM_ACT_TOT];
2938 u_trim[COMMAND_MOTOR_FRONT] = 4800.0;
2939 u_trim[COMMAND_MOTOR_RIGHT] = 4800.0;
2940 u_trim[COMMAND_MOTOR_BACK] = 4800.0;
2941 u_trim[COMMAND_MOTOR_LEFT] = 4800.0;
2942#ifndef ONELOOP_ANDI_SIMPLE_QUAD
2945 u_trim[COMMAND_RUDDER] = 0.0;
2946 u_trim[COMMAND_AILERONS] = 0.0;
2947 u_trim[COMMAND_FLAPS] = 0.0;
2948#endif
2949 u_trim[COMMAND_ROLL] = 0.0;
2950 u_trim[COMMAND_PITCH] = 0.0;
2951
2952 for (int i = 0; i < ANDI_OUTPUTS; i++)
2953 {
2954 for (int j = 0; j < ANDI_NUM_ACT_TOT; j++)
2955 {
2956 float eff = positive_non_zero(fabsf(EFF_MAT_G[i][j]));
2958 float u_range = MAX_PPRZ - u_trim[j];
2959 eff = (eff / den) * u_range;
2960 n_array[i] += eff;
2961 m_array[j] += eff;
2962 }
2963 }
2964 for (int i = 0; i < ANDI_OUTPUTS; i++)
2965 {
2966 for (int j = 0; j < ANDI_NUM_ACT_TOT; j++)
2967 {
2968 float eff = positive_non_zero(fabsf(EFF_MAT_G[i][j]));
2970 float u_range = MAX_PPRZ - u_trim[j];
2971 eff = (eff / den) * u_range;
2972 float eff2 = eff * eff;
2973 coupling_factor[i] += eff2 / (n_array[i] * m_array[j]);
2974 }
2975 }
2976 Bound(coupling_factor[5], 0.2, 0.8);
2977 // printf("Coupling factor: %f %f %f %f %f %f \n", coupling_factor[0], coupling_factor[1], coupling_factor[2], coupling_factor[3], coupling_factor[4], coupling_factor[5]);
2978 // printf("Axis effectiven: %f %f %f %f %f %f \n", n_array[0], n_array[1], n_array[2], n_array[3], n_array[4], n_array[5]);
2979}
2980
2982{
2983 int8_t i;
2984 int8_t j;
2985 for (i = 0; i < ANDI_NUM_ACT_TOT; i++)
2986 {
2987 if (i < ANDI_NUM_ACT)
2988 {
2990 }
2991 else
2992 {
2994 }
2995 }
2996 // Store the distrubance
2997 float k3;
2998 if (in_flight)
2999 {
3000 for (i = 0; i < ANDI_OUTPUTS; i++)
3001 { // For loop for prediction of acceleration
3002 oneloop_andi_model[i] = 0.0;
3003 switch (i)
3004 {
3005 case (RW_aN):
3006 k3 = 1.0; // k_pos_e.k3[0];
3007 break;
3008 case (RW_aE):
3009 k3 = 1.0; // k_pos_e.k3[1];
3010 break;
3011 case (RW_aD):
3012 k3 = 1.0; // k_pos_e.k3[2];
3013 break;
3014 case (RW_ap):
3015 k3 = k_att_e.k3[0];
3016 break;
3017 case (RW_aq):
3018 k3 = k_att_e.k3[1];
3019 break;
3020 case (RW_ar):
3021 k3 = k_att_e.k3[2];
3022 break;
3023 }
3024 k3 = positive_non_zero(k3);
3025 if (i == RW_aN)
3026 {
3027 // printf("start oneloop_andi_model : %f \n",oneloop_andi_model[i]);
3028 }
3029 for (j = 0; j < ANDI_NUM_ACT_TOT; j++)
3030 {
3032 float num = u_filt[j].o[0] * EFF_MAT_G[i][j];
3033 oneloop_andi_model[i] += num / den;
3034 }
3036 }
3043 }
3044 else
3045 {
3047 }
3048}
3050{
3052 BoundAbs(oneloop_andi_dist_bound[RW_aN], 99999.f); // Large value to not bound
3054 BoundAbs(oneloop_andi_dist_bound[RW_aE], 99999.f); // Large value to not bound
3056 BoundAbs(oneloop_andi_dist_bound[RW_aD], 99999.f); // Large value to not bound
3058 BoundAbs(oneloop_andi_dist_bound[RW_ap], 99999.f); // Large value to not bound
3060 BoundAbs(oneloop_andi_dist_bound[RW_aq], 99999.f); // Large value to not bound
3062 BoundAbs(oneloop_andi_dist_bound[RW_ar], 99999.f); // Large value to not bound
3063 // BoundAbs(oneloop_andi_dist_bound[RW_ar], oneloop_andi_yaw_dist_limit); // Bound from INDI controller
3064}
3065
3066// void dynFilter_run(struct Oneloop_DynFilt_t *mu, float u_c, float sigma){
3067// mu->mu_c_0 = mu->mu_c;
3068// mu->u_c_0 = mu->u_c;
3069// mu->u_c = u_c;
3070// mu->sigma = sigma;
3071// float c_den = (mu->fs+mu->sigma)*mu->varepsilon;
3072// float c_u_c = (mu->fs*mu->sigma+mu->varepsilon*mu->sigma)/c_den;
3073// float c_u_c_0 = (-mu->fs*mu->sigma)/c_den;
3074// float c_mu_c_0 = (mu->fs*mu->varepsilon)/c_den;
3075// mu->mu_c = c_u_c * mu->u_c + c_u_c_0 * mu->u_c_0 + c_mu_c_0 * mu->mu_c_0;
3076// }
3077void dynFilter_run(struct Oneloop_DynFilt_t *mu, float u_c, float sigma)
3078{
3079 mu->mu_c_0 = mu->mu_c;
3080 mu->u_c_0 = mu->u_c;
3081 mu->u_c = u_c;
3082 mu->sigma = sigma;
3083
3084 // Calculate ZOH-based coefficients
3085 float exp_term = expf(-mu->sigma / mu->fs); // Use expf for float precision
3086 float c_u_c = mu->sigma / mu->varepsilon;
3087 float c_u_c_0 = (-mu->sigma + mu->varepsilon - mu->varepsilon * exp_term) / mu->varepsilon;
3088 float c_mu_c_0 = exp_term;
3089
3090 mu->mu_c = c_u_c * mu->u_c + c_u_c_0 * mu->u_c_0 + c_mu_c_0 * mu->mu_c_0;
3091}
3092
3093void dynFilter_init(struct Oneloop_DynFilt_t *mu, float varepsilon, float sigma)
3094{
3096 mu->varepsilon = varepsilon;
3097 mu->sigma = sigma;
3098 mu->mu_c = 0.0;
3099 mu->u_c = 0.0;
3100 mu->mu_c_0 = 0.0;
3101 mu->u_c_0 = 0.0;
3102 // printf("DynFilter initialized with varepsilon: %f, sigma: %f, fs: %f\n", mu->varepsilon, mu->sigma, mu->fs);
3103}
3104
3109{
3110 (void)max_bank;
3111}
3112
3118
Main include for ABI (AirBorneInterface).
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
#define UNUSED(x)
Hardware independent code for commands handling.
static struct uart_periph * dev
float G2_RW[EFF_MAT_COLS_NB]
float ele_min
struct RW_Model RW
float EFF_MAT_RW[EFF_MAT_ROWS_NB][EFF_MAT_COLS_NB]
#define RW_aN
#define RW_aE
#define RW_ap
#define RW_ar
#define COMMAND_PITCH
#define COMMAND_ROLL
#define RW_aq
#define RW_aD
struct RW_skew skew
#define ELE_MIN_AS
#define Min(x, y)
Definition esc_dshot.c:110
float phi
in radians
float theta
in radians
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
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
angular rates
#define VECT2_DIFF(_c, _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 FloatEulers * stateGetNedToBodyEulersZxy_f(void)
Get vehicle body attitude ZXY euler angles (float).
Definition state.h:1320
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
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
#define false
Definition microrl.h:7
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.
static float w_approx(float p1, float p2, float p3, float rm_k)
Third Order to First Order Dynamics Approximation.
#define ONELOOP_ANDI_MAX_THETA
void init_poles(void)
Initialize Position of Poles.
struct PolePlacement p_pos_e
bool use_dyn_filter
float k2_NE_tune
float max_j_lin
float k_D
static float Wv_backup[ANDI_OUTPUTS]
static void reinit_LP(struct LP_t *LP, bool reinit)
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 Butterworth2LowPass accely_filt
float act_dynamics[ANDI_NUM_ACT_TOT]
float ratio_u_un[ANDI_NUM_ACT_TOT]
bool drop_pitch
static float Wu_backup[ANDI_NUM_ACT_TOT]
void init_filter(void)
Initialize the filters.
void reinit_controller(void)
Re-Init function of controller variables.
struct PolePlacement p_head_rm
void oneloop_andi_RM(bool half_loop, struct FloatVect3 PSA_des, int rm_order_h, int rm_order_v, bool in_flight_oneloop)
Function to generate the reference signals for the oneloop controller.
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.
void oneloop_andi_enter(bool half_loop_sp, int ctrl_type)
Function that resets important values upon engaging Oneloop ANDI.
static Butterworth2LowPass airspeed_filt
static Butterworth2LowPass filt_veloc[3]
static void eul_of_acc(float a[3], float psi)
float n_array[ANDI_OUTPUTS]
bool drop_aE
static void init_all_LP(void)
Initialize all Low Pass Filters.
float act_max_norm[ANDI_NUM_ACT_TOT]
struct WLS_t WLS_one_p
struct Gains3rdOrder k_att_rm
float max_a_nav
void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3])
Attitude Euler to Rates Conversion Function ZYX.
float oneloop_andi_filt_cutoff_v
void oneloop_andi_bound_disturbance(void)
float k_I
static Butterworth2LowPass u_filt[ANDI_NUM_ACT_TOT]
float act_dyn_ctrl[ANDI_NUM_ACT_TOT]
struct FloatEulers eulers_zxy_des
float p_ref_0[3]
struct PolePlacement p_att_rm
static float k_rm_3_3_f(float omega_n, float zeta, float p1)
struct Oneloop_DynFilt_t mu_mR
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
struct Gains3rdOrder k_att_e
float psi_des_rad
float EFF_MAT_G[ANDI_OUTPUTS][ANDI_NUM_ACT_TOT]
void rm_1st_pos(float dt, float x_2d_ref[], float x_3d_ref[], float x_2d_des[], float k3_rm[], float x_3d_bound, int n)
Reference Model Definition for 3rd order system specific to positioning with bounds.
void oneloop_andi_propagate_filters(void)
Propagate the filters.
float min_as
void guidance_set_max_climb_speed(float max_climb_speed_quad, float max_climb_speed_fwd)
bool ctrl_off
struct Gains3rdOrder k_pos_e
float nu[ANDI_OUTPUTS]
float nu_norm_max
float temp_P_error[3]
bool actuator_is_servo[ANDI_NUM_ACT_TOT]
void float_vect_diff_euler(float err[3], float a[3], float b[3])
Calculate Error between two 3D euler arrays with the psi normalized.
float oneloop_andi_sideslip(void)
Function to calculate corrections for sideslip.
float num_thrusters_oneloop
float ec_headroom
static float act_dynamics_d[ANDI_NUM_ACT_TOT]
float t_chirp
static float andi_u_n[ANDI_NUM_ACT_TOT]
float act_min_norm[ANDI_NUM_ACT_TOT]
#define ONELOOP_ANDI_DEBUG_MODE
float oneloop_andi_filt_cutoff_q
void dynFilter_init(struct Oneloop_DynFilt_t *mu, float varepsilon, float sigma)
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
float oneloop_andi_filt_cutoff_a
static float pitch_pref
static float g2_ff
float k_P
void oneloop_axis_effectiveness_calc(void)
static void send_wls_u_oneloop(struct transport_tx *trans, struct link_device *dev)
int16_t firing_counter
float f0_chirp
static float chirp_pos_j_ref(float delta_t, float f0, float k, float A)
Function to calculate the jerk reference during the chirp.
#define ONELOOP_ANDI_MAX_PHI
float oneloop_andi_sigma_min
void oneloop_from_nav(bool in_flight)
Function that maps navigation inputs to the oneloop controller for the generated autopilot.
float bound_v_from_a(float e_x, float v_bound, float a_bound)
Calculate velocity limit based on acceleration limit for a float From SUVAT we have that v^2 = u^2 + ...
struct PolePlacement p_alt_rm
void init_controller_gains(void)
Initialize Controller Gains FIXME: Calculate the gains dynamically for transition.
static void reinit_all_LP(bool reinit)
Reinitialize all the Low Pass Filters.
float oneloop_andi_sigma_max
static float positive_non_zero(float input)
Function to make sure that inputs are positive non zero vaues.
float oneloop_andi_sigma
bool chirp_on
static void send_eff_mat_stab_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
float oneloop_andi_yaw_dist_limit
void guidance_set_min_max_airspeed(float min_airspeed, float max_airspeed)
float andi_u[ANDI_NUM_ACT_TOT]
static float psi_vec[4]
void calc_normalization(void)
Calculate Normalization of actuators and discrete actuator dynamics
float fwd_sideslip_gain
struct Gains3rdOrder k_pos_e_indi
float f1_chirp
void oneloop_andi_run(bool in_flight, bool half_loop, struct FloatVect3 PSA_des, int rm_order_h, int rm_order_v)
Main function that runs the controller and performs control allocation.
float temp_I_error[3]
struct PolePlacement p_att_e
static void send_eff_mat_guid_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
static void debug_vect(struct transport_tx *trans, struct link_device *dev, char *name, float *data, int datasize)
struct PolePlacement p_alt_e
float bound_v_from_a_vect(float e_x[], float v_bound, float a_bound, int n)
Calculate velocity limit based on acceleration limit for a vector From SUVAT we have that v^2 = u^2 +...
void rm_2nd_pos(float dt, float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x_d_des[], float k2_rm[], float k3_rm[], float x_2d_bound, float x_3d_bound, int n)
Reference Model Definition for 3rd order system specific to positioning with bounds.
void reshape_wind(void)
static float g
void get_act_state_oneloop(void)
Function to reconstruct actuator state using first order dynamics.
float A_chirp
static float phi_vec[4]
struct PolePlacement p_roll_e
void ec_3rd_pos(float y_4d[], float x_des[], float x_ref[], float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x[], float x_d[], float x_2d[], float k1_e[], float k2_e[], float k3_e[], float x_d_bound, float x_2d_bound, float fb[], int n)
Error Controller Definition for 3rd order system.
struct PolePlacement p_head_e
float xdot_lim_sf
int8_t chirp_axis
static float chirp_pos_p_ref(float delta_t, float f0, float k, float A)
Function to calculate the position reference during the chirp.
struct Oneloop_LP_t oneloop_andi_model_filt
static void init_LP(struct LP_t *LP, float fc)
Initialize the Low Pass Filter Struct.
int16_t chirp_n_repeat
float andi_du[ANDI_NUM_ACT_TOT]
float max_v_nav_v
float max_v_nav
bool heading_manual
bool drop_roll
static float chirp_pos_v_ref(float delta_t, float f0, float k, float A)
Function to calculate the velocity reference during the chirp.
float t_0_chirp
float time_elapsed_chirp
static void send_wls_v_oneloop(struct transport_tx *trans, struct link_device *dev)
static float nav_target[3]
void err_nd(float err[], float a[], float b[], float k[], int n)
Calculate Scaled Error between two 3D arrays.
float k1_NE_tune
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])
#define ONELOOP_ANDI_AIRSPEED_SWITCH_THRESHOLD
float oneloop_andi_dist_bound[ANDI_OUTPUTS]
void dynFilter_run(struct Oneloop_DynFilt_t *mu, float u_c, float sigma)
static void init_filter_on_type(struct LP_t *filter, float x0)
Initialize a filter based on its type.
struct OneloopGeneral oneloop_andi
struct Gains3rdOrder k_pos_rm
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)
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.
float oneloop_andi_model[ANDI_OUTPUTS]
float m_array[ANDI_NUM_ACT_TOT]
float Wu_quad_motors_fwd
bool drop_aD
void chirp_call(bool *chirp_on, bool *chirp_first_call, float *t_0_chirp, float *time_elapsed, float f0, float f1, float t_chirp, float A, int8_t n, float psi, float p_ref[], float v_ref[], float a_ref[], float j_ref[], float p_ref_0[])
void G1G2_oneloop(int ctrl_type)
Function that samples and scales the effectiveness matrix FIXME: make this function into a for loop t...
static void send_guidance_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
float theta_pref_max
float act_max[ANDI_NUM_ACT_TOT]
bool chirp_first_call
void normalize_nu(void)
Function to normalize the pseudo control vector.
float psi_des_deg
void rm_3rd_pos(float dt, float x_ref[], float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x_des[], float k1_rm[], float k2_rm[], float k3_rm[], float x_d_bound, float x_2d_bound, float x_3d_bound, int n)
Reference Model Definition for 3rd order system specific to positioning with bounds.
struct FloatEulers eulers_zxy
void oneloop_andi_init(void)
Init function of Oneloop ANDI controller
void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3])
Attitude Rates to Euler Conversion Function ZYX.
float oneloop_andi_filt_cutoff_p
static float k_rm_1_3_f(float omega_n, float zeta, float p1)
Reference Model Gain Design.
float gi_unbounded_airspeed_sp
struct OneloopStabilizationRef sta_bounds
float oneloop_andi_filt_cutoff_r
int16_t delay_counter
struct PolePlacement p_pos_rm
float ratio_vn_v[ANDI_OUTPUTS]
float nu_n[ANDI_OUTPUTS]
bool drop_aN
static float chirp_pos_a_ref(float delta_t, float f0, float k, float A)
Function to calculate the acceleration reference during the chirp.
#define ONELOOP_ANDI_MAX_BANK
bool yaw_stick_in_auto
float actuator_state_1l[ANDI_NUM_ACT_TOT]
void vect_bound_nd(float vect[], float bound, int n)
Scale a 3D array to within a 3D bound.
void err_sum_nd(float err[], float a[], float b[], float k[], float c[], int n)
Calculate Scaled Error between two 3D arrays.
float temp_D_error[3]
PRINT_CONFIG_VAR(ONELOOP_ANDI_FILT_CUTOFF)
void integrate_nd(float dt, float a[], float a_dot[], int n)
Integrate in time 3D array.
static float dt_1l
static void send_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
struct Gains3rdOrder k_att_e_indi
static void send_oneloop_debug(struct transport_tx *trans, struct link_device *dev)
float act_min[ANDI_NUM_ACT_TOT]
bool multiple_chirp_run
static float a_thrust
float max_r
struct Oneloop_LP_t LP
struct Oneloop_DynFilt_t mu_mL
int16_t chirp_n_counter
void acc_body_bound(struct FloatVect2 *vect, float bound)
Scale a 3D array to within a 3D bound.
float * bwls_1l[ANDI_OUTPUTS]
static float k_rm_2_3_f(float omega_n, float zeta, float p1)
static float nav_target_new[3]
void ec_3rd_att(float y_4d[3], float x_des[3], float x_ref[3], float x_d_ref[3], float x_2d_ref[3], float x_3d_ref[3], float x[3], float x_d[3], float x_2d[3], float k1_e[3], float k2_e[3], float k3_e[3], struct OneloopStabilizationRef bounds, float fb[3])
Error Controller Definition for 3rd order system specific to attitude.
static float u_pref[ANDI_NUM_ACT_TOT]
static void shape_vector(float a[3])
float oneloop_andi_filt_cutoff
float coupling_factor[ANDI_OUTPUTS]
#define CTRL_INDI
#define ANDI_NUM_ACT
#define ANDI_G_SCALING
#define CTRL_ANDI
Control types.
@ BUTTERWORTH_2
@ BUTTERWORTH_4
@ LOWPASS_1
@ NOTCH
#define ANDI_NUM_ACT_TOT
#define ANDI_OUTPUTS
float max_bank
Definition oneloop_nB.c:264
float slow_pole
Definition oneloop_nB.c:672
float max_phi
Definition oneloop_nB.c:270
struct OneloopGuidanceState gui_state
struct OneloopStabilizationState sta_state
union LP_t::@275 meas_filt
float meas
float bandwidth
float meas_prev
float tau
struct OneloopGuidanceRef gui_ref
struct LP_t ax
struct OneloopStabilizationRef sta_ref
float freq
struct LP_t r_dot
struct LP_t p_dot
struct LP_t p
float out
struct LP_t az
struct LP_t q
enum FilterType filter_type
struct LP_t ay
struct LP_t q_dot
struct LP_t r
#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
bool rotwing_state_hover_motors_running(void)
struct rotwing_state_t rotwing_state
enum rotwing_states_t state
@ ROTWING_STATE_FORCE_HOVER
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)
float g2[INDI_NUM_ACT]
API to get/set the generic vehicle states.
uint8_t sys_id_doublet_running(void)
static float get_sys_time_float(void)
Get the time in seconds since startup.
Definition sys_time.h:174
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 const float scale[]
short int16_t
Typedef defining 16 bit short 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
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