Paparazzi UAS  v5.8.2_stable-0-g6260b7c
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
stabilization_attitude_quat_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 
35 
36 #include "state.h"
37 #include "generated/airframe.h"
38 #include "paparazzi.h"
39 
40 #if !defined(STABILIZATION_INDI_ACT_DYN_P) && !defined(STABILIZATION_INDI_ACT_DYN_Q) && !defined(STABILIZATION_INDI_ACT_DYN_R)
41 #error You have to define the first order time constant of the actuator dynamics!
42 #endif
43 
45 
46 struct FloatRates g1 = {STABILIZATION_INDI_G1_P, STABILIZATION_INDI_G1_Q, STABILIZATION_INDI_G1_R};
47 float g2 = STABILIZATION_INDI_G2_R;
48 struct ReferenceSystem reference_acceleration = {STABILIZATION_INDI_REF_ERR_P,
49  STABILIZATION_INDI_REF_ERR_Q,
50  STABILIZATION_INDI_REF_ERR_R,
51  STABILIZATION_INDI_REF_RATE_P,
52  STABILIZATION_INDI_REF_RATE_Q,
53  STABILIZATION_INDI_REF_RATE_R,
54 };
55 
56 struct IndiVariables indi = {
57  {0., 0., 0.},
58  {0., 0., 0.},
59  {0., 0., 0.},
60  {0., 0., 0.},
61  {0., 0., 0.},
62  {0., 0., 0.},
63  {0., 0., 0.},
64  {0., 0., 0.},
65  {0., 0., 0.},
66  {0., 0., 0.}
67 };
68 
71 
72 // Variables for adaptation
73 struct FloatRates filtered_rate_estimation = {0., 0., 0.};
76 struct FloatRates indi_u_estimation = {0., 0., 0.};
77 struct FloatRates udot_estimation = {0., 0., 0.};
78 struct FloatRates udotdot_estimation = {0., 0., 0.};
79 #define INDI_EST_SCALE 0.001 //The G values are scaled to avoid numerical problems during the estimation
80 struct FloatRates g_est = {STABILIZATION_INDI_G1_P / INDI_EST_SCALE, STABILIZATION_INDI_G1_Q / INDI_EST_SCALE, STABILIZATION_INDI_G1_R / INDI_EST_SCALE};
81 float g2_est = STABILIZATION_INDI_G2_R / INDI_EST_SCALE;
82 float mu = STABILIZATION_INDI_ADAPTIVE_MU;
83 
84 #if STABILIZATION_INDI_USE_ADAPTIVE
85 #warning "Use caution with adaptive indi. See the wiki for more info"
86 bool_t use_adaptive_indi = TRUE;
87 #else
89 #endif
90 
91 #ifndef STABILIZATION_INDI_FILT_OMEGA
92 #define STABILIZATION_INDI_FILT_OMEGA 50.0
93 #endif
94 
95 #ifndef STABILIZATION_INDI_FILT_ZETA
96 #define STABILIZATION_INDI_FILT_ZETA 0.55
97 #endif
98 
99 #define STABILIZATION_INDI_FILT_OMEGA2 (STABILIZATION_INDI_FILT_OMEGA*STABILIZATION_INDI_FILT_OMEGA)
100 
101 #ifndef STABILIZATION_INDI_FILT_OMEGA_R
102 #define STABILIZATION_INDI_FILT_OMEGA_R STABILIZATION_INDI_FILT_OMEGA
103 #define STABILIZATION_INDI_FILT_ZETA_R STABILIZATION_INDI_FILT_ZETA
104 #endif
105 
106 #define STABILIZATION_INDI_FILT_OMEGA2_R (STABILIZATION_INDI_FILT_OMEGA_R*STABILIZATION_INDI_FILT_OMEGA_R)
107 
108 #if PERIODIC_TELEMETRY
110 
111 static void send_att_indi(struct transport_tx *trans, struct link_device *dev)
112 {
113  //The estimated G values are scaled, so scale them back before sending
114  struct FloatRates g_est_disp;
115  RATES_SMUL(g_est_disp, g_est, INDI_EST_SCALE);
116  float g2_est_disp = g2_est * INDI_EST_SCALE;
117 
118  pprz_msg_send_STAB_ATTITUDE_INDI(trans, dev, AC_ID,
119  &indi.filtered_rate_deriv.p,
120  &indi.filtered_rate_deriv.q,
121  &indi.filtered_rate_deriv.r,
122  &indi.angular_accel_ref.p,
123  &indi.angular_accel_ref.q,
124  &indi.angular_accel_ref.r,
125  &g_est_disp.p,
126  &g_est_disp.q,
127  &g_est_disp.r,
128  &g2_est_disp);
129 }
130 #endif
131 
133 {
134 
135 #if PERIODIC_TELEMETRY
136  register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_STAB_ATTITUDE_INDI, send_att_indi);
137 #endif
138 }
139 
141 {
142 
143  /* reset psi setpoint to current psi angle */
145 
150  FLOAT_RATES_ZERO(indi.u);
151  FLOAT_RATES_ZERO(indi.du);
153  FLOAT_RATES_ZERO(indi.u_in);
154  FLOAT_RATES_ZERO(indi.udot);
156 
157 }
158 
160 {
161  /* set failsafe to zero roll/pitch and current heading */
164  stab_att_sp_quat.qx = 0;
165  stab_att_sp_quat.qy = 0;
167 }
168 
170 {
171  // stab_att_sp_euler.psi still used in ref..
172  stab_att_sp_euler = *rpy;
173 
175 }
176 
178 {
179  // stab_att_sp_euler.psi still used in ref..
181 
182  // compute sp_euler phi/theta for debugging/telemetry
183  /* Rotate horizontal commands to body frame by psi */
185  int32_t s_psi, c_psi;
186  PPRZ_ITRIG_SIN(s_psi, psi);
187  PPRZ_ITRIG_COS(c_psi, psi);
188  stab_att_sp_euler.phi = (-s_psi * cmd->x + c_psi * cmd->y) >> INT32_TRIG_FRAC;
189  stab_att_sp_euler.theta = -(c_psi * cmd->x + s_psi * cmd->y) >> INT32_TRIG_FRAC;
190 
191  quat_from_earth_cmd_i(&stab_att_sp_quat, cmd, heading);
192 }
193 
194 static void attitude_run_indi(int32_t indi_commands[], struct Int32Quat *att_err, bool_t in_flight __attribute__((unused)))
195 {
196  //Calculate required angular acceleration
197  struct FloatRates *body_rate = stateGetBodyRates_f();
198 #if STABILIZATION_INDI_FILTER_ROLL_RATE
199  indi.angular_accel_ref.p = reference_acceleration.err_p * QUAT1_FLOAT_OF_BFP(att_err->qx)
200  - reference_acceleration.rate_p * indi.filtered_rate.p;
201 #else
202  indi.angular_accel_ref.p = reference_acceleration.err_p * QUAT1_FLOAT_OF_BFP(att_err->qx)
203  - reference_acceleration.rate_p * body_rate->p;
204 #endif
205 #if STABILIZATION_INDI_FILTER_PITCH_RATE
206  indi.angular_accel_ref.q = reference_acceleration.err_q * QUAT1_FLOAT_OF_BFP(att_err->qy)
207  - reference_acceleration.rate_q * indi.filtered_rate.q;
208 #else
209  indi.angular_accel_ref.q = reference_acceleration.err_q * QUAT1_FLOAT_OF_BFP(att_err->qy)
210  - reference_acceleration.rate_q * body_rate->q;
211 #endif
212 #if STABILIZATION_INDI_FILTER_YAW_RATE
213  indi.angular_accel_ref.r = reference_acceleration.err_r * QUAT1_FLOAT_OF_BFP(att_err->qz)
214  - reference_acceleration.rate_r * indi.filtered_rate.r;
215 #else
216  indi.angular_accel_ref.r = reference_acceleration.err_r * QUAT1_FLOAT_OF_BFP(att_err->qz)
217  - reference_acceleration.rate_r * body_rate->r;
218 #endif
219 
220  //Incremented in angular acceleration requires increment in control input
221  //G1 is the actuator effectiveness. In the yaw axis, we need something additional: G2.
222  //It takes care of the angular acceleration caused by the change in rotation rate of the propellers
223  //(they have significant inertia, see the paper mentioned in the header for more explanation)
224  indi.du.p = 1.0 / g1.p * (indi.angular_accel_ref.p - indi.filtered_rate_deriv.p);
225  indi.du.q = 1.0 / g1.q * (indi.angular_accel_ref.q - indi.filtered_rate_deriv.q);
226  indi.du.r = 1.0 / (g1.r + g2) * (indi.angular_accel_ref.r - indi.filtered_rate_deriv.r + g2 * indi.du.r);
227 
228  //add the increment to the total control input
229  indi.u_in.p = indi.u.p + indi.du.p;
230  indi.u_in.q = indi.u.q + indi.du.q;
231  indi.u_in.r = indi.u.r + indi.du.r;
232 
233  //bound the total control input
234  Bound(indi.u_in.p, -4500, 4500);
235  Bound(indi.u_in.q, -4500, 4500);
236  Bound(indi.u_in.r, -4500, 4500);
237 
238  //Propagate input filters
239  //first order actuator dynamics
240  indi.u_act_dyn.p = indi.u_act_dyn.p + STABILIZATION_INDI_ACT_DYN_P * (indi.u_in.p - indi.u_act_dyn.p);
241  indi.u_act_dyn.q = indi.u_act_dyn.q + STABILIZATION_INDI_ACT_DYN_Q * (indi.u_in.q - indi.u_act_dyn.q);
242  indi.u_act_dyn.r = indi.u_act_dyn.r + STABILIZATION_INDI_ACT_DYN_R * (indi.u_in.r - indi.u_act_dyn.r);
243 
244  //sensor filter
247 
248  //Don't increment if thrust is off
249  if (stabilization_cmd[COMMAND_THRUST] < 300) {
250  FLOAT_RATES_ZERO(indi.u);
251  FLOAT_RATES_ZERO(indi.du);
253  FLOAT_RATES_ZERO(indi.u_in);
254  FLOAT_RATES_ZERO(indi.udot);
256  } else {
257  lms_estimation();
258  }
259 
260  /* INDI feedback */
261  indi_commands[COMMAND_ROLL] = indi.u_in.p;
262  indi_commands[COMMAND_PITCH] = indi.u_in.q;
263  indi_commands[COMMAND_YAW] = indi.u_in.r;
264 }
265 
266 void stabilization_attitude_run(bool_t enable_integrator)
267 {
268 
269  /* Propagate the second order filter on the gyroscopes */
270  struct FloatRates *body_rates = stateGetBodyRates_f();
273 
274  /* attitude error */
275  struct Int32Quat att_err;
276  struct Int32Quat *att_quat = stateGetNedToBodyQuat_i();
277 // INT32_QUAT_INV_COMP(att_err, *att_quat, stab_att_sp_quat);
278  int32_quat_inv_comp(&att_err, att_quat, &stab_att_sp_quat);
279  /* wrap it in the shortest direction */
280  int32_quat_wrap_shortest(&att_err);
281  int32_quat_normalize(&att_err);
282 
283  /* compute the INDI command */
284  attitude_run_indi(stabilization_att_indi_cmd, &att_err, enable_integrator);
285 
286  stabilization_cmd[COMMAND_ROLL] = stabilization_att_indi_cmd[COMMAND_ROLL];
287  stabilization_cmd[COMMAND_PITCH] = stabilization_att_indi_cmd[COMMAND_PITCH];
288  stabilization_cmd[COMMAND_YAW] = stabilization_att_indi_cmd[COMMAND_YAW];
289 
290  /* bound the result */
291  BoundAbs(stabilization_cmd[COMMAND_ROLL], MAX_PPRZ);
292  BoundAbs(stabilization_cmd[COMMAND_PITCH], MAX_PPRZ);
293  BoundAbs(stabilization_cmd[COMMAND_YAW], MAX_PPRZ);
294 }
295 
296 // This function reads rc commands
297 void stabilization_attitude_read_rc(bool_t in_flight, bool_t in_carefree, bool_t coordinated_turn)
298 {
299  struct FloatQuat q_sp;
300 #if USE_EARTH_BOUND_RC_SETPOINT
301  stabilization_attitude_read_rc_setpoint_quat_earth_bound_f(&q_sp, in_flight, in_carefree, coordinated_turn);
302 #else
303  stabilization_attitude_read_rc_setpoint_quat_f(&q_sp, in_flight, in_carefree, coordinated_turn);
304 #endif
306 }
307 
308 // This is a simple second order low pass filter
309 void stabilization_indi_second_order_filter(struct FloatRates *input, struct FloatRates *filter_ddx,
310  struct FloatRates *filter_dx, struct FloatRates *filter_x, float omega, float zeta, float omega_r)
311 {
312  float_rates_integrate_fi(filter_x, filter_dx, 1.0 / PERIODIC_FREQUENCY);
313  float_rates_integrate_fi(filter_dx, filter_ddx, 1.0 / PERIODIC_FREQUENCY);
314  float omega2 = omega * omega;
315  float omega2_r = omega_r * omega_r;
316 
317  filter_ddx->p = -filter_dx->p * 2 * zeta * omega + (input->p - filter_x->p) * omega2; \
318  filter_ddx->q = -filter_dx->q * 2 * zeta * omega + (input->q - filter_x->q) * omega2; \
319  filter_ddx->r = -filter_dx->r * 2 * zeta * omega_r + (input->r - filter_x->r) * omega2_r;
320 }
321 
322 // This is a Least Mean Squares adaptive filter
323 // It estiamtes the actuator effectiveness online by comparing the expected angular acceleration based on the inputs with the measured angular acceleration
324 void lms_estimation(void)
325 {
326 
327  // Only pass really low frequencies so you don't adapt to noise
328  float omega = 10.0;
329  float zeta = 0.8;
330  stabilization_indi_second_order_filter(&indi.u_act_dyn, &udotdot_estimation, &udot_estimation, &indi_u_estimation,
331  omega, zeta, omega);
332  struct FloatRates *body_rates = stateGetBodyRates_f();
333  stabilization_indi_second_order_filter(body_rates, &filtered_rate_2deriv_estimation, &filtered_rate_deriv_estimation,
334  &filtered_rate_estimation, omega, zeta, omega);
335 
336  // The inputs are scaled in order to avoid overflows
337  float du = udot_estimation.p * INDI_EST_SCALE;
338  g_est.p = g_est.p - (g_est.p * du - filtered_rate_2deriv_estimation.p) * du * mu;
339  du = udot_estimation.q * INDI_EST_SCALE;
340  g_est.q = g_est.q - (g_est.q * du - filtered_rate_2deriv_estimation.q) * du * mu;
341  du = udot_estimation.r * INDI_EST_SCALE;
342  float ddu = udotdot_estimation.r * INDI_EST_SCALE / PERIODIC_FREQUENCY;
343  float error = (g_est.r * du + g2_est * ddu - filtered_rate_2deriv_estimation.r);
344  g_est.r = g_est.r - error * du * mu / 3;
345  g2_est = g2_est - error * 1000 * ddu * mu / 3;
346 
347  //the g values should be larger than zero, otherwise there is positive feedback, the command will go to max and there is nothing to learn anymore...
348  if (g_est.p < 0.01) { g_est.p = 0.01; }
349  if (g_est.q < 0.01) { g_est.q = 0.01; }
350  if (g_est.r < 0.01) { g_est.r = 0.01; }
351  if (g2_est < 0.01) { g2_est = 0.01; }
352 
353  if (use_adaptive_indi) {
354  //Commit the estimated G values and apply the scaling
355  g1.p = g_est.p * INDI_EST_SCALE;
356  g1.q = g_est.q * INDI_EST_SCALE;
357  g1.r = g_est.r * INDI_EST_SCALE;
359  }
360 }
int32_t psi
in rad with INT32_ANGLE_FRAC
void stabilization_indi_second_order_filter(struct FloatRates *input, struct FloatRates *filter_ddx, struct FloatRates *filter_dx, struct FloatRates *filter_x, float omega, float zeta, float omega_r)
static void int32_quat_normalize(struct Int32Quat *q)
normalize a quaternion inplace
struct FloatRates udotdot_estimation
void int32_quat_inv_comp(struct Int32Quat *b2c, struct Int32Quat *a2b, struct Int32Quat *a2c)
Composition (multiplication) of two quaternions.
Generic transmission transport header.
Definition: transport.h:89
Quaternion transformation functions.
struct FloatRates udot_estimation
Periodic telemetry system header (includes downlink utility and generated code).
General attitude stabilization interface for rotorcrafts.
int32_t theta
in rad with INT32_ANGLE_FRAC
void int32_quat_of_eulers(struct Int32Quat *q, struct Int32Eulers *e)
Quaternion from Euler angles.
int32_t stabilization_attitude_get_heading_i(void)
float r
in rad/s
Read an attitude setpoint from the RC.
void stabilization_attitude_read_rc(bool_t in_flight, bool_t in_carefree, bool_t coordinated_turn)
int32_t stabilization_att_indi_cmd[COMMANDS_NB]
#define FLOAT_RATES_ZERO(_r)
float q
in rad/s
float p
in rad/s
static struct Int32Quat * stateGetNedToBodyQuat_i(void)
Get vehicle body attitude quaternion (int).
Definition: state.h:1084
#define STABILIZATION_INDI_FILT_OMEGA
void stabilization_attitude_set_rpy_setpoint_i(struct Int32Eulers *rpy)
static const float omega_r[]
struct FloatRates indi_u_estimation
void stabilization_attitude_init(void)
#define FALSE
Definition: std.h:5
struct FloatRates angular_accel_ref
Roation quaternion.
#define PPRZ_ITRIG_SIN(_s, _a)
struct Int32Eulers stab_att_sp_euler
with INT32_ANGLE_FRAC
#define STABILIZATION_INDI_FILT_OMEGA_R
#define TRUE
Definition: std.h:4
static float heading
Definition: ahrs_infrared.c:45
void stabilization_attitude_set_failsafe_setpoint(void)
void float_rates_integrate_fi(struct FloatRates *r, struct FloatRates *dr, float dt)
in place first order integration of angular rates
euler angles
#define QUAT_BFP_OF_REAL(_qi, _qf)
Definition: pprz_algebra.h:685
#define DefaultPeriodic
Set default periodic telemetry.
Definition: telemetry.h:66
#define INDI_EST_SCALE
struct ReferenceSystem reference_acceleration
struct FloatRates filtered_rate_deriv_estimation
void quat_from_earth_cmd_i(struct Int32Quat *quat, struct Int32Vect2 *cmd, int32_t heading)
#define RATES_SMUL(_ro, _ri, _s)
Definition: pprz_algebra.h:378
struct FloatRates filtered_rate_estimation
static struct FloatRates * stateGetBodyRates_f(void)
Get vehicle body angular rate (float).
Definition: state.h:1171
signed long int32_t
Definition: types.h:19
#define QUAT1_FLOAT_OF_BFP(_qi)
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:69
#define INT32_TRIG_FRAC
int32_t phi
in rad with INT32_ANGLE_FRAC
struct FloatRates g1
API to get/set the generic vehicle states.
void stabilization_attitude_read_rc_setpoint_quat_f(struct FloatQuat *q_sp, bool_t in_flight, bool_t in_carefree, bool_t coordinated_turn)
Read attitude setpoint from RC as quaternion Interprets the stick positions as axes.
#define STABILIZATION_INDI_FILT_ZETA
static void int32_quat_wrap_shortest(struct Int32Quat *q)
int32_t stabilization_cmd[COMMANDS_NB]
Stabilization commands.
Definition: stabilization.c:28
void stabilization_attitude_enter(void)
struct FloatRates g_est
#define PERIODIC_FREQUENCY
Definition: imu_aspirin2.c:47
void stabilization_attitude_run(bool_t enable_integrator)
struct FloatRates filtered_rate_deriv
Butterworth2LowPass_int filter_x
Definition: hf_float.c:105
struct IndiVariables indi
#define MAX_PPRZ
Definition: paparazzi.h:8
struct FloatRates filtered_rate_2deriv_estimation
static struct Int32Eulers * stateGetNedToBodyEulers_i(void)
Get vehicle body attitude euler angles (int).
Definition: state.h:1096
void stabilization_attitude_read_rc_setpoint_quat_earth_bound_f(struct FloatQuat *q_sp, bool_t in_flight, bool_t in_carefree, bool_t coordinated_turn)
void lms_estimation(void)
static void attitude_run_indi(int32_t indi_commands[], struct Int32Quat *att_err, bool_t in_flight)
Rotation quaternion.
angular rates
struct FloatRates filtered_rate_2deriv
void stabilization_attitude_set_earth_cmd_i(struct Int32Vect2 *cmd, int32_t heading)
int8_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint8_t _id, telemetry_cb _cb)
Register a telemetry callback function.
Definition: telemetry.c:46
#define PPRZ_ITRIG_COS(_c, _a)
struct Int32Quat stab_att_sp_quat
with INT32_QUAT_FRAC
bool_t use_adaptive_indi