Paparazzi UAS  v6.3_unstable
Paparazzi is a free software Unmanned Aircraft System.
stabilization_indi.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) Ewoud Smeur <ewoud_smeur@msn.com>
3  * MAVLab Delft University of Technology
4  *
5  * This file is part of paparazzi.
6  *
7  * paparazzi is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * paparazzi is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with paparazzi; see the file COPYING. If not, write to
19  * the Free Software Foundation, 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 
37 
39 #include "state.h"
40 #include "generated/airframe.h"
43 #include "modules/core/abi.h"
45 #include "wls/wls_alloc.h"
46 #include <stdio.h>
47 
48 // Factor that the estimated G matrix is allowed to deviate from initial one
49 #define INDI_ALLOWED_G_FACTOR 2.0
50 
51 #ifdef STABILIZATION_INDI_FILT_CUTOFF_P
52 #define STABILIZATION_INDI_FILTER_ROLL_RATE TRUE
53 #else
54 #define STABILIZATION_INDI_FILT_CUTOFF_P 20.0
55 #endif
56 
57 #ifdef STABILIZATION_INDI_FILT_CUTOFF_Q
58 #define STABILIZATION_INDI_FILTER_PITCH_RATE TRUE
59 #else
60 #define STABILIZATION_INDI_FILT_CUTOFF_Q 20.0
61 #endif
62 
63 #ifdef STABILIZATION_INDI_FILT_CUTOFF_R
64 #define STABILIZATION_INDI_FILTER_YAW_RATE TRUE
65 #else
66 #define STABILIZATION_INDI_FILT_CUTOFF_R 20.0
67 #endif
68 
69 // Default is WLS
70 #ifndef STABILIZATION_INDI_ALLOCATION_PSEUDO_INVERSE
71 #define STABILIZATION_INDI_ALLOCATION_PSEUDO_INVERSE FALSE
72 #endif
73 
74 #ifndef INDI_FILTER_RATES_SECOND_ORDER
75 #define INDI_FILTER_RATES_SECOND_ORDER FALSE
76 #endif
77 
78 // Airspeed [m/s] at which the forward flight throttle limit is used instead of
79 // the hover throttle limit.
80 #ifndef INDI_HROTTLE_LIMIT_AIRSPEED_FWD
81 #define INDI_HROTTLE_LIMIT_AIRSPEED_FWD 8.0
82 #endif
83 
84 float du_min[INDI_NUM_ACT];
85 float du_max[INDI_NUM_ACT];
86 float du_pref[INDI_NUM_ACT];
87 float indi_v[INDI_OUTPUTS];
88 float *Bwls[INDI_OUTPUTS];
89 int num_iter = 0;
90 
91 static void lms_estimation(void);
92 static void get_actuator_state(void);
93 static void calc_g1_element(float dx_error, int8_t i, int8_t j, float mu_extra);
94 static void calc_g2_element(float dx_error, int8_t j, float mu_extra);
95 #if STABILIZATION_INDI_ALLOCATION_PSEUDO_INVERSE
96 static void calc_g1g2_pseudo_inv(void);
97 #endif
98 static void bound_g_mat(void);
99 
101 struct Indi_gains indi_gains = {
102  .att = {
103  STABILIZATION_INDI_REF_ERR_P,
104  STABILIZATION_INDI_REF_ERR_Q,
105  STABILIZATION_INDI_REF_ERR_R
106  },
107  .rate = {
108  STABILIZATION_INDI_REF_RATE_P,
109  STABILIZATION_INDI_REF_RATE_Q,
110  STABILIZATION_INDI_REF_RATE_R
111  },
112 };
113 
114 #if STABILIZATION_INDI_USE_ADAPTIVE
115 bool indi_use_adaptive = true;
116 #else
117 bool indi_use_adaptive = false;
118 #endif
119 
120 #ifdef STABILIZATION_INDI_ACT_RATE_LIMIT
121 float act_rate_limit[INDI_NUM_ACT] = STABILIZATION_INDI_ACT_RATE_LIMIT;
122 #endif
123 
124 #ifdef STABILIZATION_INDI_ACT_IS_SERVO
125 bool act_is_servo[INDI_NUM_ACT] = STABILIZATION_INDI_ACT_IS_SERVO;
126 #else
127 bool act_is_servo[INDI_NUM_ACT] = {0};
128 #endif
129 
130 #ifdef STABILIZATION_INDI_ACT_PREF
131 // Preferred (neutral, least energy) actuator value
132 float act_pref[INDI_NUM_ACT] = STABILIZATION_INDI_ACT_PREF;
133 #else
134 // Assume 0 is neutral
135 float act_pref[INDI_NUM_ACT] = {0.0};
136 #endif
137 
138 float act_dyn[INDI_NUM_ACT] = STABILIZATION_INDI_ACT_DYN;
139 
140 #ifdef STABILIZATION_INDI_WLS_PRIORITIES
141 static float Wv[INDI_OUTPUTS] = STABILIZATION_INDI_WLS_PRIORITIES;
142 #else
143 //State prioritization {W Roll, W pitch, W yaw, TOTAL THRUST}
144 static float Wv[INDI_OUTPUTS] = {1000, 1000, 1, 100};
145 #endif
146 
150 #ifdef STABILIZATION_INDI_WLS_WU
151 float indi_Wu[INDI_NUM_ACT] = STABILIZATION_INDI_WLS_WU;
152 #else
153 float indi_Wu[INDI_NUM_ACT] = {[0 ... INDI_NUM_ACT-1] = 1.0};
154 #endif
155 
156 // variables needed for control
157 float actuator_state_filt_vect[INDI_NUM_ACT];
158 struct FloatRates angular_accel_ref = {0., 0., 0.};
159 struct FloatRates angular_rate_ref = {0., 0., 0.};
160 float angular_acceleration[3] = {0., 0., 0.};
161 float actuator_state[INDI_NUM_ACT];
162 float indi_u[INDI_NUM_ACT];
163 float indi_du[INDI_NUM_ACT];
165 
166 float q_filt = 0.0;
167 float r_filt = 0.0;
168 
169 // variables needed for estimation
170 float g1g2_trans_mult[INDI_OUTPUTS][INDI_OUTPUTS];
171 float g1g2inv[INDI_OUTPUTS][INDI_OUTPUTS];
172 float actuator_state_filt_vectd[INDI_NUM_ACT];
173 float actuator_state_filt_vectdd[INDI_NUM_ACT];
174 float estimation_rate_d[INDI_NUM_ACT];
175 float estimation_rate_dd[INDI_NUM_ACT];
176 float du_estimation[INDI_NUM_ACT];
177 float ddu_estimation[INDI_NUM_ACT];
178 
179 // The learning rate per axis (roll, pitch, yaw, thrust)
180 float mu1[INDI_OUTPUTS] = {0.00001, 0.00001, 0.000003, 0.000002};
181 // The learning rate for the propeller inertia (scaled by 512 wrt mu1)
182 float mu2 = 0.002;
183 
184 // other variables
185 float act_obs[INDI_NUM_ACT];
186 
187 // Number of actuators used to provide thrust
189 
193 
195 static void rpm_cb(uint8_t sender_id, struct rpm_act_t *rpm_msg, uint8_t num_act);
196 
198 static void thrust_cb(uint8_t sender_id, struct FloatVect3 thrust_increment);
201 
202 float g1g2_pseudo_inv[INDI_NUM_ACT][INDI_OUTPUTS];
203 float g2[INDI_NUM_ACT] = STABILIZATION_INDI_G2; //scaled by INDI_G_SCALING
204 float g1[INDI_OUTPUTS][INDI_NUM_ACT] = {STABILIZATION_INDI_G1_ROLL,
205  STABILIZATION_INDI_G1_PITCH, STABILIZATION_INDI_G1_YAW, STABILIZATION_INDI_G1_THRUST
206  };
207 float g1g2[INDI_OUTPUTS][INDI_NUM_ACT];
208 float g1_est[INDI_OUTPUTS][INDI_NUM_ACT];
209 float g2_est[INDI_NUM_ACT];
210 float g1_init[INDI_OUTPUTS][INDI_NUM_ACT];
211 float g2_init[INDI_NUM_ACT];
212 
218 #if INDI_FILTER_RATES_SECOND_ORDER
219 Butterworth2LowPass rates_filt_so[3];
220 #else
221 static struct FirstOrderLowPass rates_filt_fo[3];
222 #endif
223 struct FloatVect3 body_accel_f;
224 
225 void init_filters(void);
226 void sum_g1_g2(void);
227 
228 #if PERIODIC_TELEMETRY
230 static void send_indi_g(struct transport_tx *trans, struct link_device *dev)
231 {
232  pprz_msg_send_INDI_G(trans, dev, AC_ID, INDI_NUM_ACT, g1_est[0],
233  INDI_NUM_ACT, g1_est[1],
234  INDI_NUM_ACT, g1_est[2],
235  INDI_NUM_ACT, g1_est[3],
236  INDI_NUM_ACT, g2_est);
237 }
238 
239 static void send_ahrs_ref_quat(struct transport_tx *trans, struct link_device *dev)
240 {
241  struct Int32Quat *quat = stateGetNedToBodyQuat_i();
242  pprz_msg_send_AHRS_REF_QUAT(trans, dev, AC_ID,
247  &(quat->qi),
248  &(quat->qx),
249  &(quat->qy),
250  &(quat->qz));
251 }
252 
253 static void send_att_full_indi(struct transport_tx *trans, struct link_device *dev)
254 {
255  struct FloatRates *body_rates = stateGetBodyRates_f();
256  struct Int32Vect3 *body_accel_i = stateGetAccelBody_i();
257  struct FloatVect3 body_accel_f_telem;
258  ACCELS_FLOAT_OF_BFP(body_accel_f_telem, *body_accel_i);
259  float zero = 0;
260  pprz_msg_send_STAB_ATTITUDE_INDI(trans, dev, AC_ID,
261  &body_accel_f_telem.x, // input lin.acc
262  &body_accel_f_telem.y,
263  &body_accel_f_telem.z,
264  &body_rates->p, // rate
265  &body_rates->q,
266  &body_rates->r,
267  &angular_rate_ref.p, // rate.sp
270  &angular_acceleration[0], // ang.acc
273  &angular_accel_ref.p, // ang.acc.sp
276  &zero, &zero, // eff.mat
277  &zero, &zero,
278  INDI_NUM_ACT, indi_u); // out
279 }
280 #endif
281 
286 {
287  // Initialize filters
288  init_filters();
289 
290  AbiBindMsgRPM(RPM_SENSOR_ID, &rpm_ev, rpm_cb);
291  AbiBindMsgTHRUST(THRUST_INCREMENT_ID, &thrust_ev, thrust_cb);
292 
295  float_vect_zero(estimation_rate_d, INDI_NUM_ACT);
296  float_vect_zero(estimation_rate_dd, INDI_NUM_ACT);
298 
299  //Calculate G1G2
300  sum_g1_g2();
301 
302  // Do not compute if not needed
303  #if STABILIZATION_INDI_ALLOCATION_PSEUDO_INVERSE
304  //Calculate G1G2_PSEUDO_INVERSE
305  calc_g1g2_pseudo_inv();
306  #endif
307 
308  int8_t i;
309  // Initialize the array of pointers to the rows of g1g2
310  for (i = 0; i < INDI_OUTPUTS; i++) {
311  Bwls[i] = g1g2[i];
312  }
313 
314  // Initialize the estimator matrices
315  float_vect_copy(g1_est[0], g1[0], INDI_OUTPUTS * INDI_NUM_ACT);
316  float_vect_copy(g2_est, g2, INDI_NUM_ACT);
317  // Remember the initial matrices
318  float_vect_copy(g1_init[0], g1[0], INDI_OUTPUTS * INDI_NUM_ACT);
319  float_vect_copy(g2_init, g2, INDI_NUM_ACT);
320 
321  // Assume all non-servos are delivering thrust
322  num_thrusters = INDI_NUM_ACT;
323  for (i = 0; i < INDI_NUM_ACT; i++) {
325  }
326 
327 #if PERIODIC_TELEMETRY
330  register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_STAB_ATTITUDE_INDI, send_att_full_indi);
331 #endif
332 }
333 
343 {
344  /* reset psi setpoint to current psi angle */
346 
347  float_vect_zero(du_estimation, INDI_NUM_ACT);
348  float_vect_zero(ddu_estimation, INDI_NUM_ACT);
349 }
350 
354 void init_filters(void)
355 {
356  // tau = 1/(2*pi*Fc)
357  float tau = 1.0 / (2.0 * M_PI * STABILIZATION_INDI_FILT_CUTOFF);
358  float tau_est = 1.0 / (2.0 * M_PI * STABILIZATION_INDI_ESTIMATION_FILT_CUTOFF);
359  float sample_time = 1.0 / PERIODIC_FREQUENCY;
360  // Filtering of the gyroscope
361  int8_t i;
362  for (i = 0; i < 3; i++) {
363  init_butterworth_2_low_pass(&measurement_lowpass_filters[i], tau, sample_time, 0.0);
364  init_butterworth_2_low_pass(&estimation_output_lowpass_filters[i], tau_est, sample_time, 0.0);
365  }
366 
367  // Filtering of the actuators
368  for (i = 0; i < INDI_NUM_ACT; i++) {
369  init_butterworth_2_low_pass(&actuator_lowpass_filters[i], tau, sample_time, 0.0);
370  init_butterworth_2_low_pass(&estimation_input_lowpass_filters[i], tau_est, sample_time, 0.0);
371  }
372 
373  // Filtering of the accel body z
374  init_butterworth_2_low_pass(&acceleration_lowpass_filter, tau_est, sample_time, 0.0);
375 
376 #if INDI_FILTER_RATES_SECOND_ORDER
377  tau = 1.0 / (2.0 * M_PI * STABILIZATION_INDI_FILT_CUTOFF_P);
378  init_butterworth_2_low_pass(&rates_filt_so[0], tau, sample_time, 0.0);
379  tau = 1.0 / (2.0 * M_PI * STABILIZATION_INDI_FILT_CUTOFF_Q);
380  init_butterworth_2_low_pass(&rates_filt_so[1], tau, sample_time, 0.0);
381  tau = 1.0 / (2.0 * M_PI * STABILIZATION_INDI_FILT_CUTOFF_R);
382  init_butterworth_2_low_pass(&rates_filt_so[2], tau, sample_time, 0.0);
383 #else
384  // Init rate filter for feedback
385  float time_constants[3] = {1.0 / (2 * M_PI * STABILIZATION_INDI_FILT_CUTOFF_P), 1.0 / (2 * M_PI * STABILIZATION_INDI_FILT_CUTOFF_Q), 1.0 / (2 * M_PI * STABILIZATION_INDI_FILT_CUTOFF_R)};
386 
387  init_first_order_low_pass(&rates_filt_fo[0], time_constants[0], sample_time, stateGetBodyRates_f()->p);
388  init_first_order_low_pass(&rates_filt_fo[1], time_constants[1], sample_time, stateGetBodyRates_f()->q);
389  init_first_order_low_pass(&rates_filt_fo[2], time_constants[2], sample_time, stateGetBodyRates_f()->r);
390 #endif
391 }
392 
397 {
398  /* set failsafe to zero roll/pitch and current heading */
401  stab_att_sp_quat.qx = 0;
402  stab_att_sp_quat.qy = 0;
404 }
405 
412 {
413  // stab_att_sp_euler.psi still used in ref..
414  stab_att_sp_euler = *rpy;
415 
418 }
419 
424 {
425  stab_att_sp_quat = *quat;
428 }
429 
437 {
438  // stab_att_sp_euler.psi still used in ref..
440 
441  // compute sp_euler phi/theta for debugging/telemetry
442  /* Rotate horizontal commands to body frame by psi */
444  int32_t s_psi, c_psi;
445  PPRZ_ITRIG_SIN(s_psi, psi);
446  PPRZ_ITRIG_COS(c_psi, psi);
447  stab_att_sp_euler.phi = (-s_psi * cmd->x + c_psi * cmd->y) >> INT32_TRIG_FRAC;
448  stab_att_sp_euler.theta = -(c_psi * cmd->x + s_psi * cmd->y) >> INT32_TRIG_FRAC;
449 
452 }
453 
460 {
464 }
465 
473 void stabilization_indi_rate_run(struct FloatRates rate_sp, bool in_flight)
474 {
475  /* Propagate the filter on the gyroscopes */
476  struct FloatRates *body_rates = stateGetBodyRates_f();
477  float rate_vect[3] = {body_rates->p, body_rates->q, body_rates->r};
478  int8_t i;
479  for (i = 0; i < 3; i++) {
482 
483  //Calculate the angular acceleration via finite difference
485  - measurement_lowpass_filters[i].o[1]) * PERIODIC_FREQUENCY;
486 
487  // Calculate derivatives for estimation
488  float estimation_rate_d_prev = estimation_rate_d[i];
490  PERIODIC_FREQUENCY;
491  estimation_rate_dd[i] = (estimation_rate_d[i] - estimation_rate_d_prev) * PERIODIC_FREQUENCY;
492  }
493 
494  //The rates used for feedback are by default the measured rates.
495  //If there is a lot of noise on the gyroscope, it might be good to use the filtered value for feedback.
496  //Note that due to the delay, the PD controller may need relaxed gains.
497  struct FloatRates rates_filt;
498 #if STABILIZATION_INDI_FILTER_ROLL_RATE
499 #if INDI_FILTER_RATES_SECOND_ORDER
500  rates_filt.p = update_butterworth_2_low_pass(&rates_filt_so[0], body_rates->p);
501 #else
502  rates_filt.p = update_first_order_low_pass(&rates_filt_fo[0], body_rates->p);
503 #endif
504 #else
505  rates_filt.p = body_rates->p;
506 #endif
507 #if STABILIZATION_INDI_FILTER_PITCH_RATE
508 #if INDI_FILTER_RATES_SECOND_ORDER
509  rates_filt.q = update_butterworth_2_low_pass(&rates_filt_so[1], body_rates->q);
510 #else
511  rates_filt.q = update_first_order_low_pass(&rates_filt_fo[1], body_rates->q);
512 #endif
513 #else
514  rates_filt.q = body_rates->q;
515 #endif
516 #if STABILIZATION_INDI_FILTER_YAW_RATE
517 #if INDI_FILTER_RATES_SECOND_ORDER
518  rates_filt.r = update_butterworth_2_low_pass(&rates_filt_so[2], body_rates->r);
519 #else
520  rates_filt.r = update_first_order_low_pass(&rates_filt_fo[2], body_rates->r);
521 #endif
522 #else
523  rates_filt.r = body_rates->r;
524 #endif
525 
526  //calculate the virtual control (reference acceleration) based on a PD controller
527  angular_accel_ref.p = (rate_sp.p - rates_filt.p) * indi_gains.rate.p;
528  angular_accel_ref.q = (rate_sp.q - rates_filt.q) * indi_gains.rate.q;
529  angular_accel_ref.r = (rate_sp.r - rates_filt.r) * indi_gains.rate.r;
530 
531  g2_times_du = 0.0;
532  for (i = 0; i < INDI_NUM_ACT; i++) {
533  g2_times_du += g2[i] * indi_du[i];
534  }
535  //G2 is scaled by INDI_G_SCALING to make it readable
537 
538  float use_increment = 0.0;
539  if(in_flight) {
540  use_increment = 1.0;
541  }
542 
543  struct FloatVect3 v_thrust;
544  v_thrust.x = 0.0;
545  v_thrust.y = 0.0;
546  v_thrust.z = 0.0;
548  v_thrust = indi_thrust_increment;
549 
550  //update thrust command such that the current is correctly estimated
551  stabilization_cmd[COMMAND_THRUST] = 0;
552  for (i = 0; i < INDI_NUM_ACT; i++) {
553  stabilization_cmd[COMMAND_THRUST] += actuator_state[i] * -((int32_t) act_is_servo[i] - 1);
554  }
555  stabilization_cmd[COMMAND_THRUST] /= num_thrusters;
556 
557  } else {
558  // incremental thrust
559  for (i = 0; i < INDI_NUM_ACT; i++) {
560  v_thrust.z +=
561  (stabilization_cmd[COMMAND_THRUST] - use_increment*actuator_state_filt_vect[i]) * Bwls[3][i];
562  }
563  }
564 
565  // The control objective in array format
566  indi_v[0] = (angular_accel_ref.p - use_increment*angular_acceleration[0]);
567  indi_v[1] = (angular_accel_ref.q - use_increment*angular_acceleration[1]);
568  indi_v[2] = (angular_accel_ref.r - use_increment*angular_acceleration[2] + g2_times_du);
569  indi_v[3] = v_thrust.z;
570 
571 #if STABILIZATION_INDI_ALLOCATION_PSEUDO_INVERSE
572  // Calculate the increment for each actuator
573  for (i = 0; i < INDI_NUM_ACT; i++) {
574  indi_du[i] = (g1g2_pseudo_inv[i][0] * indi_v[0])
575  + (g1g2_pseudo_inv[i][1] * indi_v[1])
576  + (g1g2_pseudo_inv[i][2] * indi_v[2])
577  + (g1g2_pseudo_inv[i][3] * indi_v[3]);
578  }
579 #else
580  // Calculate the min and max increments
581  for (i = 0; i < INDI_NUM_ACT; i++) {
582  du_min[i] = -MAX_PPRZ * act_is_servo[i] - use_increment*actuator_state_filt_vect[i];
583  du_max[i] = MAX_PPRZ - use_increment*actuator_state_filt_vect[i];
584  du_pref[i] = act_pref[i] - use_increment*actuator_state_filt_vect[i];
585 
586 #ifdef GUIDANCE_INDI_MIN_THROTTLE
587  float airspeed = stateGetAirspeed_f();
588  //limit minimum thrust ap can give
589  if (!act_is_servo[i]) {
591  if (airspeed < INDI_HROTTLE_LIMIT_AIRSPEED_FWD) {
592  du_min[i] = GUIDANCE_INDI_MIN_THROTTLE - use_increment*actuator_state_filt_vect[i];
593  } else {
594  du_min[i] = GUIDANCE_INDI_MIN_THROTTLE_FWD - use_increment*actuator_state_filt_vect[i];
595  }
596  }
597  }
598 #endif
599  }
600 
601  // WLS Control Allocator
602  num_iter =
603  wls_alloc(indi_du, indi_v, du_min, du_max, Bwls, 0, 0, Wv, indi_Wu, du_pref, 10000, 10);
604 #endif
605 
606  if (in_flight) {
607  // Add the increments to the actuators
609  } else {
610  // Not in flight, so don't increment
611  float_vect_copy(indi_u, indi_du, INDI_NUM_ACT);
612  }
613 
614  // Bound the inputs to the actuators
615  for (i = 0; i < INDI_NUM_ACT; i++) {
616  if (act_is_servo[i]) {
617  BoundAbs(indi_u[i], MAX_PPRZ);
618  } else {
619  if (autopilot_get_motors_on()) {
620  Bound(indi_u[i], 0, MAX_PPRZ);
621  }
622  else {
623  indi_u[i] = -MAX_PPRZ;
624  }
625  }
626  }
627 
628  // Propagate actuator filters
630  for (i = 0; i < INDI_NUM_ACT; i++) {
634 
635  // calculate derivatives for estimation
636  float actuator_state_filt_vectd_prev = actuator_state_filt_vectd[i];
638  PERIODIC_FREQUENCY;
639  actuator_state_filt_vectdd[i] = (actuator_state_filt_vectd[i] - actuator_state_filt_vectd_prev) * PERIODIC_FREQUENCY;
640  }
641 
642  // Use online effectiveness estimation only when flying
643  if (in_flight && indi_use_adaptive) {
644  lms_estimation();
645  }
646 
647  /*Commit the actuator command*/
648  for (i = 0; i < INDI_NUM_ACT; i++) {
649  actuators_pprz[i] = (int16_t) indi_u[i];
650  }
651 
652  // Set the stab_cmd to 42 to indicate that it is not used
653  stabilization_cmd[COMMAND_ROLL] = 42;
654  stabilization_cmd[COMMAND_PITCH] = 42;
655  stabilization_cmd[COMMAND_YAW] = 42;
656 }
657 
664 void stabilization_indi_attitude_run(struct Int32Quat quat_sp, bool in_flight)
665 {
666  /* attitude error */
667  struct FloatQuat att_err;
668  struct FloatQuat *att_quat = stateGetNedToBodyQuat_f();
669  struct FloatQuat quat_sp_f;
670 
671  QUAT_FLOAT_OF_BFP(quat_sp_f, quat_sp);
672  float_quat_inv_comp_norm_shortest(&att_err, att_quat, &quat_sp_f);
673 
674  struct FloatVect3 att_fb;
675 
676 #if TILT_TWIST_CTRL
677  struct FloatQuat tilt;
678  struct FloatQuat twist;
679  float_quat_tilt_twist(&tilt, &twist, &att_err);
680  att_fb.x = tilt.qx;
681  att_fb.y = tilt.qy;
682  att_fb.z = twist.qz;
683 #else
684  att_fb.x = att_err.qx;
685  att_fb.y = att_err.qy;
686  att_fb.z = att_err.qz;
687 #endif
688 
689  // local variable to compute rate setpoints based on attitude error
690  struct FloatRates rate_sp;
691 
692  // calculate the virtual control (reference acceleration) based on a PD controller
693  rate_sp.p = indi_gains.att.p * att_fb.x / indi_gains.rate.p;
694  rate_sp.q = indi_gains.att.q * att_fb.y / indi_gains.rate.q;
695  rate_sp.r = indi_gains.att.r * att_fb.z / indi_gains.rate.r;
696 
697  // Add feed-forward rates to the attitude feedback part
698  RATES_ADD(rate_sp, stab_att_ff_rates);
699 
700  // Store for telemetry
701  angular_rate_ref.p = rate_sp.p;
702  angular_rate_ref.q = rate_sp.q;
703  angular_rate_ref.r = rate_sp.r;
704 
705  // Possibly we can use some bounding here
706  /*BoundAbs(rate_sp.r, 5.0);*/
707 
708  /* compute the INDI command */
709  stabilization_indi_rate_run(rate_sp, in_flight);
710 
711  // Reset thrust increment boolean
713 }
714 
715 // This function reads rc commands
716 void stabilization_indi_read_rc(bool in_flight, bool in_carefree, bool coordinated_turn)
717 {
718  struct FloatQuat q_sp;
719 #if USE_EARTH_BOUND_RC_SETPOINT
720  stabilization_attitude_read_rc_setpoint_quat_earth_bound_f(&q_sp, in_flight, in_carefree, coordinated_turn);
721 #else
722  stabilization_attitude_read_rc_setpoint_quat_f(&q_sp, in_flight, in_carefree, coordinated_turn);
723 #endif
724 
726 }
727 
735 {
736 #if INDI_RPM_FEEDBACK
737  float_vect_copy(actuator_state, act_obs, INDI_NUM_ACT);
738 #else
739  //actuator dynamics
740  int8_t i;
741  float UNUSED prev_actuator_state;
742  for (i = 0; i < INDI_NUM_ACT; i++) {
743  prev_actuator_state = actuator_state[i];
744 
746  + act_dyn[i] * (indi_u[i] - actuator_state[i]);
747 
748 #ifdef STABILIZATION_INDI_ACT_RATE_LIMIT
749  if ((actuator_state[i] - prev_actuator_state) > act_rate_limit[i]) {
750  actuator_state[i] = prev_actuator_state + act_rate_limit[i];
751  } else if ((actuator_state[i] - prev_actuator_state) < -act_rate_limit[i]) {
752  actuator_state[i] = prev_actuator_state - act_rate_limit[i];
753  }
754 #endif
755  }
756 
757 #endif
758 }
759 
770 void calc_g1_element(float ddx_error, int8_t i, int8_t j, float mu)
771 {
772  g1_est[i][j] = g1_est[i][j] - du_estimation[j] * mu * ddx_error;
773 }
774 
784 void calc_g2_element(float ddx_error, int8_t j, float mu)
785 {
786  g2_est[j] = g2_est[j] - ddu_estimation[j] * mu * ddx_error;
787 }
788 
794 void lms_estimation(void)
795 {
796 
797  // Get the acceleration in body axes
798  struct Int32Vect3 *body_accel_i;
799  body_accel_i = stateGetAccelBody_i();
800  ACCELS_FLOAT_OF_BFP(body_accel_f, *body_accel_i);
801 
802  // Filter the acceleration in z axis
804 
805  // Calculate the derivative of the acceleration via finite difference
806  float indi_accel_d = (acceleration_lowpass_filter.o[0]
807  - acceleration_lowpass_filter.o[1]) * PERIODIC_FREQUENCY;
808 
809  // Use xml setting for adaptive mu for lms
810  // Set default value if not defined
811  #ifndef STABILIZATION_INDI_ADAPTIVE_MU
812  float adaptive_mu_lr = 0.001;
813  #else
814  float adaptive_mu_lr = STABILIZATION_INDI_ADAPTIVE_MU;
815  #endif
816 
817  // scale the inputs to avoid numerical errors
818  float_vect_smul(du_estimation, actuator_state_filt_vectd, adaptive_mu_lr, INDI_NUM_ACT);
819  float_vect_smul(ddu_estimation, actuator_state_filt_vectdd, adaptive_mu_lr / PERIODIC_FREQUENCY, INDI_NUM_ACT);
820 
821  float ddx_estimation[INDI_OUTPUTS] = {estimation_rate_dd[0], estimation_rate_dd[1], estimation_rate_dd[2], indi_accel_d};
822 
823  //Estimation of G
824  // TODO: only estimate when du_norm2 is large enough (enough input)
825  /*float du_norm2 = du_estimation[0]*du_estimation[0] + du_estimation[1]*du_estimation[1] +du_estimation[2]*du_estimation[2] + du_estimation[3]*du_estimation[3];*/
826  int8_t i;
827  for (i = 0; i < INDI_OUTPUTS; i++) {
828  // Calculate the error between prediction and measurement
829  float ddx_error = - ddx_estimation[i];
830  int8_t j;
831  for (j = 0; j < INDI_NUM_ACT; j++) {
832  ddx_error += g1_est[i][j] * du_estimation[j];
833  if (i == 2) {
834  // Changing the momentum of the rotors gives a counter torque
835  ddx_error += g2_est[j] * ddu_estimation[j];
836  }
837  }
838 
839  // when doing the yaw axis, also use G2
840  if (i == 2) {
841  for (j = 0; j < INDI_NUM_ACT; j++) {
842  calc_g2_element(ddx_error, j, mu2);
843  }
844  } else if (i == 3) {
845  // If the acceleration change is very large (rough landing), don't adapt
846  if (fabs(indi_accel_d) > 60.0) {
847  ddx_error = 0.0;
848  }
849  }
850 
851  // Calculate the row of the G1 matrix corresponding to this axis
852  for (j = 0; j < INDI_NUM_ACT; j++) {
853  calc_g1_element(ddx_error, i, j, mu1[i]);
854  }
855  }
856 
857  bound_g_mat();
858 
859  // Save the calculated matrix to G1 and G2
860  // until thrust is included, first part of the array
861  float_vect_copy(g1[0], g1_est[0], INDI_OUTPUTS * INDI_NUM_ACT);
862  float_vect_copy(g2, g2_est, INDI_NUM_ACT);
863 
864  // Calculate sum of G1 and G2 for Bwls
865  sum_g1_g2();
866 
867 #if STABILIZATION_INDI_ALLOCATION_PSEUDO_INVERSE
868  // Calculate the inverse of (G1+G2)
869  calc_g1g2_pseudo_inv();
870 #endif
871 }
872 
877 void sum_g1_g2(void) {
878  int8_t i;
879  int8_t j;
880  for (i = 0; i < INDI_OUTPUTS; i++) {
881  for (j = 0; j < INDI_NUM_ACT; j++) {
882  if (i != 2) {
883  g1g2[i][j] = g1[i][j] / INDI_G_SCALING;
884  } else {
885  g1g2[i][j] = (g1[i][j] + g2[j]) / INDI_G_SCALING;
886  }
887  }
888  }
889 }
890 
891 #if STABILIZATION_INDI_ALLOCATION_PSEUDO_INVERSE
896 void calc_g1g2_pseudo_inv(void)
897 {
898  //G1G2*transpose(G1G2)
899  //calculate matrix multiplication of its transpose INDI_OUTPUTSxnum_act x num_actxINDI_OUTPUTS
900  float element = 0;
901  int8_t row;
902  int8_t col;
903  int8_t i;
904  for (row = 0; row < INDI_OUTPUTS; row++) {
905  for (col = 0; col < INDI_OUTPUTS; col++) {
906  element = 0;
907  for (i = 0; i < INDI_NUM_ACT; i++) {
908  element = element + g1g2[row][i] * g1g2[col][i];
909  }
910  g1g2_trans_mult[row][col] = element;
911  }
912  }
913 
914  //there are numerical errors if the scaling is not right.
915  float_vect_scale(g1g2_trans_mult[0], 1000.0, INDI_OUTPUTS * INDI_OUTPUTS);
916 
917  //inverse of 4x4 matrix
919 
920  //scale back
921  float_vect_scale(g1g2inv[0], 1000.0, INDI_OUTPUTS * INDI_OUTPUTS);
922 
923  //G1G2'*G1G2inv
924  //calculate matrix multiplication INDI_NUM_ACTxINDI_OUTPUTS x INDI_OUTPUTSxINDI_OUTPUTS
925  for (row = 0; row < INDI_NUM_ACT; row++) {
926  for (col = 0; col < INDI_OUTPUTS; col++) {
927  element = 0;
928  for (i = 0; i < INDI_OUTPUTS; i++) {
929  element = element + g1g2[i][row] * g1g2inv[col][i];
930  }
931  g1g2_pseudo_inv[row][col] = element;
932  }
933  }
934 }
935 #endif
936 
937 static void rpm_cb(uint8_t sender_id UNUSED, struct rpm_act_t *rpm_msg UNUSED, uint8_t num_act UNUSED)
938 {
939 #if INDI_RPM_FEEDBACK
940 PRINT_CONFIG_MSG("INDI_RPM_FEEDBACK");
941  int8_t i;
942  for (i = 0; i < num_act; i++) {
943  // Sanity check that index is valid
944  if (rpm_msg[i].actuator_idx < INDI_NUM_ACT) {
945  int8_t idx = rpm_msg[i].actuator_idx;
946  act_obs[idx] = (rpm_msg[i].rpm - get_servo_min(idx));
947  act_obs[idx] *= (MAX_PPRZ / (float)(get_servo_max(idx) - get_servo_min(idx)));
948  Bound(act_obs[idx], 0, MAX_PPRZ);
949  }
950  }
951 #endif
952 }
953 
957 static void thrust_cb(uint8_t UNUSED sender_id, struct FloatVect3 thrust_increment)
958 {
959  indi_thrust_increment = thrust_increment;
961 }
962 
963 static void bound_g_mat(void)
964 {
965  int8_t i;
966  int8_t j;
967  for (j = 0; j < INDI_NUM_ACT; j++) {
968  float max_limit;
969  float min_limit;
970 
971  // Limit the values of the estimated G1 matrix
972  for (i = 0; i < INDI_OUTPUTS; i++) {
973  if (g1_init[i][j] > 0.0) {
974  max_limit = g1_init[i][j] * INDI_ALLOWED_G_FACTOR;
975  min_limit = g1_init[i][j] / INDI_ALLOWED_G_FACTOR;
976  } else {
977  max_limit = g1_init[i][j] / INDI_ALLOWED_G_FACTOR;
978  min_limit = g1_init[i][j] * INDI_ALLOWED_G_FACTOR;
979  }
980 
981  if (g1_est[i][j] > max_limit) {
982  g1_est[i][j] = max_limit;
983  }
984  if (g1_est[i][j] < min_limit) {
985  g1_est[i][j] = min_limit;
986  }
987  }
988 
989  // Do the same for the G2 matrix
990  if (g2_init[j] > 0.0) {
991  max_limit = g2_init[j] * INDI_ALLOWED_G_FACTOR;
992  min_limit = g2_init[j] / INDI_ALLOWED_G_FACTOR;
993  } else {
994  max_limit = g2_init[j] / INDI_ALLOWED_G_FACTOR;
995  min_limit = g2_init[j] * INDI_ALLOWED_G_FACTOR;
996  }
997 
998  if (g2_est[j] > max_limit) {
999  g2_est[j] = max_limit;
1000  }
1001  if (g2_est[j] < min_limit) {
1002  g2_est[j] = min_limit;
1003  }
1004  }
1005 }
Main include for ABI (AirBorneInterface).
Event structure to store callbacks in a linked list.
Definition: abi_common.h:67
#define RPM_SENSOR_ID
#define THRUST_INCREMENT_ID
bool autopilot_get_motors_on(void)
get motors status
Definition: autopilot.c:244
uint8_t last_wp UNUSED
float q
in rad/s
float p
in rad/s
float r
in rad/s
static void float_vect_sum(float *o, const float *a, const float *b, const int n)
o = a + b
static void float_vect_zero(float *a, const int n)
a = 0
void float_quat_inv_comp_norm_shortest(struct FloatQuat *b2c, struct FloatQuat *a2b, struct FloatQuat *a2c)
Composition (multiplication) of two quaternions with normalization.
static void float_vect_smul(float *o, const float *a, const float s, const int n)
o = a * s
static void float_vect_scale(float *a, const float s, const int n)
a *= s
static void float_vect_copy(float *a, const float *b, const int n)
a = b
void float_quat_tilt_twist(struct FloatQuat *tilt, struct FloatQuat *twist, struct FloatQuat *quat)
Tilt twist decomposition of a quaternion (z axis)
bool float_mat_inv_4d(float invOut[4][4], float mat_in[4][4])
4x4 Matrix inverse
#define FLOAT_RATES_ZERO(_r)
Roation quaternion.
angular rates
#define QUAT_BFP_OF_REAL(_qi, _qf)
Definition: pprz_algebra.h:752
#define RATES_ADD(_a, _b)
Definition: pprz_algebra.h:344
#define QUAT_FLOAT_OF_BFP(_qf, _qi)
Definition: pprz_algebra.h:745
#define ACCELS_FLOAT_OF_BFP(_ef, _ei)
Definition: pprz_algebra.h:795
int32_t phi
in rad with INT32_ANGLE_FRAC
int32_t psi
in rad with INT32_ANGLE_FRAC
int32_t theta
in rad with INT32_ANGLE_FRAC
void int32_eulers_of_quat(struct Int32Eulers *e, struct Int32Quat *q)
#define INT32_TRIG_FRAC
void int32_quat_of_eulers(struct Int32Quat *q, struct Int32Eulers *e)
Quaternion from Euler angles.
euler angles
Rotation quaternion.
static struct Int32Quat * stateGetNedToBodyQuat_i(void)
Get vehicle body attitude quaternion (int).
Definition: state.h:1113
static struct Int32Eulers * stateGetNedToBodyEulers_i(void)
Get vehicle body attitude euler angles (int).
Definition: state.h:1125
static struct FloatQuat * stateGetNedToBodyQuat_f(void)
Get vehicle body attitude quaternion (float).
Definition: state.h:1131
static struct FloatRates * stateGetBodyRates_f(void)
Get vehicle body angular rate (float).
Definition: state.h:1200
static struct Int32Vect3 * stateGetAccelBody_i(void)
Get acceleration in Body coordinates (int).
Definition: state.h:953
static float stateGetAirspeed_f(void)
Get airspeed (float).
Definition: state.h:1407
static float p[2][2]
PRINT_CONFIG_MSG("USE_INS_NAV_INIT defaulting to TRUE")
Simple first order low pass filter with bilinear transform.
float o[2]
output history
static float update_first_order_low_pass(struct FirstOrderLowPass *filter, float value)
Update first order low pass filter state with a new value.
static void init_butterworth_2_low_pass(Butterworth2LowPass *filter, float tau, float sample_time, float value)
Init a second order Butterworth filter.
static void init_first_order_low_pass(struct FirstOrderLowPass *filter, float tau, float sample_time, float value)
Init first order low pass filter.
static float update_butterworth_2_low_pass(Butterworth2LowPass *filter, float value)
Update second order Butterworth low pass filter state with a new value.
First order low pass filter structure.
Second order low pass filter structure.
Hardware independent API for actuators (servos, motor controllers).
static float mu
Physical model parameters.
Definition: nps_fdm_rover.c:60
static uint32_t idx
#define MAX_PPRZ
Definition: paparazzi.h:8
Paparazzi floating point algebra.
#define PPRZ_ITRIG_SIN(_s, _a)
#define PPRZ_ITRIG_COS(_c, _a)
Generic interface for radio control modules.
struct HorizontalGuidance guidance_h
Definition: guidance_h.c:50
#define GUIDANCE_H_MODE_NAV
Definition: guidance_h.h:60
#define GUIDANCE_H_MODE_HOVER
Definition: guidance_h.h:59
General attitude stabilization interface for rotorcrafts.
int32_t stabilization_cmd[COMMANDS_NB]
Stabilization commands.
Definition: stabilization.c:34
struct FloatRates stab_sp_to_rates_f(struct StabilizationSetpoint *sp)
struct Int32Quat stab_sp_to_quat_i(struct StabilizationSetpoint *sp)
struct Int32Eulers stab_sp_to_eulers_i(struct StabilizationSetpoint *sp)
void quat_from_earth_cmd_i(struct Int32Quat *quat, struct Int32Vect2 *cmd, int32_t heading)
Quaternion transformation functions.
int32_t stabilization_attitude_get_heading_i(void)
void stabilization_attitude_read_rc_setpoint_quat_earth_bound_f(struct FloatQuat *q_sp, bool in_flight, bool in_carefree, bool coordinated_turn)
void stabilization_attitude_read_rc_setpoint_quat_f(struct FloatQuat *q_sp, bool in_flight, bool in_carefree, bool coordinated_turn)
Read attitude setpoint from RC as quaternion Interprets the stick positions as axes.
Read an attitude setpoint from the RC.
static void calc_g1_element(float dx_error, int8_t i, int8_t j, float mu_extra)
float du_max[INDI_NUM_ACT]
Butterworth2LowPass acceleration_lowpass_filter
static void send_ahrs_ref_quat(struct transport_tx *trans, struct link_device *dev)
void stabilization_indi_read_rc(bool in_flight, bool in_carefree, bool coordinated_turn)
void stabilization_indi_enter(void)
Function that resets important values upon engaging INDI.
static float Wv[INDI_OUTPUTS]
float act_pref[INDI_NUM_ACT]
float * Bwls[INDI_OUTPUTS]
int32_t stabilization_att_indi_cmd[COMMANDS_NB]
struct Indi_gains indi_gains
void stabilization_indi_set_failsafe_setpoint(void)
Function that calculates the failsafe setpoint.
bool act_is_servo[INDI_NUM_ACT]
void stabilization_indi_attitude_run(struct Int32Quat quat_sp, bool in_flight)
static struct FirstOrderLowPass rates_filt_fo[3]
float angular_acceleration[3]
int32_t num_thrusters
void stabilization_indi_set_earth_cmd_i(struct Int32Vect2 *cmd, int32_t heading)
float actuator_state_filt_vectd[INDI_NUM_ACT]
abi_event rpm_ev
float indi_Wu[INDI_NUM_ACT]
Weighting of different actuators in the cost function.
float r_filt
#define STABILIZATION_INDI_FILT_CUTOFF_P
static void bound_g_mat(void)
float mu1[INDI_OUTPUTS]
#define STABILIZATION_INDI_FILT_CUTOFF_Q
float g1g2[INDI_OUTPUTS][INDI_NUM_ACT]
static void calc_g2_element(float dx_error, int8_t j, float mu_extra)
float q_filt
struct Int32Eulers stab_att_sp_euler
with INT32_ANGLE_FRAC
float estimation_rate_d[INDI_NUM_ACT]
float du_estimation[INDI_NUM_ACT]
float actuator_state_filt_vectdd[INDI_NUM_ACT]
static void thrust_cb(uint8_t sender_id, struct FloatVect3 thrust_increment)
abi_event thrust_ev
#define INDI_HROTTLE_LIMIT_AIRSPEED_FWD
Butterworth2LowPass measurement_lowpass_filters[3]
bool indi_thrust_increment_set
void stabilization_indi_rate_run(struct FloatRates rate_sp, bool in_flight)
float g2[INDI_NUM_ACT]
struct FloatVect3 body_accel_f
float ddu_estimation[INDI_NUM_ACT]
float estimation_rate_dd[INDI_NUM_ACT]
float mu2
float act_obs[INDI_NUM_ACT]
float g1[INDI_OUTPUTS][INDI_NUM_ACT]
void stabilization_indi_init(void)
Function that initializes important values upon engaging INDI.
static void send_indi_g(struct transport_tx *trans, struct link_device *dev)
float act_dyn[INDI_NUM_ACT]
struct FloatRates angular_rate_ref
void stabilization_indi_set_stab_sp(struct StabilizationSetpoint *sp)
Set attitude setpoint from stabilization setpoint struct.
float du_min[INDI_NUM_ACT]
float g1g2inv[INDI_OUTPUTS][INDI_OUTPUTS]
void stabilization_indi_set_rpy_setpoint_i(struct Int32Eulers *rpy)
float actuator_state_filt_vect[INDI_NUM_ACT]
struct FloatRates angular_accel_ref
float g1g2_trans_mult[INDI_OUTPUTS][INDI_OUTPUTS]
#define STABILIZATION_INDI_FILT_CUTOFF_R
bool indi_use_adaptive
float g2_init[INDI_NUM_ACT]
float du_pref[INDI_NUM_ACT]
float g2_times_du
struct FloatVect3 indi_thrust_increment
Butterworth2LowPass estimation_input_lowpass_filters[INDI_NUM_ACT]
void sum_g1_g2(void)
Function that sums g1 and g2 to obtain the g1g2 matrix It also undoes the scaling that was done to ma...
float g1g2_pseudo_inv[INDI_NUM_ACT][INDI_OUTPUTS]
float g2_est[INDI_NUM_ACT]
float g1_init[INDI_OUTPUTS][INDI_NUM_ACT]
struct Int32Quat stab_att_sp_quat
with INT32_QUAT_FRAC
float actuator_state[INDI_NUM_ACT]
static void lms_estimation(void)
Function that estimates the control effectiveness of each actuator online.
static void send_att_full_indi(struct transport_tx *trans, struct link_device *dev)
#define INDI_ALLOWED_G_FACTOR
float g1_est[INDI_OUTPUTS][INDI_NUM_ACT]
float indi_v[INDI_OUTPUTS]
void stabilization_indi_set_quat_setpoint_i(struct Int32Quat *quat)
static void rpm_cb(uint8_t sender_id, struct rpm_act_t *rpm_msg, uint8_t num_act)
int num_iter
float indi_u[INDI_NUM_ACT]
static void get_actuator_state(void)
Function that tries to get actuator feedback.
Butterworth2LowPass actuator_lowpass_filters[INDI_NUM_ACT]
struct FloatRates stab_att_ff_rates
void init_filters(void)
Function that resets the filters to zeros.
Butterworth2LowPass estimation_output_lowpass_filters[3]
float indi_du[INDI_NUM_ACT]
#define INDI_G_SCALING
#define STABILIZATION_INDI_ESTIMATION_FILT_CUTOFF
#define STABILIZATION_INDI_FILT_CUTOFF
struct FloatRates rate
struct FloatRates att
API to get/set the generic vehicle states.
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:74
Stabilization setpoint.
Definition: stabilization.h:42
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
int int32_t
Typedef defining 32 bit int type.
Definition: vl53l1_types.h:83
short int16_t
Typedef defining 16 bit short type.
Definition: vl53l1_types.h:93
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98
signed char int8_t
Typedef defining 8 bit char type.
Definition: vl53l1_types.h:103
float heading
Definition: wedgebug.c:258
int wls_alloc(float *u, float *v, float *umin, float *umax, float **B, float *u_guess, float *W_init, float *Wv, float *Wu, float *up, float gamma_sq, int imax)
active set algorithm for control allocation
Definition: wls_alloc.c:112