Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
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 #ifdef STABILIZATION_ANDI_ROTWING_V3A
86 #include "modules/rot_wing_drone/wing_rotation_controller_v3a.h"
87 #endif
88 #include "modules/core/abi.h"
90 #include "math/wls/wls_alloc.h"
93 
94 
95 #include <stdio.h>
96 
97 // Number of real actuators (e.g. motors, servos)
98 #ifndef ONELOOP_ANDI_NUM_THRUSTERS
99 float num_thrusters_oneloop = 4.0; // Number of motors used for thrust
100 #else
101 float num_thrusters_oneloop = ONELOOP_ANDI_NUM_THRUSTERS;
102 #endif
103 
104 #ifdef ONELOOP_ANDI_FILT_CUTOFF
105 float oneloop_andi_filt_cutoff = ONELOOP_ANDI_FILT_CUTOFF;
106 #else
108 #endif
109 
110 #ifdef ONELOOP_ANDI_FILT_CUTOFF_ACC
111 float oneloop_andi_filt_cutoff_a = ONELOOP_ANDI_FILT_CUTOFF_ACC;
112 #else
114 #endif
115 
116 #ifdef ONELOOP_ANDI_FILT_CUTOFF_VEL
117 float oneloop_andi_filt_cutoff_v = ONELOOP_ANDI_FILT_CUTOFF_VEL;
118 #else
120 #endif
121 
122 #ifdef ONELOOP_ANDI_FILT_CUTOFF_POS
123 float oneloop_andi_filt_cutoff_p = ONELOOP_ANDI_FILT_CUTOFF_POS;
124 #else
126 #endif
127 
128 #ifdef ONELOOP_ANDI_FILT_CUTOFF_P
129 #define ONELOOP_ANDI_FILTER_ROLL_RATE TRUE
130 #else
131 #define ONELOOP_ANDI_FILT_CUTOFF_P 20.0
132 #endif
133 
134 #ifdef ONELOOP_ANDI_FILT_CUTOFF_Q
135 #define ONELOOP_ANDI_FILTER_PITCH_RATE TRUE
136 #else
137 #define ONELOOP_ANDI_FILT_CUTOFF_Q 20.0
138 #endif
139 
140 #ifdef ONELOOP_ANDI_FILT_CUTOFF_R
141 #define ONELOOP_ANDI_FILTER_YAW_RATE TRUE
142 #else
143 #define ONELOOP_ANDI_FILT_CUTOFF_R 20.0
144 #endif
145 
146 #ifdef ONELOOP_ANDI_ACT_IS_SERVO
147 bool actuator_is_servo[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_ACT_IS_SERVO;
148 #else
150 #endif
151 
152 #ifdef ONELOOP_ANDI_ACT_DYN
153 float act_dynamics[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_ACT_DYN;
154 #else
155 #error "You must specify the actuator dynamics"
157 #endif
158 
159 #ifdef ONELOOP_ANDI_ACT_MAX
160 float act_max[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_ACT_MAX;
161 #else
163 #endif
164 
165 #ifdef ONELOOP_ANDI_ACT_MIN
166 float act_min[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_ACT_MIN;
167 #else
168 float act_min[ANDI_NUM_ACT_TOT] = = {0.0};
169 #endif
170 
171 #ifdef ONELOOP_ANDI_ACT_MAX_NORM
172 float act_max_norm[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_ACT_MAX_NORM;
173 #else
175 #endif
176 
177 #ifdef ONELOOP_ANDI_ACT_MIN_NORM
178 float act_min_norm[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_ACT_MIN_NORM;
179 #else
181 #endif
182 
183 #ifdef ONELOOP_ANDI_WV // {ax_dot,ay_dot,az_dot,p_ddot,q_ddot,r_ddot}
184 static float Wv[ANDI_OUTPUTS] = ONELOOP_ANDI_WV;
185 static float Wv_wls[ANDI_OUTPUTS] = ONELOOP_ANDI_WV;
186 #else
187 static float Wv[ANDI_OUTPUTS] = {1.0};
188 static float Wv_wls[ANDI_OUTPUTS] = {1.0};
189 #endif
190 
191 #ifdef ONELOOP_ANDI_WU // {de,dr,daL,daR,mF,mB,mL,mR,mP,phi,theta}
192 static float Wu[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_WU;
193 #else
194 static float Wu[ANDI_NUM_ACT_TOT] = {1.0};
195 #endif
196 
197 #ifdef ONELOOP_ANDI_U_PREF
198 static float u_pref[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_U_PREF;
199 #else
200 static float u_pref[ANDI_NUM_ACT_TOT] = {0.0};
201 #endif
202 
203 #ifndef ONELOOP_ANDI_DEBUG_MODE
204 #error "Debug Mode not defined"
205 #define ONELOOP_ANDI_DEBUG_MODE FALSE;
206 #endif
207 
208 #ifndef ONELOOP_ANDI_AC_HAS_PUSHER
209 #error "Did not specify if ac has a pusher"
210 #define ONELOOP_ANDI_AC_HAS_PUSHER FALSE;
211 #endif
212 
213 #if !ONELOOP_ANDI_AC_HAS_PUSHER
214 #define ONELOOP_ANDI_PUSHER_IDX 0
215 #endif
216 
217 #ifndef ONELOOP_ANDI_PUSHER_IDX
218 #error "Did not specify pusher index"
219 #define ONELOOP_ANDI_PUSHER_IDX 4
220 #endif
221 
222 #if ANDI_NUM_ACT_TOT != WLS_N_U
223 #error Matrix-WLS_N_U is not equal to the number of actuators: define WLS_N_U == ANDI_NUM_ACT_TOT in airframe file
224 #define WLS_N_U == ANDI_NUM_ACT_TOT
225 #endif
226 #if ANDI_OUTPUTS != WLS_N_V
227 #error Matrix-WLS_N_V is not equal to the number of controlled axis: define WLS_N_V == ANDI_OUTPUTS in airframe file
228 #define WLS_N_V == ANDI_OUTPUTS
229 #endif
230 
231 
232 /* Declaration of Navigation Variables*/
233 #ifdef ONELOOP_MAX_ACC
234 float max_a_nav = ONELOOP_MAX_ACC;
235 #else
236 float max_a_nav = 4.0; // (35[N]/6.5[Kg]) = 5.38[m/s2] [0.8 SF]
237 #endif
238 
239 #ifdef ONELOOP_MAX_JERK
240 float max_j_nav = ONELOOP_MAX_JERK;
241 #else
242 float max_j_nav = 500.0; // Pusher Test shows erros above 2[Hz] ramp commands [0.6 SF]
243 #endif
244 
245 #ifdef ONELOOP_MAX_AIRSPEED
246 float max_v_nav = ONELOOP_MAX_AIRSPEED; // Consider implications of difference Ground speed and airspeed
247 #else
248 float max_v_nav = 5.0;
249 #endif
250 
251 
252 // DELETE ONCE NAV HYBRID IS MADE COMPATIBLE WITH ANY GUIDANCE///////////////////////////////////////////
253 #ifndef GUIDANCE_INDI_SPEED_GAIN
254 #define GUIDANCE_INDI_SPEED_GAIN 1.8
255 #define GUIDANCE_INDI_SPEED_GAINZ 1.8
256 #endif
257 
258 #ifndef GUIDANCE_INDI_POS_GAIN
259 #define GUIDANCE_INDI_POS_GAIN 0.5
260 #define GUIDANCE_INDI_POS_GAINZ 0.5
261 #endif
262 
263 #ifndef GUIDANCE_INDI_LIFTD_ASQ
264 #define GUIDANCE_INDI_LIFTD_ASQ 0.20
265 #endif
266 
267 /* If lift effectiveness at low airspeed not defined,
268  * just make one interpolation segment that connects to
269  * the quadratic part from 12 m/s onward
270  */
271 #ifndef GUIDANCE_INDI_LIFTD_P50
272 #define GUIDANCE_INDI_LIFTD_P80 (GUIDANCE_INDI_LIFTD_ASQ*12*12)
273 #define GUIDANCE_INDI_LIFTD_P50 (GUIDANCE_INDI_LIFTD_P80/2)
274 #endif
275 
278  .pos_gainz = GUIDANCE_INDI_POS_GAINZ,
279 
280  .speed_gain = GUIDANCE_INDI_SPEED_GAIN,
281  .speed_gainz = GUIDANCE_INDI_SPEED_GAINZ,
282 
283  .heading_bank_gain = 5.0,
284  .liftd_asq = GUIDANCE_INDI_LIFTD_ASQ, // coefficient of airspeed squared
285  .liftd_p80 = GUIDANCE_INDI_LIFTD_P80,
286  .liftd_p50 = GUIDANCE_INDI_LIFTD_P50,
287 };
288 bool force_forward = false;
290 
291 /* Define Section of the functions used in this module*/
292 void init_poles(void);
293 void calc_normalization(void);
294 void sum_g1g2_1l(void);
295 void get_act_state_oneloop(void);
297 void init_filter(void);
298 void init_controller(void);
299 void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3]);
300 void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3]);
301 void err_nd(float err[], float a[], float b[], float k[], int n);
302 void integrate_nd(float dt, float a[], float a_dot[], int n);
303 void vect_bound_nd(float vect[], float bound, int n);
304 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);
305 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);
306 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);
307 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]);
308 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);
309 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);
310 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);
311 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]);
312 void calc_model(void);
313 
314 /* Define messages of the module*/
315 #if PERIODIC_TELEMETRY
317 
318 static void send_eff_mat_g_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
319 {
320  float zero = 0.0;
321  pprz_msg_send_EFF_MAT_G(trans, dev, AC_ID,
328  1, &zero,
329  1, &zero);
330 }
331 static void send_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
332 {
333  pprz_msg_send_STAB_ATTITUDE(trans, dev, AC_ID,
352  ANDI_OUTPUTS, nu,
354 }
355 
356 static void send_guidance_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
357 {
358  pprz_msg_send_GUIDANCE(trans, dev, AC_ID,
379  &oneloop_andi.gui_ref.jer[2]);
380 }
381 #endif
382 
383 /*Define general struct of the Oneloop ANDI controller*/
385 
386 /* Oneloop Misc variables*/
387 static float use_increment = 0.0;
388 static float nav_target[3]; // Can be a position, speed or acceleration depending on the guidance H mode
389 static float dt_1l = 1./PERIODIC_FREQUENCY;
390 static float g = 9.81; // [m/s^2] Gravitational Acceleration
391 
392 /* Oneloop Control Variables*/
399 static float a_thrust = 0.0;
400 
401 /*Attitude related variables*/
402 struct Int32Eulers stab_att_sp_euler_1l;// here for now to correct warning, can be better eploited in the future
403 struct Int32Quat stab_att_sp_quat_1l; // here for now to correct warning, can be better eploited in the future
405 struct FloatEulers eulers_zxy;
406 static float psi_des_rad = 0.0;
407 float psi_des_deg = 0.0;
408 static float psi_vec[4] = {0.0, 0.0, 0.0, 0.0};
409 
410 /*WLS Settings*/
411 static float gamma_wls = 1000.0;
415 static int number_iter = 0;
416 
417 /*Complementary Filter Variables*/
418 static float model_pred[ANDI_OUTPUTS];
419 static float ang_acc[3];
420 static float lin_acc[3];
421 
422 
423 /*Declaration of Reference Model and Error Controller Gains*/
424 struct PolePlacement p_att_e;
425 struct PolePlacement p_att_rm;
426 /*Position Loop*/
427 struct PolePlacement p_pos_e;
428 struct PolePlacement p_pos_rm;
429 /*Altitude Loop*/
430 struct PolePlacement p_alt_e;
431 struct PolePlacement p_alt_rm;
432 /*Heading Loop*/
433 struct PolePlacement p_head_e;
434 struct PolePlacement p_head_rm;
435 /*Gains of EC and RM*/
436 struct Gains3rdOrder k_att_e;
437 struct Gains3rdOrder k_att_rm;
438 struct Gains2ndOrder k_head_e;
439 struct Gains2ndOrder k_head_rm;
440 struct Gains3rdOrder k_pos_e;
441 struct Gains3rdOrder k_pos_rm;
442 
443 /* Effectiveness Matrix definition */
444 float g2_1l[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_G2; //scaled by INDI_G_SCALING
445 float g1_1l[ANDI_OUTPUTS][ANDI_NUM_ACT_TOT] = {ONELOOP_ANDI_G1_ZERO, ONELOOP_ANDI_G1_ZERO, ONELOOP_ANDI_G1_THRUST, ONELOOP_ANDI_G1_ROLL, ONELOOP_ANDI_G1_PITCH, ONELOOP_ANDI_G1_YAW};
450 
451 /*Filters Initialization*/
452 static struct FirstOrderLowPass filt_accel_ned[3];
453 static struct FirstOrderLowPass rates_filt_fo[3];
454 static struct FirstOrderLowPass model_pred_a_filt[3];
457 
458 
460 static float positive_non_zero(float input)
461 {
462  if (input < FLT_EPSILON) {
463  input = 0.00001;
464  }
465  return input;
466 }
467 
470 static float k_e_1_3_f(float p1, float p2, float p3) {
471  p1 = positive_non_zero(p1);
472  p2 = positive_non_zero(p2);
473  p3 = positive_non_zero(p3);
474  return (p1 * p2 * p3);
475 }
476 
477 static float k_e_2_3_f(float p1, float p2, float p3) {
478  p1 = positive_non_zero(p1);
479  p2 = positive_non_zero(p2);
480  p3 = positive_non_zero(p3);
481  return (p1 * p2 + p1 * p3 + p2 * p3);
482 }
483 
484 static float k_e_3_3_f(float p1, float p2, float p3) {
485  p1 = positive_non_zero(p1);
486  p2 = positive_non_zero(p2);
487  p3 = positive_non_zero(p3);
488  return (p1 + p2 + p3);
489 }
490 
491 static float k_e_1_2_f(float p1, float p2) {
492  p1 = positive_non_zero(p1);
493  p2 = positive_non_zero(p2);
494  return (p1 * p2);
495 }
496 
497 static float k_e_2_2_f(float p1, float p2) {
498  p1 = positive_non_zero(p1);
499  p2 = positive_non_zero(p2);
500  return (p1 + p2);
501 }
502 
503 static float k_e_1_3_f_v2(float omega_n, UNUSED float zeta, float p1) {
504  omega_n = positive_non_zero(omega_n);
505  p1 = positive_non_zero(p1);
506  return (omega_n * omega_n * p1);
507 }
508 
509 static float k_e_2_3_f_v2(float omega_n, float zeta, float p1) {
510  omega_n = positive_non_zero(omega_n);
511  zeta = positive_non_zero(zeta);
512  p1 = positive_non_zero(p1);
513  return (omega_n * omega_n + 2 * zeta * omega_n * p1);
514 }
515 
516 static float k_e_3_3_f_v2(float omega_n, float zeta, float p1) {
517  omega_n = positive_non_zero(omega_n);
518  zeta = positive_non_zero(zeta);
519  p1 = positive_non_zero(p1);
520  return (2 * zeta * omega_n + p1);
521 }
522 
525 static float k_rm_1_3_f(float omega_n, float zeta, float p1) {
526  omega_n = positive_non_zero(omega_n);
527  zeta = positive_non_zero(zeta);
528  p1 = positive_non_zero(p1);
529  return (omega_n * omega_n * p1) / (omega_n * omega_n + omega_n * p1 * zeta * 2.0);
530 }
531 
532 static float k_rm_2_3_f(float omega_n, float zeta, float p1) {
533  omega_n = positive_non_zero(omega_n);
534  zeta = positive_non_zero(zeta);
535  p1 = positive_non_zero(p1);
536  return (omega_n * omega_n + omega_n * p1 * zeta * 2.0) / (p1 + omega_n * zeta * 2.0);
537 }
538 
539 static float k_rm_3_3_f(float omega_n, float zeta, float p1) {
540  omega_n = positive_non_zero(omega_n);
541  zeta = positive_non_zero(p1);
542  p1 = positive_non_zero(zeta);
543  return p1 + omega_n * zeta * 2.0;
544 }
545 
546 static float k_rm_1_2_f(float omega_n, float zeta) {
547  omega_n = positive_non_zero(omega_n);
548  zeta = positive_non_zero(zeta);
549  return omega_n / (2.0 * zeta);
550 }
551 
552 static float k_rm_2_2_f(float omega_n, float zeta) {
553  omega_n = positive_non_zero(omega_n);
554  zeta = positive_non_zero(zeta);
555  return 2.0 * zeta * omega_n;
556 }
557 
559 void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3])
560 {
561  float sphi = sinf(e[0]);
562  float cphi = cosf(e[0]);
563  float stheta = sinf(e[1]);
564  float ctheta = cosf(e[1]);
565  r[0] = edot[0] - stheta * edot[2];
566  r[1] = cphi * edot[1] + sphi * ctheta * edot[2];
567  r[2] = -sphi * edot[1] + cphi * ctheta * edot[2];
568 }
569 
571 void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3])
572 {
573  float sphi = sinf(e[0]);
574  float cphi = cosf(e[0]);
575  float stheta = sinf(e[1]);
576  float ctheta = cosf(e[1]);
577  if (fabs(ctheta) < FLT_EPSILON){
578  ctheta = FLT_EPSILON;
579  }
580  edot[0] = r[0] + sphi*stheta/ctheta*r[1] + cphi*stheta/ctheta*r[2];
581  edot[1] = cphi*r[1] - sphi*r[2];
582  edot[2] = sphi/ctheta*r[1] + cphi/ctheta*r[2];
583 }
584 
586 void err_nd(float err[], float a[], float b[], float k[], int n)
587 {
588  int8_t i;
589  for (i = 0; i < n; i++) {
590  err[i] = k[i] * (a[i] - b[i]);
591  }
592 }
593 
595 void integrate_nd(float dt, float a[], float a_dot[], int n)
596 {
597  int8_t i;
598  for (i = 0; i < n; i++) {
599  a[i] = a[i] + dt * a_dot[i];
600  }
601 }
602 
604 void vect_bound_nd(float vect[], float bound, int n) {
605  float norm = float_vect_norm(vect,n);
606  norm = positive_non_zero(norm);
607  if((norm-bound) > FLT_EPSILON) {
608  float scale = bound/norm;
609  int8_t i;
610  for(i = 0; i < n; i++) {
611  vect[i] *= scale;
612  }
613  }
614 }
615 
630 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]){
631  float e_x[3];
632  float e_x_rates[3];
633  float e_x_d[3];
634  float e_x_2d[3];
635  float x_d_eul_ref[3];
636  err_nd(e_x, x_des, x_ref, k1_rm, 3);
637  float temp_diff = x_des[2] - x_ref[2];
638  NormRadAngle(temp_diff);
639  e_x[2] = k1_rm[2] * temp_diff; // Correction for Heading error +-Pi
640  float_rates_of_euler_dot_vec(e_x_rates, x_ref, e_x);
641  err_nd(e_x_d, e_x_rates, x_d_ref, k2_rm, 3);
642  err_nd(e_x_2d, e_x_d, x_2d_ref, k3_rm, 3);
643  float_vect_copy(x_3d_ref,e_x_2d,3);
644  if(ow_psi){x_3d_ref[2] = psi_overwrite[3];}
645  integrate_nd(dt, x_2d_ref, x_3d_ref, 3);
646  if(ow_psi){x_2d_ref[2] = psi_overwrite[2];}
647  integrate_nd(dt, x_d_ref, x_2d_ref, 3);
648  if(ow_psi){x_d_ref[2] = psi_overwrite[1];}
649  float_euler_dot_of_rates_vec(x_d_ref, x_ref, x_d_eul_ref);
650  integrate_nd(dt, x_ref, x_d_eul_ref, 3);
651  if(ow_psi){x_ref[2] = psi_overwrite[0];}
652  NormRadAngle(x_ref[2]);
653 }
654 
667 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){
668  float e_x = k1_rm * (x_des- *x_ref);
669  float e_x_d = k2_rm * (e_x- *x_d_ref);
670  float e_x_2d = k3_rm * (e_x_d- *x_2d_ref);
671  *x_3d_ref = e_x_2d;
672  *x_2d_ref = (*x_2d_ref + dt * (*x_3d_ref));
673  *x_d_ref = (*x_d_ref + dt * (*x_2d_ref));
674  *x_ref = (*x_ref + dt * (*x_d_ref ));
675 }
676 
689 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){
690  float temp_diff = x_des - *x_ref;
691  NormRadAngle(temp_diff);
692  float e_x = k1_rm * temp_diff;
693  float e_x_d = k2_rm * (e_x- *x_d_ref);
694  float e_x_2d = k3_rm * (e_x_d- *x_2d_ref);
695  *x_3d_ref = e_x_2d;
696  *x_2d_ref = (*x_2d_ref + dt * (*x_3d_ref));
697  *x_d_ref = (*x_d_ref + dt * (*x_2d_ref));
698  *x_ref = (*x_ref + dt * (*x_d_ref ));
699 }
700 
717 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){
718  float e_x[n];
719  float e_x_d[n];
720  float e_x_2d[n];
721  err_nd(e_x, x_des, x_ref, k1_rm, n);
722  vect_bound_nd(e_x,x_d_bound, n);
723  err_nd(e_x_d, e_x, x_d_ref, k2_rm, n);
724  vect_bound_nd(e_x_d,x_2d_bound, n);
725  err_nd(e_x_2d, e_x_d, x_2d_ref, k3_rm, n);
726  float_vect_copy(x_3d_ref,e_x_2d,n);
727  vect_bound_nd(x_3d_ref, x_3d_bound, n);
728  integrate_nd(dt, x_2d_ref, x_3d_ref, n);
729  integrate_nd(dt, x_d_ref, x_2d_ref, n);
730  integrate_nd(dt, x_ref, x_d_ref, n);
731 }
732 
746 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){
747  float e_x_d[n];
748  float e_x_2d[n];
749  err_nd(e_x_d, x_d_des, x_d_ref, k2_rm, n);
750  vect_bound_nd(e_x_d,x_2d_bound, n);
751  err_nd(e_x_2d, e_x_d, x_2d_ref, k3_rm, n);
752  float_vect_copy(x_3d_ref,e_x_2d,n);
753  vect_bound_nd(x_3d_ref, x_3d_bound, n);
754  integrate_nd(dt, x_2d_ref, x_3d_ref, n);
755  integrate_nd(dt, x_d_ref, x_2d_ref, n);
756 }
757 
768 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){
769  float e_x_2d[n];
770  err_nd(e_x_2d, x_2d_des, x_2d_ref, k3_rm, n);
771  float_vect_copy(x_3d_ref,e_x_2d,n);
772  vect_bound_nd(x_3d_ref, x_3d_bound, n);
773  integrate_nd(dt, x_2d_ref, x_3d_ref, n);
774 }
775 
776 
789 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){
790  float e_x = k1_rm * (x_des- *x_ref);
791  float e_x_d = k2_rm * (e_x- *x_d_ref);
792  *x_2d_ref = e_x_d;
793  *x_d_ref = (*x_d_ref + dt * (*x_2d_ref));
794  *x_ref = (*x_ref + dt * (*x_d_ref ));
795 }
796 
812 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){
813  float y_4d = k1_e*(x_ref-x)+k2_e*(x_d_ref-x_d)+k3_e*(x_2d_ref-x_2d)+x_3d_ref;
814  return y_4d;
815 }
816 
832 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]){
833  float y_4d_1[3];
834  float y_4d_2[3];
835  float y_4d_3[3];
836  err_nd(y_4d_1, x_ref, x, k1_e, 3);
837  float temp_diff = x_ref[2] - x[2];
838  NormRadAngle(temp_diff);
839  float e_x = temp_diff;
840  y_4d_1[2] = k1_e[2] * e_x; // Correction for Heading error +-Pi
841  err_nd(y_4d_2, x_d_ref, x_d, k2_e, 3);
842  err_nd(y_4d_3, x_2d_ref, x_2d, k3_e, 3);
843  float_vect_copy(y_4d,x_3d_ref,3);
844  float_vect_sum(y_4d, y_4d, y_4d_1, 3);
845  float_vect_sum(y_4d, y_4d, y_4d_2, 3);
846  float_vect_sum(y_4d, y_4d, y_4d_3, 3);
847 }
848 
861 static float ec_2rd(float x_ref, float x_d_ref, float x_2d_ref, float x, float x_d, float k1_e, float k2_e){
862  float y_3d = k1_e*(x_ref-x)+k2_e*(x_d_ref-x_d)+x_2d_ref;
863  return y_3d;
864 }
865 
866 
874 static float w_approx(float p1, float p2, float p3, float rm_k){
875  p1 = positive_non_zero(p1);
876  p2 = positive_non_zero(p2);
877  p3 = positive_non_zero(p3);
878  rm_k = positive_non_zero(rm_k);
879  float tao = (p1*p2+p1*p3+p2*p3)/(p1*p2*p3)/(rm_k);
880  tao = positive_non_zero(tao);
881  return 1.0/tao;
882 }
887 void init_poles(void){
888  p_att_e.omega_n = 7.68;
889  p_att_e.zeta = 1.0;
891 
892  p_att_rm.omega_n = 6.14;
893  p_att_rm.zeta = 1.0;
895 
896  p_pos_e.omega_n = 1.41;
897  p_pos_e.zeta = 0.85;
898  p_pos_e.p3 = 6.0;
899 
900  p_pos_rm.omega_n = 0.6;
901  p_pos_rm.zeta = 1.0;
902  p_pos_rm.p3 = 6.0;
903 
904  p_alt_e.omega_n = 3.54;
905  p_alt_e.zeta = 0.85;
906  p_alt_e.p3 = 6.0;
907 
908  p_alt_rm.omega_n = 2.0;
909  p_alt_rm.zeta = 1.0;
911 
912  p_head_e.omega_n = 1.5;
913  p_head_e.zeta = 1.0;
915 }
920 void init_controller(void){
921  /*Register a variable from nav_hybrid. SHould be improved when nav hybrid is final.*/
923  /*Some calculations in case new poles have been specified*/
928  /*Attitude Loop*/
932  k_att_e.k1[1] = k_att_e.k1[0];
933  k_att_e.k2[1] = k_att_e.k2[0];
934  k_att_e.k3[1] = k_att_e.k3[0];
938  k_att_rm.k1[1] = k_att_rm.k1[0];
939  k_att_rm.k2[1] = k_att_rm.k2[0];
940  k_att_rm.k3[1] = k_att_rm.k3[0];
941 
942  /*Position Loop*/
943 
947  k_pos_e.k1[1] = k_pos_e.k1[0];
948  k_pos_e.k2[1] = k_pos_e.k2[0];
949  k_pos_e.k3[1] = k_pos_e.k3[0];
953  k_pos_rm.k1[1] = k_pos_rm.k1[0];
954  k_pos_rm.k2[1] = k_pos_rm.k2[0];
955  k_pos_rm.k3[1] = k_pos_rm.k3[0];
956 
957  gih_params.pos_gain = k_pos_rm.k1[0]; //delete once nav hybrid is fixed
958  gih_params.speed_gain = k_pos_rm.k2[0]; //delete once nav hybrid is fixed
959 
960  /*Altitude Loop*/
967  gih_params.pos_gainz = k_pos_rm.k1[2]; //delete once nav hybrid is fixed
968  gih_params.speed_gainz = k_pos_rm.k2[2]; //delete once nav hybrid is fixed
969 
970  /*Heading Loop Manual*/
975 
976  /*Heading Loop NAV*/
983 
984  /*Approximated Dynamics*/
987 }
988 
989 
991 void init_filter(void)
992 {
993  float tau = 1.0 / (2.0 * M_PI *oneloop_andi_filt_cutoff);
994  float tau_a = 1.0 / (2.0 * M_PI * oneloop_andi_filt_cutoff_a);
995  float sample_time = 1.0 / PERIODIC_FREQUENCY;
996 
997  // Filtering of the Inputs with 3 dimensions (e.g. rates and accelerations)
998  int8_t i;
999  for (i = 0; i < 3; i++) {
1000  init_butterworth_2_low_pass(&att_dot_meas_lowpass_filters[i], tau, sample_time, 0.0);
1001  init_first_order_low_pass(&filt_accel_ned[i], tau_a, sample_time, 0.0 );
1002  }
1003 
1004  // Init rate filter for feedback
1005  float time_constants[3] = {1.0 / (2 * M_PI * ONELOOP_ANDI_FILT_CUTOFF_P), 1.0 / (2 * M_PI * ONELOOP_ANDI_FILT_CUTOFF_Q), 1.0 / (2 * M_PI * ONELOOP_ANDI_FILT_CUTOFF_R)};
1006  init_first_order_low_pass(&rates_filt_fo[0], time_constants[0], sample_time, stateGetBodyRates_f()->p);
1007  init_first_order_low_pass(&rates_filt_fo[1], time_constants[1], sample_time, stateGetBodyRates_f()->q);
1008  init_first_order_low_pass(&rates_filt_fo[2], time_constants[2], sample_time, stateGetBodyRates_f()->r);
1009 
1010  // Remember to change the time constant if you provide different P Q R filters
1011  for (i = 0; i < ANDI_OUTPUTS; i++){
1012  if (i < 3){
1013  init_butterworth_2_low_pass(&model_pred_filt[i], tau_a, sample_time, 0.0);
1014  init_first_order_low_pass(&model_pred_a_filt[i], tau_a, sample_time, 0.0);
1015  } else {
1016  init_butterworth_2_low_pass(&model_pred_filt[i], tau, sample_time, 0.0);
1017  }
1018  }
1019 }
1020 
1021 
1024  struct NedCoor_f *accel = stateGetAccelNed_f();
1025  struct FloatRates *body_rates = stateGetBodyRates_f();
1026  float rate_vect[3] = {body_rates->p, body_rates->q, body_rates->r};
1030 
1031 
1032  calc_model();
1033  int8_t i;
1034  for (i = 0; i < ANDI_OUTPUTS; i++){
1036  }
1037 
1038  for (i = 0; i < 3; i++) {
1041  update_first_order_low_pass(&rates_filt_fo[i], rate_vect[i]);
1042 
1043  ang_acc[i] = (att_dot_meas_lowpass_filters[i].o[0]- att_dot_meas_lowpass_filters[i].o[1]) * PERIODIC_FREQUENCY + model_pred[3+i] - model_pred_filt[3+i].o[0];
1045 }}
1046 
1049 {
1050  oneloop_andi.half_loop = true;
1051  init_poles();
1052  // Make sure that the dynamics are positive and non-zero
1053  int8_t i;
1054  for (i = 0; i < ANDI_NUM_ACT_TOT; i++) {
1056  }
1057  // Initialize Effectiveness matrix
1059  sum_g1g2_1l();
1060  for (i = 0; i < ANDI_OUTPUTS; i++) {
1061  bwls_1l[i] = g1g2_1l[i];
1062  }
1063 
1064  // Initialize filters and other variables
1065  init_filter();
1066  init_controller();
1079  eulers_zxy_des.phi = 0.0;
1080  eulers_zxy_des.theta = 0.0;
1081  eulers_zxy_des.psi = 0.0;
1083 
1084  // Start telemetry
1085  #if PERIODIC_TELEMETRY
1086  register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_STAB_ATTITUDE, send_oneloop_andi);
1089  #endif
1090 }
1091 
1098 void oneloop_andi_enter(bool half_loop_sp)
1099 {
1100  oneloop_andi.half_loop = half_loop_sp;
1102  psi_des_deg = eulers_zxy.psi * 180.0 / M_PI;
1104  sum_g1g2_1l();
1105  init_filter();
1106  init_controller();
1107  /* Stabilization Reset */
1115  eulers_zxy_des.phi = 0.0;
1116  eulers_zxy_des.theta = 0.0;
1117  eulers_zxy_des.psi = 0.0;
1119  /*Guidance Reset*/
1120 }
1121 
1129 void oneloop_andi_RM(bool half_loop, struct FloatVect3 PSA_des, int rm_order_h, int rm_order_v)
1130 {
1131  // Initialize some variables
1132  a_thrust = 0.0;
1133  nav_target[0] = PSA_des.x;
1134  nav_target[1] = PSA_des.y;
1135  nav_target[2] = PSA_des.z;
1136  float thrust_cmd_1l = 0.0;
1137  float des_r = 0.0;
1138  // Generate reference signals with reference model
1139  if(half_loop){
1140  // Disregard X and Y jerk objectives
1141  Wv_wls[0] = 0.0;
1142  Wv_wls[1] = 0.0;
1143  // Overwrite references with actual signals (for consistent plotting)
1148  // Set desired attitude with stick input
1149  eulers_zxy_des.phi = (float) (radio_control_get(RADIO_ROLL))/MAX_PPRZ*45.0*M_PI/180.0;
1150  eulers_zxy_des.theta = (float) (radio_control_get(RADIO_PITCH))/MAX_PPRZ*45.0*M_PI/180.0;
1153  // Create commands adhoc to get actuators to the wanted level
1154  thrust_cmd_1l = (float) radio_control_get(RADIO_THROTTLE);
1155  Bound(thrust_cmd_1l,0.0,MAX_PPRZ);
1156  int8_t i;
1157  for (i = 0; i < ANDI_NUM_ACT; i++) {
1158  a_thrust +=(thrust_cmd_1l - use_increment*actuator_state_1l[i]) * bwls_1l[2][i] / (ratio_u_un[i] * ratio_vn_v[i]);
1159  }
1160  // Overwrite Yaw Ref with desired Yaw setting (for consistent plotting)
1162  // Set desired Yaw rate with stick input
1163  des_r = (float) (radio_control_get(RADIO_YAW))/MAX_PPRZ*3.0;
1164  BoundAbs(des_r,3.0);
1165  // Generate reference signals
1169  }else{
1170  // Make sure X and Y jerk objectives are active
1171  Wv_wls[0] = Wv[0];
1172  Wv_wls[1] = Wv[1];
1173  // Register Attitude Setpoints from previous loop
1174  float att_des[3] = {eulers_zxy_des.phi, eulers_zxy_des.theta, psi_des_rad};
1175  // Generate Reference signals for positioning using RM
1176  if (rm_order_h == 3){
1178  } else if (rm_order_h == 2){
1181  } else if (rm_order_h == 1){
1185  }
1186 
1187  // The RM functions want an array as input. Create a single entry array and write the vertical guidance entries.
1188  float single_value_ref[1] = {oneloop_andi.gui_ref.pos[2]};
1189  float single_value_d_ref[1] = {oneloop_andi.gui_ref.vel[2]};
1190  float single_value_2d_ref[1] = {oneloop_andi.gui_ref.acc[2]};
1191  float single_value_3d_ref[1] = {oneloop_andi.gui_ref.jer[2]};
1192  float single_value_nav_target[1] = {nav_target[2]};
1193  float single_value_k1_rm[1] = {k_pos_rm.k1[2]};
1194  float single_value_k2_rm[1] = {k_pos_rm.k2[2]};
1195  float single_value_k3_rm[1] = {k_pos_rm.k3[2]};
1196 
1197  if (rm_order_v == 3){
1198  rm_3rd_pos(dt_1l, single_value_ref, single_value_d_ref, single_value_2d_ref, single_value_3d_ref, single_value_nav_target, single_value_k1_rm, single_value_k2_rm, single_value_k3_rm, max_v_nav, max_a_nav, max_j_nav, 1);
1199  oneloop_andi.gui_ref.pos[2] = single_value_ref[0];
1200  oneloop_andi.gui_ref.vel[2] = single_value_d_ref[0];
1201  oneloop_andi.gui_ref.acc[2] = single_value_2d_ref[0];
1202  oneloop_andi.gui_ref.jer[2] = single_value_3d_ref[0];
1203  } else if (rm_order_v == 2){
1204  rm_2nd_pos(dt_1l, single_value_d_ref, single_value_2d_ref, single_value_3d_ref, single_value_nav_target, single_value_k2_rm, single_value_k3_rm, max_a_nav, max_j_nav, 1);
1206  oneloop_andi.gui_ref.vel[2] = single_value_d_ref[0];
1207  oneloop_andi.gui_ref.acc[2] = single_value_2d_ref[0];
1208  oneloop_andi.gui_ref.jer[2] = single_value_3d_ref[0];
1209  } else if (rm_order_v == 1){
1210  rm_1st_pos(dt_1l, single_value_2d_ref, single_value_3d_ref, single_value_nav_target, single_value_k3_rm, max_j_nav, 1);
1213  oneloop_andi.gui_ref.acc[2] = single_value_2d_ref[0];
1214  oneloop_andi.gui_ref.jer[2] = single_value_3d_ref[0];
1215  }
1216  // Generate Reference signals for attitude using RM
1217  // FIX ME ow not yet defined, will be useful in the future to have accurate psi tracking in NAV functions
1218  bool ow_psi = false;
1220 }
1221 }
1222 
1231 void oneloop_andi_run(bool in_flight, bool half_loop, struct FloatVect3 PSA_des, int rm_order_h, int rm_order_v)
1232 {
1233  // 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
1235  init_controller();
1238  sum_g1g2_1l();
1239 
1240  // If drone is not on the ground use incremental law
1241  use_increment = 0.0;
1242  bool in_flight_oneloop = false;
1243  if(in_flight) {
1244  use_increment = 1.0;
1245  in_flight_oneloop = true;
1246  }
1248  in_flight_oneloop = false;
1249  }
1250 
1251  // Update desired Heading (psi_des_rad) based on previous loop or changed setting
1252  psi_des_rad = psi_des_deg * M_PI / 180.0;
1253 
1254  // Register the state of the drone in the variables used in RM and EC
1255  // (1) Attitude related
1259  oneloop_andi_propagate_filters(); //needs to be after update of attitude vector
1266  // (2) Position related
1276 
1277  // Update the effectiveness matrix used in WLS
1278  int8_t i;
1279  for (i = 0; i < ANDI_OUTPUTS; i++) {
1280  bwls_1l[i] = g1g2_1l[i];
1281  }
1282 
1283  // Run the Reference Model (RM)
1284  oneloop_andi_RM(half_loop, PSA_des, rm_order_h, rm_order_v);
1285  // Generate pseudo control for stabilization vector (nu) based on error controller
1286  if(half_loop){
1287  nu[0] = 0.0;
1288  nu[1] = 0.0;
1289  nu[2] = a_thrust;
1293  }else{
1294  float y_4d_att[3];
1299  nu[3] = y_4d_att[0];
1300  nu[4] = y_4d_att[1];
1301  nu[5] = y_4d_att[2];
1302  }
1303 
1304  // Calculate the min and max increments
1305  for (i = 0; i < ANDI_NUM_ACT_TOT; i++) {
1306  if(i<ANDI_NUM_ACT){
1310  }else{
1314  }
1315  }
1316  // WLS Control Allocator
1318 
1319  for (i = 0; i < ANDI_NUM_ACT_TOT; i++){
1320  andi_du[i] = (float)(andi_du_n[i] * ratio_u_un[i]);
1321  }
1322 
1323  if (in_flight_oneloop) {
1324  // Add the increments to the actuators
1328  } else {
1329  // Not in flight, so don't increment
1333  }
1334 
1335  // TODO : USE THE PROVIDED MAX AND MIN and change limits for phi and theta
1336  // Bound the inputs to the actuators
1337  for (i = 0; i < ANDI_NUM_ACT_TOT; i++) {
1338  Bound(andi_u[i], act_min[i], act_max[i]);
1339  }
1340 
1341  /*Commit the actuator command*/
1342  stabilization_cmd[COMMAND_THRUST] = 0;
1343  for (i = 0; i < ANDI_NUM_ACT; i++) {
1344  actuators_pprz[i] = (int16_t) andi_u[i];
1345  stabilization_cmd[COMMAND_THRUST] += actuator_state_1l[i];
1346  }
1347  stabilization_cmd[COMMAND_THRUST] = stabilization_cmd[COMMAND_THRUST]/num_thrusters_oneloop;
1351  } else {
1354  }
1355  psi_des_deg = psi_des_rad * 180.0 / M_PI;
1356 }
1357 
1360 {
1361  int8_t i;
1362  float prev_actuator_state_1l;
1363  for (i = 0; i < ANDI_NUM_ACT; i++) {
1364  prev_actuator_state_1l = actuator_state_1l[i];
1365  actuator_state_1l[i] = prev_actuator_state_1l + act_dynamics_d[i] * (andi_u[i] - prev_actuator_state_1l);
1366  if(!autopilot_get_motors_on()){
1367  actuator_state_1l[i] = 0.0;
1368  }
1369  Bound(actuator_state_1l[i],0,MAX_PPRZ);
1370  }
1371 }
1372 
1377 void sum_g1g2_1l(void) {
1378  //struct FloatEulers *euler = stateGetNedToBodyEulers_f();
1379  float sphi = sinf(eulers_zxy.phi);
1380  float cphi = cosf(eulers_zxy.phi);
1381  float stheta = sinf(eulers_zxy.theta);
1382  float ctheta = cosf(eulers_zxy.theta);
1383  float spsi = sinf(eulers_zxy.psi);
1384  float cpsi = cosf(eulers_zxy.psi);
1385  float T = -9.81; //minus gravity is a guesstimate of the thrust force, thrust measurement would be better
1386  float P = 0.0;
1389  }
1390  float scaler;
1391  int i = 0;
1392  for (i = 0; i < ANDI_NUM_ACT_TOT; i++) {
1393  // Effectiveness vector for real actuators (e.g. motors, servos)
1394  if (i < ANDI_NUM_ACT){
1395  scaler = act_dynamics[i] * ratio_u_un[i] * ratio_vn_v[i] / ANDI_G_SCALING;
1396  g1g2_1l[0][i] = (cpsi * stheta + ctheta * sphi * spsi) * g1_1l[2][i] * scaler;
1397  g1g2_1l[1][i] = (spsi * stheta - cpsi * ctheta * sphi) * g1_1l[2][i] * scaler;
1398  g1g2_1l[2][i] = (cphi * ctheta ) * g1_1l[2][i] * scaler;
1399  g1g2_1l[3][i] = (g1_1l[3][i]) * scaler;
1400  g1g2_1l[4][i] = (g1_1l[4][i]) * scaler;
1401  g1g2_1l[5][i] = (g1_1l[5][i] + g2_1l[i]) * scaler;
1403  g1g2_1l[0][i] = (cpsi * ctheta - sphi * spsi * stheta) * g1_1l[2][i] * scaler;
1404  g1g2_1l[1][i] = (ctheta * spsi + cpsi * sphi * stheta) * g1_1l[2][i] * scaler;
1405  g1g2_1l[2][i] = (- cphi * stheta ) * g1_1l[2][i] * scaler;
1406  g1g2_1l[3][i] = 0.0;
1407  g1g2_1l[4][i] = 0.0;
1408  g1g2_1l[5][i] = 0.0;
1409  }
1410  }else{
1411  scaler = act_dynamics[i] * ratio_u_un[i] * ratio_vn_v[i];
1412  // Effectiveness vector for Phi (virtual actuator)
1413  if (i == ANDI_NUM_ACT){
1414  g1g2_1l[0][i] = ( cphi * ctheta * spsi * T - cphi * spsi * stheta * P) * scaler;
1415  g1g2_1l[1][i] = (-cphi * ctheta * cpsi * T + cphi * cpsi * stheta * P) * scaler;
1416  g1g2_1l[2][i] = (-sphi * ctheta * T + sphi * stheta * P) * scaler;
1417  g1g2_1l[3][i] = 0.0;
1418  g1g2_1l[4][i] = 0.0;
1419  g1g2_1l[5][i] = 0.0;
1420  }
1421  // Effectiveness vector for Theta (virtual actuator)
1422  if (i == ANDI_NUM_ACT+1){
1423  g1g2_1l[0][i] = ((ctheta*cpsi - sphi*stheta*spsi) * T - (cpsi * stheta + ctheta * sphi * spsi) * P) * scaler;
1424  g1g2_1l[1][i] = ((ctheta*spsi + sphi*stheta*cpsi) * T - (spsi * stheta - cpsi * ctheta * sphi) * P) * scaler;
1425  g1g2_1l[2][i] = (-stheta * cphi * T - cphi * ctheta * P) * scaler;
1426  g1g2_1l[3][i] = 0.0;
1427  g1g2_1l[4][i] = 0.0;
1428  g1g2_1l[5][i] = 0.0;
1429  }
1430  }
1431  }
1432 }
1433 
1436  int8_t i;
1437  for (i = 0; i < ANDI_NUM_ACT_TOT; i++){
1438  act_dynamics_d[i] = 1.0-exp(-act_dynamics[i]*dt_1l);
1439  Bound(act_dynamics_d[i],0.00001,1.0);
1440  ratio_vn_v[i] = 1.0;
1441  Bound(act_max[i],0,MAX_PPRZ);
1442  Bound(act_min[i],-MAX_PPRZ,0);
1443  float ratio_numerator = act_max[i]-act_min[i];
1444  ratio_numerator = positive_non_zero(ratio_numerator);// make sure numerator is non-zero
1445  float ratio_denominator = act_max_norm[i]-act_min_norm[i];
1446  ratio_denominator = positive_non_zero(ratio_denominator); // make sure denominator is non-zero
1447  ratio_u_un[i] = ratio_numerator/ratio_denominator;
1448  ratio_u_un[i] = positive_non_zero(ratio_u_un[i]);// make sure ratio is not zero
1449  }
1450 }
1451 
1453 void calc_model(void){
1454  int8_t i;
1455  int8_t j;
1456  // Absolute Model Prediction :
1457  float sphi = sinf(eulers_zxy.phi);
1458  float cphi = cosf(eulers_zxy.phi);
1459  float stheta = sinf(eulers_zxy.theta);
1460  float ctheta = cosf(eulers_zxy.theta);
1461  float spsi = sinf(eulers_zxy.psi);
1462  float cpsi = cosf(eulers_zxy.psi);
1463  float T = -9.81;
1465 
1466  model_pred[0] = (cpsi * stheta + ctheta * sphi * spsi) * T + (cpsi * ctheta + sphi * spsi * stheta) * P;
1467  model_pred[1] = (spsi * stheta - cpsi * ctheta * sphi) * T + (ctheta * spsi + cpsi * sphi * stheta) * P;
1468  model_pred[2] = g + cphi * ctheta * T - cphi * stheta * P;
1469 
1470  for (i = 3; i < ANDI_OUTPUTS; i++){ // For loop for prediction of angular acceleration
1471  model_pred[i] = 0.0; //
1472  for (j = 0; j < ANDI_NUM_ACT; j++){
1473  model_pred[i] = model_pred[i] + actuator_state_1l[j] * g1g2_1l[i][j] / (act_dynamics[j] * ratio_u_un[j] * ratio_vn_v[j]);
1474  }
1475  }
1476 }
1477 
1479 void oneloop_from_nav(bool in_flight)
1480 {
1481  if (!in_flight) {
1482  oneloop_andi_enter(false);
1483  }
1484  struct FloatVect3 PSA_des;
1485  PSA_des.x = stateGetPositionNed_f()->x;
1486  PSA_des.y = stateGetPositionNed_f()->y;
1487  PSA_des.z = stateGetPositionNed_f()->z;
1488  int rm_order_h = 3;
1489  int rm_order_v = 3;
1490  // Oneloop controller wants desired targets and handles reference generation internally
1491  switch (nav.setpoint_mode) {
1492  case NAV_SETPOINT_MODE_POS:
1495  rm_order_h = 3;
1496  break;
1500  rm_order_h = 2;
1501  break;
1502  }
1503  switch (nav.vertical_mode) {
1504  case NAV_VERTICAL_MODE_ALT:
1506  rm_order_v = 3;
1507  break;
1510  rm_order_v = 2;
1511  break;
1512  }
1513  oneloop_andi_run(in_flight, false, PSA_des, rm_order_h, rm_order_v);
1514 }
1515 
1516 
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:290
uint8_t mode
current autopilot mode
Definition: autopilot.h:63
uint8_t last_wp UNUSED
static const float scale[]
float q
in rad/s
float phi
in radians
float p
in rad/s
float r
in rad/s
float theta
in radians
float psi
in radians
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||
euler angles
angular rates
#define POS_FLOAT_OF_BFP(_ai)
#define SPEED_FLOAT_OF_BFP(_ai)
#define POS_BFP_OF_REAL(_af)
#define SPEED_BFP_OF_REAL(_af)
euler angles
Rotation quaternion.
static struct NedCoor_f * stateGetAccelNed_f(void)
Get acceleration in NED coordinates (float).
Definition: state.h:1038
static struct FloatQuat * stateGetNedToBodyQuat_f(void)
Get vehicle body attitude quaternion (float).
Definition: state.h:1131
static struct NedCoor_f * stateGetPositionNed_f(void)
Get position in local NED coordinates (float).
Definition: state.h:710
static struct FloatRates * stateGetBodyRates_f(void)
Get vehicle body angular rate (float).
Definition: state.h:1200
static struct NedCoor_f * stateGetSpeedNed_f(void)
Get ground speed in local NED coordinates (float).
Definition: state.h:908
static float p[2][2]
Simple first order low pass filter with bilinear transform.
float o[2]
output history
static float update_first_order_low_pass(struct FirstOrderLowPass *filter, float value)
Update first order low pass filter state with a new value.
static void init_butterworth_2_low_pass(Butterworth2LowPass *filter, float tau, float sample_time, float value)
Init a second order Butterworth filter.
static void init_first_order_low_pass(struct FirstOrderLowPass *filter, float tau, float sample_time, float value)
Init first order low pass filter.
static float update_butterworth_2_low_pass(Butterworth2LowPass *filter, float value)
Update second order Butterworth low pass filter state with a new value.
First order low pass filter structure.
Second order low pass filter structure.
Hardware independent API for actuators (servos, motor controllers).
float nav_max_speed
Specific navigation functions for hybrid aircraft.
static float k_e_3_3_f_v2(float omega_n, float zeta, float p1)
Definition: oneloop_andi.c:516
static float k_e_1_3_f(float p1, float p2, float p3)
Error Controller Gain Design.
Definition: oneloop_andi.c:470
static float w_approx(float p1, float p2, float p3, float rm_k)
Third Order to First Order Dynamics Approximation.
Definition: oneloop_andi.c:874
void init_poles(void)
Initialize Position of Poles.
Definition: oneloop_andi.c:887
static struct FirstOrderLowPass filt_accel_ned[3]
Definition: oneloop_andi.c:452
struct PolePlacement p_pos_e
Definition: oneloop_andi.c:427
static float ang_acc[3]
Definition: oneloop_andi.c:419
bool force_forward
forward flight for hybrid nav
Definition: oneloop_andi.c:288
static float du_pref_1l[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:414
static float k_e_3_3_f(float p1, float p2, float p3)
Definition: oneloop_andi.c:484
float act_dynamics[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:156
float ratio_u_un[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:448
void init_filter(void)
Initialize the filters.
Definition: oneloop_andi.c:991
struct PolePlacement p_head_rm
Definition: oneloop_andi.c:434
#define GUIDANCE_INDI_SPEED_GAINZ
Definition: oneloop_andi.c:255
static float k_e_2_3_f_v2(float omega_n, float zeta, float p1)
Definition: oneloop_andi.c:509
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])
Error Controller Definition for 3rd order system specific to attitude.
Definition: oneloop_andi.c:832
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])
Reference Model Definition for 3rd order system with attitude conversion functions.
Definition: oneloop_andi.c:630
float act_max_norm[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:174
struct Gains3rdOrder k_att_rm
Definition: oneloop_andi.c:437
float max_a_nav
Definition: oneloop_andi.c:236
struct guidance_indi_hybrid_params gih_params
Definition: oneloop_andi.c:276
void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3])
Attitude Euler to Rates Conversion Function.
Definition: oneloop_andi.c:571
float oneloop_andi_filt_cutoff_v
Definition: oneloop_andi.c:119
struct FloatEulers eulers_zxy_des
Definition: oneloop_andi.c:404
static float du_min_1l[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:412
static float du_max_1l[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:413
struct Int32Eulers stab_att_sp_euler_1l
Definition: oneloop_andi.c:402
struct PolePlacement p_att_rm
Definition: oneloop_andi.c:425
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.
Definition: oneloop_andi.c:812
static float Wv_wls[ANDI_OUTPUTS]
Definition: oneloop_andi.c:188
static float k_rm_3_3_f(float omega_n, float zeta, float p1)
Definition: oneloop_andi.c:539
float g1g2_1l[ANDI_OUTPUTS][ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:446
static struct FirstOrderLowPass rates_filt_fo[3]
Definition: oneloop_andi.c:453
struct Gains3rdOrder k_att_e
Definition: oneloop_andi.c:436
static float psi_des_rad
Definition: oneloop_andi.c:406
static float model_pred[ANDI_OUTPUTS]
Definition: oneloop_andi.c:418
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.
Definition: oneloop_andi.c:768
void oneloop_andi_propagate_filters(void)
Propagate the filters.
#define ONELOOP_ANDI_PUSHER_IDX
Definition: oneloop_andi.c:214
struct Gains3rdOrder k_pos_e
Definition: oneloop_andi.c:440
float nu[ANDI_OUTPUTS]
Definition: oneloop_andi.c:396
bool actuator_is_servo[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:149
float num_thrusters_oneloop
Definition: oneloop_andi.c:99
struct Gains2ndOrder k_head_rm
Definition: oneloop_andi.c:439
static float act_dynamics_d[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:397
float act_min_norm[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:180
#define ONELOOP_ANDI_DEBUG_MODE
Definition: oneloop_andi.c:205
float oneloop_andi_filt_cutoff_a
Definition: oneloop_andi.c:113
static Butterworth2LowPass model_pred_filt[ANDI_OUTPUTS]
Definition: oneloop_andi.c:456
float g1_1l[ANDI_OUTPUTS][ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:445
static float gamma_wls
Definition: oneloop_andi.c:411
#define GUIDANCE_INDI_LIFTD_ASQ
Definition: oneloop_andi.c:264
float max_j_nav
Definition: oneloop_andi.c:242
void oneloop_from_nav(bool in_flight)
Function that maps navigation inputs to the oneloop controller for the generated autopilot.
#define GUIDANCE_INDI_POS_GAIN
Definition: oneloop_andi.c:259
struct PolePlacement p_alt_rm
Definition: oneloop_andi.c:431
void oneloop_andi_RM(bool half_loop, struct FloatVect3 PSA_des, int rm_order_h, int rm_order_v)
Function to generate the reference signals for the oneloop controller.
struct Gains2ndOrder k_head_e
Definition: oneloop_andi.c:438
static float positive_non_zero(float input)
Function to make sure that inputs are positive non zero vaues.
Definition: oneloop_andi.c:460
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.
Definition: oneloop_andi.c:667
float andi_u[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:393
static float psi_vec[4]
Definition: oneloop_andi.c:408
void calc_normalization(void)
Calculate Normalization of actuators and discrete actuator dynamics
#define ONELOOP_ANDI_FILT_CUTOFF_R
Definition: oneloop_andi.c:143
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
Definition: oneloop_andi.c:424
struct PolePlacement p_alt_e
Definition: oneloop_andi.c:430
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.
Definition: oneloop_andi.c:746
static float g
Definition: oneloop_andi.c:390
static float andi_du_n[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:395
void get_act_state_oneloop(void)
Function to reconstruct actuator state using first order dynamics.
static float k_e_1_2_f(float p1, float p2)
Definition: oneloop_andi.c:491
#define GUIDANCE_INDI_LIFTD_P50
Definition: oneloop_andi.c:273
static float ec_2rd(float x_ref, float x_d_ref, float x_2d_ref, float x, float x_d, float k1_e, float k2_e)
Error Controller Definition for 2rd order system.
Definition: oneloop_andi.c:861
struct PolePlacement p_head_e
Definition: oneloop_andi.c:433
#define ONELOOP_ANDI_FILT_CUTOFF_Q
Definition: oneloop_andi.c:137
static int number_iter
Definition: oneloop_andi.c:415
float g2_1l[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:444
float andi_du[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:394
float max_v_nav
Definition: oneloop_andi.c:248
struct Int32Quat stab_att_sp_quat_1l
Definition: oneloop_andi.c:403
static float nav_target[3]
Definition: oneloop_andi.c:388
void err_nd(float err[], float a[], float b[], float k[], int n)
Calculate Scaled Error between two 3D arrays.
Definition: oneloop_andi.c:586
static float k_e_1_3_f_v2(float omega_n, UNUSED float zeta, float p1)
Definition: oneloop_andi.c:503
void calc_model(void)
Function that calculates the model prediction for the complementary filter.
struct OneloopGeneral oneloop_andi
Definition: oneloop_andi.c:384
float ratio_vn_v[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:449
struct Gains3rdOrder k_pos_rm
Definition: oneloop_andi.c:441
static float use_increment
Definition: oneloop_andi.c:387
static struct FirstOrderLowPass model_pred_a_filt[3]
Definition: oneloop_andi.c:454
static float Wv[ANDI_OUTPUTS]
Definition: oneloop_andi.c:187
#define ONELOOP_ANDI_AC_HAS_PUSHER
Definition: oneloop_andi.c:210
void init_controller(void)
Initialize Controller Gains FIXME: Calculate the gains dynamically for transition.
Definition: oneloop_andi.c:920
static float k_e_2_3_f(float p1, float p2, float p3)
Definition: oneloop_andi.c:477
static void send_guidance_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
Definition: oneloop_andi.c:356
float act_max[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:162
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.
Definition: oneloop_andi.c:689
float psi_des_deg
Definition: oneloop_andi.c:407
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.
Definition: oneloop_andi.c:717
void oneloop_andi_enter(bool half_loop_sp)
Function that resets important values upon engaging Oneloop ANDI.
struct FloatEulers eulers_zxy
Definition: oneloop_andi.c:405
void oneloop_andi_init(void)
Init function of Oneloop ANDI controller
static float Wu[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:194
void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3])
Attitude Rates to Euler Conversion Function.
Definition: oneloop_andi.c:559
float oneloop_andi_filt_cutoff_p
Definition: oneloop_andi.c:125
static float k_rm_1_3_f(float omega_n, float zeta, float p1)
Reference Model Gain Design.
Definition: oneloop_andi.c:525
static Butterworth2LowPass att_dot_meas_lowpass_filters[3]
Definition: oneloop_andi.c:455
static float k_e_2_2_f(float p1, float p2)
Definition: oneloop_andi.c:497
#define ONELOOP_ANDI_FILT_CUTOFF_P
Definition: oneloop_andi.c:131
struct PolePlacement p_pos_rm
Definition: oneloop_andi.c:428
#define GUIDANCE_INDI_POS_GAINZ
Definition: oneloop_andi.c:260
void sum_g1g2_1l(void)
Function that sums g1 and g2 to obtain the g1_g2 matrix.
void vect_bound_nd(float vect[], float bound, int n)
Scale a 3D array to within a 3D bound.
Definition: oneloop_andi.c:604
static float k_rm_2_2_f(float omega_n, float zeta)
Definition: oneloop_andi.c:552
void integrate_nd(float dt, float a[], float a_dot[], int n)
Integrate in time 3D array.
Definition: oneloop_andi.c:595
static float dt_1l
Definition: oneloop_andi.c:389
static void send_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
Definition: oneloop_andi.c:331
float act_min[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:168
float actuator_state_1l[ANDI_NUM_ACT]
Definition: oneloop_andi.c:398
static float a_thrust
Definition: oneloop_andi.c:399
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.
Definition: oneloop_andi.c:789
static void send_eff_mat_g_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
Definition: oneloop_andi.c:318
float * bwls_1l[ANDI_OUTPUTS]
Definition: oneloop_andi.c:447
static float k_rm_1_2_f(float omega_n, float zeta)
Definition: oneloop_andi.c:546
#define GUIDANCE_INDI_LIFTD_P80
Definition: oneloop_andi.c:272
static float k_rm_2_3_f(float omega_n, float zeta, float p1)
Definition: oneloop_andi.c:532
static float lin_acc[3]
Definition: oneloop_andi.c:420
#define GUIDANCE_INDI_SPEED_GAIN
Definition: oneloop_andi.c:254
static float u_pref[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:200
float oneloop_andi_filt_cutoff
Definition: oneloop_andi.c:107
struct OneloopGuidanceState gui_state
Definition: oneloop_andi.h:106
struct OneloopStabilizationState sta_state
Definition: oneloop_andi.h:108
#define ANDI_NUM_ACT
Definition: oneloop_andi.h:35
#define ANDI_G_SCALING
Definition: oneloop_andi.h:54
struct OneloopGuidanceRef gui_ref
Definition: oneloop_andi.h:105
struct OneloopStabilizationRef sta_ref
Definition: oneloop_andi.h:107
#define ANDI_NUM_ACT_TOT
Definition: oneloop_andi.h:48
#define ANDI_OUTPUTS
Definition: oneloop_andi.h:52
#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
Generic interface for radio control modules.
static pprz_t radio_control_get(uint8_t idx)
Get a radio control channel value.
Definition: radio_control.h:94
#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
struct EnuCoor_f carrot
carrot position (also used for GCS display)
Definition: navigation.h:127
#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
int32_t stabilization_cmd[COMMANDS_NB]
Stabilization commands.
Definition: stabilization.c:34
API to get/set the generic vehicle states.
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:74
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]
Definition: trilateration.c:31
short int16_t
Typedef defining 16 bit short type.
Definition: vl53l1_types.h:93
signed char int8_t
Typedef defining 8 bit char type.
Definition: vl53l1_types.h:103
float b
Definition: wedgebug.c:202
int wls_alloc(float *u, float *v, float *umin, float *umax, float **B, float *u_guess, float *W_init, float *Wv, float *Wu, float *up, float gamma_sq, int imax, int n_u, int n_v)
active set algorithm for control allocation
Definition: wls_alloc.c:108