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 #include "modules/core/abi.h"
88 #include "math/wls/wls_alloc.h"
92 #include "modules/core/commands.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
104 float num_thrusters_oneloop = 4.0; // Number of motors used for thrust
105 #else
106 float num_thrusters_oneloop = ONELOOP_ANDI_NUM_THRUSTERS;
107 #endif
108 
109 #ifndef ONELOOP_ANDI_SCHEDULING
110 #define ONELOOP_ANDI_SCHEDULING FALSE
111 #endif
112 
113 #ifdef ONELOOP_ANDI_FILT_CUTOFF
114 float oneloop_andi_filt_cutoff = ONELOOP_ANDI_FILT_CUTOFF;
115 #else
117 #endif
118 
119 #ifdef ONELOOP_ANDI_FILT_CUTOFF_ACC
120 float oneloop_andi_filt_cutoff_a = ONELOOP_ANDI_FILT_CUTOFF_ACC;
121 #else
123 #endif
124 
125 #ifdef ONELOOP_ANDI_FILT_CUTOFF_VEL
126 float oneloop_andi_filt_cutoff_v = ONELOOP_ANDI_FILT_CUTOFF_VEL;
127 #else
129 #endif
130 PRINT_CONFIG_VAR(ONELOOP_ANDI_FILT_CUTOFF_VEL)
131 #ifdef ONELOOP_ANDI_FILT_CUTOFF_POS
132 float oneloop_andi_filt_cutoff_pos = 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
139 float oneloop_andi_filt_cutoff_p = ONELOOP_ANDI_FILT_CUTOFF_P;
140 #else
142 #endif
143 
144 #ifdef ONELOOP_ANDI_FILT_CUTOFF_Q
145 #define ONELOOP_ANDI_FILTER_PITCH_RATE TRUE
146 float oneloop_andi_filt_cutoff_q = ONELOOP_ANDI_FILT_CUTOFF_Q;
147 #else
149 #endif
150 
151 #ifdef ONELOOP_ANDI_FILT_CUTOFF_R
152 #define ONELOOP_ANDI_FILTER_YAW_RATE TRUE
153 float oneloop_andi_filt_cutoff_r = ONELOOP_ANDI_FILT_CUTOFF_R;
154 #else
156 #endif
157 
158 PRINT_CONFIG_VAR(ONELOOP_ANDI_FILT_CUTOFF);
159 PRINT_CONFIG_VAR(ONELOOP_ANDI_FILT_CUTOFF_Q);
160 PRINT_CONFIG_VAR(ONELOOP_ANDI_FILT_CUTOFF_P);
161 PRINT_CONFIG_VAR(ONELOOP_ANDI_FILT_CUTOFF_R);
162 #ifndef MAX_R
163 float max_r = RadOfDeg(120.0);
164 #else
165 float max_r = RadOfDeg(MAX_R);
166 #endif
167 
168 #ifdef ONELOOP_ANDI_ACT_IS_SERVO
169 bool actuator_is_servo[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_ACT_IS_SERVO;
170 #else
172 #endif
173 
174 #ifdef ONELOOP_ANDI_ACT_DYN
175 float act_dynamics[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_ACT_DYN;
176 #else
177 #error "You must specify the actuator dynamics"
179 #endif
180 
181 #ifdef ONELOOP_ANDI_ACT_MAX
182 float act_max[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_ACT_MAX;
183 #else
185 #endif
186 
187 #ifdef ONELOOP_ANDI_ACT_MIN
188 float act_min[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_ACT_MIN;
189 #else
190 float act_min[ANDI_NUM_ACT_TOT] = = {0.0};
191 #endif
192 
193 #ifdef ONELOOP_ANDI_ACT_MAX_NORM
194 float act_max_norm[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_ACT_MAX_NORM;
195 #else
197 #endif
198 
199 #ifdef ONELOOP_ANDI_ACT_MIN_NORM
200 float act_min_norm[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_ACT_MIN_NORM;
201 #else
203 #endif
204 
205 #ifdef ONELOOP_ANDI_NU_NORM_MAX
206 float nu_norm_max = ONELOOP_ANDI_NU_NORM_MAX;
207 #else
208 float nu_norm_max = 1.0;
209 #endif
210 
211 #ifdef ONELOOP_ANDI_U_PREF
212 static float u_pref[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_U_PREF;
213 #else
214 static 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
228 float theta_pref_max = RadOfDeg(20.0);
229 #else
230 float theta_pref_max = RadOfDeg(ONELOOP_THETA_PREF_MAX);
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
250 float 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
254 float max_j_nav = ONELOOP_MAX_JERK;
255 #else
256 float 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
260 float max_j_ang = ONELOOP_MAX_ANGULAR_JERK;
261 #else
262 float max_j_ang = 1000.0;
263 #endif
264 
265 #ifdef NAV_HYBRID_MAX_AIRSPEED
266 float max_v_nav = NAV_HYBRID_MAX_AIRSPEED; // Consider implications of difference Ground speed and airspeed
267 #else
268 float max_v_nav = 5.0;
269 #endif
270 float max_as = 19.0f;
271 float min_as = 0.0f;
272 
273 #ifdef NAV_HYBRID_MAX_SPEED_V
274 float max_v_nav_v = NAV_HYBRID_MAX_SPEED_V;
275 #else
276 float max_v_nav_v = 1.5;
277 #endif
278 
279 #ifndef FWD_SIDESLIP_GAIN
280 float fwd_sideslip_gain = 0.2;
281 #else
282 float fwd_sideslip_gain = FWD_SIDESLIP_GAIN;
283 #endif
284 
285 #ifndef ONELOOP_ANDI_WU_QUAD_MOTORS_FWD
286 float Wu_quad_motors_fwd = 6.0;
287 #else
288 float Wu_quad_motors_fwd = ONELOOP_ANDI_WU_QUAD_MOTORS_FWD;
289 #endif
290 
291 
292 /* Define Section of the functions used in this module*/
293 void init_poles(void);
294 void init_poles_att(void);
295 void init_poles_pos(void);
296 void calc_normalization(void);
297 void normalize_nu(void);
298 void G1G2_oneloop(int ctrl_type);
299 void get_act_state_oneloop(void);
301 void init_filter(void);
302 void init_controller(void);
303 void float_rates_of_euler_dot_vec(float r[3], float e[3], float edot[3]);
304 void float_euler_dot_of_rates_vec(float r[3], float e[3], float edot[3]);
305 void err_nd(float err[], float a[], float b[], float k[], int n);
306 void err_sum_nd(float err[], float a[], float b[], float k[], float c[], int n);
307 void integrate_nd(float dt, float a[], float a_dot[], int n);
308 void vect_bound_nd(float vect[], float bound, int n);
309 void acc_body_bound(struct FloatVect2* vect, float bound);
310 float bound_v_from_a(float e_x[], float v_bound, float a_bound, int n);
311 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);
312 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);
313 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);
314 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);
315 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);
316 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);
317 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);
318 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);
319 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);
320 void calc_model(void);
321 float oneloop_andi_sideslip(void);
322 void reshape_wind(void);
323 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[]);
324 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[]);
325 void init_cf2(struct CF2_t *cf, float fc);
326 void init_cf4(struct CF4_t *cf, float fc);
327 void init_all_cf(void);
328 void reinit_cf2(struct CF2_t *cf, bool reinit);
329 void reinit_cf4(struct CF4_t *cf, bool reinit);
330 void reinit_all_cf(bool reinit);
331 
332 /*Define general struct of the Oneloop ANDI controller*/
334 
335 /* Oneloop Misc variables*/
336 static float use_increment = 0.0;
337 static float nav_target[3]; // Can be a position, speed or acceleration depending on the guidance H mode
338 static float nav_target_new[3];
339 static float dt_1l = 1./PERIODIC_FREQUENCY;
340 static float g = 9.81; // [m/s^2] Gravitational Acceleration
341 float k_as = 2.0;
344 
345 /* Oneloop Control Variables*/
353 static float a_thrust = 0.0;
354 static float g2_ff= 0.0;
355 
356 /*Attitude related variables*/
357 struct Int32Eulers stab_att_sp_euler_1l;// here for now to correct warning, can be better eploited in the future
358 struct Int32Quat stab_att_sp_quat_1l; // here for now to correct warning, can be better eploited in the future
360 struct FloatEulers eulers_zxy;
361 //static float psi_des_rad = 0.0;
362 float psi_des_rad = 0.0;
363 float psi_des_deg = 0.0;
364 static float psi_vec[4] = {0.0, 0.0, 0.0, 0.0};
365 
366 #if ONELOOP_ANDI_HEADING_MANUAL
367 bool heading_manual = true;
368 #else
369 bool heading_manual = false;
370 #endif
371 #if ONELOOP_ANDI_YAW_STICK_IN_AUTO
372 bool yaw_stick_in_auto = true;
373 #else
374 bool yaw_stick_in_auto = false;
375 #endif
376 bool ctrl_off = false;
377 /*WLS Settings*/
378 
379 static float pitch_pref = 0;
380 struct WLS_t WLS_one_p = {
381  .nu = ANDI_NUM_ACT_TOT,
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}
404 static float Wv_backup[ANDI_OUTPUTS] = ONELOOP_ANDI_WV;
405 #else
406 static 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}
410 static float Wu_backup[ANDI_NUM_ACT_TOT] = ONELOOP_ANDI_WU;
411 #else
412 static float Wu_backup[ANDI_NUM_ACT_TOT] = {1.0};
413 #endif
414 
415 /*Complementary Filter Variables*/
416 struct Oneloop_CF_t cf;
417 static struct Oneloop_notch_t oneloop_notch;
418 
419 /*Chirp test Variables*/
420 bool chirp_on = false;
421 bool chirp_first_call = true;
422 float time_elapsed_chirp = 0.0;
423 float t_0_chirp = 0.0;
424 float f0_chirp = 0.8 / (2.0 * M_PI);
425 float f1_chirp = 0.8 / (2.0 * M_PI);
426 float t_chirp = 45.0;
427 float A_chirp = 1.0;
429 float p_ref_0[3] = {0.0, 0.0, 0.0};
430 
431 /*Declaration of Reference Model and Error Controller Gains*/
432 struct PolePlacement p_att_e;
433 struct PolePlacement p_att_rm;
434 /*Position Loop*/
435 struct PolePlacement p_pos_e;
436 struct PolePlacement p_pos_rm;
437 /*Altitude Loop*/
438 struct PolePlacement p_alt_e;
439 struct PolePlacement p_alt_rm;
440 /*Heading Loop*/
441 struct PolePlacement p_head_e;
442 struct PolePlacement p_head_rm;
443 /*Gains of EC and RM ANDI*/
444 struct Gains3rdOrder k_att_e;
445 struct Gains3rdOrder k_att_rm;
446 struct Gains3rdOrder k_pos_e;
447 struct Gains3rdOrder k_pos_rm;
448 /*Gains of EC and RM INDI*/
451 
452 /* Effectiveness Matrix definition */
457 
458 /*Filters Initialization*/
459 static Butterworth2LowPass filt_veloc_N; // Low pass filter for velocity NED - oneloop_andi_filt_cutoff_a (tau_a)
462 static Butterworth2LowPass accely_filt; // Low pass filter for acceleration in y direction - oneloop_andi_filt_cutoff (tau)
463 static 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 // }
487 static 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 }
491 static 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 }
495 static void send_eff_mat_stab_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
496 {
497  float zero = 0.0;
498  pprz_msg_send_EFF_MAT_STAB(trans, dev, AC_ID,
502  1, &zero,
503  1, &zero);
504 }
505 
506 static void send_eff_mat_guid_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
507 {
508  pprz_msg_send_EFF_MAT_GUID(trans, dev, AC_ID,
512 }
513 static void send_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
514 {
515  float temp_eulers_zxy_des[3] = {eulers_zxy_des.phi, eulers_zxy_des.theta, eulers_zxy_des.psi};
516  pprz_msg_send_STAB_ATTITUDE(trans, dev, AC_ID,
517  3, temp_eulers_zxy_des,
526 }
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 // }
533 static void send_guidance_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
534 {
535  pprz_msg_send_GUIDANCE(trans, dev, AC_ID,
556  &oneloop_andi.gui_ref.jer[2]);
557 }
558 
559 static void debug_vect(struct transport_tx *trans, struct link_device *dev, char *name, float *data, int datasize)
560 {
561  pprz_msg_send_DEBUG_VECT(trans, dev, AC_ID,
562  strlen(name), name,
563  datasize, data);
564 }
565 
566 static void send_oneloop_debug(struct transport_tx *trans, struct link_device *dev)
567 {
568  float temp_debug_vect[9];
569  temp_debug_vect[0] = cf.ax.model;
570  temp_debug_vect[1] = cf.ay.model;
571  temp_debug_vect[2] = cf.az.model;
572  temp_debug_vect[3] = cf.p_dot.model;
573  temp_debug_vect[4] = cf.q_dot.model;
574  temp_debug_vect[5] = cf.r_dot.model;
575  temp_debug_vect[6] = cf.p.model;
576  temp_debug_vect[7] = cf.q.model;
577  temp_debug_vect[8] = cf.r.model;
578  debug_vect(trans, dev, "model_cf", temp_debug_vect, 9);
579 }
580 #endif
581 
583 static float positive_non_zero(float input)
584 {
585  if (input < FLT_EPSILON) {
586  input = 0.00001;
587  }
588  return input;
589 }
590 
593 static 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 
599 static 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 
605 static 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 
611 static 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 
618 static 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 
627 static 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 
634 static 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 
641 static 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 
649 void 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 
661 void 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 
676 void 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 
685 void 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 
695 void 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 
704 void vect_bound_nd(float vect[], float bound, int n) {
705  float norm = float_vect_norm(vect,n);
706  norm = positive_non_zero(norm);
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 
717 void 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]);
725  norm = positive_non_zero(norm);
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];
729  acc_b_y_2 = positive_non_zero(acc_b_y_2);
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 
737 float 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 
758 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){
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];
766  NormRadAngle(temp_diff);
767  e_x[2] = k1_rm[2] * temp_diff; // Correction for Heading error +-Pi
768  float_rates_of_euler_dot_vec(e_x_rates, x_ref, e_x);
769  err_nd(e_x_d, e_x_rates, x_d_ref, k2_rm, 3);
770  err_nd(e_x_2d, e_x_d, x_2d_ref, k3_rm, 3);
771  float_vect_copy(x_3d_ref,e_x_2d,3);
772  vect_bound_nd(x_3d_ref, max_ang_jerk, 3);
773  if(ow_psi){x_3d_ref[2] = psi_overwrite[3];}
774  integrate_nd(dt, x_2d_ref, x_3d_ref, 3);
775  if(ow_psi){x_2d_ref[2] = psi_overwrite[2];}
776  integrate_nd(dt, x_d_ref, x_2d_ref, 3);
777  if(ow_psi){x_d_ref[2] = psi_overwrite[1];}
778  float_euler_dot_of_rates_vec(x_d_ref, x_ref, x_d_eul_ref);
779  integrate_nd(dt, x_ref, x_d_eul_ref, 3);
780  if(ow_psi){x_ref[2] = psi_overwrite[0];}
781  NormRadAngle(x_ref[2]);
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 
799 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){
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 
821 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){
822  float temp_diff = x_des - *x_ref;
823  NormRadAngle(temp_diff);
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 
849 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){
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);
854  float max_x_d = bound_v_from_a(e_x, x_d_bound, x_2d_bound, n);
855  vect_bound_nd(e_x, max_x_d, n);
856  err_nd(e_x_d, e_x, x_d_ref, k2_rm, n);
857  vect_bound_nd(e_x_d,x_2d_bound, n);
858  err_nd(e_x_2d, e_x_d, x_2d_ref, k3_rm, n);
859  float_vect_copy(x_3d_ref,e_x_2d,n);
860  vect_bound_nd(x_3d_ref, x_3d_bound, n);
861  integrate_nd(dt, x_2d_ref, x_3d_ref, n);
862  integrate_nd(dt, x_d_ref, x_2d_ref, n);
863  integrate_nd(dt, x_ref, x_d_ref, n);
864 }
865 
879 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){
880  float e_x_d[n];
881  float e_x_2d[n];
882  err_nd(e_x_d, x_d_des, x_d_ref, k2_rm, n);
883  vect_bound_nd(e_x_d,x_2d_bound, n);
884  err_nd(e_x_2d, e_x_d, x_2d_ref, k3_rm, n);
885  float_vect_copy(x_3d_ref,e_x_2d,n);
886  vect_bound_nd(x_3d_ref, x_3d_bound, n);
887  integrate_nd(dt, x_2d_ref, x_3d_ref, n);
888  integrate_nd(dt, x_d_ref, x_2d_ref, n);
889 }
890 
901 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){
902  float e_x_2d[n];
903  err_nd(e_x_2d, x_2d_des, x_2d_ref, k3_rm, n);
904  float_vect_copy(x_3d_ref,e_x_2d,n);
905  vect_bound_nd(x_3d_ref, x_3d_bound, n);
906  integrate_nd(dt, x_2d_ref, x_3d_ref, n);
907 }
908 
909 
922 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){
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 
945 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){
946  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;
947  return y_4d;
948 }
949 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){
950  float e_x_d[n];
951  float e_x_2d[n];
952 
953  err_sum_nd(e_x_d, x_ref, x, k1_e, x_d_ref, n);
954  vect_bound_nd(e_x_d, x_d_bound, n);
955 
956  err_sum_nd(e_x_2d, e_x_d, x_d, k2_e, x_2d_ref, n);
957  vect_bound_nd(e_x_2d,x_2d_bound, n);
958 
959  err_sum_nd(y_4d, e_x_2d, x_2d, k3_e, x_3d_ref, n);
960  vect_bound_nd(y_4d, x_3d_bound, n);
961 }
977 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){
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];
983  NormRadAngle(temp_diff);
984  float e_x = temp_diff;
985  y_4d_1[2] = k1_e[2] * e_x; // Correction for Heading error +-Pi
986  err_nd(y_4d_2, x_d_ref, x_d, k2_e, 3);
987  err_nd(y_4d_3, x_2d_ref, x_2d, k3_e, 3);
988  float_vect_copy(y_4d,x_3d_ref,3);
989  float_vect_sum(y_4d, y_4d, y_4d_1, 3);
990  float_vect_sum(y_4d, y_4d, y_4d_2, 3);
991  float_vect_sum(y_4d, y_4d, y_4d_3, 3);
992  vect_bound_nd(y_4d, max_ang_jerk, 3);
993 }
994 
1002 static 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);
1006  rm_k = positive_non_zero(rm_k);
1007  float tao = (p1*p2+p1*p3+p2*p3)/(p1*p2*p3)/(rm_k);
1008  tao = positive_non_zero(tao);
1009  return 1.0/tao;
1010 }
1011 
1019 static float ec_poles(float p_rm, float slow_pole, float k){
1020  p_rm = positive_non_zero(p_rm);
1021  slow_pole = positive_non_zero(slow_pole);
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 
1031 void init_poles_att(void){
1032  float slow_pole = 22.0; // Pole of the slowest dynamics used in the attitude controller
1033  p_att_e.omega_n = ec_poles(p_att_rm.omega_n, slow_pole, 1.28);
1034  p_head_e.omega_n = ec_poles(p_head_rm.omega_n, slow_pole, 1.28);
1035 }
1036 void init_poles_pos(void){
1037  act_dynamics[COMMAND_ROLL] = w_approx(p_att_rm.p3, p_att_rm.p3, p_att_rm.p3, 1.0);
1038  act_dynamics[COMMAND_PITCH] = w_approx(p_att_rm.p3, p_att_rm.p3, p_att_rm.p3, 1.0);
1039  float slow_pole = act_dynamics[COMMAND_ROLL]; // Pole of the slowest dynamics used in the position controller
1040  p_pos_e.omega_n = ec_poles(p_pos_rm.omega_n,slow_pole,1.28);//1.0;
1041  p_alt_e.omega_n = ec_poles(p_alt_rm.omega_n,slow_pole,1.28);//1.0;// 3.0;
1042 }
1043 
1048 void 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 
1057  p_att_e.omega_n = ec_poles(p_att_rm.omega_n, slow_pole, 1.28); //4.50;
1058  p_att_e.zeta = 1.0;
1059  p_att_e.p3 = slow_pole;
1060 
1061  p_head_rm.omega_n = 7.0; // 7.0 2.56
1062  p_head_rm.zeta = 1.0;
1064 
1065  p_head_e.omega_n = ec_poles(p_head_rm.omega_n, slow_pole, 1.28); //1.80;
1066  p_head_e.zeta = 1.0;
1067  p_head_e.p3 = slow_pole;
1068 
1069  act_dynamics[COMMAND_ROLL] = w_approx(p_att_rm.p3, p_att_rm.p3, p_att_rm.p3, 1.0);
1070  act_dynamics[COMMAND_PITCH] = w_approx(p_att_rm.p3, p_att_rm.p3, p_att_rm.p3, 1.0);
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
1075  p_pos_rm.omega_n = 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 
1082  p_pos_e.omega_n = ec_poles(p_pos_rm.omega_n,slow_pole,1.28);//1.0;
1083  p_pos_e.zeta = 1.0;
1084  p_pos_e.p3 = slow_pole;
1085 #ifdef ONELOOP_ANDI_POLES_ALT_OMEGA_N
1086  p_alt_rm.omega_n = 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 
1102 void init_controller(void){
1103  /*Register a variable from nav_hybrid. Should be improved when nav hybrid is final.*/
1104  float max_wind = 20.0;
1105  max_v_nav = nav_max_speed + max_wind;
1107  /*Some calculations in case new poles have been specified*/
1108  init_poles_att();
1109  init_poles_pos();
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*/
1204  act_dynamics[COMMAND_ROLL] = w_approx(p_att_rm.p3, p_att_rm.p3, p_att_rm.p3, 1.0);
1205  act_dynamics[COMMAND_PITCH] = w_approx(p_att_rm.p3, p_att_rm.p3, p_att_rm.p3, 1.0);
1206 }
1207 // Complementary Filters Functions -----------------------------------------------------------
1209 void 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 }
1220 void 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 }
1231 void init_all_cf(void){
1235  init_cf4(&cf.p_dot, 2.0);
1236  init_cf4(&cf.q_dot, 2.0);
1241 }
1243 void 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 }
1252 void 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 }
1261 void reinit_all_cf(bool reinit){
1262  reinit_cf2(&cf.ax, reinit);
1263  reinit_cf2(&cf.ay, reinit);
1264  reinit_cf2(&cf.az, reinit);
1265  reinit_cf4(&cf.p_dot, reinit);
1266  reinit_cf4(&cf.q_dot, reinit);
1267  reinit_cf2(&cf.r_dot, reinit);
1268  reinit_cf2(&cf.p, reinit);
1269  reinit_cf2(&cf.q, reinit);
1270  reinit_cf2(&cf.r, reinit);
1271 }
1272 //------------------------------------------------------------------------------------------
1274 void init_filter(void)
1275 {
1276  // Store Notch filter values
1277 #ifdef ONELOOP_ANDI_ROLL_STRUCTURAL_MODE_FREQ
1278  oneloop_notch.roll.freq = 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
1283  oneloop_notch.pitch.freq = 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
1288  oneloop_notch.yaw.freq = ONELOOP_ANDI_YAW_STRUCTURAL_MODE_FREQ,
1289 #else
1290  oneloop_notch.yaw.freq = 17.90,
1291 #endif
1294  oneloop_notch.yaw.bandwidth = 4.0;
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");
1304  init_butterworth_2_low_pass(&filt_veloc_N, tau_v, 1.0 / PERIODIC_FREQUENCY, 0.0);
1305  init_butterworth_2_low_pass(&filt_veloc_E, tau_v, 1.0 / PERIODIC_FREQUENCY, 0.0);
1306  init_butterworth_2_low_pass(&filt_veloc_D, tau_v, 1.0 / PERIODIC_FREQUENCY, 0.0);
1307  init_butterworth_2_low_pass(&accely_filt, tau, 1.0 / PERIODIC_FREQUENCY, 0.0);
1308  init_butterworth_2_low_pass(&airspeed_filt, tau, 1.0 / PERIODIC_FREQUENCY, 0.0);
1309 }
1310 
1311 
1314  reinit_all_cf(false);
1315  struct NedCoor_f *accel = stateGetAccelNed_f();
1316  struct NedCoor_f *veloc = stateGetSpeedNed_f();
1317  //printf("veloc: %f %f %f\n", veloc->x, veloc->y, veloc->z);
1318  struct FloatRates *body_rates = stateGetBodyRates_f();
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
1326  float temp_p_dot = (body_rates->p-cf.p.feedback)*PERIODIC_FREQUENCY;
1327  float temp_q_dot = (body_rates->q-cf.q.feedback)*PERIODIC_FREQUENCY;
1328  float temp_r_dot = (body_rates->r-cf.r.feedback)*PERIODIC_FREQUENCY;
1329 #ifdef USE_ROLL_NOTCH
1331 #else
1332  cf.p_dot.feedback = temp_p_dot;
1333 #endif
1334 #ifdef USE_PITCH_NOTCH
1336 #else
1337  cf.q_dot.feedback = temp_q_dot;
1338 #endif
1339 #ifdef USE_YAW_NOTCH
1341 #else
1342  cf.r_dot.feedback = temp_r_dot;
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
1372  cf.ax.out = cf.ax.feedback_filt.o[0] + cf.ax.model - cf.ax.model_filt.o[0];
1373  cf.ay.out = cf.ay.feedback_filt.o[0] + cf.ay.model - cf.ay.model_filt.o[0];
1374  cf.az.out = cf.az.feedback_filt.o[0] + cf.az.model - cf.az.model_filt.o[0];
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
1381  cf.p.model = cf.p.model + cf.p_dot.out / PERIODIC_FREQUENCY;
1382  cf.q.model = cf.q.model + cf.q_dot.out / PERIODIC_FREQUENCY;
1383  cf.r.model = cf.r.model + cf.r_dot.out / PERIODIC_FREQUENCY;
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
1393  float accely = ACCEL_FLOAT_OF_BFP(stateGetAccelBody_i()->y);
1395  float airspeed_meas = stateGetAirspeed_f();
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();
1420  init_controller();
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
1438  register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_STAB_ATTITUDE, send_oneloop_andi);
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 
1456 void oneloop_andi_enter(bool half_loop_sp, int ctrl_type)
1457 {
1458  ele_min = 0.0;
1459  oneloop_andi.half_loop = half_loop_sp;
1460  oneloop_andi.ctrl_type = ctrl_type;
1462  psi_des_deg = DegOfRad(eulers_zxy.psi);
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();
1471  init_controller();
1472  /* Stabilization Reset */
1479  eulers_zxy_des.phi = 0.0;
1480  eulers_zxy_des.theta = 0.0;
1482  /*Guidance Reset*/
1483 }
1484 
1492 void 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
1524  NormRadAngle(psi_des_rad);
1525  // Register Attitude Setpoints from previous loop
1526  if (!in_flight_oneloop){
1528  }
1530  float att_des[3] = {eulers_zxy_des.phi, eulers_zxy_des.theta, eulers_zxy_des.psi};
1531  // Create commands adhoc to get actuators to the wanted level
1532  thrust_cmd_1l = (float) radio_control_get(RADIO_THROTTLE);
1533  Bound(thrust_cmd_1l,0.0,MAX_PPRZ);
1534  int8_t i;
1535  for (i = 0; i < ANDI_NUM_ACT; i++) {
1536  a_thrust +=(thrust_cmd_1l - use_increment*actuator_state_1l[i]) * bwls_1l[2][i] / (ratio_u_un[i] * ratio_vn_v[RW_aD]);
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){
1559  psi_des_rad = RadOfDeg(psi_des_deg);
1560  if (yaw_stick_in_auto){
1562  }
1563  } else {
1564  float ref_mag_vel = float_vect_norm(oneloop_andi.gui_ref.vel,2);
1566  NormRadAngle(psi_des_rad);
1567  if (ref_mag_vel > 3.0){
1568  float psi_gs = atan2f(oneloop_andi.gui_ref.vel[1],oneloop_andi.gui_ref.vel[0]);
1569  float delta_des_gs = psi_gs-psi_des_rad; // Calculate current yaw difference between des and gs
1570  NormRadAngle(delta_des_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
1572  delta_des_gs *= RadOfDeg(60.0)/fabs(delta_des_gs);
1573  psi_des_rad = psi_gs - delta_des_gs;
1574  NormRadAngle(psi_des_rad);
1575  }
1576  }
1577  }
1578  // Register Attitude Setpoints from previous loop
1579  if (!in_flight_oneloop){
1581  }
1583  float att_des[3] = {eulers_zxy_des.phi, eulers_zxy_des.theta, eulers_zxy_des.psi};
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]};
1586  float single_value_d_ref[1] = {oneloop_andi.gui_ref.vel[2]};
1587  float single_value_2d_ref[1] = {oneloop_andi.gui_ref.acc[2]};
1588  float single_value_3d_ref[1] = {oneloop_andi.gui_ref.jer[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){
1594  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_v, max_a_nav, max_j_nav, 1);
1595  oneloop_andi.gui_ref.pos[2] = single_value_ref[0];
1596  oneloop_andi.gui_ref.vel[2] = single_value_d_ref[0];
1597  oneloop_andi.gui_ref.acc[2] = single_value_2d_ref[0];
1598  oneloop_andi.gui_ref.jer[2] = single_value_3d_ref[0];
1599  } else if (rm_order_v == 2){
1600  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);
1602  oneloop_andi.gui_ref.vel[2] = single_value_d_ref[0];
1603  oneloop_andi.gui_ref.acc[2] = single_value_2d_ref[0];
1604  oneloop_andi.gui_ref.jer[2] = single_value_3d_ref[0];
1605  } else if (rm_order_v == 1){
1606  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);
1609  oneloop_andi.gui_ref.acc[2] = single_value_2d_ref[0];
1610  oneloop_andi.gui_ref.jer[2] = single_value_3d_ref[0];
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 
1629 void 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
1633  init_controller();
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)
1688  oneloop_andi_RM(half_loop, PSA_des, rm_order_h, rm_order_v, in_flight_oneloop);
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){
1721  Bound(pitch_pref,0.0,theta_pref_max);
1722  }
1723  u_pref[COMMAND_PITCH] = pitch_pref;
1724  // Calculate the min and max increments
1725  for (i = 0; i < ANDI_NUM_ACT_TOT; i++) {
1726  switch (i) {
1727  case COMMAND_MOTOR_FRONT:
1728  case COMMAND_MOTOR_RIGHT:
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  }
1746  case COMMAND_MOTOR_PUSHER:
1747  case COMMAND_RUDDER:
1750  WLS_one_p.u_pref[i] = (u_pref[i] - actuator_state_1l[i])/ratio_u_un[i];
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  }
1760  WLS_one_p.u_pref[i] = (u_pref[i] - actuator_state_1l[i])/ratio_u_un[i];
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  }
1770  WLS_one_p.u_pref[i] = (u_pref[i] - actuator_state_1l[i])/ratio_u_un[i];
1771  break;
1772  case COMMAND_ELEVATOR:
1775  u_pref[i] = RW.ele_pref;
1776  WLS_one_p.u_pref[i] = (u_pref[i] - actuator_state_1l[i])/ratio_u_un[i];
1777  break;
1778  case COMMAND_ROLL:
1782  break;
1783  case COMMAND_PITCH:
1784  if (RW.skew.deg > 70.0){
1785  WLS_one_p.u_min[i] = (RadOfDeg(-17.0) - oneloop_andi.sta_state.att[i-ANDI_NUM_ACT])/ratio_u_un[i];
1786  WLS_one_p.u_max[i] = (RadOfDeg(17.0) - oneloop_andi.sta_state.att[i-ANDI_NUM_ACT])/ratio_u_un[i];
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
1806  andi_u[COMMAND_ROLL] = andi_du[COMMAND_ROLL] + oneloop_andi.sta_state.att[0];
1807  andi_u[COMMAND_PITCH] = andi_du[COMMAND_PITCH] + oneloop_andi.sta_state.att[1];
1808  } else {
1809  // Not in flight, so don't increment
1811  andi_u[COMMAND_ROLL] = andi_du[COMMAND_ROLL];
1812  andi_u[COMMAND_PITCH] = andi_du[COMMAND_PITCH];
1813  }
1814 #ifdef COMMAND_MOTOR_PUSHER
1815  if ((half_loop)){
1816  andi_u[COMMAND_MOTOR_PUSHER] = radio_control.values[RADIO_AUX4];
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  }
1832  commands[COMMAND_THRUST] = (commands[COMMAND_MOTOR_FRONT] + commands[COMMAND_MOTOR_RIGHT] + commands[COMMAND_MOTOR_BACK] + commands[COMMAND_MOTOR_LEFT])/num_thrusters_oneloop;
1833  autopilot.throttle = commands[COMMAND_THRUST];
1834  stabilization.cmd[COMMAND_THRUST] = commands[COMMAND_THRUST];
1836  eulers_zxy_des.phi = andi_u[COMMAND_ROLL];
1837  eulers_zxy_des.theta = andi_u[COMMAND_PITCH];
1838  } else {
1839  eulers_zxy_des.phi = andi_u[COMMAND_ROLL];
1840  eulers_zxy_des.theta = andi_u[COMMAND_PITCH];
1841  }
1842  if (heading_manual){
1843  psi_des_deg = DegOfRad(psi_des_rad);
1844  }
1845 
1846  stabilization.cmd[COMMAND_ROLL] = (int16_t) (DegOfRad(eulers_zxy_des.phi ) * MAX_PPRZ / DegOfRad(ONELOOP_ANDI_MAX_PHI ));
1847  stabilization.cmd[COMMAND_PITCH] = (int16_t) (DegOfRad(eulers_zxy_des.theta) * MAX_PPRZ / DegOfRad(ONELOOP_ANDI_MAX_THETA));
1848  stabilization.cmd[COMMAND_YAW] = (int16_t) (psi_des_deg * MAX_PPRZ / 180.0);
1849 }
1850 
1853 {
1854  int8_t i;
1855  float prev_actuator_state_1l;
1856  for (i = 0; i < ANDI_NUM_ACT; i++) {
1857  prev_actuator_state_1l = actuator_state_1l[i];
1858  actuator_state_1l[i] = prev_actuator_state_1l + act_dynamics_d[i] * (andi_u[i] - prev_actuator_state_1l);
1859  if(!autopilot_get_motors_on()){
1860  actuator_state_1l[i] = 0.0;
1861  }
1862  Bound(actuator_state_1l[i],act_min[i], act_max[i]);
1863  }
1864 }
1865 
1870 void 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
1935  float ratio_denominator = act_max_norm[i]-act_min_norm[i];
1936  ratio_denominator = positive_non_zero(ratio_denominator); // make sure denominator is non-zero
1937  ratio_u_un[i] = ratio_numerator/ratio_denominator;
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++){
1941  float ratio_numerator = positive_non_zero(nu_norm_max);
1942  float ratio_denominator = 1.0;
1943  switch (i) {
1944  case (RW_aN):
1945  case (RW_aE):
1946  case (RW_aD):
1947  ratio_denominator = positive_non_zero(max_j_nav);
1948  ratio_vn_v[i] = ratio_numerator/ratio_denominator;
1949  break;
1950  case (RW_ap):
1951  case (RW_aq):
1952  case (RW_ar):
1953  ratio_denominator = positive_non_zero(max_j_ang);
1954  ratio_vn_v[i] = ratio_numerator/ratio_denominator;
1955  break;
1956  }
1957  }
1958 }
1959 
1961 void 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 
1970 void 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 {
1994  model_pqr_dot[i] = model_pqr_dot[i] + actuator_state_1l[j] * EFF_MAT_RW[i+3][j];
1995  }
1996  }
1997  }
1998  cf.p_dot.model = model_pqr_dot[0];
1999  cf.q_dot.model = model_pqr_dot[1];
2000  cf.r_dot.model = model_pqr_dot[2];
2001 }
2002 
2004 void oneloop_from_nav(bool in_flight)
2005 {
2006  if (!in_flight) {
2008  }
2009  struct FloatVect3 PSA_des;
2010  PSA_des.x = stateGetPositionNed_f()->x;
2011  PSA_des.y = stateGetPositionNed_f()->y;
2012  PSA_des.z = stateGetPositionNed_f()->z;
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) {
2017  case NAV_SETPOINT_MODE_POS:
2020  rm_order_h = 3;
2021  break;
2025  rm_order_h = 2;
2026  break;
2027  }
2028  switch (nav.vertical_mode) {
2029  case NAV_VERTICAL_MODE_ALT:
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.
2051  float coordinated_turn_roll = eulers_zxy.phi;
2052  // Prevent flipping
2053  if( (eulers_zxy.theta > 0.0f) && ( fabs(eulers_zxy.phi) < eulers_zxy.theta)) {
2054  coordinated_turn_roll = ((eulers_zxy.phi > 0.0f) - (eulers_zxy.phi < 0.0f)) * eulers_zxy.theta;
2055  }
2056  BoundAbs(coordinated_turn_roll, max_phi);
2057  omega = g / airspeed_turn * tanf(coordinated_turn_roll);
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 
2066 static 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 }
2071 static 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 }
2076 static 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 }
2081 static 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 
2097 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[]) {
2098  f0 = positive_non_zero(f0);
2099  f1 = positive_non_zero(f1);
2101  A = positive_non_zero(A);
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;
2114  float p_ref_chirp = chirp_pos_p_ref(time_elapsed, f0, k, A);
2115  float v_ref_chirp = chirp_pos_v_ref(time_elapsed, f0, k, A);
2116  float a_ref_chirp = chirp_pos_a_ref(time_elapsed, f0, k, A);
2117  float j_ref_chirp = chirp_pos_j_ref(time_elapsed, f0, k, A);
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...
2153  pitch_pref = p_ref_chirp;
2154  pitch_pref = (pitch_pref / A + 1.0) * (theta_pref_max / 2.0);
2155  float pitch_offset = RadOfDeg(5.0);
2156  pitch_pref = pitch_pref + pitch_offset;
2157  Bound(pitch_pref,0.0,25.0);
2158  }
2159 }
2160 
2161 void 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;
2166  *t_0 = get_sys_time_float();
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){
2172  *time_elapsed = get_sys_time_float() - *t_0;
2173  chirp_pos(*time_elapsed, f0, f1, t_chirp, A, n, psi, p_ref, v_ref, a_ref, j_ref, p_ref_0);
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 
2190 void reshape_wind(void)
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;
2199  struct FloatVect2 groundspeed = { oneloop_andi.gui_state.vel[0], oneloop_andi.gui_state.vel[1] };
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
2205  float norm_des_as = FLOAT_VECT2_NORM(des_as_NE);
2206  gi_unbounded_airspeed_sp = norm_des_as;
2207  //Check if some minimum airspeed is desired (e.g. to prevent stall)
2208  if (norm_des_as < min_as) {
2209  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;
2216  if (FLOAT_VECT2_NORM(windspeed) < max_as) {
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  }
2228  des_as_NE.x = groundspeed_factor * NT_v_NE.x - windspeed.x;
2229  des_as_NE.y = groundspeed_factor * NT_v_NE.y - windspeed.y;
2230  NT_v_NE.x = groundspeed_factor * NT_v_NE.x;
2231  NT_v_NE.y = groundspeed_factor * NT_v_NE.y;
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
2236  if (((airspeed > ONELOOP_ANDI_AIRSPEED_SWITCH_THRESHOLD) && (norm_des_as > (ONELOOP_ANDI_AIRSPEED_SWITCH_THRESHOLD+2.0f)))|| (force_forward)){
2237  float delta_psi = atan2f(des_as_NE.y, des_as_NE.x) - psi;
2238  FLOAT_ANGLE_NORMALIZE(delta_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 
2251 void guidance_set_min_max_airspeed(float min_airspeed, float max_airspeed) {
2252  min_as = min_airspeed;
2253  max_as = max_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
pprz_t commands[COMMANDS_NB]
Definition: commands.c:30
Hardware independent code for commands handling.
uint8_t last_wp UNUSED
static const float scale[]
float G2_RW[EFF_MAT_COLS_NB]
float ele_min
struct RW_Model RW
float EFF_MAT_RW[EFF_MAT_ROWS_NB][EFF_MAT_COLS_NB]
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 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
#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)
Definition: pprz_algebra.h:92
#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.
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.
Definition: notch_filter.h:83
static void notch_filter_init(struct SecondOrderNotchFilter *filter, float cutoff_frequency, float bandwidth, uint16_t sample_frequency)
Initialize second order notch filter.
Definition: notch_filter.h:119
static float k_e_3_3_f_v2(float omega_n, float zeta, float p1)
Definition: oneloop_andi.c:618
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
Definition: oneloop_andi.c:225
void init_poles(void)
Initialize Position of Poles.
struct PolePlacement p_pos_e
Definition: oneloop_andi.c:435
static float Wv_backup[ANDI_OUTPUTS]
Definition: oneloop_andi.c:406
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
Definition: oneloop_andi.c:462
float act_dynamics[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:178
float ratio_u_un[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:455
static float Wu_backup[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:412
void init_filter(void)
Initialize the filters.
struct PolePlacement p_head_rm
Definition: oneloop_andi.c:442
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
Definition: oneloop_andi.c:463
static float k_e_2_3_f_v2(float omega_n, float zeta, float p1)
Definition: oneloop_andi.c:611
static float k_e_1_2_f_v2(float omega, float zeta)
Error Controller Gain Design.
Definition: oneloop_andi.c:593
float act_max_norm[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:196
struct WLS_t WLS_one_p
Definition: oneloop_andi.c:380
struct Gains3rdOrder k_att_rm
Definition: oneloop_andi.c:445
float max_a_nav
Definition: oneloop_andi.c:250
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:661
float oneloop_andi_filt_cutoff_v
Definition: oneloop_andi.c:128
struct FloatEulers eulers_zxy_des
Definition: oneloop_andi.c:359
float p_ref_0[3]
Definition: oneloop_andi.c:429
struct Int32Eulers stab_att_sp_euler_1l
Definition: oneloop_andi.c:357
struct PolePlacement p_att_rm
Definition: oneloop_andi.c:433
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:945
static float k_rm_3_3_f(float omega_n, float zeta, float p1)
Definition: oneloop_andi.c:641
int16_t temp_pitch
Definition: oneloop_andi.c:342
float max_as
Definition: oneloop_andi.c:270
struct Gains3rdOrder k_att_e
Definition: oneloop_andi.c:444
float psi_des_rad
Definition: oneloop_andi.c:362
float EFF_MAT_G[ANDI_OUTPUTS][ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:454
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:901
void oneloop_andi_propagate_filters(void)
Propagate the filters.
float min_as
Definition: oneloop_andi.c:271
bool ctrl_off
Definition: oneloop_andi.c:376
struct Gains3rdOrder k_pos_e
Definition: oneloop_andi.c:446
float nu[ANDI_OUTPUTS]
Definition: oneloop_andi.c:349
float nu_norm_max
Definition: oneloop_andi.c:208
static Butterworth2LowPass filt_veloc_E
Definition: oneloop_andi.c:460
bool actuator_is_servo[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:171
float oneloop_andi_sideslip(void)
Function to calculate corrections for sideslip.
float num_thrusters_oneloop
Definition: oneloop_andi.c:104
static float act_dynamics_d[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:351
float t_chirp
Definition: oneloop_andi.c:426
float act_min_norm[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:202
#define ONELOOP_ANDI_DEBUG_MODE
Definition: oneloop_andi.c:218
float oneloop_andi_filt_cutoff_q
Definition: oneloop_andi.c:148
float oneloop_andi_filt_cutoff_a
Definition: oneloop_andi.c:122
static float ec_poles(float p_rm, float slow_pole, float k)
Calculate EC poles given RM poles.
static float pitch_pref
Definition: oneloop_andi.c:379
static float g2_ff
Definition: oneloop_andi.c:354
static void send_wls_u_oneloop(struct transport_tx *trans, struct link_device *dev)
Definition: oneloop_andi.c:491
float f0_chirp
Definition: oneloop_andi.c:424
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
Definition: oneloop_andi.c:223
float max_j_nav
Definition: oneloop_andi.c:256
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
Definition: oneloop_andi.c:439
float max_j_ang
Definition: oneloop_andi.c:262
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.
Definition: oneloop_andi.c:977
static float positive_non_zero(float input)
Function to make sure that inputs are positive non zero vaues.
Definition: oneloop_andi.c:583
bool chirp_on
Definition: oneloop_andi.c:420
static void send_eff_mat_stab_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
Definition: oneloop_andi.c:495
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.
Definition: oneloop_andi.c:799
float andi_u[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:346
static float psi_vec[4]
Definition: oneloop_andi.c:364
void calc_normalization(void)
Calculate Normalization of actuators and discrete actuator dynamics
struct Oneloop_CF_t cf
Definition: oneloop_andi.c:416
float fwd_sideslip_gain
Definition: oneloop_andi.c:280
struct Gains3rdOrder k_pos_e_indi
Definition: oneloop_andi.c:450
float f1_chirp
Definition: oneloop_andi.c:425
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
Definition: oneloop_andi.c:432
static void send_eff_mat_guid_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
Definition: oneloop_andi.c:506
static void debug_vect(struct transport_tx *trans, struct link_device *dev, char *name, float *data, int datasize)
Definition: oneloop_andi.c:559
struct PolePlacement p_alt_e
Definition: oneloop_andi.c:438
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:879
float bound_v_from_a(float e_x[], float v_bound, float a_bound, int n)
Calculate velocity limit based on acceleration limit.
Definition: oneloop_andi.c:737
void reshape_wind(void)
static float g
Definition: oneloop_andi.c:340
static float andi_du_n[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:348
void get_act_state_oneloop(void)
Function to reconstruct actuator state using first order dynamics.
float A_chirp
Definition: oneloop_andi.c:427
struct PolePlacement p_head_e
Definition: oneloop_andi.c:441
int8_t chirp_axis
Definition: oneloop_andi.c:428
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]
Definition: oneloop_andi.c:347
float max_v_nav_v
Definition: oneloop_andi.c:276
float max_v_nav
Definition: oneloop_andi.c:268
bool heading_manual
Definition: oneloop_andi.c:369
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
Definition: oneloop_andi.c:423
struct Int32Quat stab_att_sp_quat_1l
Definition: oneloop_andi.c:358
float time_elapsed_chirp
Definition: oneloop_andi.c:422
static void send_wls_v_oneloop(struct transport_tx *trans, struct link_device *dev)
Definition: oneloop_andi.c:487
static float nav_target[3]
Definition: oneloop_andi.c:337
void err_nd(float err[], float a[], float b[], float k[], int n)
Calculate Scaled Error between two 3D arrays.
Definition: oneloop_andi.c:676
static float k_e_1_3_f_v2(float omega_n, UNUSED float zeta, float p1)
Definition: oneloop_andi.c:605
#define ONELOOP_ANDI_AIRSPEED_SWITCH_THRESHOLD
Definition: oneloop_andi.c:243
void calc_model(void)
Function that calculates the model prediction for the complementary filter.
struct OneloopGeneral oneloop_andi
Definition: oneloop_andi.c:333
struct Gains3rdOrder k_pos_rm
Definition: oneloop_andi.c:447
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
Definition: oneloop_andi.c:286
static float use_increment
Definition: oneloop_andi.c:336
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)
Definition: oneloop_andi.c:533
float theta_pref_max
Definition: oneloop_andi.c:228
float act_max[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:184
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:821
bool chirp_first_call
Definition: oneloop_andi.c:421
static Butterworth2LowPass filt_veloc_D
Definition: oneloop_andi.c:461
static Butterworth2LowPass filt_veloc_N
Definition: oneloop_andi.c:459
void normalize_nu(void)
Function to normalize the pseudo control vector.
float psi_des_deg
Definition: oneloop_andi.c:363
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:849
struct FloatEulers eulers_zxy
Definition: oneloop_andi.c:360
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.
Definition: oneloop_andi.c:649
float oneloop_andi_filt_cutoff_p
Definition: oneloop_andi.c:141
static struct Oneloop_notch_t oneloop_notch
Definition: oneloop_andi.c:417
static float k_rm_1_3_f(float omega_n, float zeta, float p1)
Reference Model Gain Design.
Definition: oneloop_andi.c:627
static float k_e_2_2_f_v2(float omega, float zeta)
Definition: oneloop_andi.c:599
float gi_unbounded_airspeed_sp
Definition: oneloop_andi.c:343
float oneloop_andi_filt_cutoff_r
Definition: oneloop_andi.c:155
void init_poles_att(void)
Initialize Position of Poles.
float k_as
Definition: oneloop_andi.c:341
struct PolePlacement p_pos_rm
Definition: oneloop_andi.c:436
float ratio_vn_v[ANDI_OUTPUTS]
Definition: oneloop_andi.c:456
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)
Definition: oneloop_andi.c:949
float nu_n[ANDI_OUTPUTS]
Definition: oneloop_andi.c:350
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
Definition: oneloop_andi.c:222
bool yaw_stick_in_auto
Definition: oneloop_andi.c:374
void vect_bound_nd(float vect[], float bound, int n)
Scale a 3D array to within a 3D bound.
Definition: oneloop_andi.c:704
void err_sum_nd(float err[], float a[], float b[], float k[], float c[], int n)
Calculate Scaled Error between two 3D arrays.
Definition: oneloop_andi.c:685
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.
Definition: oneloop_andi.c:695
static float dt_1l
Definition: oneloop_andi.c:339
static void send_oneloop_andi(struct transport_tx *trans, struct link_device *dev)
Definition: oneloop_andi.c:513
struct Gains3rdOrder k_att_e_indi
Definition: oneloop_andi.c:449
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.
Definition: oneloop_andi.c:758
static void send_oneloop_debug(struct transport_tx *trans, struct link_device *dev)
Definition: oneloop_andi.c:566
float act_min[ANDI_NUM_ACT_TOT]
Definition: oneloop_andi.c:190
float actuator_state_1l[ANDI_NUM_ACT]
Definition: oneloop_andi.c:352
static float a_thrust
Definition: oneloop_andi.c:353
float oneloop_andi_filt_cutoff_pos
Definition: oneloop_andi.c:134
float max_r
Definition: oneloop_andi.c:163
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:922
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.
Definition: oneloop_andi.c:717
float * bwls_1l[ANDI_OUTPUTS]
Definition: oneloop_andi.c:453
void init_poles_pos(void)
static float k_rm_2_3_f(float omega_n, float zeta, float p1)
Definition: oneloop_andi.c:634
static float nav_target_new[3]
Definition: oneloop_andi.c:338
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]
Definition: oneloop_andi.c:214
float oneloop_andi_filt_cutoff
Definition: oneloop_andi.c:116
struct OneloopGuidanceState gui_state
Definition: oneloop_andi.h:130
struct notch_axis_t yaw
Definition: oneloop_andi.h:194
struct OneloopStabilizationState sta_state
Definition: oneloop_andi.h:132
struct CF4_t q_dot
Definition: oneloop_andi.h:179
Butterworth2LowPass feedback_filt
Definition: oneloop_andi.h:170
float feedback
Definition: oneloop_andi.h:169
float out
Definition: oneloop_andi.h:171
struct CF2_t az
Definition: oneloop_andi.h:183
float model
Definition: oneloop_andi.h:157
#define CTRL_INDI
Definition: oneloop_andi.h:60
#define ANDI_NUM_ACT
Definition: oneloop_andi.h:37
Butterworth4LowPass feedback_filt
Definition: oneloop_andi.h:160
Butterworth4LowPass model_filt
Definition: oneloop_andi.h:158
struct OneloopGuidanceRef gui_ref
Definition: oneloop_andi.h:129
#define CTRL_ANDI
Control types.
Definition: oneloop_andi.h:59
struct CF2_t p
Definition: oneloop_andi.h:175
struct OneloopStabilizationRef sta_ref
Definition: oneloop_andi.h:131
struct notch_axis_t pitch
Definition: oneloop_andi.h:193
#define ANDI_NUM_ACT_TOT
Definition: oneloop_andi.h:50
struct CF2_t ay
Definition: oneloop_andi.h:182
float feedback
Definition: oneloop_andi.h:159
struct notch_axis_t roll
Definition: oneloop_andi.h:192
struct CF2_t q
Definition: oneloop_andi.h:176
struct CF2_t r
Definition: oneloop_andi.h:177
float model
Definition: oneloop_andi.h:167
struct SecondOrderNotchFilter filter
Definition: oneloop_andi.h:187
#define ANDI_OUTPUTS
Definition: oneloop_andi.h:54
struct CF2_t r_dot
Definition: oneloop_andi.h:180
struct CF2_t ax
Definition: oneloop_andi.h:181
struct CF4_t p_dot
Definition: oneloop_andi.h:178
float out
Definition: oneloop_andi.h:161
Butterworth2LowPass model_filt
Definition: oneloop_andi.h:168
#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
Definition: radio_control.c:33
Generic interface for radio control modules.
pprz_t values[RADIO_CONTROL_NB_CHANNEL]
Definition: radio_control.h:67
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
#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
Definition: rotwing_state.c:99
enum rotwing_states_t state
Definition: rotwing_state.h:63
bool hover_motors_enabled
Definition: rotwing_state.h:65
@ ROTWING_STATE_FORCE_HOVER
Definition: rotwing_state.h:42
struct Stabilization stabilization
Definition: stabilization.c:41
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]
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
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