Paparazzi UAS v7.0_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
26
32
45
78/* Include necessary header files */
81#include "state.h"
82#include "generated/airframe.h"
85#include "modules/core/abi.h"
88#include "math/wls/wls_alloc.h"
94#include <stdio.h>
95#if INS_EXT_POSE
97#endif
98
99#include "modules/gps/gps.h" // DELETE FIX
100//#include "nps/nps_fdm.h"
101
102// Number of real actuators (e.g. motors, servos)
103#ifndef ONELOOP_ANDI_NUM_THRUSTERS
104float num_thrusters_oneloop = 4.0; // Number of motors used for thrust
105#else
107#endif
108
109#ifndef ONELOOP_ANDI_SCHEDULING
110#define ONELOOP_ANDI_SCHEDULING FALSE
111#endif
112
113#ifdef ONELOOP_ANDI_FILT_CUTOFF
115#else
117#endif
118
119#ifdef ONELOOP_ANDI_FILT_CUTOFF_ACC
121#else
123#endif
124
125#ifdef ONELOOP_ANDI_FILT_CUTOFF_VEL
127#else
129#endif
131#ifdef ONELOOP_ANDI_FILT_CUTOFF_POS
133#else
135#endif
136
137#ifdef ONELOOP_ANDI_FILT_CUTOFF_P
138#define ONELOOP_ANDI_FILTER_ROLL_RATE TRUE
140#else
142#endif
143
144#ifdef ONELOOP_ANDI_FILT_CUTOFF_Q
145#define ONELOOP_ANDI_FILTER_PITCH_RATE TRUE
147#else
149#endif
150
151#ifdef ONELOOP_ANDI_FILT_CUTOFF_R
152#define ONELOOP_ANDI_FILTER_YAW_RATE TRUE
154#else
156#endif
157
162#ifndef MAX_R
163float max_r = RadOfDeg(120.0);
164#else
165float max_r = RadOfDeg(MAX_R);
166#endif
167
168#ifdef ONELOOP_ANDI_ACT_IS_SERVO
170#else
172#endif
173
174#ifdef ONELOOP_ANDI_ACT_DYN
176#else
177#error "You must specify the actuator dynamics"
179#endif
180
181#ifdef ONELOOP_ANDI_ACT_MAX
183#else
185#endif
186
187#ifdef ONELOOP_ANDI_ACT_MIN
189#else
190float act_min[ANDI_NUM_ACT_TOT] = = {0.0};
191#endif
192
193#ifdef ONELOOP_ANDI_ACT_MAX_NORM
195#else
197#endif
198
199#ifdef ONELOOP_ANDI_ACT_MIN_NORM
201#else
203#endif
204
205#ifdef ONELOOP_ANDI_NU_NORM_MAX
207#else
208float nu_norm_max = 1.0;
209#endif
210
211#ifdef ONELOOP_ANDI_U_PREF
213#else
214static float u_pref[ANDI_NUM_ACT_TOT] = {0.0};
215#endif
216
217#ifndef ONELOOP_ANDI_DEBUG_MODE
218#define ONELOOP_ANDI_DEBUG_MODE FALSE
219#endif
220
221// Assume phi and theta are the first actuators after the real ones unless otherwise specified
222#define ONELOOP_ANDI_MAX_BANK act_max[COMMAND_ROLL] // assuming abs of max and min is the same
223#define ONELOOP_ANDI_MAX_PHI act_max[COMMAND_ROLL] // assuming abs of max and min is the same
224
225#define ONELOOP_ANDI_MAX_THETA act_max[COMMAND_PITCH] // assuming abs of max and min is the same
226
227#ifndef ONELOOP_THETA_PREF_MAX
229#else
231#endif
232
233#if ANDI_NUM_ACT_TOT != WLS_N_U_MAX
234#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
235#define WLS_N_U_MAX == ANDI_NUM_ACT_TOT
236#endif
237#if ANDI_OUTPUTS != WLS_N_V_MAX
238#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
239#define WLS_N_V_MAX == ANDI_OUTPUTS
240#endif
241
242#ifndef ONELOOP_ANDI_AIRSPEED_SWITCH_THRESHOLD
243#define ONELOOP_ANDI_AIRSPEED_SWITCH_THRESHOLD 10.0
244#endif
245
246/* Declaration of Navigation Variables*/
247#ifdef NAV_HYBRID_MAX_DECELERATION
249#else
250float max_a_nav = 4.0; // (35[N]/6.5[Kg]) = 5.38[m/s2] [0.8 SF]
251#endif
252
253#ifdef ONELOOP_MAX_JERK
255#else
256float max_j_nav = 500.0; // Pusher Test shows erros above 2[Hz] ramp commands [0.6 SF]
257#endif
258
259#ifdef ONELOOP_MAX_ANGULAR_JERK
261#else
262float max_j_ang = 1000.0;
263#endif
264
265#ifdef NAV_HYBRID_MAX_AIRSPEED
266float max_v_nav = NAV_HYBRID_MAX_AIRSPEED; // Consider implications of difference Ground speed and airspeed
267#else
268float max_v_nav = 5.0;
269#endif
270float max_as = 19.0f;
271float min_as = 0.0f;
272
273#ifdef NAV_HYBRID_MAX_SPEED_V
275#else
276float max_v_nav_v = 1.5;
277#endif
278
279#ifndef FWD_SIDESLIP_GAIN
281#else
283#endif
284
285#ifndef ONELOOP_ANDI_WU_QUAD_MOTORS_FWD
287#else
289#endif
290
291
292/* Define Section of the functions used in this module*/
293void init_poles(void);
294void init_poles_att(void);
295void init_poles_pos(void);
296void calc_normalization(void);
297void normalize_nu(void);
298void G1G2_oneloop(int ctrl_type);
299void get_act_state_oneloop(void);
301void init_filter(void);
302void init_controller(void);
303void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3]);
304void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3]);
305void err_nd(float err[], float a[], float b[], float k[], int n);
306void err_sum_nd(float err[], float a[], float b[], float k[], float c[], int n);
307void integrate_nd(float dt, float a[], float a_dot[], int n);
308void vect_bound_nd(float vect[], float bound, int n);
309void acc_body_bound(struct FloatVect2* vect, float bound);
310float bound_v_from_a(float e_x[], float v_bound, float a_bound, int n);
311void rm_2nd(float dt, float* x_ref, float* x_d_ref, float* x_2d_ref, float x_des, float k1_rm, float k2_rm);
312void rm_3rd(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);
313void rm_3rd_head(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);
314void 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], float max_ang_jerk);
315void 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);
316void 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);
317void 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);
318void ec_3rd_att(float y_4d[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], float max_ang_jerk);
319void ec_3rd_pos(float y_4d[], 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 x_3d_bound, int n);
320void calc_model(void);
321float oneloop_andi_sideslip(void);
322void reshape_wind(void);
323void 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[]);
324void 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[]);
325void init_cf2(struct CF2_t *cf, float fc);
326void init_cf4(struct CF4_t *cf, float fc);
327void init_all_cf(void);
328void reinit_cf2(struct CF2_t *cf, bool reinit);
329void reinit_cf4(struct CF4_t *cf, bool reinit);
330void reinit_all_cf(bool reinit);
331
332/*Define general struct of the Oneloop ANDI controller*/
334
335/* Oneloop Misc variables*/
336static float use_increment = 0.0;
337static float nav_target[3]; // Can be a position, speed or acceleration depending on the guidance H mode
338static float nav_target_new[3];
339static float dt_1l = 1./PERIODIC_FREQUENCY;
340static float g = 9.81; // [m/s^2] Gravitational Acceleration
341float k_as = 2.0;
344
345/* Oneloop Control Variables*/
353static float a_thrust = 0.0;
354static float g2_ff= 0.0;
355
356/*Attitude related variables*/
357struct Int32Eulers stab_att_sp_euler_1l;// here for now to correct warning, can be better eploited in the future
358struct Int32Quat stab_att_sp_quat_1l; // here for now to correct warning, can be better eploited in the future
361//static float psi_des_rad = 0.0;
362float psi_des_rad = 0.0;
363float psi_des_deg = 0.0;
364static float psi_vec[4] = {0.0, 0.0, 0.0, 0.0};
365
366#if ONELOOP_ANDI_HEADING_MANUAL
367bool heading_manual = true;
368#else
369bool heading_manual = false;
370#endif
371#if ONELOOP_ANDI_YAW_STICK_IN_AUTO
372bool yaw_stick_in_auto = true;
373#else
374bool yaw_stick_in_auto = false;
375#endif
376bool ctrl_off = false;
377/*WLS Settings*/
378
379static float pitch_pref = 0;
380struct WLS_t WLS_one_p = {
382 .nv = ANDI_OUTPUTS,
383 .gamma_sq = 100.0,
384 .v = {0.0},
385#ifdef ONELOOP_ANDI_WV // {ax_dot,ay_dot,az_dot,p_ddot,q_ddot,r_ddot}
386 .Wv = ONELOOP_ANDI_WV,
387#else
388 .Wv = {1.0},
389#endif
390#ifdef ONELOOP_ANDI_WU // {de,dr,daL,daR,mF,mB,mL,mR,mP,phi,theta}
391 .Wu = ONELOOP_ANDI_WU,
392#else
393 .Wu = {1.0},
394#endif
395 .u_pref = {0.0},
396 .u_min = {0.0},
397 .u_max = {0.0},
398 .PC = 0.0,
399 .SC = 0.0,
400 .iter = 0
401};
402
403#ifdef ONELOOP_ANDI_WV // {ax_dot,ay_dot,az_dot,p_ddot,q_ddot,r_ddot}
405#else
406static float Wv_backup[ANDI_OUTPUTS] = {1.0};
407#endif
408
409#ifdef ONELOOP_ANDI_WU // {mF,mR,mB,mL,mP,de,dr,da,df,phi,theta}
411#else
412static float Wu_backup[ANDI_NUM_ACT_TOT] = {1.0};
413#endif
414
415/*Complementary Filter Variables*/
418
419/*Chirp test Variables*/
420bool chirp_on = false;
423float t_0_chirp = 0.0;
424float f0_chirp = 0.8 / (2.0 * M_PI);
425float f1_chirp = 0.8 / (2.0 * M_PI);
426float t_chirp = 45.0;
427float A_chirp = 1.0;
429float p_ref_0[3] = {0.0, 0.0, 0.0};
430
431/*Declaration of Reference Model and Error Controller Gains*/
434/*Position Loop*/
437/*Altitude Loop*/
440/*Heading Loop*/
443/*Gains of EC and RM ANDI*/
448/*Gains of EC and RM INDI*/
451
452/* Effectiveness Matrix definition */
457
458/*Filters Initialization*/
459static Butterworth2LowPass filt_veloc_N; // Low pass filter for velocity NED - oneloop_andi_filt_cutoff_a (tau_a)
462static Butterworth2LowPass accely_filt; // Low pass filter for acceleration in y direction - oneloop_andi_filt_cutoff (tau)
463static Butterworth2LowPass airspeed_filt; // Low pass filter for airspeed - oneloop_andi_filt_cutoff (tau)
464/* Define messages of the module*/
465#if PERIODIC_TELEMETRY
467// static void send_cf_oneloop(struct transport_tx *trans, struct link_device *dev)
468// {
469// 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};
470// 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};
471// 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};
472// 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};
473// 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};
474// 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};
475// //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};
476// //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};
477// 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};
478// pprz_msg_send_COMPLEMENTARY_FILTER(trans, dev, AC_ID,
479// 5, temp_cf_p,
480// 5, temp_cf_q,
481// 5, temp_cf_r,
482// 5, temp_cf_p_dot,
483// 5, temp_cf_q_dot,
484// 5, temp_cf_r_dot,
485// 5, temp_cf_az);
486// }
487static void send_wls_v_oneloop(struct transport_tx *trans, struct link_device *dev)
488{
489 send_wls_v("one", &WLS_one_p, trans, dev);
490}
491static void send_wls_u_oneloop(struct transport_tx *trans, struct link_device *dev)
492{
493 send_wls_u("one", &WLS_one_p, trans, dev);
494}
496{
497 float zero = 0.0;
502 1, &zero,
503 1, &zero);
504}
505
527// static void send_oneloop_actuator_state(struct transport_tx *trans, struct link_device *dev)
528// {
529// pprz_msg_send_ACTUATOR_STATE(trans, dev, AC_ID,
530// ANDI_NUM_ACT, actuator_state_1l,
531// ANDI_NUM_ACT_TOT, andi_u);
532// }
558
559static void debug_vect(struct transport_tx *trans, struct link_device *dev, char *name, float *data, int datasize)
560{
562 strlen(name), name,
563 datasize, data);
564}
565
566static void send_oneloop_debug(struct transport_tx *trans, struct link_device *dev)
567{
568 float temp_debug_vect[9];
578 debug_vect(trans, dev, "model_cf", temp_debug_vect, 9);
579}
580#endif
581
583static float positive_non_zero(float input)
584{
585 if (input < FLT_EPSILON) {
586 input = 0.00001;
587 }
588 return input;
589}
590
593static float k_e_1_2_f_v2(float omega, float zeta) {
594 omega = positive_non_zero(omega);
595 zeta = positive_non_zero(zeta);
596 return (omega * omega);
597}
598
599static float k_e_2_2_f_v2(float omega, float zeta) {
600 omega = positive_non_zero(omega);
601 zeta = positive_non_zero(zeta);
602 return (2* zeta * omega);
603}
604
605static float k_e_1_3_f_v2(float omega_n, UNUSED float zeta, float p1) {
606 omega_n = positive_non_zero(omega_n);
607 p1 = positive_non_zero(p1);
608 return (omega_n * omega_n * p1);
609}
610
611static float k_e_2_3_f_v2(float omega_n, float zeta, float p1) {
612 omega_n = positive_non_zero(omega_n);
613 zeta = positive_non_zero(zeta);
614 p1 = positive_non_zero(p1);
615 return (omega_n * omega_n + 2 * zeta * omega_n * p1);
616}
617
618static float k_e_3_3_f_v2(float omega_n, float zeta, float p1) {
619 omega_n = positive_non_zero(omega_n);
620 zeta = positive_non_zero(zeta);
621 p1 = positive_non_zero(p1);
622 return (2 * zeta * omega_n + p1);
623}
624
627static float k_rm_1_3_f(float omega_n, float zeta, float p1) {
628 omega_n = positive_non_zero(omega_n);
629 zeta = positive_non_zero(zeta);
630 p1 = positive_non_zero(p1);
631 return (omega_n * omega_n * p1) / (omega_n * omega_n + omega_n * p1 * zeta * 2.0);
632}
633
634static float k_rm_2_3_f(float omega_n, float zeta, float p1) {
635 omega_n = positive_non_zero(omega_n);
636 zeta = positive_non_zero(zeta);
637 p1 = positive_non_zero(p1);
638 return (omega_n * omega_n + omega_n * p1 * zeta * 2.0) / (p1 + omega_n * zeta * 2.0);
639}
640
641static float k_rm_3_3_f(float omega_n, float zeta, float p1) {
642 omega_n = positive_non_zero(omega_n);
643 zeta = positive_non_zero(zeta);
644 p1 = positive_non_zero(p1);
645 return p1 + omega_n * zeta * 2.0;
646}
647
649void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3])
650{
651 float sphi = sinf(e[0]);
652 float cphi = cosf(e[0]);
653 float stheta = sinf(e[1]);
654 float ctheta = cosf(e[1]);
655 r[0] = edot[0] - stheta * edot[2];
656 r[1] = cphi * edot[1] + sphi * ctheta * edot[2];
657 r[2] = -sphi * edot[1] + cphi * ctheta * edot[2];
658}
659
661void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3])
662{
663 float sphi = sinf(e[0]);
664 float cphi = cosf(e[0]);
665 float stheta = sinf(e[1]);
666 float ctheta = cosf(e[1]);
667 if (fabs(ctheta) < FLT_EPSILON){
668 ctheta = FLT_EPSILON;
669 }
670 edot[0] = r[0] + sphi*stheta/ctheta*r[1] + cphi*stheta/ctheta*r[2];
671 edot[1] = cphi*r[1] - sphi*r[2];
672 edot[2] = sphi/ctheta*r[1] + cphi/ctheta*r[2];
673}
674
676void err_nd(float err[], float a[], float b[], float k[], int n)
677{
678 int8_t i;
679 for (i = 0; i < n; i++) {
680 err[i] = k[i] * (a[i] - b[i]);
681 }
682}
683
685void err_sum_nd(float err[], float a[], float b[], float k[], float c[], int n)
686{
687 int8_t i;
688 for (i = 0; i < n; i++) {
689 err[i] = k[i] * (a[i] - b[i]);
690 err[i] += c[i];
691 }
692}
693
695void integrate_nd(float dt, float a[], float a_dot[], int n)
696{
697 int8_t i;
698 for (i = 0; i < n; i++) {
699 a[i] = a[i] + dt * a_dot[i];
700 }
701}
702
704void vect_bound_nd(float vect[], float bound, int n) {
705 float norm = float_vect_norm(vect,n);
707 if((norm-bound) > FLT_EPSILON) {
708 float scale = bound/norm;
709 int8_t i;
710 for(i = 0; i < n; i++) {
711 vect[i] *= scale;
712 }
713 }
714}
715
717void acc_body_bound(struct FloatVect2* vect, float bound) {
718 int n = 2;
719 float v[2] = {vect->x, vect->y};
720 float sign_v0 = (v[0] > 0.f) ? 1.f : (v[0] < 0.f) ? -1.f : 0.f;
721 float sign_v1 = (v[1] > 0.f) ? 1.f : (v[1] < 0.f) ? -1.f : 0.f;
722 float norm = float_vect_norm(v,n);
723 v[0] = fabsf(v[0]);
724 v[1] = fabsf(v[1]);
726 if((norm-bound) > FLT_EPSILON) {
727 v[0] = Min(v[0], bound);
728 float acc_b_y_2 = bound*bound - v[0]*v[0];
730 v[1] = sqrtf(acc_b_y_2);
731 }
732 vect->x = sign_v0*v[0];
733 vect->y = sign_v1*v[1];
734}
735
737float bound_v_from_a(float e_x[], float v_bound, float a_bound, int n) {
738 float norm = float_vect_norm(e_x,n);
739 norm = fmaxf(norm, 1.0);
740 float v_bound_a = sqrtf(fabs(2.0 * a_bound * norm));
741 return fminf(v_bound, v_bound_a);
742}
743
758void 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], float max_ang_jerk){
759 float e_x[3];
760 float e_x_rates[3];
761 float e_x_d[3];
762 float e_x_2d[3];
763 float x_d_eul_ref[3];
764 err_nd(e_x, x_des, x_ref, k1_rm, 3);
765 float temp_diff = x_des[2] - x_ref[2];
767 e_x[2] = k1_rm[2] * temp_diff; // Correction for Heading error +-Pi
773 if(ow_psi){x_3d_ref[2] = psi_overwrite[3];}
775 if(ow_psi){x_2d_ref[2] = psi_overwrite[2];}
777 if(ow_psi){x_d_ref[2] = psi_overwrite[1];}
780 if(ow_psi){x_ref[2] = psi_overwrite[0];}
782 //printf("k1_rm: %f %f %f\n", k1_rm[0], k1_rm[1], k1_rm[2]);
783 //printf("k2_rm: %f %f %f\n", k2_rm[0], k2_rm[1], k2_rm[2]);
784 //printf("k3_rm: %f %f %f\n", k3_rm[0], k3_rm[1], k3_rm[2]);
785}
786
799void rm_3rd(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){
800 float e_x = k1_rm * (x_des- *x_ref);
801 float e_x_d = k2_rm * (e_x- *x_d_ref);
802 float e_x_2d = k3_rm * (e_x_d- *x_2d_ref);
803 *x_3d_ref = e_x_2d;
804 *x_2d_ref = (*x_2d_ref + dt * (*x_3d_ref));
805 *x_d_ref = (*x_d_ref + dt * (*x_2d_ref));
806 *x_ref = (*x_ref + dt * (*x_d_ref ));
807}
808
821void rm_3rd_head(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){
822 float temp_diff = x_des - *x_ref;
824 float e_x = k1_rm * temp_diff;
825 float e_x_d = k2_rm * (e_x- *x_d_ref);
826 float e_x_2d = k3_rm * (e_x_d- *x_2d_ref);
827 *x_3d_ref = e_x_2d;
828 *x_2d_ref = (*x_2d_ref + dt * (*x_3d_ref));
829 *x_d_ref = (*x_d_ref + dt * (*x_2d_ref));
830 *x_ref = (*x_ref + dt * (*x_d_ref ));
831}
832
849void 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){
850 float e_x[n];
851 float e_x_d[n];
852 float e_x_2d[n];
853 err_nd(e_x, x_des, x_ref, k1_rm, n);
863 integrate_nd(dt, x_ref, x_d_ref, n);
864}
865
879void 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){
880 float e_x_d[n];
881 float e_x_2d[n];
889}
890
901void 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){
902 float e_x_2d[n];
907}
908
909
922void rm_2nd(float dt, float* x_ref, float* x_d_ref, float* x_2d_ref, float x_des, float k1_rm, float k2_rm){
923 float e_x = k1_rm * (x_des- *x_ref);
924 float e_x_d = k2_rm * (e_x- *x_d_ref);
925 *x_2d_ref = e_x_d;
926 *x_d_ref = (*x_d_ref + dt * (*x_2d_ref));
927 *x_ref = (*x_ref + dt * (*x_d_ref ));
928}
929
945static float ec_3rd(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){
947 return y_4d;
948}
949void ec_3rd_pos( float y_4d[], 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 x_3d_bound, int n){
950 float e_x_d[n];
951 float e_x_2d[n];
952
955
958
961}
977void ec_3rd_att(float y_4d[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], float max_ang_jerk){
978 float y_4d_1[3];
979 float y_4d_2[3];
980 float y_4d_3[3];
981 err_nd(y_4d_1, x_ref, x, k1_e, 3);
982 float temp_diff = x_ref[2] - x[2];
984 float e_x = temp_diff;
985 y_4d_1[2] = k1_e[2] * e_x; // Correction for Heading error +-Pi
993}
994
1002static float w_approx(float p1, float p2, float p3, float rm_k){
1003 p1 = positive_non_zero(p1);
1004 p2 = positive_non_zero(p2);
1005 p3 = positive_non_zero(p3);
1007 float tao = (p1*p2+p1*p3+p2*p3)/(p1*p2*p3)/(rm_k);
1009 return 1.0/tao;
1010}
1011
1019static float ec_poles(float p_rm, float slow_pole, float k){
1022 k = positive_non_zero(k);
1023 float omega_n = (2*p_rm*slow_pole*k)/(3*slow_pole-p_rm);
1024 return omega_n;
1025}
1026
1032 float slow_pole = 22.0; // Pole of the slowest dynamics used in the attitude controller
1035}
1039 float slow_pole = act_dynamics[COMMAND_ROLL]; // Pole of the slowest dynamics used in the position controller
1041 p_alt_e.omega_n = ec_poles(p_alt_rm.omega_n,slow_pole,1.28);//1.0;// 3.0;
1042}
1043
1048void init_poles(void){
1049
1050 // Attitude Controller Poles----------------------------------------------------------
1051 float slow_pole = 22.0; // Pole of the slowest dynamics used in the attitude controller
1052
1053 p_att_rm.omega_n = 10.0; // 10.0 4.71
1054 p_att_rm.zeta = 1.0;
1056
1058 p_att_e.zeta = 1.0;
1060
1061 p_head_rm.omega_n = 7.0; // 7.0 2.56
1062 p_head_rm.zeta = 1.0;
1064
1066 p_head_e.zeta = 1.0;
1068
1071
1072 // Position Controller Poles----------------------------------------------------------
1073 slow_pole = act_dynamics[COMMAND_ROLL]; // Pole of the slowest dynamics used in the position controller
1074#ifdef ONELOOP_ANDI_POLES_POS_OMEGA_N
1076#else
1077 p_pos_rm.omega_n = 0.93; //2.2;
1078#endif
1079 p_pos_rm.zeta = 1.0;
1081
1083 p_pos_e.zeta = 1.0;
1084 p_pos_e.p3 = slow_pole;
1085#ifdef ONELOOP_ANDI_POLES_ALT_OMEGA_N
1087#else
1088 p_alt_rm.omega_n = 0.93; //2.2;
1089#endif
1090 p_alt_rm.zeta = 1.0;
1092
1093 p_alt_e.omega_n = ec_poles(p_alt_rm.omega_n,slow_pole,1.28);//1.0;// 3.0;
1094 p_alt_e.zeta = 1.0;
1095 p_alt_e.p3 = slow_pole;
1096}
1097
1103 /*Register a variable from nav_hybrid. Should be improved when nav hybrid is final.*/
1104 float max_wind = 20.0;
1107 /*Some calculations in case new poles have been specified*/
1114
1115 //--ANDI Controller gains --------------------------------------------------------------------------------
1116 /*Attitude Loop*/
1120 k_att_e.k1[1] = k_att_e.k1[0];
1121 k_att_e.k2[1] = k_att_e.k2[0];
1122 k_att_e.k3[1] = k_att_e.k3[0];
1123
1127 k_att_rm.k1[1] = k_att_rm.k1[0];
1128 k_att_rm.k2[1] = k_att_rm.k2[0];
1129 k_att_rm.k3[1] = k_att_rm.k3[0];
1130
1131 //printf("Attitude RM Gains: %f %f %f\n", k_att_rm.k1[0], k_att_rm.k2[0], k_att_rm.k3[0]);
1132 //printf("Attitude E Gains: %f %f %f\n", k_att_e.k1[0], k_att_e.k2[0], k_att_e.k3[0]);
1133 //printf("Heading E Gains: %f %f %f\n", k_att_e.k1[2], k_att_e.k2[2], k_att_e.k3[2]);
1134 /*Heading Loop NAV*/
1138
1142
1143 /*Position Loop*/
1144 // k_pos_e.k1[0] = k_e_1_3_f_v2(p_pos_e.omega_n, p_pos_e.zeta, p_pos_e.p3);
1145 // k_pos_e.k2[0] = k_e_2_3_f_v2(p_pos_e.omega_n, p_pos_e.zeta, p_pos_e.p3);
1146 // k_pos_e.k3[0] = k_e_3_3_f_v2(p_pos_e.omega_n, p_pos_e.zeta, p_pos_e.p3);
1150 k_pos_e.k1[1] = k_pos_e.k1[0];
1151 k_pos_e.k2[1] = k_pos_e.k2[0];
1152 k_pos_e.k3[1] = k_pos_e.k3[0];
1153
1157 k_pos_rm.k1[1] = k_pos_rm.k1[0];
1158 k_pos_rm.k2[1] = k_pos_rm.k2[0];
1159 k_pos_rm.k3[1] = k_pos_rm.k3[0];
1162
1163 /*Altitude Loop*/
1164 // k_pos_e.k1[2] = k_e_1_3_f_v2(p_alt_e.omega_n, p_alt_e.zeta, p_alt_e.p3);
1165 // k_pos_e.k2[2] = k_e_2_3_f_v2(p_alt_e.omega_n, p_alt_e.zeta, p_alt_e.p3);
1166 // k_pos_e.k3[2] = k_e_3_3_f_v2(p_alt_e.omega_n, p_alt_e.zeta, p_alt_e.p3);
1170
1174
1175 //--INDI Controller gains --------------------------------------------------------------------------------
1176 /*Attitude Loop*/
1179 k_att_e_indi.k3[0] = 1.0;
1180 k_att_e_indi.k1[1] = k_att_e_indi.k1[0];
1181 k_att_e_indi.k2[1] = k_att_e_indi.k2[0];
1182 k_att_e_indi.k3[1] = k_att_e_indi.k3[0];
1183
1184 /*Heading Loop NAV*/
1187 k_att_e_indi.k3[2] = 1.0;
1188
1189 /*Position Loop*/
1192 k_pos_e_indi.k3[0] = 1.0;
1193 k_pos_e_indi.k1[1] = k_pos_e_indi.k1[0];
1194 k_pos_e_indi.k2[1] = k_pos_e_indi.k2[0];
1195 k_pos_e_indi.k3[1] = k_pos_e_indi.k3[0];
1196
1197 /*Altitude Loop*/
1200 k_pos_e_indi.k3[2] = 1.0;
1201
1202 //------------------------------------------------------------------------------------------
1203 /*Approximated Dynamics*/
1206}
1207// Complementary Filters Functions -----------------------------------------------------------
1209void init_cf2(struct CF2_t *cf, float fc){
1210 cf->freq = fc;
1211 cf->freq_set = fc;
1212 cf->tau = 1/(2*M_PI*cf->freq);
1213 init_butterworth_2_low_pass(&cf->model_filt, cf->tau, 1.0 / PERIODIC_FREQUENCY, 0.0);
1214 init_butterworth_2_low_pass(&cf->feedback_filt, cf->tau, 1.0 / PERIODIC_FREQUENCY, 0.0);
1215 cf->model = 0.0;
1216 cf->feedback = 0.0;
1217 cf->out = 0.0;
1218}
1220void init_cf4(struct CF4_t *cf, float fc){
1221 cf->freq = fc;
1222 cf->freq_set = fc;
1223 cf->tau = 1/(2*M_PI*cf->freq);
1224 init_butterworth_4_low_pass(&cf->model_filt, cf->tau, 1.0 / PERIODIC_FREQUENCY, 0.0);
1225 init_butterworth_4_low_pass(&cf->feedback_filt, cf->tau, 1.0 / PERIODIC_FREQUENCY, 0.0);
1226 cf->model = 0.0;
1227 cf->feedback = 0.0;
1228 cf->out = 0.0;
1229}
1243void reinit_cf2(struct CF2_t *cf, bool reinit){
1244 if(cf->freq != cf->freq_set || reinit){
1245 cf->freq = cf->freq_set;
1246 cf->tau = 1/(2*M_PI*cf->freq);
1247 init_butterworth_2_low_pass(&cf->model_filt, cf->tau, 1.0 / PERIODIC_FREQUENCY, get_butterworth_2_low_pass(&cf->model_filt));
1248 init_butterworth_2_low_pass(&cf->feedback_filt, cf->tau, 1.0 / PERIODIC_FREQUENCY, get_butterworth_2_low_pass(&cf->feedback_filt));
1249 }
1250}
1252void reinit_cf4(struct CF4_t *cf, bool reinit){
1253 if(cf->freq != cf->freq_set || reinit){
1254 cf->freq = cf->freq_set;
1255 cf->tau = 1/(2*M_PI*cf->freq);
1256 init_butterworth_4_low_pass(&cf->model_filt, cf->tau, 1.0 / PERIODIC_FREQUENCY, get_butterworth_4_low_pass(&cf->model_filt));
1257 init_butterworth_4_low_pass(&cf->feedback_filt, cf->tau, 1.0 / PERIODIC_FREQUENCY, get_butterworth_4_low_pass(&cf->feedback_filt));
1258 }
1259}
1272//------------------------------------------------------------------------------------------
1274void init_filter(void)
1275{
1276 // Store Notch filter values
1277#ifdef ONELOOP_ANDI_ROLL_STRUCTURAL_MODE_FREQ
1279#else
1280 oneloop_notch.roll.freq = 8.46,
1281#endif
1282#ifdef ONELOOP_ANDI_PITCH_STRUCTURAL_MODE_FREQ
1284#else
1285 oneloop_notch.pitch.freq = 6.44,
1286#endif
1287#ifdef ONELOOP_ANDI_YAW_STRUCTURAL_MODE_FREQ
1289#else
1290 oneloop_notch.yaw.freq = 17.90,
1291#endif
1295 // Initialize Notch filters
1299 // Filtering of the velocities
1300 float tau = 1.0 / (2.0 * M_PI * oneloop_andi_filt_cutoff);
1301 float tau_v = 1.0 / (2.0 * M_PI * oneloop_andi_filt_cutoff_v);
1302 //printf("tau: %f tau_v: %f\n", tau, tau_v);
1303 //printf("initializing filters\n");
1309}
1310
1311
1314 reinit_all_cf(false);
1315 struct NedCoor_f *accel = stateGetAccelNed_f();
1317 //printf("veloc: %f %f %f\n", veloc->x, veloc->y, veloc->z);
1319 // Store Feedbacks in the Complementary Filters
1320 cf.ax.feedback = accel->x;
1321 cf.ay.feedback = accel->y;
1322 cf.az.feedback = accel->z;
1323//#define USE_ROLL_NOTCH
1324//#define USE_PITCH_NOTCH
1325#define USE_YAW_NOTCH
1329#ifdef USE_ROLL_NOTCH
1331#else
1333#endif
1334#ifdef USE_PITCH_NOTCH
1336#else
1338#endif
1339#ifdef USE_YAW_NOTCH
1341#else
1343#endif
1344 cf.p.feedback = body_rates->p;
1345 cf.q.feedback = body_rates->q;
1346 cf.r.feedback = body_rates->r;
1347 // Update Filters of Feedbacks
1357 //printf("veloc: %f %f %f\n", veloc->x, veloc->y, veloc->z);
1361 //printf("veloc_filt: %f %f %f\n", filt_veloc_N.o[0], filt_veloc_E.o[0], filt_veloc_D.o[0]);
1362 // Calculate Model Predictions for Linear and Angular Accelerations Using the Effectiveness Matrix
1363 calc_model();
1364 // Update Filters of Model Predictions for Linear and Angular Accelerations
1371 // Calculate Complementary Filter outputs for Linear and Angular Accelerations
1375 //cf.p_dot.out = cf.p_dot.feedback_filt.o[0] + cf.p_dot.model - cf.p_dot.model_filt.o[0];
1377 //cf.q_dot.out = cf.q_dot.feedback_filt.o[0] + cf.q_dot.model - cf.q_dot.model_filt.o[0];
1380 // Calculate Model Predictions for Angular Rates Using the output of the angular acceleration Complementary Filter
1384 // Update Filters of Model Predictions for Angular Rates
1388 // Calculate Complementary Filter outputs for Angular Rates
1389 cf.p.out = cf.p.feedback_filt.o[0] + cf.p.model - cf.p.model_filt.o[0];
1390 cf.q.out = cf.q.feedback_filt.o[0] + cf.q.model - cf.q.model_filt.o[0];
1391 cf.r.out = cf.r.feedback_filt.o[0] + cf.r.model - cf.r.model_filt.o[0];
1392 // Propagate filter for sideslip correction
1396 Bound(airspeed_meas, 0.0, 30.0);
1398}
1399
1402{
1403 oneloop_andi.half_loop = true;
1405 init_poles();
1406 // Make sure that the dynamics are positive and non-zero
1407 int8_t i;
1408 for (i = 0; i < ANDI_NUM_ACT_TOT; i++) {
1410 }
1411 // Initialize Effectiveness matrix
1414 for (i = 0; i < ANDI_OUTPUTS; i++) {
1415 bwls_1l[i] = EFF_MAT_G[i];
1416 }
1417 // Initialize filters and other variables
1418 init_all_cf();
1419 init_filter();
1433 eulers_zxy_des.phi = 0.0;
1434 eulers_zxy_des.theta = 0.0;
1435 eulers_zxy_des.psi = 0.0;
1436 // Start telemetry
1437 #if PERIODIC_TELEMETRY
1442 // register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_ACTUATOR_STATE, send_oneloop_actuator_state);
1446 // register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_COMPLEMENTARY_FILTER, send_cf_oneloop);
1447 #endif
1448}
1449
1456void oneloop_andi_enter(bool half_loop_sp, int ctrl_type)
1457{
1458 ele_min = 0.0;
1460 oneloop_andi.ctrl_type = ctrl_type;
1465 int8_t i;
1466 for (i = 0; i < ANDI_OUTPUTS; i++) {
1467 bwls_1l[i] = EFF_MAT_G[i];
1468 }
1469 reinit_all_cf(true);
1470 init_filter();
1472 /* Stabilization Reset */
1479 eulers_zxy_des.phi = 0.0;
1480 eulers_zxy_des.theta = 0.0;
1482 /*Guidance Reset*/
1483}
1484
1492void oneloop_andi_RM(bool half_loop, struct FloatVect3 PSA_des, int rm_order_h, int rm_order_v, bool in_flight_oneloop)
1493{
1494 // Initialize some variables
1495 a_thrust = 0.0;
1496 nav_target[0] = PSA_des.x;
1497 nav_target[1] = PSA_des.y;
1498 nav_target[2] = PSA_des.z;
1499 float thrust_cmd_1l = 0.0;
1500 float des_r = 0.0;
1501 // Generate reference signals with reference model
1502 if(half_loop){
1503 // Disregard X and Y jerk objectives
1504 WLS_one_p.Wv[0] = 0.0;
1505 WLS_one_p.Wv[1] = 0.0;
1506 // Overwrite references with actual signals (for consistent plotting)
1511 // Set desired attitude with stick input
1514 // Set desired Yaw rate with stick input
1515 des_r = (float) (radio_control_get(RADIO_YAW))/MAX_PPRZ*max_r; // Get yaw rate from stick
1516 BoundAbs(des_r,max_r); // Bound yaw rate
1517 float delta_psi_des_rad = des_r * dt_1l; // Integrate desired Yaw rate to get desired change in yaw
1518 float delta_psi_rad = eulers_zxy_des.psi-eulers_zxy.psi; // Calculate current yaw difference between des and actual
1519 NormRadAngle(delta_psi_rad); // Normalize the difference
1520 if (fabs(delta_psi_rad) > RadOfDeg(30.0)){ // If difference is bigger than 10 deg do not further increment desired
1521 delta_psi_des_rad = 0.0;
1522 }
1523 psi_des_rad += delta_psi_des_rad; // Incrementdesired yaw
1525 // Register Attitude Setpoints from previous loop
1526 if (!in_flight_oneloop){
1528 }
1531 // Create commands adhoc to get actuators to the wanted level
1534 int8_t i;
1535 for (i = 0; i < ANDI_NUM_ACT; i++) {
1537 }
1539 }else{
1540 // Make sure X and Y jerk objectives are active
1541 WLS_one_p.Wv[0] = Wv_backup[0];
1542 WLS_one_p.Wv[1] = Wv_backup[1];
1543 // Generate Reference signals for positioning using RM
1544 if (rm_order_h == 3){
1546 } else if (rm_order_h == 2){
1549 reshape_wind();//returns accel sp as nav target new
1551 // 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_nav, 2);
1552 } else if (rm_order_h == 1){
1556 }
1557 // Update desired Heading (psi_des_rad) based on previous loop or changed setting
1558 if (heading_manual){
1560 if (yaw_stick_in_auto){
1562 }
1563 } else {
1567 if (ref_mag_vel > 3.0){
1569 float delta_des_gs = psi_gs-psi_des_rad; // Calculate current yaw difference between des and gs
1571 if (fabs(delta_des_gs) > RadOfDeg(60.0)){ // If difference is bigger than 60 deg bound the des psi angle so that it does not deviate too much
1575 }
1576 }
1577 }
1578 // Register Attitude Setpoints from previous loop
1579 if (!in_flight_oneloop){
1581 }
1584 // The RM functions want an array as input. Create a single entry array and write the vertical guidance entries.
1585 float single_value_ref[1] = {oneloop_andi.gui_ref.pos[2]};
1589 float single_value_nav_target[1] = {nav_target[2]};
1590 float single_value_k1_rm[1] = {k_pos_rm.k1[2]};
1591 float single_value_k2_rm[1] = {k_pos_rm.k2[2]};
1592 float single_value_k3_rm[1] = {k_pos_rm.k3[2]};
1593 if (rm_order_v == 3){
1599 } else if (rm_order_v == 2){
1605 } else if (rm_order_v == 1){
1611 }
1612 // Run chirp test if turnerd on (overwrite the guidance references)
1614 // Generate Reference signals for attitude using RM
1615 // FIX ME ow not yet defined, will be useful in the future to have accurate psi tracking in NAV functions
1616 bool ow_psi = false;
1618 }
1619}
1620
1629void oneloop_andi_run(bool in_flight, bool half_loop, struct FloatVect3 PSA_des, int rm_order_h, int rm_order_v)
1630{
1631 // 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
1637 int8_t i;
1638 for (i = 0; i < ANDI_OUTPUTS; i++) {
1639 bwls_1l[i] = EFF_MAT_G[i];
1640 }
1641
1642 // If drone is not on the ground use incremental law
1643 use_increment = 0.0;
1644 bool in_flight_oneloop = false;
1645 if(in_flight) {
1646 use_increment = 1.0;
1647 in_flight_oneloop = true;
1648 }
1650 in_flight_oneloop = false;
1651 }
1652
1653 // Register the state of the drone in the variables used in RM and EC
1654 // (1) Attitude related
1658 oneloop_andi_propagate_filters(); //needs to be after update of attitude vector
1665 // (2) Position related
1675 // Calculated feedforward signal for yaw control
1676 g2_ff = 0.0;
1677
1678 for (i = 0; i < ANDI_NUM_ACT; i++) {
1680 g2_ff += G2_RW[i] * act_dynamics[i] * andi_du[i];
1681 } else if (oneloop_andi.ctrl_type == CTRL_INDI){
1682 g2_ff += G2_RW[i]* andi_du_n[i];
1683 }
1684 }
1685 //G2 is scaled by ANDI_G_SCALING to make it readable
1686 g2_ff = g2_ff;
1687 // Run the Reference Model (RM)
1689 // Guidance Pseudo Control Vector (nu) based on error controller
1690 if(half_loop){
1691 nu[0] = 0.0;
1692 nu[1] = 0.0;
1693 nu[2] = a_thrust;
1694 ctrl_off = false;
1695 }else{
1698 // nu[0] = ec_3rd(oneloop_andi.gui_ref.pos[0], oneloop_andi.gui_ref.vel[0], oneloop_andi.gui_ref.acc[0], oneloop_andi.gui_ref.jer[0], oneloop_andi.gui_state.pos[0], oneloop_andi.gui_state.vel[0], oneloop_andi.gui_state.acc[0], k_pos_e.k1[0], k_pos_e.k2[0], k_pos_e.k3[0]);
1699 // nu[1] = ec_3rd(oneloop_andi.gui_ref.pos[1], oneloop_andi.gui_ref.vel[1], oneloop_andi.gui_ref.acc[1], oneloop_andi.gui_ref.jer[1], oneloop_andi.gui_state.pos[1], oneloop_andi.gui_state.vel[1], oneloop_andi.gui_state.acc[1], k_pos_e.k1[1], k_pos_e.k2[1], k_pos_e.k3[1]);
1700 // nu[2] = ec_3rd(oneloop_andi.gui_ref.pos[2], oneloop_andi.gui_ref.vel[2], oneloop_andi.gui_ref.acc[2], oneloop_andi.gui_ref.jer[2], oneloop_andi.gui_state.pos[2], oneloop_andi.gui_state.vel[2], oneloop_andi.gui_state.acc[2], k_pos_e.k1[2], k_pos_e.k2[2], k_pos_e.k3[2]);
1701 } else if (oneloop_andi.ctrl_type == CTRL_INDI){
1705 }
1706 }
1707 // Attitude Pseudo Control Vector (nu) based on error controller
1708 float y_4d_att[3];
1711 } else if (oneloop_andi.ctrl_type == CTRL_INDI){
1712 float dummy0[3] = {0.0, 0.0, 0.0};
1714 }
1715 nu[3] = y_4d_att[0];
1716 nu[4] = y_4d_att[1];
1717 nu[5] = y_4d_att[2] + g2_ff;
1718 if (!chirp_on){
1722 }
1724 // Calculate the min and max increments
1725 for (i = 0; i < ANDI_NUM_ACT_TOT; i++) {
1726 switch (i) {
1729 case COMMAND_MOTOR_BACK:
1730 case COMMAND_MOTOR_LEFT: {
1731 float skew_bound = RW.skew.deg;
1732 Bound(skew_bound,70.0,90.0);
1733 float Wu_sched = (Wu_quad_motors_fwd-Wu_backup[i])/(90.0-70.0)*(skew_bound-70)+Wu_backup[i];
1734 WLS_one_p.Wu[i] = Wu_sched;
1740 } else
1741 {
1742 WLS_one_p.u_max[i] = (0.0 - actuator_state_1l[i])/ratio_u_un[i];
1743 }
1744 break;
1745 }
1747 case COMMAND_RUDDER:
1751 break;
1752 case COMMAND_AILERONS:
1753 if(RW.skew.deg > 25.0){
1756 } else {
1757 WLS_one_p.u_min[i] = (0.0 - actuator_state_1l[i])/ratio_u_un[i];
1758 WLS_one_p.u_max[i] = (0.0 - actuator_state_1l[i])/ratio_u_un[i];
1759 }
1761 break;
1762 case COMMAND_FLAPS:
1763 if(RW.skew.deg > 50.0){
1766 } else {
1767 WLS_one_p.u_min[i] = (0.0 - actuator_state_1l[i])/ratio_u_un[i];
1768 WLS_one_p.u_max[i] = (0.0 - actuator_state_1l[i])/ratio_u_un[i];
1769 }
1771 break;
1772 case COMMAND_ELEVATOR:
1775 u_pref[i] = RW.ele_pref;
1777 break;
1778 case COMMAND_ROLL:
1782 break;
1783 case COMMAND_PITCH:
1784 if (RW.skew.deg > 70.0){
1787 } else {
1790 }
1792 break;
1793 }
1794 }
1795 // WLS Control Allocator
1796 normalize_nu();
1797 wls_alloc(&WLS_one_p, bwls_1l, 0, 0, 10);
1798 for (i = 0; i < ANDI_NUM_ACT_TOT; i++){
1799 andi_du_n[i] = WLS_one_p.u[i];
1800 andi_du[i] = (float)(andi_du_n[i] * ratio_u_un[i]);
1801 }
1802
1803 if (in_flight_oneloop) {
1804 // Add the increments to the actuators
1808 } else {
1809 // Not in flight, so don't increment
1813 }
1814#ifdef COMMAND_MOTOR_PUSHER
1815 if ((half_loop)){
1817 }
1818#endif
1819 // TODO : USE THE PROVIDED MAX AND MIN and change limits for phi and theta
1820 // Bound the inputs to the actuators
1821 for (i = 0; i < ANDI_NUM_ACT_TOT; i++) {
1822 Bound(andi_u[i], act_min[i], act_max[i]);
1823 }
1824
1825 /*Commit the actuator command*/
1826 for (i = 0; i < ANDI_NUM_ACT; i++) {
1827 commands[i] = (int16_t) andi_u[i];
1828 }
1830 commands[COMMAND_MOTOR_PUSHER] = 0;//Min(1000,andi_u[COMMAND_MOTOR_PUSHER]);
1831 }
1838 } else {
1841 }
1842 if (heading_manual){
1844 }
1845
1849}
1850
1853{
1854 int8_t i;
1856 for (i = 0; i < ANDI_NUM_ACT; i++) {
1860 actuator_state_1l[i] = 0.0;
1861 }
1863 }
1864}
1865
1870void G1G2_oneloop(int ctrl_type) {
1871 int i = 0;
1872 float scaler = 1.0;
1873 for (i = 0; i < ANDI_NUM_ACT_TOT; i++) {
1874
1875 switch (i) {
1876 case (COMMAND_MOTOR_FRONT):
1877 case (COMMAND_MOTOR_RIGHT):
1878 case (COMMAND_MOTOR_BACK):
1879 case (COMMAND_MOTOR_LEFT):
1880 case (COMMAND_MOTOR_PUSHER):
1881 case (COMMAND_ELEVATOR):
1882 case (COMMAND_RUDDER):
1883 case (COMMAND_AILERONS):
1884 case (COMMAND_FLAPS):
1885 if(ctrl_type == CTRL_ANDI){
1886 scaler = act_dynamics[i] * ratio_u_un[i];
1887 } else if (ctrl_type == CTRL_INDI){
1888 scaler = ratio_u_un[i];
1889 }
1890 break;
1891 case (COMMAND_ROLL):
1892 case (COMMAND_PITCH):
1893 if(ctrl_type == CTRL_ANDI){
1894 scaler = act_dynamics[i] * ratio_u_un[i];
1895 } else if (ctrl_type == CTRL_INDI){
1896 scaler = ratio_u_un[i];
1897 }
1898 break;
1899 default:
1900 break;
1901 }
1902 int j = 0;
1904 for (j = 0; j < ANDI_OUTPUTS; j++) {
1905 EFF_MAT_G[j][i] = EFF_MAT_RW[j][i] * scaler * ratio_vn_v[j];
1906 if (airspeed_filt.o[0] < ELE_MIN_AS && i == COMMAND_ELEVATOR){
1907 EFF_MAT_G[j][i] = 0.0;
1908 }
1909 if (turn_quad_off && i < 4){
1910 EFF_MAT_G[j][i] = 0.0;
1911 }
1912 if (ctrl_off && i < 4 && j == 5){ //hack test
1913 EFF_MAT_G[j][i] = 0.0;
1914 }
1915 if (ctrl_off && i < 4 && j == 4){ //hack test
1916 EFF_MAT_G[j][i] = 0.0;
1917 }
1918 if (ctrl_off && i < 4 && j == 3){ //hack test
1919 EFF_MAT_G[j][i] = 0.0;
1920 }
1921 }
1922 }
1923}
1924
1927 int8_t i;
1928 for (i = 0; i < ANDI_NUM_ACT_TOT; i++){
1929 act_dynamics_d[i] = 1.0-exp(-act_dynamics[i]*dt_1l);
1930 Bound(act_dynamics_d[i],0.00001,1.0);
1931 Bound(act_max[i],0,MAX_PPRZ);
1932 Bound(act_min[i],-MAX_PPRZ,0);
1933 float ratio_numerator = act_max[i]-act_min[i];
1934 ratio_numerator = positive_non_zero(ratio_numerator);// make sure numerator is non-zero
1936 ratio_denominator = positive_non_zero(ratio_denominator); // make sure denominator is non-zero
1938 ratio_u_un[i] = positive_non_zero(ratio_u_un[i]);// make sure ratio is not zero
1939 }
1940 for (i = 0; i < ANDI_OUTPUTS; i++){
1942 float ratio_denominator = 1.0;
1943 switch (i) {
1944 case (RW_aN):
1945 case (RW_aE):
1946 case (RW_aD):
1949 break;
1950 case (RW_ap):
1951 case (RW_aq):
1952 case (RW_ar):
1955 break;
1956 }
1957 }
1958}
1959
1961void normalize_nu(void){
1962 int8_t i;
1963 for (i = 0; i < ANDI_OUTPUTS; i++){
1964 nu_n[i] = nu[i] * ratio_vn_v[i];
1965 WLS_one_p.v[i] = nu_n[i];
1966 }
1967}
1968
1970void calc_model(void){
1971 int8_t i;
1972 int8_t j;
1973 // // Absolute Model Prediction :
1974 float sphi = sinf(eulers_zxy.phi);
1975 float cphi = cosf(eulers_zxy.phi);
1976 float stheta = sinf(eulers_zxy.theta);
1977 float ctheta = cosf(eulers_zxy.theta);
1978 float spsi = sinf(eulers_zxy.psi);
1979 float cpsi = cosf(eulers_zxy.psi);
1980 // Thrust and Pusher force estimation
1981 float L = RW.wing.L / RW.m; // Lift specific force
1982 float T = RW.T / RW.m; // Thrust specific force. Minus gravity is a guesstimate.
1983 float P = RW.P / RW.m; // Pusher specific force
1984
1985 cf.ax.model = -(cpsi * stheta + ctheta * sphi * spsi) * T + (cpsi * ctheta - sphi * spsi * stheta) * P - sphi * spsi * L;
1986 cf.ay.model = -(spsi * stheta - cpsi * ctheta * sphi) * T + (ctheta * spsi + cpsi * sphi * stheta) * P + cpsi * sphi * L;
1987 cf.az.model = g - cphi * ctheta * T - cphi * stheta * P - cphi * L;
1988 float model_pqr_dot[3] = {0.0, 0.0, 0.0};
1989 for (i = 0; i < 3; i++){ // For loop for prediction of angular acceleration
1990 for (j = 0; j < ANDI_NUM_ACT; j++){
1991 if(j == COMMAND_ELEVATOR){
1992 model_pqr_dot[i] = model_pqr_dot[i] + (actuator_state_1l[j] - RW.ele_pref) * EFF_MAT_RW[i+3][j]; // Ele pref is incidence angle
1993 } else {
1995 }
1996 }
1997 }
2001}
2002
2004void oneloop_from_nav(bool in_flight)
2005{
2006 if (!in_flight) {
2008 }
2009 struct FloatVect3 PSA_des;
2013 int rm_order_h = 3;
2014 int rm_order_v = 3;
2015 // Oneloop controller wants desired targets and handles reference generation internally
2016 switch (nav.setpoint_mode) {
2020 rm_order_h = 3;
2021 break;
2025 rm_order_h = 2;
2026 break;
2027 }
2028 switch (nav.vertical_mode) {
2031 rm_order_v = 3;
2032 break;
2035 rm_order_v = 2;
2036 break;
2037 }
2038 oneloop_andi_run(in_flight, false, PSA_des, rm_order_h, rm_order_v);
2039}
2040
2043{
2044 // Coordinated turn
2045 // feedforward estimate angular rotation omega = g*tan(phi)/v
2046 float omega = 0.0;
2047 const float max_phi = RadOfDeg(ONELOOP_ANDI_MAX_BANK);
2048 float airspeed_turn = airspeed_filt.o[0];
2049 Bound(airspeed_turn, 1.0f, 30.0f);
2050 // Use the current roll angle to determine the corresponding heading rate of change.
2052 // Prevent flipping
2053 if( (eulers_zxy.theta > 0.0f) && ( fabs(eulers_zxy.phi) < eulers_zxy.theta)) {
2055 }
2058 #ifdef FWD_SIDESLIP_GAIN
2059 // Add sideslip correction
2060 omega -= accely_filt.o[0]*fwd_sideslip_gain;
2061 #endif
2062 return omega;
2063}
2064
2066static float chirp_pos_p_ref(float delta_t, float f0, float k, float A){
2067 float p_ref_fun = sinf(delta_t * M_PI * (f0 + k * delta_t) * 2.0);
2068 return (A * p_ref_fun);
2069}
2071static float chirp_pos_v_ref(float delta_t, float f0, float k, float A){
2072 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);
2073 return (A * v_ref_fun);
2074}
2076static float chirp_pos_a_ref(float delta_t, float f0, float k, float A){
2077 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;
2078 return (A * a_ref_fun);
2079}
2081static float chirp_pos_j_ref(float delta_t, float f0, float k, float A){
2082 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;
2083 return (A * j_ref_fun);
2084}
2085
2097void 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[]) {
2102 if ((f1-f0) < -FLT_EPSILON){
2103 f1 = f0;
2104 }
2105 // 0 body x, 1 body y, 2 body z, 3 pitch pref
2106 if (n > 3){
2107 n = 0;
2108 }
2109 if (n < 0){
2110 n = 0;
2111 }
2112 // I think there should not be a problem with f1 being equal to f0
2113 float k = (f1 - f0) / t_chirp;
2118
2119 float spsi = sinf(psi);
2120 float cpsi = cosf(psi);
2121 float mult_0 = 0.0;
2122 float mult_1 = 0.0;
2123 float mult_2 = 0.0;
2124 if (n == 0){
2125 mult_0 = cpsi;
2126 mult_1 = spsi;
2127 mult_2 = 0.0;
2128 }else if(n==1){
2129 mult_0 = -spsi;
2130 mult_1 = cpsi;
2131 mult_2 = 0.0;
2132 }else if(n==2){
2133 mult_0 = 0.0;
2134 mult_1 = 0.0;
2135 mult_2 = 1.0;
2136 }
2137 // Do not overwrite the reference if chirp is not on that axis
2138 if (n == 2){
2139 p_ref[2] = p_ref_0[2] + p_ref_chirp * mult_2;
2140 v_ref[2] = v_ref_chirp * mult_2;
2141 a_ref[2] = a_ref_chirp * mult_2;
2142 j_ref[2] = j_ref_chirp * mult_2;
2143 } else if (n < 2){
2144 p_ref[0] = p_ref_0[0] + p_ref_chirp * mult_0;
2145 p_ref[1] = p_ref_0[1] + p_ref_chirp * mult_1;
2146 v_ref[0] = v_ref_chirp * mult_0;
2147 v_ref[1] = v_ref_chirp * mult_1;
2148 a_ref[0] = a_ref_chirp * mult_0;
2149 a_ref[1] = a_ref_chirp * mult_1;
2150 j_ref[0] = j_ref_chirp * mult_0;
2151 j_ref[1] = j_ref_chirp * mult_1;
2152 } else { //Pitch preferred chirp, for now a little bit hacked in...
2154 pitch_pref = (pitch_pref / A + 1.0) * (theta_pref_max / 2.0);
2155 float pitch_offset = RadOfDeg(5.0);
2157 Bound(pitch_pref,0.0,25.0);
2158 }
2159}
2160
2161void 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[]){
2162 if (*chirp_on){
2163 if (*chirp_first_call){
2164 *time_elapsed = 0.0;
2165 *chirp_first_call = false;
2167 p_ref_0[0] = p_ref[0];
2168 p_ref_0[1] = p_ref[1];
2169 p_ref_0[2] = p_ref[2];
2170 }
2171 if (*time_elapsed < t_chirp){
2174 } else {
2175 *chirp_on = false;
2176 *chirp_first_call = true;
2177 *time_elapsed = 0.0;
2178 *t_0 = 0.0;
2180 }
2181 }
2182}
2183
2186 return ! motors_on;
2187}
2188
2189
2191{
2192 float psi = eulers_zxy.psi;
2193 float cpsi = cosf(psi);
2194 float spsi = sinf(psi);
2195 float airspeed = airspeed_filt.o[0];
2196 struct FloatVect2 NT_v_NE = {nav_target[0], nav_target[1]}; // Nav target in North and East frame
2197 struct FloatVect2 airspeed_v = { cpsi * airspeed, spsi * airspeed };
2198 struct FloatVect2 windspeed;
2200 struct FloatVect2 des_as_NE;
2201 struct FloatVect2 des_as_B;
2202 struct FloatVect2 des_acc_B;
2203 VECT2_DIFF(windspeed, groundspeed, airspeed_v); // Wind speed in North and East frame
2204 VECT2_DIFF(des_as_NE, NT_v_NE, windspeed); // Desired airspeed in North and East frame
2207 //Check if some minimum airspeed is desired (e.g. to prevent stall)
2208 if (norm_des_as < min_as) {
2210 }
2211 nav_target_new[0] = NT_v_NE.x;
2212 nav_target_new[1] = NT_v_NE.y;
2213 // 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
2214 if ((norm_des_as > max_as)||(force_forward)){
2215 float groundspeed_factor = 0.0f;
2217 float av = NT_v_NE.x * NT_v_NE.x + NT_v_NE.y * NT_v_NE.y; // norm squared of nav target
2218 float bv = -2.f * (windspeed.x * NT_v_NE.x + windspeed.y * NT_v_NE.y);
2219 float cv = windspeed.x * windspeed.x + windspeed.y * windspeed.y - max_as * max_as;
2220 float dv = bv * bv - 4.0f * av * cv;
2221 // dv can only be positive, but just in case
2222 if (dv < 0.0f) {
2223 dv = fabsf(dv);
2224 }
2225 float d_sqrt = sqrtf(dv);
2226 groundspeed_factor = (-bv + d_sqrt) / (2.0f * av);
2227 }
2232 }
2233 norm_des_as = FLOAT_VECT2_NORM(des_as_NE); // Recalculate norm of desired airspeed
2234 des_as_B.x = norm_des_as; // Desired airspeed in body x frame
2235 des_as_B.y = 0.0; // Desired airspeed in body y frame
2237 float delta_psi = atan2f(des_as_NE.y, des_as_NE.x) - psi;
2239 des_acc_B.y = delta_psi * 5.0;//gih_params.heading_bank_gain;
2240 des_acc_B.x = (des_as_B.x - airspeed) * k_pos_rm.k2[0];//gih_params.speed_gain;
2241 acc_body_bound(&des_acc_B, max_a_nav); // Scale down side acceleration if norm is too large
2242 nav_target_new[0] = cpsi * des_acc_B.x - spsi * des_acc_B.y;
2243 nav_target_new[1] = spsi * des_acc_B.x + cpsi * des_acc_B.y;
2244 } else {
2245 nav_target_new[0] = (NT_v_NE.x - groundspeed.x) * k_pos_rm.k2[0];
2246 nav_target_new[1] = (NT_v_NE.y - groundspeed.y) * k_pos_rm.k2[1];
2247 }
2249}
2250
2251void guidance_set_min_max_airspeed(float min_airspeed, float max_airspeed) {
2252 min_as = min_airspeed;
2254}
2255
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
uint8_t mode
current autopilot mode
Definition autopilot.h:63
#define UNUSED(x)
Hardware independent code for commands handling.
static const float scale[]
float G2_RW[EFF_MAT_COLS_NB]
struct RW_Model RW
float EFF_MAT_RW[EFF_MAT_ROWS_NB][EFF_MAT_COLS_NB]
struct wing_model wing
#define RW_aN
#define RW_aE
#define RW_ap
#define ELE_MIN_AS
#define RW_ar
struct RW_skew skew
#define RW_aq
#define RW_aD
#define Min(x, y)
Definition esc_dshot.c:109
Device independent GPS code (interface)
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
void float_eulers_of_quat_zxy(struct FloatEulers *e, struct FloatQuat *q)
euler rotation 'ZXY' This rotation order is useful if you need 90 deg pitch
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)
euler angles
Rotation quaternion.
#define A
static struct NedCoor_f * stateGetAccelNed_f(void)
Get acceleration in NED coordinates (float).
Definition state.h:1195
static struct FloatQuat * stateGetNedToBodyQuat_f(void)
Get vehicle body attitude quaternion (float).
Definition state.h:1294
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:1367
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:1590
int32_t max_airspeed
bool force_forward
forward flight for hybrid nav
Integrated Navigation System interface.
Simple first order low pass filter with bilinear transform.
float o[2]
output history
struct SecondOrderLowPass lp2
static float get_butterworth_2_low_pass(Butterworth2LowPass *filter)
Get current value of the second order Butterworth low pass filter.
static float get_butterworth_4_low_pass(Butterworth4LowPass *filter)
Get current value of the fourth order Butterworth low pass filter.
static void init_butterworth_4_low_pass(Butterworth4LowPass *filter, float tau, float sample_time, float value)
Init a fourth order Butterworth filter.
static void init_butterworth_2_low_pass(Butterworth2LowPass *filter, float tau, float sample_time, float value)
Init a second order Butterworth filter.
static float update_butterworth_2_low_pass(Butterworth2LowPass *filter, float value)
Update second order Butterworth low pass filter state with a new value.
static float update_butterworth_4_low_pass(Butterworth4LowPass *filter, float value)
Update fourth order Butterworth low pass filter state with a new value.
Second order low pass filter structure.
uint16_t foo
Definition main_demo5.c:58
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 k_e_3_3_f_v2(float omega_n, float zeta, float p1)
void reinit_all_cf(bool reinit)
Reinitialize all the Complementary Filters.
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
static float Wv_backup[ANDI_OUTPUTS]
void chirp_pos(float time_elapsed, float f0, float f1, float t_chirp, float A, int8_t n, float psi, float p_ref[], float v_ref[], float a_ref[], float j_ref[], float p_ref_0[])
Reference Model Definition for 3rd order system specific to positioning with bounds.
static Butterworth2LowPass accely_filt
float act_dynamics[ANDI_NUM_ACT_TOT]
float ratio_u_un[ANDI_NUM_ACT_TOT]
static float Wu_backup[ANDI_NUM_ACT_TOT]
void init_filter(void)
Initialize the filters.
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_andi_enter(bool half_loop_sp, int ctrl_type)
Function that resets important values upon engaging Oneloop ANDI.
static Butterworth2LowPass airspeed_filt
static float k_e_2_3_f_v2(float omega_n, float zeta, float p1)
static float k_e_1_2_f_v2(float omega, float zeta)
Error Controller Gain Design.
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.
float oneloop_andi_filt_cutoff_v
struct FloatEulers eulers_zxy_des
float p_ref_0[3]
struct Int32Eulers stab_att_sp_euler_1l
struct PolePlacement p_att_rm
static float ec_3rd(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)
Error Controller Definition for 3rd order system.
static float k_rm_3_3_f(float omega_n, float zeta, float p1)
int16_t temp_pitch
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
bool ctrl_off
struct Gains3rdOrder k_pos_e
float nu[ANDI_OUTPUTS]
float nu_norm_max
static Butterworth2LowPass filt_veloc_E
bool actuator_is_servo[ANDI_NUM_ACT_TOT]
float oneloop_andi_sideslip(void)
Function to calculate corrections for sideslip.
float num_thrusters_oneloop
static float act_dynamics_d[ANDI_NUM_ACT_TOT]
float t_chirp
float act_min_norm[ANDI_NUM_ACT_TOT]
#define ONELOOP_ANDI_DEBUG_MODE
float oneloop_andi_filt_cutoff_q
float oneloop_andi_filt_cutoff_a
static float ec_poles(float p_rm, float slow_pole, float k)
Calculate EC poles given RM poles.
static float pitch_pref
static float g2_ff
static void send_wls_u_oneloop(struct transport_tx *trans, struct link_device *dev)
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 max_j_nav
void oneloop_from_nav(bool in_flight)
Function that maps navigation inputs to the oneloop controller for the generated autopilot.
struct PolePlacement p_alt_rm
float max_j_ang
void ec_3rd_att(float y_4d[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], float max_ang_jerk)
Error Controller Definition for 3rd order system specific to attitude.
static float positive_non_zero(float input)
Function to make sure that inputs are positive non zero vaues.
bool chirp_on
static void send_eff_mat_stab_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
void guidance_set_min_max_airspeed(float min_airspeed, float max_airspeed)
void rm_3rd(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)
Reference Model Definition for 3rd order system.
float andi_u[ANDI_NUM_ACT_TOT]
static float psi_vec[4]
void calc_normalization(void)
Calculate Normalization of actuators and discrete actuator dynamics
struct Oneloop_CF_t cf
float fwd_sideslip_gain
struct Gains3rdOrder k_pos_e_indi
float f1_chirp
void init_cf4(struct CF4_t *cf, float fc)
Initialize the Complementary Filters 4th Order Butterworth.
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.
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
void rm_2nd_pos(float dt, float x_d_ref[], float x_2d_ref[], float x_3d_ref[], float x_d_des[], float k2_rm[], float k3_rm[], float x_2d_bound, float x_3d_bound, int n)
Reference Model Definition for 3rd order system specific to positioning with bounds.
float bound_v_from_a(float e_x[], float v_bound, float a_bound, int n)
Calculate velocity limit based on acceleration limit.
void reshape_wind(void)
static float g
static float andi_du_n[ANDI_NUM_ACT_TOT]
void get_act_state_oneloop(void)
Function to reconstruct actuator state using first order dynamics.
float A_chirp
struct PolePlacement p_head_e
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.
float andi_du[ANDI_NUM_ACT_TOT]
float max_v_nav_v
float max_v_nav
bool heading_manual
static float chirp_pos_v_ref(float delta_t, float f0, float k, float A)
Function to calculate the velocity reference during the chirp.
void init_cf2(struct CF2_t *cf, float fc)
Initialize the Complementary Filters 2nd Order Butterworth.
float t_0_chirp
struct Int32Quat stab_att_sp_quat_1l
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.
static float k_e_1_3_f_v2(float omega_n, UNUSED float zeta, float p1)
#define ONELOOP_ANDI_AIRSPEED_SWITCH_THRESHOLD
void calc_model(void)
Function that calculates the model prediction for the complementary filter.
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...
float Wu_quad_motors_fwd
static float use_increment
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 init_controller(void)
Initialize Controller Gains FIXME: Calculate the gains dynamically for transition.
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]
void rm_3rd_head(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)
Reference Model Definition for 3rd order system specific to the heading angle.
bool chirp_first_call
static Butterworth2LowPass filt_veloc_D
static Butterworth2LowPass filt_veloc_N
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.
float oneloop_andi_filt_cutoff_p
static struct Oneloop_notch_t oneloop_notch
static float k_rm_1_3_f(float omega_n, float zeta, float p1)
Reference Model Gain Design.
static float k_e_2_2_f_v2(float omega, float zeta)
float gi_unbounded_airspeed_sp
float oneloop_andi_filt_cutoff_r
void init_poles_att(void)
Initialize Position of Poles.
float k_as
struct PolePlacement p_pos_rm
float ratio_vn_v[ANDI_OUTPUTS]
void ec_3rd_pos(float y_4d[], 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 x_3d_bound, int n)
float nu_n[ANDI_OUTPUTS]
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
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.
PRINT_CONFIG_VAR(ONELOOP_ANDI_FILT_CUTOFF)
void reinit_cf4(struct CF4_t *cf, bool reinit)
Reinitialize 4th Order CF if new frequency setting or if forced.
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
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], float max_ang_jerk)
Reference Model Definition for 3rd order system with attitude conversion functions.
static void send_oneloop_debug(struct transport_tx *trans, struct link_device *dev)
float act_min[ANDI_NUM_ACT_TOT]
float actuator_state_1l[ANDI_NUM_ACT]
static float a_thrust
float oneloop_andi_filt_cutoff_pos
float max_r
void rm_2nd(float dt, float *x_ref, float *x_d_ref, float *x_2d_ref, float x_des, float k1_rm, float k2_rm)
Reference Model Definition for 2nd order system.
void init_all_cf(void)
Initialize all the Complementary Filters.
void acc_body_bound(struct FloatVect2 *vect, float bound)
Scale a 3D array to within a 3D bound.
float * bwls_1l[ANDI_OUTPUTS]
void init_poles_pos(void)
static float k_rm_2_3_f(float omega_n, float zeta, float p1)
static float nav_target_new[3]
void reinit_cf2(struct CF2_t *cf, bool reinit)
Reinitialize 2nd Order CF if new frequency setting or if forced.
static float u_pref[ANDI_NUM_ACT_TOT]
float oneloop_andi_filt_cutoff
struct OneloopGuidanceState gui_state
struct notch_axis_t yaw
struct OneloopStabilizationState sta_state
struct CF4_t q_dot
Butterworth2LowPass feedback_filt
float feedback
float out
struct CF2_t az
float model
#define CTRL_INDI
#define ANDI_NUM_ACT
Butterworth4LowPass feedback_filt
Butterworth4LowPass model_filt
struct OneloopGuidanceRef gui_ref
#define CTRL_ANDI
Control types.
struct CF2_t p
struct OneloopStabilizationRef sta_ref
struct notch_axis_t pitch
#define ANDI_NUM_ACT_TOT
struct CF2_t ay
float feedback
struct notch_axis_t roll
struct CF2_t q
struct CF2_t r
float model
struct SecondOrderNotchFilter filter
#define ANDI_OUTPUTS
struct CF2_t r_dot
struct CF2_t ax
struct CF4_t p_dot
float out
Butterworth2LowPass model_filt
#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.
#define AP_MODE_ATTITUDE_DIRECT
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:78
struct Stabilization stabilization
int32_t cmd[COMMANDS_NB]
output command vector, range from [-MAX_PPRZ:MAX_PPRZ] (store for messages)
API to get/set the generic vehicle states.
static const struct usb_device_descriptor dev
Definition usb_ser_hw.c:74
static float get_sys_time_float(void)
Get the time in seconds since startup.
Definition sys_time.h:138
int8_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint8_t _id, telemetry_cb _cb)
Register a telemetry callback function.
Definition telemetry.c:51
Periodic telemetry system header (includes downlink utility and generated code).
#define DefaultPeriodic
Set default periodic telemetry.
Definition telemetry.h:66
static float P[3][3]
short int16_t
Typedef defining 16 bit short type.
signed char int8_t
Typedef defining 8 bit char type.
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