diff --git a/conf/firmwares/subsystems/rotorcraft/stabilization_indi.makefile b/conf/firmwares/subsystems/rotorcraft/stabilization_indi.makefile
index 6e561aa342..64c6ce90da 100644
--- a/conf/firmwares/subsystems/rotorcraft/stabilization_indi.makefile
+++ b/conf/firmwares/subsystems/rotorcraft/stabilization_indi.makefile
@@ -1,6 +1,5 @@
STAB_ATT_CFLAGS = -DSTABILIZATION_ATTITUDE_TYPE_INT
STAB_ATT_CFLAGS += -DSTABILIZATION_ATTITUDE_TYPE_H=\"stabilization/stabilization_attitude_quat_indi.h\"
-STAB_ATT_SRCS = $(SRC_FIRMWARE)/stabilization/stabilization_attitude_ref_quat_int.c
STAB_ATT_SRCS += $(SRC_FIRMWARE)/stabilization/stabilization_attitude_quat_indi.c
STAB_ATT_SRCS += $(SRC_FIRMWARE)/stabilization/stabilization_attitude_quat_transformations.c
STAB_ATT_SRCS += $(SRC_FIRMWARE)/stabilization/stabilization_attitude_rc_setpoint.c
diff --git a/conf/settings/control/stabilization_att_float_quat.xml b/conf/settings/control/stabilization_att_float_quat.xml
index 3bdefb1bb2..0f103da585 100644
--- a/conf/settings/control/stabilization_att_float_quat.xml
+++ b/conf/settings/control/stabilization_att_float_quat.xml
@@ -22,12 +22,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/conf/settings/control/stabilization_att_int_quat.xml b/conf/settings/control/stabilization_att_int_quat.xml
index b76196174b..fd84e02734 100644
--- a/conf/settings/control/stabilization_att_int_quat.xml
+++ b/conf/settings/control/stabilization_att_int_quat.xml
@@ -17,12 +17,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/sw/airborne/boards/bebop/video.c b/sw/airborne/boards/bebop/video.c
index 02ce1de85e..cef73a2b46 100644
--- a/sw/airborne/boards/bebop/video.c
+++ b/sw/airborne/boards/bebop/video.c
@@ -95,6 +95,7 @@ static bool_t _write(int fd, char *data, uint8_t cnt)
/**
* Initialisation of the Aptina MT9V117 CMOS sensor
+ * (1/6 inch VGA, bottom camera)
*/
void mt9v117_init(void)
{
@@ -378,6 +379,7 @@ uint16_t mt9f002_read_reg16(uint16_t reg)
/**
* Initialisation of the Aptina MT9F002 CMOS sensor
+ * (1/2.3 inch 14Mp, front camera)
*/
void mt9f002_init(void)
{
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_float.c b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_float.c
index 02ec04bd55..6da16c6b05 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_float.c
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_float.c
@@ -35,9 +35,16 @@
#include "math/pprz_algebra_float.h"
#include "state.h"
+#ifndef USE_ATT_REF
+#define USE_ATT_REF 1
+#endif
+
struct FloatAttitudeGains stabilization_gains;
struct FloatEulers stabilization_att_sum_err;
+struct FloatEulers stab_att_sp_euler;
+struct AttRefEulerFloat att_ref_euler_f;
+
float stabilization_att_fb_cmd[COMMANDS_NB];
float stabilization_att_ff_cmd[COMMANDS_NB];
@@ -76,22 +83,22 @@ static void send_att_ref(struct transport_tx *trans, struct link_device *dev)
&stab_att_sp_euler.phi,
&stab_att_sp_euler.theta,
&stab_att_sp_euler.psi,
- &stab_att_ref_euler.phi,
- &stab_att_ref_euler.theta,
- &stab_att_ref_euler.psi,
- &stab_att_ref_rate.p,
- &stab_att_ref_rate.q,
- &stab_att_ref_rate.r,
- &stab_att_ref_accel.p,
- &stab_att_ref_accel.q,
- &stab_att_ref_accel.r);
+ &att_ref_euler_f.euler.phi,
+ &att_ref_euler_f.euler.theta,
+ &att_ref_euler_f.euler.psi,
+ &att_ref_euler_f.rate.p,
+ &att_ref_euler_f.rate.q,
+ &att_ref_euler_f.rate.r,
+ &att_ref_euler_f.accel.p,
+ &att_ref_euler_f.accel.q,
+ &att_ref_euler_f.accel.r);
}
#endif
void stabilization_attitude_init(void)
{
- stabilization_attitude_ref_init();
+ attitude_ref_euler_float_init(&att_ref_euler_f);
VECT3_ASSIGN(stabilization_gains.p,
STABILIZATION_ATTITUDE_PHI_PGAIN,
@@ -132,7 +139,7 @@ void stabilization_attitude_enter(void)
/* reset psi setpoint to current psi angle */
stab_att_sp_euler.psi = stabilization_attitude_get_heading_f();
- stabilization_attitude_ref_enter();
+ attitude_ref_euler_float_enter(&att_ref_euler_f, stab_att_sp_euler.psi);
FLOAT_EULERS_ZERO(stabilization_att_sum_err);
}
@@ -169,21 +176,28 @@ void stabilization_attitude_set_earth_cmd_i(struct Int32Vect2 *cmd, int32_t head
void stabilization_attitude_run(bool_t in_flight)
{
- stabilization_attitude_ref_update();
+#if USE_ATT_REF
+ static const float dt = (1./PERIODIC_FREQUENCY);
+ attitude_ref_euler_float_update(&att_ref_euler_f, &stab_att_sp_euler, dt);
+#else
+ EULERS_COPY(att_ref_euler_f.euler, stab_att_sp_euler);
+ FLOAT_RATES_ZERO(att_ref_euler_f.rate);
+ FLOAT_RATES_ZERO(att_ref_euler_f.accel);
+#endif
/* Compute feedforward */
stabilization_att_ff_cmd[COMMAND_ROLL] =
- stabilization_gains.dd.x * stab_att_ref_accel.p;
+ stabilization_gains.dd.x * att_ref_euler_f.accel.p;
stabilization_att_ff_cmd[COMMAND_PITCH] =
- stabilization_gains.dd.y * stab_att_ref_accel.q;
+ stabilization_gains.dd.y * att_ref_euler_f.accel.q;
stabilization_att_ff_cmd[COMMAND_YAW] =
- stabilization_gains.dd.z * stab_att_ref_accel.r;
+ stabilization_gains.dd.z * att_ref_euler_f.accel.r;
/* Compute feedback */
/* attitude error */
struct FloatEulers *att_float = stateGetNedToBodyEulers_f();
struct FloatEulers att_err;
- EULERS_DIFF(att_err, stab_att_ref_euler, *att_float);
+ EULERS_DIFF(att_err, att_ref_euler_f.euler, *att_float);
FLOAT_ANGLE_NORMALIZE(att_err.psi);
if (in_flight) {
@@ -197,7 +211,7 @@ void stabilization_attitude_run(bool_t in_flight)
/* rate error */
struct FloatRates *rate_float = stateGetBodyRates_f();
struct FloatRates rate_err;
- RATES_DIFF(rate_err, stab_att_ref_rate, *rate_float);
+ RATES_DIFF(rate_err, att_ref_euler_f.rate, *rate_float);
/* PID */
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_float.h b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_float.h
index 08e4dd235c..ca9a044d71 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_float.h
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_float.h
@@ -35,4 +35,7 @@
extern struct FloatAttitudeGains stabilization_gains;
extern struct FloatEulers stabilization_att_sum_err;
+extern struct FloatEulers stab_att_sp_euler;
+extern struct AttRefEulerFloat att_ref_euler_f;
+
#endif /* STABILIZATION_ATTITUDE_EULER_FLOAT_H */
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_int.c b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_int.c
index 0effe51aef..65a0c4e848 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_int.c
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_int.c
@@ -35,6 +35,11 @@
#include "math/pprz_algebra_int.h"
#include "state.h"
+/** explicitly define to zero to disable attitude reference generation */
+#ifndef USE_ATTITUDE_REF
+#define USE_ATTITUDE_REF 1
+#endif
+
struct Int32AttitudeGains stabilization_gains;
/* warn if some gains are still negative */
@@ -55,12 +60,15 @@ struct Int32Eulers stabilization_att_sum_err;
int32_t stabilization_att_fb_cmd[COMMANDS_NB];
int32_t stabilization_att_ff_cmd[COMMANDS_NB];
+struct Int32Eulers stab_att_sp_euler;
+struct AttRefEulerInt att_ref_euler_i;
+
static inline void reset_psi_ref_from_body(void)
{
//sp has been set from body using stabilization_attitude_get_yaw_i, use that value
- stab_att_ref_euler.psi = stab_att_sp_euler.psi << (REF_ANGLE_FRAC - INT32_ANGLE_FRAC);
- stab_att_ref_rate.r = 0;
- stab_att_ref_accel.r = 0;
+ att_ref_euler_i.euler.psi = stab_att_sp_euler.psi << (REF_ANGLE_FRAC - INT32_ANGLE_FRAC);
+ att_ref_euler_i.rate.r = 0;
+ att_ref_euler_i.accel.r = 0;
}
#if PERIODIC_TELEMETRY
@@ -96,22 +104,24 @@ static void send_att_ref(struct transport_tx *trans, struct link_device *dev)
&stab_att_sp_euler.phi,
&stab_att_sp_euler.theta,
&stab_att_sp_euler.psi,
- &stab_att_ref_euler.phi,
- &stab_att_ref_euler.theta,
- &stab_att_ref_euler.psi,
- &stab_att_ref_rate.p,
- &stab_att_ref_rate.q,
- &stab_att_ref_rate.r,
- &stab_att_ref_accel.p,
- &stab_att_ref_accel.q,
- &stab_att_ref_accel.r);
+ &att_ref_euler_i.euler.phi,
+ &att_ref_euler_i.euler.theta,
+ &att_ref_euler_i.euler.psi,
+ &att_ref_euler_i.rate.p,
+ &att_ref_euler_i.rate.q,
+ &att_ref_euler_i.rate.r,
+ &att_ref_euler_i.accel.p,
+ &att_ref_euler_i.accel.q,
+ &att_ref_euler_i.accel.r);
}
#endif
void stabilization_attitude_init(void)
{
- stabilization_attitude_ref_init();
+ INT_EULERS_ZERO(stab_att_sp_euler);
+
+ attitude_ref_euler_int_init(&att_ref_euler_i);
VECT3_ASSIGN(stabilization_gains.p,
@@ -188,22 +198,28 @@ void stabilization_attitude_run(bool_t in_flight)
{
/* update reference */
- stabilization_attitude_ref_update();
+#if USE_ATTITUDE_REF
+ attitude_ref_euler_int_update(&att_ref_euler_i, &stab_att_sp_euler);
+#else
+ INT32_EULERS_LSHIFT(att_ref_euler_i.euler, stab_att_sp_euler, (REF_ANGLE_FRAC - INT32_ANGLE_FRAC));
+ INT_RATES_ZERO(att_ref_euler_i.rate);
+ INT_RATES_ZERO(att_ref_euler_i.accel);
+#endif
/* compute feedforward command */
stabilization_att_ff_cmd[COMMAND_ROLL] =
- OFFSET_AND_ROUND(stabilization_gains.dd.x * stab_att_ref_accel.p, 5);
+ OFFSET_AND_ROUND(stabilization_gains.dd.x * att_ref_euler_i.accel.p, 5);
stabilization_att_ff_cmd[COMMAND_PITCH] =
- OFFSET_AND_ROUND(stabilization_gains.dd.y * stab_att_ref_accel.q, 5);
+ OFFSET_AND_ROUND(stabilization_gains.dd.y * att_ref_euler_i.accel.q, 5);
stabilization_att_ff_cmd[COMMAND_YAW] =
- OFFSET_AND_ROUND(stabilization_gains.dd.z * stab_att_ref_accel.r, 5);
+ OFFSET_AND_ROUND(stabilization_gains.dd.z * att_ref_euler_i.accel.r, 5);
/* compute feedback command */
/* attitude error */
const struct Int32Eulers att_ref_scaled = {
- OFFSET_AND_ROUND(stab_att_ref_euler.phi, (REF_ANGLE_FRAC - INT32_ANGLE_FRAC)),
- OFFSET_AND_ROUND(stab_att_ref_euler.theta, (REF_ANGLE_FRAC - INT32_ANGLE_FRAC)),
- OFFSET_AND_ROUND(stab_att_ref_euler.psi, (REF_ANGLE_FRAC - INT32_ANGLE_FRAC))
+ OFFSET_AND_ROUND(att_ref_euler_i.euler.phi, (REF_ANGLE_FRAC - INT32_ANGLE_FRAC)),
+ OFFSET_AND_ROUND(att_ref_euler_i.euler.theta, (REF_ANGLE_FRAC - INT32_ANGLE_FRAC)),
+ OFFSET_AND_ROUND(att_ref_euler_i.euler.psi, (REF_ANGLE_FRAC - INT32_ANGLE_FRAC))
};
struct Int32Eulers att_err;
struct Int32Eulers *ltp_to_body_euler = stateGetNedToBodyEulers_i();
@@ -220,9 +236,9 @@ void stabilization_attitude_run(bool_t in_flight)
/* rate error */
const struct Int32Rates rate_ref_scaled = {
- OFFSET_AND_ROUND(stab_att_ref_rate.p, (REF_RATE_FRAC - INT32_RATE_FRAC)),
- OFFSET_AND_ROUND(stab_att_ref_rate.q, (REF_RATE_FRAC - INT32_RATE_FRAC)),
- OFFSET_AND_ROUND(stab_att_ref_rate.r, (REF_RATE_FRAC - INT32_RATE_FRAC))
+ OFFSET_AND_ROUND(att_ref_euler_i.rate.p, (REF_RATE_FRAC - INT32_RATE_FRAC)),
+ OFFSET_AND_ROUND(att_ref_euler_i.rate.q, (REF_RATE_FRAC - INT32_RATE_FRAC)),
+ OFFSET_AND_ROUND(att_ref_euler_i.rate.r, (REF_RATE_FRAC - INT32_RATE_FRAC))
};
struct Int32Rates rate_err;
struct Int32Rates *body_rate = stateGetBodyRates_i();
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_int.h b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_int.h
index eba7a64b82..996c5c1a39 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_int.h
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_euler_int.h
@@ -27,4 +27,7 @@
extern struct Int32Eulers stabilization_att_sum_err;
+extern struct Int32Eulers stab_att_sp_euler;
+extern struct AttRefEulerInt att_ref_euler_i;
+
#endif /* STABILIZATION_ATTITUDE_EULER_INT_H */
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_float.c b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_float.c
index 0da354e16a..cf7e1817ec 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_float.c
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_float.c
@@ -37,6 +37,11 @@
struct FloatAttitudeGains stabilization_gains[STABILIZATION_ATTITUDE_GAIN_NB];
+struct FloatEulers stab_att_sp_euler;
+struct FloatQuat stab_att_sp_quat;
+
+struct AttRefQuatFloat att_ref_quat_f;
+
struct FloatQuat stabilization_att_sum_err_quat;
struct FloatRates last_body_rate;
@@ -126,22 +131,26 @@ static void send_att_ref(struct transport_tx *trans, struct link_device *dev)
&stab_att_sp_euler.phi,
&stab_att_sp_euler.theta,
&stab_att_sp_euler.psi,
- &stab_att_ref_euler.phi,
- &stab_att_ref_euler.theta,
- &stab_att_ref_euler.psi,
- &stab_att_ref_rate.p,
- &stab_att_ref_rate.q,
- &stab_att_ref_rate.r,
- &stab_att_ref_accel.p,
- &stab_att_ref_accel.q,
- &stab_att_ref_accel.r);
+ &att_ref_quat_f.euler.phi,
+ &att_ref_quat_f.euler.theta,
+ &att_ref_quat_f.euler.psi,
+ &att_ref_quat_f.rate.p,
+ &att_ref_quat_f.rate.q,
+ &att_ref_quat_f.rate.r,
+ &att_ref_quat_f.accel.p,
+ &att_ref_quat_f.accel.q,
+ &att_ref_quat_f.accel.r);
}
#endif
void stabilization_attitude_init(void)
{
-
- stabilization_attitude_ref_init();
+ /* setpoints */
+ FLOAT_EULERS_ZERO(stab_att_sp_euler);
+ float_quat_identity(&stab_att_sp_quat);
+ /* reference */
+ attitude_ref_quat_float_init(&att_ref_quat_f);
+ attitude_ref_quat_float_schedule(&att_ref_quat_f, STABILIZATION_ATTITUDE_GAIN_IDX_DEFAULT);
for (int i = 0; i < STABILIZATION_ATTITUDE_GAIN_NB; i++) {
VECT3_ASSIGN(stabilization_gains[i].p, phi_pgain[i], theta_pgain[i], psi_pgain[i]);
@@ -174,7 +183,7 @@ void stabilization_attitude_gain_schedule(uint8_t idx)
return;
}
gain_idx = idx;
- stabilization_attitude_ref_schedule(idx);
+ attitude_ref_quat_float_schedule(&att_ref_quat_f, idx);
}
void stabilization_attitude_enter(void)
@@ -183,7 +192,7 @@ void stabilization_attitude_enter(void)
/* reset psi setpoint to current psi angle */
stab_att_sp_euler.psi = stabilization_attitude_get_heading_f();
- stabilization_attitude_ref_enter();
+ attitude_ref_quat_float_enter(&att_ref_quat_f, stab_att_sp_euler.psi);
float_quat_identity(&stabilization_att_sum_err_quat);
}
@@ -289,7 +298,8 @@ void stabilization_attitude_run(bool_t enable_integrator)
/*
* Update reference
*/
- stabilization_attitude_ref_update();
+ static const float dt = (1./PERIODIC_FREQUENCY);
+ attitude_ref_quat_float_update(&att_ref_quat_f, &stab_att_sp_quat, dt);
/*
* Compute errors for feedback
@@ -298,14 +308,14 @@ void stabilization_attitude_run(bool_t enable_integrator)
/* attitude error */
struct FloatQuat att_err;
struct FloatQuat *att_quat = stateGetNedToBodyQuat_f();
- float_quat_inv_comp(&att_err, att_quat, &stab_att_ref_quat);
+ float_quat_inv_comp(&att_err, att_quat, &att_ref_quat_f.quat);
/* wrap it in the shortest direction */
float_quat_wrap_shortest(&att_err);
/* rate error */
struct FloatRates rate_err;
struct FloatRates *body_rate = stateGetBodyRates_f();
- RATES_DIFF(rate_err, stab_att_ref_rate, *body_rate);
+ RATES_DIFF(rate_err, att_ref_quat_f.rate, *body_rate);
/* rate_d error */
RATES_DIFF(body_rate_d, *body_rate, last_body_rate);
RATES_COPY(last_body_rate, *body_rate);
@@ -324,7 +334,7 @@ void stabilization_attitude_run(bool_t enable_integrator)
float_quat_identity(&stabilization_att_sum_err_quat);
}
- attitude_run_ff(stabilization_att_ff_cmd, &stabilization_gains[gain_idx], &stab_att_ref_accel);
+ attitude_run_ff(stabilization_att_ff_cmd, &stabilization_gains[gain_idx], &att_ref_quat_f.accel);
attitude_run_fb(stabilization_att_fb_cmd, &stabilization_gains[gain_idx], &att_err, &rate_err, &body_rate_d,
&stabilization_att_sum_err_quat);
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_float.h b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_float.h
index 8655fc23ac..7edc3d11ac 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_float.h
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_float.h
@@ -28,12 +28,38 @@
#ifndef STABILIZATION_ATTITUDE_QUAT_FLOAT_H
#define STABILIZATION_ATTITUDE_QUAT_FLOAT_H
+#include "generated/airframe.h"
#include "firmwares/rotorcraft/stabilization/stabilization_attitude_common_float.h"
#include "firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_float.h"
+#ifndef STABILIZATION_ATTITUDE_GAIN_NB
+#define STABILIZATION_ATTITUDE_GAIN_NB 1
+#endif
+
+#ifndef STABILIZATION_ATTITUDE_GAIN_IDX_DEFAULT
+#define STABILIZATION_ATTITUDE_GAIN_IDX_DEFAULT 0
+#endif
+
extern struct FloatAttitudeGains stabilization_gains[];
+extern struct FloatEulers stab_att_sp_euler;
+extern struct FloatQuat stab_att_sp_quat;
+
+extern struct AttRefQuatFloat att_ref_quat_f;
+
+
void stabilization_attitude_gain_schedule(uint8_t idx);
+/* settings handlers */
+#define stabilization_attitude_quat_float_SetOmegaP(_val) { \
+ attitude_ref_quat_float_set_omega_p(&att_ref_quat_f, _val); \
+ }
+#define stabilization_attitude_quat_float_SetOmegaQ(_val) { \
+ attitude_ref_quat_float_set_omega_q(&att_ref_quat_f, _val); \
+ }
+#define stabilization_attitude_quat_float_SetOmegaR(_val) { \
+ attitude_ref_quat_float_set_omega_r(&att_ref_quat_f, _val); \
+ }
+
#endif /* STABILIZATION_ATTITUDE_QUAT_FLOAT_H */
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_indi.c b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_indi.c
index 79a198b587..ba6fd36851 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_indi.c
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_indi.c
@@ -66,6 +66,9 @@ struct IndiVariables indi = {
{0., 0., 0.}
};
+struct Int32Eulers stab_att_sp_euler;
+struct Int32Quat stab_att_sp_quat;
+
// Variables for adaptation
struct FloatRates filtered_rate_estimation = {0., 0., 0.};
struct FloatRates filtered_rate_deriv_estimation = {0., 0., 0.};
@@ -129,8 +132,6 @@ static void send_att_indi(struct transport_tx *trans, struct link_device *dev)
void stabilization_attitude_init(void)
{
- stabilization_attitude_ref_init();
-
#if PERIODIC_TELEMETRY
register_periodic_telemetry(DefaultPeriodic, "STAB_ATTITUDE_INDI", send_att_indi);
#endif
@@ -142,8 +143,6 @@ void stabilization_attitude_enter(void)
/* reset psi setpoint to current psi angle */
stab_att_sp_euler.psi = stabilization_attitude_get_heading_i();
- stabilization_attitude_ref_enter();
-
FLOAT_RATES_ZERO(indi.filtered_rate);
FLOAT_RATES_ZERO(indi.filtered_rate_deriv);
FLOAT_RATES_ZERO(indi.filtered_rate_2deriv);
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_indi.h b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_indi.h
index 11492a138d..8b68e65827 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_indi.h
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_indi.h
@@ -64,6 +64,9 @@ extern struct ReferenceSystem reference_acceleration;
extern struct FloatRates g_est;
extern bool_t use_adaptive_indi;
+extern struct Int32Eulers stab_att_sp_euler; ///< with #INT32_ANGLE_FRAC
+extern struct Int32Quat stab_att_sp_quat; ///< with #INT32_QUAT_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);
void lms_estimation(void);
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_int.c b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_int.c
index 7cc023ccce..c57804a256 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_int.c
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_int.c
@@ -60,6 +60,11 @@ struct Int32Quat stabilization_att_sum_err_quat;
int32_t stabilization_att_fb_cmd[COMMANDS_NB];
int32_t stabilization_att_ff_cmd[COMMANDS_NB];
+struct Int32Quat stab_att_sp_quat;
+struct Int32Eulers stab_att_sp_euler;
+
+struct AttRefQuatInt att_ref_quat_i;
+
#define IERROR_SCALE 128
#define GAIN_PRESCALER_FF 48
#define GAIN_PRESCALER_P 12
@@ -95,29 +100,32 @@ static void send_att(struct transport_tx *trans, struct link_device *dev) //FI
static void send_att_ref(struct transport_tx *trans, struct link_device *dev)
{
+ // ref eulers in message are with REF_ANGLE_FRAC, convert
+ struct Int32Eulers ref_euler;
+ INT32_EULERS_LSHIFT(ref_euler, att_ref_quat_i.euler, (REF_ANGLE_FRAC - INT32_ANGLE_FRAC));
pprz_msg_send_STAB_ATTITUDE_REF_INT(trans, dev, AC_ID,
&stab_att_sp_euler.phi,
&stab_att_sp_euler.theta,
&stab_att_sp_euler.psi,
- &stab_att_ref_euler.phi,
- &stab_att_ref_euler.theta,
- &stab_att_ref_euler.psi,
- &stab_att_ref_rate.p,
- &stab_att_ref_rate.q,
- &stab_att_ref_rate.r,
- &stab_att_ref_accel.p,
- &stab_att_ref_accel.q,
- &stab_att_ref_accel.r);
+ &ref_euler.phi,
+ &ref_euler.theta,
+ &ref_euler.psi,
+ &att_ref_quat_i.rate.p,
+ &att_ref_quat_i.rate.q,
+ &att_ref_quat_i.rate.r,
+ &att_ref_quat_i.accel.p,
+ &att_ref_quat_i.accel.q,
+ &att_ref_quat_i.accel.r);
}
static void send_ahrs_ref_quat(struct transport_tx *trans, struct link_device *dev)
{
struct Int32Quat *quat = stateGetNedToBodyQuat_i();
pprz_msg_send_AHRS_REF_QUAT(trans, dev, AC_ID,
- &stab_att_ref_quat.qi,
- &stab_att_ref_quat.qx,
- &stab_att_ref_quat.qy,
- &stab_att_ref_quat.qz,
+ &att_ref_quat_i.quat.qi,
+ &att_ref_quat_i.quat.qx,
+ &att_ref_quat_i.quat.qy,
+ &att_ref_quat_i.quat.qz,
&(quat->qi),
&(quat->qx),
&(quat->qy),
@@ -128,7 +136,7 @@ static void send_ahrs_ref_quat(struct transport_tx *trans, struct link_device *d
void stabilization_attitude_init(void)
{
- stabilization_attitude_ref_init();
+ attitude_ref_quat_int_init(&att_ref_quat_i);
int32_quat_identity(&stabilization_att_sum_err_quat);
@@ -145,7 +153,7 @@ void stabilization_attitude_enter(void)
/* reset psi setpoint to current psi angle */
stab_att_sp_euler.psi = stabilization_attitude_get_heading_i();
- stabilization_attitude_ref_enter();
+ attitude_ref_quat_int_enter(&att_ref_quat_i, stab_att_sp_euler.psi);
int32_quat_identity(&stabilization_att_sum_err_quat);
@@ -224,8 +232,11 @@ void stabilization_attitude_run(bool_t enable_integrator)
/*
* Update reference
+ * Warning: dt is currently not used in the quat_int ref impl
+ * PERIODIC_FREQUENCY is assumed to be 512Hz
*/
- stabilization_attitude_ref_update();
+ static const float dt = (1./PERIODIC_FREQUENCY);
+ attitude_ref_quat_int_update(&att_ref_quat_i, &stab_att_sp_quat, dt);
/*
* Compute errors for feedback
@@ -234,16 +245,16 @@ void stabilization_attitude_run(bool_t enable_integrator)
/* attitude error */
struct Int32Quat att_err;
struct Int32Quat *att_quat = stateGetNedToBodyQuat_i();
- INT32_QUAT_INV_COMP(att_err, *att_quat, stab_att_ref_quat);
+ INT32_QUAT_INV_COMP(att_err, *att_quat, att_ref_quat_i.quat);
/* wrap it in the shortest direction */
int32_quat_wrap_shortest(&att_err);
int32_quat_normalize(&att_err);
/* rate error */
const struct Int32Rates rate_ref_scaled = {
- OFFSET_AND_ROUND(stab_att_ref_rate.p, (REF_RATE_FRAC - INT32_RATE_FRAC)),
- OFFSET_AND_ROUND(stab_att_ref_rate.q, (REF_RATE_FRAC - INT32_RATE_FRAC)),
- OFFSET_AND_ROUND(stab_att_ref_rate.r, (REF_RATE_FRAC - INT32_RATE_FRAC))
+ OFFSET_AND_ROUND(att_ref_quat_i.rate.p, (REF_RATE_FRAC - INT32_RATE_FRAC)),
+ OFFSET_AND_ROUND(att_ref_quat_i.rate.q, (REF_RATE_FRAC - INT32_RATE_FRAC)),
+ OFFSET_AND_ROUND(att_ref_quat_i.rate.r, (REF_RATE_FRAC - INT32_RATE_FRAC))
};
struct Int32Rates rate_err;
struct Int32Rates *body_rate = stateGetBodyRates_i();
@@ -264,7 +275,7 @@ void stabilization_attitude_run(bool_t enable_integrator)
}
/* compute the feed forward command */
- attitude_run_ff(stabilization_att_ff_cmd, &stabilization_gains, &stab_att_ref_accel);
+ attitude_run_ff(stabilization_att_ff_cmd, &stabilization_gains, &att_ref_quat_i.accel);
/* compute the feed back command */
attitude_run_fb(stabilization_att_fb_cmd, &stabilization_gains, &att_err, &rate_err, &stabilization_att_sum_err_quat);
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_int.h b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_int.h
index 84c954ac86..b9a05837cd 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_int.h
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_quat_int.h
@@ -27,4 +27,30 @@
#include "math/pprz_algebra_int.h"
+extern struct Int32Quat stab_att_sp_quat; ///< with #INT32_QUAT_FRAC
+extern struct Int32Eulers stab_att_sp_euler; ///< with #INT32_ANGLE_FRAC
+
+extern struct AttRefQuatInt att_ref_quat_i;
+
+/* settings handlers for ref model params */
+#define stabilization_attitude_quat_int_SetOmegaP(_val) { \
+ attitude_ref_quat_int_set_omega_p(&att_ref_quat_i, _val); \
+ }
+#define stabilization_attitude_quat_int_SetOmegaQ(_val) { \
+ attitude_ref_quat_int_set_omega_q(&att_ref_quat_i, _val); \
+ }
+#define stabilization_attitude_quat_int_SetOmegaR(_val) { \
+ attitude_ref_quat_int_set_omega_r(&att_ref_quat_i, _val); \
+ }
+
+#define stabilization_attitude_quat_int_SetZetaP(_val) { \
+ attitude_ref_quat_int_set_zeta_p(&att_ref_quat_i, _val); \
+ }
+#define stabilization_attitude_quat_int_SetZetaQ(_val) { \
+ attitude_ref_quat_int_set_zeta_q(&att_ref_quat_i, _val); \
+ }
+#define stabilization_attitude_quat_int_SetZetaR(_val) { \
+ attitude_ref_quat_int_set_zeta_r(&att_ref_quat_i, _val); \
+ }
+
#endif /* STABILIZATION_ATTITUDE_QUAT_INT_H */
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_float.c b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_float.c
index de93c7be81..b9bc4524f7 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_float.c
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_float.c
@@ -25,31 +25,12 @@
* Rotorcraft attitude reference generation in euler float version.
*/
-#include "firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_float.h"
-#include "firmwares/rotorcraft/stabilization/stabilization_attitude_ref_saturate.h"
#include "generated/airframe.h"
-struct FloatEulers stab_att_sp_euler;
-struct FloatEulers stab_att_ref_euler;
-struct FloatRates stab_att_ref_rate;
-struct FloatRates stab_att_ref_accel;
-
-void stabilization_attitude_ref_init(void)
-{
-
- FLOAT_EULERS_ZERO(stab_att_sp_euler);
- FLOAT_EULERS_ZERO(stab_att_ref_euler);
- FLOAT_RATES_ZERO(stab_att_ref_rate);
- FLOAT_RATES_ZERO(stab_att_ref_accel);
-
-}
-
-
-/*
- * Reference
- */
-#define DT_UPDATE (1./PERIODIC_FREQUENCY)
+#include "firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_float.h"
+#include "firmwares/rotorcraft/stabilization/stabilization_attitude_ref_saturate.h"
+/* shortcuts for saturation defines */
#define REF_ACCEL_MAX_P STABILIZATION_ATTITUDE_REF_MAX_PDOT
#define REF_ACCEL_MAX_Q STABILIZATION_ATTITUDE_REF_MAX_QDOT
#define REF_ACCEL_MAX_R STABILIZATION_ATTITUDE_REF_MAX_RDOT
@@ -58,6 +39,7 @@ void stabilization_attitude_ref_init(void)
#define REF_RATE_MAX_Q STABILIZATION_ATTITUDE_REF_MAX_Q
#define REF_RATE_MAX_R STABILIZATION_ATTITUDE_REF_MAX_R
+/* shortcuts for ref model parametes used in update */
#define OMEGA_P STABILIZATION_ATTITUDE_REF_OMEGA_P
#define OMEGA_Q STABILIZATION_ATTITUDE_REF_OMEGA_Q
#define OMEGA_R STABILIZATION_ATTITUDE_REF_OMEGA_R
@@ -66,63 +48,70 @@ void stabilization_attitude_ref_init(void)
#define ZETA_Q STABILIZATION_ATTITUDE_REF_ZETA_Q
#define ZETA_R STABILIZATION_ATTITUDE_REF_ZETA_R
+static inline void reset_psi_ref(struct AttRefEulerFloat *ref, float psi);
-#define USE_REF 1
-
-static inline void reset_psi_ref_from_body(void)
+/*
+ *
+ * Implementation.
+ * Should not rely on any global variables, so these functions can be used like a lib.
+ *
+ */
+void attitude_ref_euler_float_init(struct AttRefEulerFloat *ref)
{
- //sp has been set from body using stabilization_attitude_get_yaw_f, use that value
- stab_att_ref_euler.psi = stab_att_sp_euler.psi;
- stab_att_ref_rate.r = 0;
- stab_att_ref_accel.r = 0;
+ FLOAT_EULERS_ZERO(ref->euler);
+ FLOAT_RATES_ZERO(ref->rate);
+ FLOAT_RATES_ZERO(ref->accel);
}
-void stabilization_attitude_ref_enter()
+void attitude_ref_euler_float_enter(struct AttRefEulerFloat *ref, float psi)
{
- reset_psi_ref_from_body();
+ reset_psi_ref(ref, psi);
}
-void stabilization_attitude_ref_update()
+void attitude_ref_euler_float_update(struct AttRefEulerFloat *ref, struct FloatEulers *sp_eulers, float dt)
{
-#if USE_REF
-
/* dumb integrate reference attitude */
struct FloatRates delta_rate;
- RATES_SMUL(delta_rate, stab_att_ref_rate, DT_UPDATE);
+ RATES_SMUL(delta_rate, ref->rate, dt);
struct FloatEulers delta_angle;
EULERS_ASSIGN(delta_angle, delta_rate.p, delta_rate.q, delta_rate.r);
- EULERS_ADD(stab_att_ref_euler, delta_angle);
- FLOAT_ANGLE_NORMALIZE(stab_att_ref_euler.psi);
+ EULERS_ADD(ref->euler, delta_angle);
+ FLOAT_ANGLE_NORMALIZE(ref->euler.psi);
/* integrate reference rotational speeds */
struct FloatRates delta_accel;
- RATES_SMUL(delta_accel, stab_att_ref_accel, DT_UPDATE);
- RATES_ADD(stab_att_ref_rate, delta_accel);
+ RATES_SMUL(delta_accel, ref->accel, dt);
+ RATES_ADD(ref->rate, delta_accel);
/* compute reference attitude error */
struct FloatEulers ref_err;
- EULERS_DIFF(ref_err, stab_att_ref_euler, stab_att_sp_euler);
+ EULERS_DIFF(ref_err, ref->euler, *sp_eulers);
/* wrap it in the shortest direction */
FLOAT_ANGLE_NORMALIZE(ref_err.psi);
/* compute reference angular accelerations */
- stab_att_ref_accel.p = -2.*ZETA_P * OMEGA_P * stab_att_ref_rate.p - OMEGA_P * OMEGA_P * ref_err.phi;
- stab_att_ref_accel.q = -2.*ZETA_Q * OMEGA_P * stab_att_ref_rate.q - OMEGA_Q * OMEGA_Q * ref_err.theta;
- stab_att_ref_accel.r = -2.*ZETA_R * OMEGA_P * stab_att_ref_rate.r - OMEGA_R * OMEGA_R * ref_err.psi;
+ ref->accel.p = -2.*ZETA_P * OMEGA_P * ref->rate.p - OMEGA_P * OMEGA_P * ref_err.phi;
+ ref->accel.q = -2.*ZETA_Q * OMEGA_P * ref->rate.q - OMEGA_Q * OMEGA_Q * ref_err.theta;
+ ref->accel.r = -2.*ZETA_R * OMEGA_P * ref->rate.r - OMEGA_R * OMEGA_R * ref_err.psi;
/* saturate acceleration */
const struct FloatRates MIN_ACCEL = { -REF_ACCEL_MAX_P, -REF_ACCEL_MAX_Q, -REF_ACCEL_MAX_R };
const struct FloatRates MAX_ACCEL = { REF_ACCEL_MAX_P, REF_ACCEL_MAX_Q, REF_ACCEL_MAX_R };
- RATES_BOUND_BOX(stab_att_ref_accel, MIN_ACCEL, MAX_ACCEL);
+ RATES_BOUND_BOX(ref->accel, MIN_ACCEL, MAX_ACCEL);
/* saturate speed and trim accel accordingly */
- SATURATE_SPEED_TRIM_ACCEL();
-
-#else /* !USE_REF */
- EULERS_COPY(stab_att_ref_euler, stabilization_att_sp);
- FLOAT_RATES_ZERO(stab_att_ref_rate);
- FLOAT_RATES_ZERO(stab_att_ref_accel);
-#endif /* USE_REF */
-
+ SATURATE_SPEED_TRIM_ACCEL(*ref);
+}
+
+/*
+ *
+ * Local helper functions.
+ *
+ */
+static inline void reset_psi_ref(struct AttRefEulerFloat *ref, float psi)
+{
+ ref->euler.psi = psi;
+ ref->rate.r = 0;
+ ref->accel.r = 0;
}
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_float.h b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_float.h
index ba55615872..f09ece8669 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_float.h
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_float.h
@@ -19,12 +19,20 @@
* Boston, MA 02111-1307, USA.
*/
-#ifndef STABILIZATION_ATTITUDE_FLOAT_REF_EULER_FLOAT_H
-#define STABILIZATION_ATTITUDE_FLOAT_REF_EULER_FLOAT_H
+#ifndef STABILIZATION_ATTITUDE_REF_EULER_FLOAT_H
+#define STABILIZATION_ATTITUDE_REF_EULER_FLOAT_H
-#include "stabilization_attitude_ref_float.h"
+#include "math/pprz_algebra_float.h"
-void stabilization_attitude_ref_enter(void);
+/** Attitude reference state/output (euler float) */
+struct AttRefEulerFloat {
+ struct FloatEulers euler;
+ struct FloatRates rate;
+ struct FloatRates accel;
+};
+extern void attitude_ref_euler_float_init(struct AttRefEulerFloat *ref);
+extern void attitude_ref_euler_float_enter(struct AttRefEulerFloat *ref, float psi);
+extern void attitude_ref_euler_float_update(struct AttRefEulerFloat *ref, struct FloatEulers *sp_eulers, float dt);
-#endif /* STABILIZATION_ATTITUDE_FLOAT_REF_EULER_FLOAT_H */
+#endif /* STABILIZATION_ATTITUDE_REF_EULER_FLOAT_H */
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_int.c b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_int.c
index fa7f6a4b20..336b882210 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_int.c
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_int.c
@@ -28,20 +28,6 @@
#include "firmwares/rotorcraft/stabilization/stabilization_attitude_ref_saturate.h"
#include "generated/airframe.h"
-struct Int32Eulers stab_att_sp_euler;
-struct Int32Eulers stab_att_ref_euler; ///< with #REF_ANGLE_FRAC
-struct Int32Rates stab_att_ref_rate;
-struct Int32Rates stab_att_ref_accel;
-
-void stabilization_attitude_ref_init(void)
-{
-
- INT_EULERS_ZERO(stab_att_sp_euler);
- INT_EULERS_ZERO(stab_att_ref_euler);
- INT_RATES_ZERO(stab_att_ref_rate);
- INT_RATES_ZERO(stab_att_ref_accel);
-
-}
#define F_UPDATE_RES 9
#define F_UPDATE (1<euler);
+ INT_RATES_ZERO(ref->rate);
+ INT_RATES_ZERO(ref->accel);
+}
-#if USE_ATTITUDE_REF
+/**
+ * Propagate reference model.
+ * FIXME: has hardcoded timestep (512Hz via fixed F_UPDATE_RES)
+ */
+void attitude_ref_euler_int_update(struct AttRefEulerInt *ref, struct Int32Eulers *sp_euler)
+{
/* dumb integrate reference attitude */
const struct Int32Eulers d_angle = {
- stab_att_ref_rate.p >> (F_UPDATE_RES + REF_RATE_FRAC - REF_ANGLE_FRAC),
- stab_att_ref_rate.q >> (F_UPDATE_RES + REF_RATE_FRAC - REF_ANGLE_FRAC),
- stab_att_ref_rate.r >> (F_UPDATE_RES + REF_RATE_FRAC - REF_ANGLE_FRAC)
+ ref->rate.p >> (F_UPDATE_RES + REF_RATE_FRAC - REF_ANGLE_FRAC),
+ ref->rate.q >> (F_UPDATE_RES + REF_RATE_FRAC - REF_ANGLE_FRAC),
+ ref->rate.r >> (F_UPDATE_RES + REF_RATE_FRAC - REF_ANGLE_FRAC)
};
- EULERS_ADD(stab_att_ref_euler, d_angle);
- ANGLE_REF_NORMALIZE(stab_att_ref_euler.psi);
+ EULERS_ADD(ref->euler, d_angle);
+ ANGLE_REF_NORMALIZE(ref->euler.psi);
/* integrate reference rotational speeds */
const struct Int32Rates d_rate = {
- stab_att_ref_accel.p >> (F_UPDATE_RES + REF_ACCEL_FRAC - REF_RATE_FRAC),
- stab_att_ref_accel.q >> (F_UPDATE_RES + REF_ACCEL_FRAC - REF_RATE_FRAC),
- stab_att_ref_accel.r >> (F_UPDATE_RES + REF_ACCEL_FRAC - REF_RATE_FRAC)
+ ref->accel.p >> (F_UPDATE_RES + REF_ACCEL_FRAC - REF_RATE_FRAC),
+ ref->accel.q >> (F_UPDATE_RES + REF_ACCEL_FRAC - REF_RATE_FRAC),
+ ref->accel.r >> (F_UPDATE_RES + REF_ACCEL_FRAC - REF_RATE_FRAC)
};
- RATES_ADD(stab_att_ref_rate, d_rate);
+ RATES_ADD(ref->rate, d_rate);
/* attitude setpoint with REF_ANGLE_FRAC */
struct Int32Eulers sp_ref;
- INT32_EULERS_LSHIFT(sp_ref, stab_att_sp_euler, (REF_ANGLE_FRAC - INT32_ANGLE_FRAC));
+ INT32_EULERS_LSHIFT(sp_ref, *sp_euler, (REF_ANGLE_FRAC - INT32_ANGLE_FRAC));
/* compute reference attitude error */
struct Int32Eulers ref_err;
- EULERS_DIFF(ref_err, stab_att_ref_euler, sp_ref);
+ EULERS_DIFF(ref_err, ref->euler, sp_ref);
/* wrap it in the shortest direction */
ANGLE_REF_NORMALIZE(ref_err.psi);
/* compute reference angular accelerations */
const struct Int32Rates accel_rate = {
- ((int32_t)(-2.*ZETA_OMEGA_P) * (stab_att_ref_rate.p >> (REF_RATE_FRAC - REF_ACCEL_FRAC)))
+ ((int32_t)(-2.*ZETA_OMEGA_P) * (ref->rate.p >> (REF_RATE_FRAC - REF_ACCEL_FRAC)))
>> (ZETA_OMEGA_P_RES),
- ((int32_t)(-2.*ZETA_OMEGA_Q) * (stab_att_ref_rate.q >> (REF_RATE_FRAC - REF_ACCEL_FRAC)))
+ ((int32_t)(-2.*ZETA_OMEGA_Q) * (ref->rate.q >> (REF_RATE_FRAC - REF_ACCEL_FRAC)))
>> (ZETA_OMEGA_Q_RES),
- ((int32_t)(-2.*ZETA_OMEGA_R) * (stab_att_ref_rate.r >> (REF_RATE_FRAC - REF_ACCEL_FRAC)))
+ ((int32_t)(-2.*ZETA_OMEGA_R) * (ref->rate.r >> (REF_RATE_FRAC - REF_ACCEL_FRAC)))
>> (ZETA_OMEGA_R_RES)
};
@@ -137,20 +128,12 @@ void stabilization_attitude_ref_update()
((int32_t)(-OMEGA_2_R) * (ref_err.psi >> (REF_ANGLE_FRAC - REF_ACCEL_FRAC))) >> (OMEGA_2_R_RES)
};
- RATES_SUM(stab_att_ref_accel, accel_rate, accel_angle);
+ RATES_SUM(ref->accel, accel_rate, accel_angle);
/* saturate acceleration */
const struct Int32Rates MIN_ACCEL = { -REF_ACCEL_MAX_P, -REF_ACCEL_MAX_Q, -REF_ACCEL_MAX_R };
const struct Int32Rates MAX_ACCEL = { REF_ACCEL_MAX_P, REF_ACCEL_MAX_Q, REF_ACCEL_MAX_R };
- RATES_BOUND_BOX(stab_att_ref_accel, MIN_ACCEL, MAX_ACCEL);
+ RATES_BOUND_BOX(ref->accel, MIN_ACCEL, MAX_ACCEL);
/* saturate speed and trim accel accordingly */
- SATURATE_SPEED_TRIM_ACCEL();
-
-#else /* !USE_ATTITUDE_REF */
- INT32_EULERS_LSHIFT(stab_att_ref_euler, stab_att_sp_euler, (REF_ANGLE_FRAC - INT32_ANGLE_FRAC));
- INT_RATES_ZERO(stab_att_ref_rate);
- INT_RATES_ZERO(stab_att_ref_accel);
-#endif /* USE_ATTITUDE_REF */
-
}
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_int.h b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_int.h
index 08579a412a..accf8e89b6 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_int.h
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_euler_int.h
@@ -29,4 +29,15 @@
#include "stabilization_attitude_ref_int.h"
+/** Attitude reference models and state/output (euler int) */
+struct AttRefEulerInt {
+ struct Int32Eulers euler; ///< with #REF_ANGLE_FRAC
+ struct Int32Rates rate; ///< with #REF_RATE_FRAC
+ struct Int32Rates accel; ///< with #REF_ACCEL_FRAC
+};
+
+extern void attitude_ref_euler_int_init(struct AttRefEulerInt *ref);
+extern void attitude_ref_euler_int_enter(struct AttRefEulerInt *ref, int32_t psi);
+extern void attitude_ref_euler_int_update(struct AttRefEulerInt *ref, struct Int32Eulers *sp_euler);
+
#endif /* STABILIZATION_ATTITUDE_REF_EULER_INT_H */
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_float.h b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_float.h
deleted file mode 100644
index fb62bcc457..0000000000
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_float.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2008-2009 Antoine Drouin
- *
- * This file is part of paparazzi.
- *
- * paparazzi is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * paparazzi is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with paparazzi; see the file COPYING. If not, write to
- * the Free Software Foundation, 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/** @file stabilization_attitude_ref_float.h
- * Rotorcraft attitude reference generation API.
- * Common to all floating-point reference generators (euler and quaternion)
- */
-
-#ifndef STABILIZATION_ATTITUDE_REF_FLOAT_H
-#define STABILIZATION_ATTITUDE_REF_FLOAT_H
-
-#include "math/pprz_algebra_float.h"
-
-extern struct FloatEulers stab_att_sp_euler;
-extern struct FloatQuat stab_att_sp_quat;
-extern struct FloatEulers stab_att_ref_euler;
-extern struct FloatQuat stab_att_ref_quat;
-extern struct FloatRates stab_att_ref_rate;
-extern struct FloatRates stab_att_ref_accel;
-
-struct FloatRefModel {
- struct FloatRates omega;
- struct FloatRates zeta;
-};
-
-extern struct FloatRefModel stab_att_ref_model[];
-
-extern void stabilization_attitude_ref_init(void);
-extern void stabilization_attitude_ref_update(void);
-
-#endif /* STABILIZATION_ATTITUDE_REF_FLOAT_H */
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_int.h b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_int.h
index b004b357cf..7c20a5122a 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_int.h
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_int.h
@@ -33,12 +33,4 @@
#define REF_RATE_FRAC 16
#define REF_ANGLE_FRAC 20
-extern struct Int32Eulers stab_att_sp_euler; ///< with #INT32_ANGLE_FRAC
-extern struct Int32Eulers stab_att_ref_euler; ///< with #REF_ANGLE_FRAC
-extern struct Int32Rates stab_att_ref_rate; ///< with #REF_RATE_FRAC
-extern struct Int32Rates stab_att_ref_accel; ///< with #REF_ACCEL_FRAC
-
-extern void stabilization_attitude_ref_init(void);
-extern void stabilization_attitude_ref_update(void);
-
#endif /* STABILIZATION_ATTITUDE_REF_INT_H */
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_float.c b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_float.c
index ea3aab080a..14f6206b9a 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_float.c
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_float.c
@@ -32,6 +32,12 @@
#include "firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_float.h"
#include "firmwares/rotorcraft/stabilization/stabilization_attitude_ref_saturate.h"
+/// default to fast but less precise quaternion integration
+#ifndef STABILIZATION_ATTITUDE_REF_QUAT_INFINITESIMAL_STEP
+#define STABILIZATION_ATTITUDE_REF_QUAT_INFINITESIMAL_STEP TRUE
+#endif
+
+/* shortcuts for saturation defines */
#define REF_ACCEL_MAX_P STABILIZATION_ATTITUDE_REF_MAX_PDOT
#define REF_ACCEL_MAX_Q STABILIZATION_ATTITUDE_REF_MAX_QDOT
#define REF_ACCEL_MAX_R STABILIZATION_ATTITUDE_REF_MAX_RDOT
@@ -40,17 +46,8 @@
#define REF_RATE_MAX_Q STABILIZATION_ATTITUDE_REF_MAX_Q
#define REF_RATE_MAX_R STABILIZATION_ATTITUDE_REF_MAX_R
-struct FloatEulers stab_att_sp_euler;
-struct FloatQuat stab_att_sp_quat;
-struct FloatEulers stab_att_ref_euler;
-struct FloatQuat stab_att_ref_quat;
-struct FloatRates stab_att_ref_rate;
-struct FloatRates stab_att_ref_accel;
-
-struct FloatRefModel stab_att_ref_model[STABILIZATION_ATTITUDE_GAIN_NB];
-
-static int ref_idx = STABILIZATION_ATTITUDE_GAIN_IDX_DEFAULT;
+/* parameters used for initialization */
static const float omega_p[] = STABILIZATION_ATTITUDE_REF_OMEGA_P;
static const float zeta_p[] = STABILIZATION_ATTITUDE_REF_ZETA_P;
static const float omega_q[] = STABILIZATION_ATTITUDE_REF_OMEGA_Q;
@@ -58,147 +55,149 @@ static const float zeta_q[] = STABILIZATION_ATTITUDE_REF_ZETA_Q;
static const float omega_r[] = STABILIZATION_ATTITUDE_REF_OMEGA_R;
static const float zeta_r[] = STABILIZATION_ATTITUDE_REF_ZETA_R;
-struct FloatRates two_omega_squared[STABILIZATION_ATTITUDE_GAIN_NB];
-
-static inline void reset_psi_ref_from_body(void)
-{
- //sp has been set from body using stabilization_attitude_get_yaw_f, use that value
- stab_att_ref_euler.psi = stab_att_sp_euler.psi;
- stab_att_ref_rate.r = 0;
- stab_att_ref_accel.r = 0;
-}
-
-static inline void update_ref_quat_from_eulers(void)
-{
- struct FloatRMat ref_rmat;
- float_rmat_of_eulers(&ref_rmat, &stab_att_ref_euler);
- float_quat_of_rmat(&stab_att_ref_quat, &ref_rmat);
- float_quat_wrap_shortest(&stab_att_ref_quat);
-}
-
-void stabilization_attitude_ref_idx_set_omega_p(uint8_t idx, float omega)
-{
- stab_att_ref_model[idx].omega.p = omega;
- two_omega_squared[idx].p = 2 * omega * omega;
-}
-
-void stabilization_attitude_ref_idx_set_omega_q(uint8_t idx, float omega)
-{
- stab_att_ref_model[idx].omega.q = omega;
- two_omega_squared[idx].q = 2 * omega * omega;
-}
-
-void stabilization_attitude_ref_idx_set_omega_r(uint8_t idx, float omega)
-{
- stab_att_ref_model[idx].omega.r = omega;
- two_omega_squared[idx].r = 2 * omega * omega;
-}
-
-void stabilization_attitude_ref_set_omega_p(float omega)
-{
- stabilization_attitude_ref_idx_set_omega_p(ref_idx, omega);
-}
-
-void stabilization_attitude_ref_set_omega_q(float omega)
-{
- stabilization_attitude_ref_idx_set_omega_q(ref_idx, omega);
-}
-
-void stabilization_attitude_ref_set_omega_r(float omega)
-{
- stabilization_attitude_ref_idx_set_omega_r(ref_idx, omega);
-}
-
-
-void stabilization_attitude_ref_init(void)
-{
-
- FLOAT_EULERS_ZERO(stab_att_sp_euler);
- float_quat_identity(&stab_att_sp_quat);
- FLOAT_EULERS_ZERO(stab_att_ref_euler);
- float_quat_identity(&stab_att_ref_quat);
- FLOAT_RATES_ZERO(stab_att_ref_rate);
- FLOAT_RATES_ZERO(stab_att_ref_accel);
-
- for (int i = 0; i < STABILIZATION_ATTITUDE_GAIN_NB; i++) {
- RATES_ASSIGN(stab_att_ref_model[i].omega, omega_p[i], omega_q[i], omega_r[i]);
- RATES_ASSIGN(stab_att_ref_model[i].zeta, zeta_p[i], zeta_q[i], zeta_r[i]);
- RATES_ASSIGN(two_omega_squared[i], 2 * omega_p[i]*omega_p[i], 2 * omega_q[i]*omega_q[i], 2 * omega_r[i]*omega_r[i]);
- }
-
-}
-
-void stabilization_attitude_ref_schedule(uint8_t idx)
-{
- ref_idx = idx;
-}
-
-void stabilization_attitude_ref_enter(void)
-{
- reset_psi_ref_from_body();
- update_ref_quat_from_eulers();
-}
+static inline void reset_psi_ref(struct AttRefQuatFloat *ref, float psi);
/*
- * Reference
+ *
+ * Implementation.
+ * Should not rely on any global variables, so these functions can be used like a lib.
+ *
*/
-#define DT_UPDATE (1./PERIODIC_FREQUENCY)
+void attitude_ref_quat_float_init(struct AttRefQuatFloat *ref)
+{
+ FLOAT_EULERS_ZERO(ref->euler);
+ float_quat_identity(&ref->quat);
+ FLOAT_RATES_ZERO(ref->rate);
+ FLOAT_RATES_ZERO(ref->accel);
-// default to fast but less precise quaternion integration
-#ifndef STABILIZATION_ATTITUDE_REF_QUAT_INFINITESIMAL_STEP
-#define STABILIZATION_ATTITUDE_REF_QUAT_INFINITESIMAL_STEP TRUE
-#endif
+ for (int i = 0; i < STABILIZATION_ATTITUDE_GAIN_NB; i++) {
+ RATES_ASSIGN(ref->model[i].omega, omega_p[i], omega_q[i], omega_r[i]);
+ RATES_ASSIGN(ref->model[i].zeta, zeta_p[i], zeta_q[i], zeta_r[i]);
+ RATES_ASSIGN(ref->model[i].two_omega2, 2 * omega_p[i]*omega_p[i], 2 * omega_q[i]*omega_q[i], 2 * omega_r[i]*omega_r[i]);
+ }
-void stabilization_attitude_ref_update(void)
+ ref->cur_idx = 0;
+}
+
+void attitude_ref_quat_float_enter(struct AttRefQuatFloat *ref, float psi)
+{
+ reset_psi_ref(ref, psi);
+}
+
+
+void attitude_ref_quat_float_update(struct AttRefQuatFloat *ref, struct FloatQuat *sp_quat, float dt)
{
/* integrate reference attitude */
#if STABILIZATION_ATTITUDE_REF_QUAT_INFINITESIMAL_STEP
struct FloatQuat qdot;
- float_quat_derivative(&qdot, &stab_att_ref_rate, &stab_att_ref_quat);
- QUAT_SMUL(qdot, qdot, DT_UPDATE);
- QUAT_ADD(stab_att_ref_quat, qdot);
+ float_quat_derivative(&qdot, &ref->rate, &ref->quat);
+ QUAT_SMUL(qdot, qdot, dt);
+ QUAT_ADD(ref->quat, qdot);
#else // use finite step (involves trig)
struct FloatQuat delta_q;
- float_quat_differential(&delta_q, &stab_att_ref_rate, DT_UPDATE);
+ float_quat_differential(&delta_q, &ref->rate, dt);
/* compose new ref_quat by quaternion multiplication of delta rotation and current ref_quat */
struct FloatQuat new_ref_quat;
- float_quat_comp(&new_ref_quat, &stab_att_ref_quat, &delta_q);
- QUAT_COPY(stab_att_ref_quat, new_ref_quat);
+ float_quat_comp(&new_ref_quat, &ref->quat, &delta_q);
+ QUAT_COPY(ref->quat, new_ref_quat);
#endif
- float_quat_normalize(&stab_att_ref_quat);
+ float_quat_normalize(&ref->quat);
/* integrate reference rotational speeds */
struct FloatRates delta_rate;
- RATES_SMUL(delta_rate, stab_att_ref_accel, DT_UPDATE);
- RATES_ADD(stab_att_ref_rate, delta_rate);
+ RATES_SMUL(delta_rate, ref->accel, dt);
+ RATES_ADD(ref->rate, delta_rate);
/* compute reference angular accelerations */
struct FloatQuat err;
/* compute reference attitude error */
- float_quat_inv_comp(&err, &stab_att_sp_quat, &stab_att_ref_quat);
+ float_quat_inv_comp(&err, sp_quat, &ref->quat);
/* wrap it in the shortest direction */
float_quat_wrap_shortest(&err);
/* propagate the 2nd order linear model: xdotdot = -2*zeta*omega*xdot - omega^2*x */
/* since error quaternion contains the half-angles we get 2*omega^2*err */
- stab_att_ref_accel.p = -2.*stab_att_ref_model[ref_idx].zeta.p * stab_att_ref_model[ref_idx].omega.p *
- stab_att_ref_rate.p
- - two_omega_squared[ref_idx].p * err.qx;
- stab_att_ref_accel.q = -2.*stab_att_ref_model[ref_idx].zeta.q * stab_att_ref_model[ref_idx].omega.q *
- stab_att_ref_rate.q
- - two_omega_squared[ref_idx].q * err.qy;
- stab_att_ref_accel.r = -2.*stab_att_ref_model[ref_idx].zeta.r * stab_att_ref_model[ref_idx].omega.r *
- stab_att_ref_rate.r
- - two_omega_squared[ref_idx].r * err.qz;
+ ref->accel.p = -2.*ref->model[ref->cur_idx].zeta.p * ref->model[ref->cur_idx].omega.p * ref->rate.p -
+ ref->model[ref->cur_idx].two_omega2.p * err.qx;
+ ref->accel.q = -2.*ref->model[ref->cur_idx].zeta.q * ref->model[ref->cur_idx].omega.q * ref->rate.q -
+ ref->model[ref->cur_idx].two_omega2.q * err.qy;
+ ref->accel.r = -2.*ref->model[ref->cur_idx].zeta.r * ref->model[ref->cur_idx].omega.r * ref->rate.r -
+ ref->model[ref->cur_idx].two_omega2.r * err.qz;
/* saturate acceleration */
const struct FloatRates MIN_ACCEL = { -REF_ACCEL_MAX_P, -REF_ACCEL_MAX_Q, -REF_ACCEL_MAX_R };
const struct FloatRates MAX_ACCEL = { REF_ACCEL_MAX_P, REF_ACCEL_MAX_Q, REF_ACCEL_MAX_R };
- RATES_BOUND_BOX(stab_att_ref_accel, MIN_ACCEL, MAX_ACCEL);
+ RATES_BOUND_BOX(ref->accel, MIN_ACCEL, MAX_ACCEL);
/* saturate angular speed and trim accel accordingly */
- SATURATE_SPEED_TRIM_ACCEL();
+ SATURATE_SPEED_TRIM_ACCEL(*ref);
/* compute ref_euler */
- float_eulers_of_quat(&stab_att_ref_euler, &stab_att_ref_quat);
+ float_eulers_of_quat(&ref->euler, &ref->quat);
+}
+
+
+
+/*
+ *
+ * Local helper functions.
+ *
+ */
+static inline void reset_psi_ref(struct AttRefQuatFloat *ref, float psi)
+{
+ ref->euler.psi = psi;
+ ref->rate.r = 0;
+ ref->accel.r = 0;
+
+ // recalc quat from eulers
+ float_quat_of_eulers(&ref->quat, &ref->euler);
+ float_quat_wrap_shortest(&ref->quat);
+}
+
+
+/*
+ *
+ * Setting of the reference model parameters
+ *
+ */
+void attitude_ref_quat_float_idx_set_omega_p(struct AttRefQuatFloat *ref, uint8_t idx, float omega)
+{
+ ref->model[idx].omega.p = omega;
+ ref->model[idx].two_omega2.p = 2 * omega * omega;
+}
+
+void attitude_ref_quat_float_idx_set_omega_q(struct AttRefQuatFloat *ref, uint8_t idx, float omega)
+{
+ ref->model[idx].omega.q = omega;
+ ref->model[idx].two_omega2.q = 2 * omega * omega;
+}
+
+void attitude_ref_quat_float_idx_set_omega_r(struct AttRefQuatFloat *ref, uint8_t idx, float omega)
+{
+ ref->model[idx].omega.r = omega;
+ ref->model[idx].two_omega2.r = 2 * omega * omega;
+}
+
+void attitude_ref_quat_float_set_omega_p(struct AttRefQuatFloat *ref, float omega)
+{
+ attitude_ref_quat_float_idx_set_omega_p(ref, ref->cur_idx, omega);
+}
+
+void attitude_ref_quat_float_set_omega_q(struct AttRefQuatFloat *ref, float omega)
+{
+ attitude_ref_quat_float_idx_set_omega_q(ref, ref->cur_idx, omega);
+}
+
+void attitude_ref_quat_float_set_omega_r(struct AttRefQuatFloat *ref, float omega)
+{
+ attitude_ref_quat_float_idx_set_omega_r(ref, ref->cur_idx, omega);
+}
+
+
+/*
+ * schedule a different model
+ */
+void attitude_ref_quat_float_schedule(struct AttRefQuatFloat *ref, uint8_t idx)
+{
+ ref->cur_idx = idx;
}
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_float.h b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_float.h
index dfb8ee2031..38cc9081da 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_float.h
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_float.h
@@ -27,37 +27,48 @@
*
*/
-#ifndef STABILIZATION_ATTITUDE_FLOAT_REF_QUAT_FLOAT_H
-#define STABILIZATION_ATTITUDE_FLOAT_REF_QUAT_FLOAT_H
+#ifndef STABILIZATION_ATTITUDE_REF_QUAT_FLOAT_H
+#define STABILIZATION_ATTITUDE_REF_QUAT_FLOAT_H
-#include "stabilization_attitude_ref_float.h"
+#include "generated/airframe.h"
+#include "math/pprz_algebra_float.h"
#ifndef STABILIZATION_ATTITUDE_GAIN_NB
#define STABILIZATION_ATTITUDE_GAIN_NB 1
#endif
-#ifndef STABILIZATION_ATTITUDE_GAIN_IDX_DEFAULT
-#define STABILIZATION_ATTITUDE_GAIN_IDX_DEFAULT 0
-#endif
+/** Attitude reference model parameters (float) */
+struct FloatRefModel {
+ struct FloatRates omega;
+ struct FloatRates zeta;
+ /// cached value of 2*omega*omega
+ struct FloatRates two_omega2;
+};
-void stabilization_attitude_ref_enter(void);
-void stabilization_attitude_ref_schedule(uint8_t idx);
+/** Attitude reference models and state/output (float) */
+struct AttRefQuatFloat {
+ struct FloatEulers euler;
+ struct FloatQuat quat;
+ struct FloatRates rate;
+ struct FloatRates accel;
+ uint8_t cur_idx;
+ struct FloatRefModel model[STABILIZATION_ATTITUDE_GAIN_NB];
+};
-extern void stabilization_attitude_ref_idx_set_omega_p(uint8_t idx, float omega);
-extern void stabilization_attitude_ref_idx_set_omega_q(uint8_t idx, float omega);
-extern void stabilization_attitude_ref_idx_set_omega_r(uint8_t idx, float omega);
-extern void stabilization_attitude_ref_set_omega_p(float omega);
-extern void stabilization_attitude_ref_set_omega_q(float omega);
-extern void stabilization_attitude_ref_set_omega_r(float omega);
-#define stabilization_attitude_ref_quat_float_SetOmegaP(_val) { \
- stabilization_attitude_ref_set_omega_p(_val); \
- }
-#define stabilization_attitude_ref_quat_float_SetOmegaQ(_val) { \
- stabilization_attitude_ref_set_omega_q(_val); \
- }
-#define stabilization_attitude_ref_quat_float_SetOmegaR(_val) { \
- stabilization_attitude_ref_set_omega_r(_val); \
- }
+extern void attitude_ref_quat_float_init(struct AttRefQuatFloat *ref);
+extern void attitude_ref_quat_float_enter(struct AttRefQuatFloat *ref, float psi);
+extern void attitude_ref_quat_float_update(struct AttRefQuatFloat *ref, struct FloatQuat *sp_quat, float dt);
-#endif /* STABILIZATION_ATTITUDE_FLOAT_REF_QUAT_FLOAT_H */
+
+extern void attitude_ref_quat_float_schedule(struct AttRefQuatFloat *ref, uint8_t idx);
+
+extern void attitude_ref_quat_float_idx_set_omega_p(struct AttRefQuatFloat *ref, uint8_t idx, float omega);
+extern void attitude_ref_quat_float_idx_set_omega_q(struct AttRefQuatFloat *ref, uint8_t idx, float omega);
+extern void attitude_ref_quat_float_idx_set_omega_r(struct AttRefQuatFloat *ref, uint8_t idx, float omega);
+extern void attitude_ref_quat_float_set_omega_p(struct AttRefQuatFloat *ref, float omega);
+extern void attitude_ref_quat_float_set_omega_q(struct AttRefQuatFloat *ref, float omega);
+extern void attitude_ref_quat_float_set_omega_r(struct AttRefQuatFloat *ref, float omega);
+
+
+#endif /* STABILIZATION_ATTITUDE_REF_QUAT_FLOAT_H */
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_int.c b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_int.c
index abf5dcf762..57da453133 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_int.c
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_int.c
@@ -40,214 +40,215 @@
#define REF_RATE_MAX_R BFP_OF_REAL(STABILIZATION_ATTITUDE_REF_MAX_R, REF_RATE_FRAC)
-struct Int32Eulers stab_att_sp_euler;
-struct Int32Quat stab_att_sp_quat;
-struct Int32Eulers stab_att_ref_euler;
-struct Int32Quat stab_att_ref_quat;
-struct Int32Rates stab_att_ref_rate;
-struct Int32Rates stab_att_ref_accel;
-
-struct FloatRefModel stab_att_ref_model = {
- {STABILIZATION_ATTITUDE_REF_OMEGA_P, STABILIZATION_ATTITUDE_REF_OMEGA_Q, STABILIZATION_ATTITUDE_REF_OMEGA_R},
- {STABILIZATION_ATTITUDE_REF_ZETA_P, STABILIZATION_ATTITUDE_REF_ZETA_Q, STABILIZATION_ATTITUDE_REF_ZETA_R}
-};
#define TWO_ZETA_OMEGA_RES 10
#define TWO_OMEGA_2_RES 7
-static struct Int32Rates two_zeta_omega;
-static struct Int32Rates two_omega_2;
-
-static void update_ref_model_p(void)
-{
- two_zeta_omega.p = BFP_OF_REAL((2 * stab_att_ref_model.zeta.p * stab_att_ref_model.omega.p), TWO_ZETA_OMEGA_RES);
- two_omega_2.p = BFP_OF_REAL((2 * stab_att_ref_model.omega.p * stab_att_ref_model.omega.p), TWO_OMEGA_2_RES);
-}
-
-static void update_ref_model_q(void)
-{
- two_zeta_omega.q = BFP_OF_REAL((2 * stab_att_ref_model.zeta.q * stab_att_ref_model.omega.q), TWO_ZETA_OMEGA_RES);
- two_omega_2.q = BFP_OF_REAL((2 * stab_att_ref_model.omega.q * stab_att_ref_model.omega.q), TWO_OMEGA_2_RES);
-}
-
-static void update_ref_model_r(void)
-{
- two_zeta_omega.r = BFP_OF_REAL((2 * stab_att_ref_model.zeta.r * stab_att_ref_model.omega.r), TWO_ZETA_OMEGA_RES);
- two_omega_2.r = BFP_OF_REAL((2 * stab_att_ref_model.omega.r * stab_att_ref_model.omega.r), TWO_OMEGA_2_RES);
-}
-
-static void update_ref_model(void)
-{
- update_ref_model_p();
- update_ref_model_q();
- update_ref_model_r();
-}
-void stabilization_attitude_ref_set_omega_p(float omega_p)
-{
- stab_att_ref_model.omega.p = omega_p;
- update_ref_model_p();
-}
-
-void stabilization_attitude_ref_set_omega_q(float omega_q)
-{
- stab_att_ref_model.omega.q = omega_q;
- update_ref_model_q();
-}
-
-void stabilization_attitude_ref_set_omega_r(float omega_r)
-{
- stab_att_ref_model.omega.r = omega_r;
- update_ref_model_r();
-}
-
-void stabilization_attitude_ref_set_omega(struct FloatRates *omega)
-{
- stabilization_attitude_ref_set_omega_p(omega->p);
- stabilization_attitude_ref_set_omega_q(omega->q);
- stabilization_attitude_ref_set_omega_r(omega->r);
-}
-
-void stabilization_attitude_ref_set_zeta_p(float zeta_p)
-{
- stab_att_ref_model.zeta.p = zeta_p;
- update_ref_model_p();
-}
-
-void stabilization_attitude_ref_set_zeta_q(float zeta_q)
-{
- stab_att_ref_model.zeta.q = zeta_q;
- update_ref_model_q();
-}
-
-void stabilization_attitude_ref_set_zeta_r(float zeta_r)
-{
- stab_att_ref_model.zeta.r = zeta_r;
- update_ref_model_r();
-}
-
-void stabilization_attitude_ref_set_zeta(struct FloatRates *zeta)
-{
- stabilization_attitude_ref_set_zeta_p(zeta->p);
- stabilization_attitude_ref_set_zeta_q(zeta->q);
- stabilization_attitude_ref_set_zeta_r(zeta->r);
-}
-
-
-static inline void reset_psi_ref_from_body(void)
-{
- //sp has been set from body using stabilization_attitude_get_yaw_i, use that value
- stab_att_ref_euler.psi = stab_att_sp_euler.psi << (REF_ANGLE_FRAC - INT32_ANGLE_FRAC);
- stab_att_ref_rate.r = 0;
- stab_att_ref_accel.r = 0;
-}
-
-void stabilization_attitude_ref_init(void)
-{
-
- INT_EULERS_ZERO(stab_att_sp_euler);
- int32_quat_identity(&stab_att_sp_quat);
- INT_EULERS_ZERO(stab_att_ref_euler);
- int32_quat_identity(&stab_att_ref_quat);
- INT_RATES_ZERO(stab_att_ref_rate);
- INT_RATES_ZERO(stab_att_ref_accel);
-
- update_ref_model();
-
-}
-
-void stabilization_attitude_ref_enter(void)
-{
- reset_psi_ref_from_body();
-
- /* convert reference attitude with REF_ANGLE_FRAC to eulers with normal INT32_ANGLE_FRAC */
- struct Int32Eulers ref_eul;
- INT32_EULERS_RSHIFT(ref_eul, stab_att_ref_euler, (REF_ANGLE_FRAC - INT32_ANGLE_FRAC));
- int32_quat_of_eulers(&stab_att_ref_quat, &ref_eul);
- int32_quat_wrap_shortest(&stab_att_ref_quat);
-
- /* set reference rate and acceleration to zero */
- memset(&stab_att_ref_accel, 0, sizeof(struct Int32Rates));
- memset(&stab_att_ref_rate, 0, sizeof(struct Int32Rates));
-}
+static inline void reset_psi_ref(struct AttRefQuatInt *ref, int32_t psi);
+static void update_ref_model_p(struct AttRefQuatInt *ref);
+static void update_ref_model_q(struct AttRefQuatInt *ref);
+static void update_ref_model_r(struct AttRefQuatInt *ref);
+static void update_ref_model(struct AttRefQuatInt *ref);
/*
- * Reference
+ *
+ * Implementation.
+ * Should not rely on any global variables, so these functions can be used like a lib.
+ *
*/
-#define DT_UPDATE (1./PERIODIC_FREQUENCY)
+void attitude_ref_quat_int_init(struct AttRefQuatInt *ref)
+{
+ INT_EULERS_ZERO(ref->euler);
+ int32_quat_identity(&ref->quat);
+ INT_RATES_ZERO(ref->rate);
+ INT_RATES_ZERO(ref->accel);
+
+ struct FloatRates omega0 = {STABILIZATION_ATTITUDE_REF_OMEGA_P,
+ STABILIZATION_ATTITUDE_REF_OMEGA_Q,
+ STABILIZATION_ATTITUDE_REF_OMEGA_R};
+ struct FloatRates zeta0 = {STABILIZATION_ATTITUDE_REF_ZETA_P,
+ STABILIZATION_ATTITUDE_REF_ZETA_Q,
+ STABILIZATION_ATTITUDE_REF_ZETA_R};
+ attitude_ref_quat_int_set_omega(ref, &omega0);
+ attitude_ref_quat_int_set_zeta(ref, &zeta0);
+
+ /* calc the intermediate cached values */
+ update_ref_model(ref);
+}
+
+void attitude_ref_quat_int_enter(struct AttRefQuatInt *ref, int32_t psi)
+{
+ reset_psi_ref(ref, psi);
+
+ int32_quat_of_eulers(&ref->quat, &ref->euler);
+ int32_quat_wrap_shortest(&ref->quat);
+
+ /* set reference rate and acceleration to zero */
+ memset(&ref->accel, 0, sizeof(struct Int32Rates));
+ memset(&ref->rate, 0, sizeof(struct Int32Rates));
+}
+
// CAUTION! Periodic frequency is assumed to be 512 Hz
// which is equal to >> 9
#define F_UPDATE_RES 9
#define OFFSET_AND_ROUND(_a, _b) (((_a)+(1<<((_b)-1)))>>(_b))
-
-
-void stabilization_attitude_ref_update(void)
+/**
+ * Propagate reference.
+ * CAUTION! Periodic frequency is assumed to be 512 Hz.
+ * FIXME: use dt instead of hardcoded 512Hz via F_UPDATE_RES
+ */
+void attitude_ref_quat_int_update(struct AttRefQuatInt *ref, struct Int32Quat *sp_quat,
+ float dt __attribute__((unused)))
{
-
/* integrate reference attitude */
const struct Int32Rates rate_ref_scaled = {
- OFFSET_AND_ROUND(stab_att_ref_rate.p, (REF_RATE_FRAC - INT32_RATE_FRAC)),
- OFFSET_AND_ROUND(stab_att_ref_rate.q, (REF_RATE_FRAC - INT32_RATE_FRAC)),
- OFFSET_AND_ROUND(stab_att_ref_rate.r, (REF_RATE_FRAC - INT32_RATE_FRAC))
+ OFFSET_AND_ROUND(ref->rate.p, (REF_RATE_FRAC - INT32_RATE_FRAC)),
+ OFFSET_AND_ROUND(ref->rate.q, (REF_RATE_FRAC - INT32_RATE_FRAC)),
+ OFFSET_AND_ROUND(ref->rate.r, (REF_RATE_FRAC - INT32_RATE_FRAC))
};
struct Int32Quat qdot;
- int32_quat_derivative(&qdot, &rate_ref_scaled, &stab_att_ref_quat);
- //QUAT_SMUL(qdot, qdot, DT_UPDATE);
+ int32_quat_derivative(&qdot, &rate_ref_scaled, &ref->quat);
qdot.qi = qdot.qi >> F_UPDATE_RES;
qdot.qx = qdot.qx >> F_UPDATE_RES;
qdot.qy = qdot.qy >> F_UPDATE_RES;
qdot.qz = qdot.qz >> F_UPDATE_RES;
- QUAT_ADD(stab_att_ref_quat, qdot);
- int32_quat_normalize(&stab_att_ref_quat);
+ QUAT_ADD(ref->quat, qdot);
+ int32_quat_normalize(&ref->quat);
/* integrate reference rotational speeds
* delta rate = ref_accel * dt
* ref_rate = old_ref_rate + delta_rate
*/
const struct Int32Rates delta_rate = {
- stab_att_ref_accel.p >> (F_UPDATE_RES + REF_ACCEL_FRAC - REF_RATE_FRAC),
- stab_att_ref_accel.q >> (F_UPDATE_RES + REF_ACCEL_FRAC - REF_RATE_FRAC),
- stab_att_ref_accel.r >> (F_UPDATE_RES + REF_ACCEL_FRAC - REF_RATE_FRAC)
+ ref->accel.p >> (F_UPDATE_RES + REF_ACCEL_FRAC - REF_RATE_FRAC),
+ ref->accel.q >> (F_UPDATE_RES + REF_ACCEL_FRAC - REF_RATE_FRAC),
+ ref->accel.r >> (F_UPDATE_RES + REF_ACCEL_FRAC - REF_RATE_FRAC)
};
- RATES_ADD(stab_att_ref_rate, delta_rate);
+ RATES_ADD(ref->rate, delta_rate);
/* compute reference angular accelerations */
struct Int32Quat err;
/* compute reference attitude error */
- int32_quat_inv_comp(&err, &stab_att_sp_quat, &stab_att_ref_quat);
+ int32_quat_inv_comp(&err, sp_quat, &ref->quat);
/* wrap it in the shortest direction */
int32_quat_wrap_shortest(&err);
/* propagate the 2nd order linear model : accel = -2*zeta*omega * rate - omega^2 * angle */
const struct Int32Rates accel_rate = {
- (-two_zeta_omega.p * (stab_att_ref_rate.p >> (REF_RATE_FRAC - REF_ACCEL_FRAC))) >> (TWO_ZETA_OMEGA_RES),
- (-two_zeta_omega.q * (stab_att_ref_rate.q >> (REF_RATE_FRAC - REF_ACCEL_FRAC))) >> (TWO_ZETA_OMEGA_RES),
- (-two_zeta_omega.r * (stab_att_ref_rate.r >> (REF_RATE_FRAC - REF_ACCEL_FRAC))) >> (TWO_ZETA_OMEGA_RES)
+ (-ref->model.two_zeta_omega.p * (ref->rate.p >> (REF_RATE_FRAC - REF_ACCEL_FRAC))) >> (TWO_ZETA_OMEGA_RES),
+ (-ref->model.two_zeta_omega.q * (ref->rate.q >> (REF_RATE_FRAC - REF_ACCEL_FRAC))) >> (TWO_ZETA_OMEGA_RES),
+ (-ref->model.two_zeta_omega.r * (ref->rate.r >> (REF_RATE_FRAC - REF_ACCEL_FRAC))) >> (TWO_ZETA_OMEGA_RES)
};
/* since error quaternion contains the half-angles we get 2*omega^2*err */
const struct Int32Rates accel_angle = {
- (-two_omega_2.p * (err.qx >> (INT32_QUAT_FRAC - REF_ACCEL_FRAC))) >> (TWO_OMEGA_2_RES),
- (-two_omega_2.q * (err.qy >> (INT32_QUAT_FRAC - REF_ACCEL_FRAC))) >> (TWO_OMEGA_2_RES),
- (-two_omega_2.r * (err.qz >> (INT32_QUAT_FRAC - REF_ACCEL_FRAC))) >> (TWO_OMEGA_2_RES)
+ (-ref->model.two_omega2.p * (err.qx >> (INT32_QUAT_FRAC - REF_ACCEL_FRAC))) >> (TWO_OMEGA_2_RES),
+ (-ref->model.two_omega2.q * (err.qy >> (INT32_QUAT_FRAC - REF_ACCEL_FRAC))) >> (TWO_OMEGA_2_RES),
+ (-ref->model.two_omega2.r * (err.qz >> (INT32_QUAT_FRAC - REF_ACCEL_FRAC))) >> (TWO_OMEGA_2_RES)
};
- RATES_SUM(stab_att_ref_accel, accel_rate, accel_angle);
+ RATES_SUM(ref->accel, accel_rate, accel_angle);
/* saturate acceleration */
const struct Int32Rates MIN_ACCEL = { -REF_ACCEL_MAX_P, -REF_ACCEL_MAX_Q, -REF_ACCEL_MAX_R };
const struct Int32Rates MAX_ACCEL = { REF_ACCEL_MAX_P, REF_ACCEL_MAX_Q, REF_ACCEL_MAX_R };
- RATES_BOUND_BOX(stab_att_ref_accel, MIN_ACCEL, MAX_ACCEL);
+ RATES_BOUND_BOX(ref->accel, MIN_ACCEL, MAX_ACCEL);
/* saturate angular speed and trim accel accordingly */
- SATURATE_SPEED_TRIM_ACCEL();
+ SATURATE_SPEED_TRIM_ACCEL(*ref);
- /* compute ref_euler for debugging and telemetry */
- struct Int32Eulers ref_eul;
- int32_eulers_of_quat(&ref_eul, &stab_att_ref_quat);
- INT32_EULERS_LSHIFT(stab_att_ref_euler, ref_eul, (REF_ANGLE_FRAC - INT32_ANGLE_FRAC));
+ /* compute euler representation for debugging and telemetry */
+ int32_eulers_of_quat(&ref->euler, &ref->quat);
+}
+
+
+
+
+static void update_ref_model_p(struct AttRefQuatInt *ref)
+{
+ ref->model.two_zeta_omega.p = BFP_OF_REAL((2 * ref->model.zeta.p * ref->model.omega.p), TWO_ZETA_OMEGA_RES);
+ ref->model.two_omega2.p = BFP_OF_REAL((2 * ref->model.omega.p * ref->model.omega.p), TWO_OMEGA_2_RES);
+}
+
+static void update_ref_model_q(struct AttRefQuatInt *ref)
+{
+ ref->model.two_zeta_omega.q = BFP_OF_REAL((2 * ref->model.zeta.q * ref->model.omega.q), TWO_ZETA_OMEGA_RES);
+ ref->model.two_omega2.q = BFP_OF_REAL((2 * ref->model.omega.q * ref->model.omega.q), TWO_OMEGA_2_RES);
+}
+
+static void update_ref_model_r(struct AttRefQuatInt *ref)
+{
+ ref->model.two_zeta_omega.r = BFP_OF_REAL((2 * ref->model.zeta.r * ref->model.omega.r), TWO_ZETA_OMEGA_RES);
+ ref->model.two_omega2.r = BFP_OF_REAL((2 * ref->model.omega.r * ref->model.omega.r), TWO_OMEGA_2_RES);
+}
+
+static void update_ref_model(struct AttRefQuatInt *ref)
+{
+ update_ref_model_p(ref);
+ update_ref_model_q(ref);
+ update_ref_model_r(ref);
+}
+
+
+void attitude_ref_quat_int_set_omega_p(struct AttRefQuatInt *ref, float omega_p)
+{
+ ref->model.omega.p = omega_p;
+ update_ref_model_p(ref);
+}
+
+void attitude_ref_quat_int_set_omega_q(struct AttRefQuatInt *ref, float omega_q)
+{
+ ref->model.omega.q = omega_q;
+ update_ref_model_q(ref);
+}
+
+void attitude_ref_quat_int_set_omega_r(struct AttRefQuatInt *ref, float omega_r)
+{
+ ref->model.omega.r = omega_r;
+ update_ref_model_r(ref);
+}
+
+void attitude_ref_quat_int_set_omega(struct AttRefQuatInt *ref, struct FloatRates *omega)
+{
+ attitude_ref_quat_int_set_omega_p(ref, omega->p);
+ attitude_ref_quat_int_set_omega_q(ref, omega->q);
+ attitude_ref_quat_int_set_omega_r(ref, omega->r);
+}
+
+void attitude_ref_quat_int_set_zeta_p(struct AttRefQuatInt *ref, float zeta_p)
+{
+ ref->model.zeta.p = zeta_p;
+ update_ref_model_p(ref);
+}
+
+void attitude_ref_quat_int_set_zeta_q(struct AttRefQuatInt *ref, float zeta_q)
+{
+ ref->model.zeta.q = zeta_q;
+ update_ref_model_q(ref);
+}
+
+void attitude_ref_quat_int_set_zeta_r(struct AttRefQuatInt *ref, float zeta_r)
+{
+ ref->model.zeta.r = zeta_r;
+ update_ref_model_r(ref);
+}
+
+void attitude_ref_quat_int_set_zeta(struct AttRefQuatInt *ref, struct FloatRates *zeta)
+{
+ attitude_ref_quat_int_set_zeta_p(ref, zeta->p);
+ attitude_ref_quat_int_set_zeta_q(ref, zeta->q);
+ attitude_ref_quat_int_set_zeta_r(ref, zeta->r);
+}
+
+
+static inline void reset_psi_ref(struct AttRefQuatInt *ref, int32_t psi)
+{
+ ref->euler.psi = psi;
+ ref->rate.r = 0;
+ ref->accel.r = 0;
}
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_int.h b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_int.h
index 52754dd537..20612318ad 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_int.h
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_int.h
@@ -32,49 +32,39 @@
#include "stabilization_attitude_ref_int.h"
-extern struct Int32Quat stab_att_sp_quat; ///< with #INT32_QUAT_FRAC
-extern struct Int32Quat stab_att_ref_quat; ///< with #INT32_QUAT_FRAC
-
-void stabilization_attitude_ref_enter(void);
-
/* ref model is in float and then used to precompute ref values in int */
#include "math/pprz_algebra_float.h"
+/** Attitude reference model parameters (quat int) */
struct FloatRefModel {
struct FloatRates omega;
struct FloatRates zeta;
+ /* cached intermediate values in int */
+ struct Int32Rates two_zeta_omega;
+ struct Int32Rates two_omega2;
};
-extern struct FloatRefModel stab_att_ref_model;
+/** Attitude reference models and state/output (quat int) */
+struct AttRefQuatInt {
+ struct Int32Eulers euler; ///< with #INT32_ANGLE_FRAC
+ struct Int32Quat quat;
+ struct Int32Rates rate; ///< with #REF_RATE_FRAC
+ struct Int32Rates accel; ///< with #REF_ACCEL_FRAC
+ struct FloatRefModel model;
+};
-extern void stabilization_attitude_ref_set_omega(struct FloatRates *omega);
-extern void stabilization_attitude_ref_set_omega_p(float omega_p);
-extern void stabilization_attitude_ref_set_omega_q(float omega_q);
-extern void stabilization_attitude_ref_set_omega_r(float omega_r);
+extern void attitude_ref_quat_int_init(struct AttRefQuatInt *ref);
+extern void attitude_ref_quat_int_enter(struct AttRefQuatInt *ref, int32_t psi);
+extern void attitude_ref_quat_int_update(struct AttRefQuatInt *ref, struct Int32Quat *sp_quat, float dt);
-extern void stabilization_attitude_ref_set_zeta(struct FloatRates *zeta);
-extern void stabilization_attitude_ref_set_zeta_p(float zeta_p);
-extern void stabilization_attitude_ref_set_zeta_q(float zeta_q);
-extern void stabilization_attitude_ref_set_zeta_r(float zeta_r);
+extern void attitude_ref_quat_int_set_omega(struct AttRefQuatInt *ref, struct FloatRates *omega);
+extern void attitude_ref_quat_int_set_omega_p(struct AttRefQuatInt *ref, float omega_p);
+extern void attitude_ref_quat_int_set_omega_q(struct AttRefQuatInt *ref, float omega_q);
+extern void attitude_ref_quat_int_set_omega_r(struct AttRefQuatInt *ref, float omega_r);
-#define stabilization_attitude_ref_quat_int_SetOmegaP(_val) { \
- stabilization_attitude_ref_set_omega_p(_val); \
- }
-#define stabilization_attitude_ref_quat_int_SetOmegaQ(_val) { \
- stabilization_attitude_ref_set_omega_q(_val); \
- }
-#define stabilization_attitude_ref_quat_int_SetOmegaR(_val) { \
- stabilization_attitude_ref_set_omega_r(_val); \
- }
-
-#define stabilization_attitude_ref_quat_int_SetZetaP(_val) { \
- stabilization_attitude_ref_set_zeta_p(_val); \
- }
-#define stabilization_attitude_ref_quat_int_SetZetaQ(_val) { \
- stabilization_attitude_ref_set_zeta_q(_val); \
- }
-#define stabilization_attitude_ref_quat_int_SetZetaR(_val) { \
- stabilization_attitude_ref_set_zeta_r(_val); \
- }
+extern void attitude_ref_quat_int_set_zeta(struct AttRefQuatInt *ref, struct FloatRates *zeta);
+extern void attitude_ref_quat_int_set_zeta_p(struct AttRefQuatInt *ref, float zeta_p);
+extern void attitude_ref_quat_int_set_zeta_q(struct AttRefQuatInt *ref, float zeta_q);
+extern void attitude_ref_quat_int_set_zeta_r(struct AttRefQuatInt *ref, float zeta_r);
#endif /* STABILIZATION_ATTITUDE_REF_QUAT_INT_H */
diff --git a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_saturate.h b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_saturate.h
index 30fac212a3..3452022552 100644
--- a/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_saturate.h
+++ b/sw/airborne/firmwares/rotorcraft/stabilization/stabilization_attitude_ref_saturate.h
@@ -26,37 +26,37 @@
#ifndef STABILIZATION_ATTITUDE_REF_SATURATE_H
#define STABILIZATION_ATTITUDE_REF_SATURATE_H
-#define SATURATE_SPEED_TRIM_ACCEL() { \
- if (stab_att_ref_rate.p >= REF_RATE_MAX_P) { \
- stab_att_ref_rate.p = REF_RATE_MAX_P; \
- if (stab_att_ref_accel.p > 0) \
- stab_att_ref_accel.p = 0; \
- } \
- else if (stab_att_ref_rate.p <= -REF_RATE_MAX_P) { \
- stab_att_ref_rate.p = -REF_RATE_MAX_P; \
- if (stab_att_ref_accel.p < 0) \
- stab_att_ref_accel.p = 0; \
- } \
- if (stab_att_ref_rate.q >= REF_RATE_MAX_Q) { \
- stab_att_ref_rate.q = REF_RATE_MAX_Q; \
- if (stab_att_ref_accel.q > 0) \
- stab_att_ref_accel.q = 0; \
- } \
- else if (stab_att_ref_rate.q <= -REF_RATE_MAX_Q) { \
- stab_att_ref_rate.q = -REF_RATE_MAX_Q; \
- if (stab_att_ref_accel.q < 0) \
- stab_att_ref_accel.q = 0; \
- } \
- if (stab_att_ref_rate.r >= REF_RATE_MAX_R) { \
- stab_att_ref_rate.r = REF_RATE_MAX_R; \
- if (stab_att_ref_accel.r > 0) \
- stab_att_ref_accel.r = 0; \
- } \
- else if (stab_att_ref_rate.r <= -REF_RATE_MAX_R) { \
- stab_att_ref_rate.r = -REF_RATE_MAX_R; \
- if (stab_att_ref_accel.r < 0) \
- stab_att_ref_accel.r = 0; \
- } \
+#define SATURATE_SPEED_TRIM_ACCEL(_ref) { \
+ if ((_ref).rate.p >= REF_RATE_MAX_P) { \
+ (_ref).rate.p = REF_RATE_MAX_P; \
+ if ((_ref).accel.p > 0) \
+ (_ref).accel.p = 0; \
+ } \
+ else if ((_ref).rate.p <= -REF_RATE_MAX_P) { \
+ (_ref).rate.p = -REF_RATE_MAX_P; \
+ if ((_ref).accel.p < 0) \
+ (_ref).accel.p = 0; \
+ } \
+ if ((_ref).rate.q >= REF_RATE_MAX_Q) { \
+ (_ref).rate.q = REF_RATE_MAX_Q; \
+ if ((_ref).accel.q > 0) \
+ (_ref).accel.q = 0; \
+ } \
+ else if ((_ref).rate.q <= -REF_RATE_MAX_Q) { \
+ (_ref).rate.q = -REF_RATE_MAX_Q; \
+ if ((_ref).accel.q < 0) \
+ (_ref).accel.q = 0; \
+ } \
+ if ((_ref).rate.r >= REF_RATE_MAX_R) { \
+ (_ref).rate.r = REF_RATE_MAX_R; \
+ if ((_ref).accel.r > 0) \
+ (_ref).accel.r = 0; \
+ } \
+ else if ((_ref).rate.r <= -REF_RATE_MAX_R) { \
+ (_ref).rate.r = -REF_RATE_MAX_R; \
+ if ((_ref).accel.r < 0) \
+ (_ref).accel.r = 0; \
+ } \
}
diff --git a/sw/airborne/test/stabilization/compare_ref_quat.py b/sw/airborne/test/stabilization/compare_ref_quat.py
index 76fc8d3a15..0ccdfd3bea 100755
--- a/sw/airborne/test/stabilization/compare_ref_quat.py
+++ b/sw/airborne/test/stabilization/compare_ref_quat.py
@@ -5,46 +5,45 @@ from __future__ import division, print_function, absolute_import
import numpy as np
import matplotlib.pyplot as plt
-import ref_quat_float
-import ref_quat_int
+from ref_quat_float import RefQuatFloat
+from ref_quat_int import RefQuatInt
steps = 512 * 2
-ref_eul_res = np.zeros((steps, 3))
-ref_quat_res = np.zeros((steps, 3))
+ref_float_res = np.zeros((steps, 3))
+ref_int_res = np.zeros((steps, 3))
-ref_quat_float.init()
-ref_quat_int.init()
-
-# reset psi and update_ref_quat_from_eulers
-ref_quat_float.enter()
-ref_quat_int.enter()
+ref_float = RefQuatFloat()
+ref_int = RefQuatInt()
q_sp = np.array([0.92387956, 0.38268346, 0., 0.])
-ref_quat_float.sp_quat.array = q_sp
-ref_quat_int.sp_quat.array = q_sp * (1 << 15)
+ref_float.setpoint = q_sp
+ref_int.setpoint = q_sp
+#print(ref_int.setpoint)
+
+dt = 1/512
for i in range(0, steps):
- ref_quat_float.update()
- ref_eul_res[i, :] = ref_quat_float.ref_euler.array
- ref_quat_int.update()
- ref_quat_res[i, :] = ref_quat_int.ref_euler.array / (1 << 20)
+ ref_float.update(dt)
+ ref_float_res[i, :] = ref_float.eulers
+ ref_int.update(dt)
+ ref_int_res[i, :] = ref_int.eulers
plt.figure(1)
plt.subplot(311)
plt.title("reference in euler angles")
-plt.plot(np.degrees(ref_eul_res[:, 0]), 'g')
-plt.plot(np.degrees(ref_quat_res[:, 0]), 'r')
+plt.plot(np.degrees(ref_float_res[:, 0]), 'g')
+plt.plot(np.degrees(ref_int_res[:, 0]), 'r')
plt.ylabel("phi [deg]")
plt.subplot(312)
-plt.plot(np.degrees(ref_eul_res[:, 1]), 'g')
-plt.plot(np.degrees(ref_quat_res[:, 1]), 'r')
+plt.plot(np.degrees(ref_float_res[:, 1]), 'g')
+plt.plot(np.degrees(ref_int_res[:, 1]), 'r')
plt.ylabel("theta [deg]")
plt.subplot(313)
-plt.plot(np.degrees(ref_eul_res[:, 2]), 'g')
-plt.plot(np.degrees(ref_quat_res[:, 2]), 'r')
+plt.plot(np.degrees(ref_float_res[:, 2]), 'g')
+plt.plot(np.degrees(ref_int_res[:, 2]), 'r')
plt.ylabel("psi [deg]")
plt.show()
diff --git a/sw/airborne/test/stabilization/ref_quat_float.pxd b/sw/airborne/test/stabilization/ref_quat_float.pxd
new file mode 100644
index 0000000000..58fea98e11
--- /dev/null
+++ b/sw/airborne/test/stabilization/ref_quat_float.pxd
@@ -0,0 +1,24 @@
+from pprz_algebra_float_c cimport FloatQuat, FloatEulers, FloatRates
+
+cdef extern from "stabilization/stabilization_attitude_ref_quat_float.h":
+ #struct FloatRefModel:
+ # FloatRates omega
+ # FloatRates zeta
+
+ struct AttRefQuatFloat:
+ FloatEulers euler
+ FloatQuat quat
+ FloatRates rate
+ FloatRates accel
+
+ void attitude_ref_quat_float_init(AttRefQuatFloat *ref)
+ void attitude_ref_quat_float_enter(AttRefQuatFloat *ref, float psi)
+ void attitude_ref_quat_float_update(AttRefQuatFloat *ref, FloatQuat *sp_quat, float dt)
+
+ void attitude_ref_quat_float_set_omega_p(AttRefQuatFloat *ref, float omega)
+ void attitude_ref_quat_float_set_omega_q(AttRefQuatFloat *ref, float omega)
+ void attitude_ref_quat_float_set_omega_r(AttRefQuatFloat *ref, float omega)
+
+
+#cdef class RefQuatFloat:
+# cdef AttRefQuatFloat ref
diff --git a/sw/airborne/test/stabilization/ref_quat_float.pyx b/sw/airborne/test/stabilization/ref_quat_float.pyx
index 1509ee3e87..899efa15e8 100644
--- a/sw/airborne/test/stabilization/ref_quat_float.pyx
+++ b/sw/airborne/test/stabilization/ref_quat_float.pyx
@@ -1,60 +1,29 @@
-cdef extern from "stdint.h":
- ctypedef unsigned long int uintptr_t
-
-
+cimport ref_quat_float
+from pprz_algebra_float_c cimport FloatQuat
import numpy as np
-cimport numpy as np
-cimport pprz_algebra_float_c
-from algebra_float import FloatQuat, FloatEulers, FloatRates
+cdef class RefQuatFloat:
+ cdef ref_quat_float.AttRefQuatFloat ref
+ cdef FloatQuat sp_quat
+ def __cinit__(self):
+ ref_quat_float.attitude_ref_quat_float_init(&self.ref)
+ self.setpoint = [1.0, 0, 0, 0]
-cdef extern from "stabilization/stabilization_attitude_ref_quat_float.h":
- void stabilization_attitude_ref_init()
- void stabilization_attitude_ref_update()
- void stabilization_attitude_ref_enter()
- void stabilization_attitude_ref_schedule(int idx)
+ cpdef update(self, dt, setpoint=None):
+ if setpoint is not None:
+ self.setpoint = setpoint
+ ref_quat_float.attitude_ref_quat_float_update(&self.ref, &self.sp_quat, dt)
- pprz_algebra_float_c.FloatEulers stab_att_sp_euler
- pprz_algebra_float_c.FloatQuat stab_att_sp_quat
- pprz_algebra_float_c.FloatEulers stab_att_ref_euler
- pprz_algebra_float_c.FloatQuat stab_att_ref_quat
- pprz_algebra_float_c.FloatRates stab_att_ref_rate
- pprz_algebra_float_c.FloatRates stab_att_ref_accel
+ property setpoint:
+ def __get__(self):
+ return np.array([self.sp_quat.qi, self.sp_quat.qx, self.sp_quat.qy, self.sp_quat.qz])
+ def __set__(self, sp):
+ self.sp_quat.qi = sp[0]
+ self.sp_quat.qx = sp[1]
+ self.sp_quat.qy = sp[2]
+ self.sp_quat.qz = sp[3]
-
-sp_euler = FloatEulers( &stab_att_sp_euler)
-sp_quat = FloatQuat( &stab_att_sp_quat)
-ref_euler = FloatEulers( &stab_att_ref_euler)
-ref_quat = FloatQuat( &stab_att_ref_quat)
-ref_rate = FloatRates( &stab_att_ref_rate)
-ref_accel = FloatRates( &stab_att_ref_accel)
-
-
-def init():
- stabilization_attitude_ref_init()
-
-def enter():
- stabilization_attitude_ref_enter()
-
-def update():
- stabilization_attitude_ref_update()
-
-"""
-# test some different set methods
-def set_sp_euler(**kwds):
- global stab_att_sp_euler
- cdef pprz_algebra_float_c.FloatEulers c_sp = kwds
- stab_att_sp_euler = c_sp
-
-def set_sp_euler(phi=0.0, theta=0.0, psi=0.0):
- global sp_euler
- sp_euler.phi = phi
- sp_euler.theta = theta
- sp_euler.psi = psi
-
-def set_sp_quat(**kwds):
- global stab_att_sp_quat
- cdef pprz_algebra_float_c.FloatQuat c_sp = kwds
- stab_att_sp_quat = c_sp
-"""
+ property eulers:
+ def __get__(self):
+ return np.array([self.ref.euler.phi, self.ref.euler.theta, self.ref.euler.psi])
diff --git a/sw/airborne/test/stabilization/ref_quat_int.pxd b/sw/airborne/test/stabilization/ref_quat_int.pxd
new file mode 100644
index 0000000000..30aaa5a254
--- /dev/null
+++ b/sw/airborne/test/stabilization/ref_quat_int.pxd
@@ -0,0 +1,23 @@
+from libc.stdint cimport int32_t
+
+from pprz_algebra_int_c cimport Int32Quat, Int32Eulers, Int32Rates
+from pprz_algebra_float_c cimport FloatRates
+
+cdef extern from "stabilization/stabilization_attitude_ref_quat_int.h":
+ struct FloatRefModel:
+ FloatRates omega
+ FloatRates zeta
+
+ struct AttRefQuatInt:
+ Int32Eulers euler
+ Int32Quat quat
+ Int32Rates rate
+ Int32Rates accel
+ FloatRefModel model
+
+ void attitude_ref_quat_int_init(AttRefQuatInt *ref)
+ void attitude_ref_quat_int_enter(AttRefQuatInt *ref, int32_t psi)
+ void attitude_ref_quat_int_update(AttRefQuatInt *ref, Int32Quat *sp_quat, float dt)
+
+ void attitude_ref_quat_int_set_omega(AttRefQuatInt *ref, FloatRates *omega)
+ void attitude_ref_quat_int_set_zeta(AttRefQuatInt *ref, FloatRates *zeta)
diff --git a/sw/airborne/test/stabilization/ref_quat_int.pyx b/sw/airborne/test/stabilization/ref_quat_int.pyx
index 0e4d265495..e81344ffe9 100644
--- a/sw/airborne/test/stabilization/ref_quat_int.pyx
+++ b/sw/airborne/test/stabilization/ref_quat_int.pyx
@@ -1,37 +1,32 @@
-cdef extern from "stdint.h":
- ctypedef unsigned long int uintptr_t
+cimport ref_quat_int
+from pprz_algebra_int_c cimport Int32Quat
+import numpy as np
+cdef class RefQuatInt:
+ cdef ref_quat_int.AttRefQuatInt ref
+ cdef Int32Quat sp_quat
-cimport pprz_algebra_int_c
-from algebra_int import Int32Quat, Int32Eulers, Int32Rates
+ def __cinit__(self):
+ ref_quat_int.attitude_ref_quat_int_init(&self.ref)
+ self.setpoint = [1.0, 0, 0, 0]
+ cpdef update(self, dt, setpoint=None):
+ if setpoint is not None:
+ self.setpoint = setpoint
+ ref_quat_int.attitude_ref_quat_int_update(&self.ref, &self.sp_quat, dt)
+ #self.c_update(&self.sp_quat, dt)
-cdef extern from "stabilization/stabilization_attitude_ref_quat_int.h":
- void stabilization_attitude_ref_init()
- void stabilization_attitude_ref_update()
- void stabilization_attitude_ref_enter()
+ property setpoint:
+ def __get__(self):
+ quat = np.array([self.sp_quat.qi, self.sp_quat.qx, self.sp_quat.qy, self.sp_quat.qz], dtype='d')
+ return quat / (1 << 15)
+ def __set__(self, sp):
+ self.sp_quat.qi = sp[0] * (1 << 15)
+ self.sp_quat.qx = sp[1] * (1 << 15)
+ self.sp_quat.qy = sp[2] * (1 << 15)
+ self.sp_quat.qz = sp[3] * (1 << 15)
- pprz_algebra_int_c.Int32Eulers stab_att_sp_euler
- pprz_algebra_int_c.Int32Quat stab_att_sp_quat
- pprz_algebra_int_c.Int32Eulers stab_att_ref_euler
- pprz_algebra_int_c.Int32Quat stab_att_ref_quat
- pprz_algebra_int_c.Int32Rates stab_att_ref_rate
- pprz_algebra_int_c.Int32Rates stab_att_ref_accel
-
-
-sp_euler = Int32Eulers( &stab_att_sp_euler)
-sp_quat = Int32Quat( &stab_att_sp_quat)
-ref_euler = Int32Eulers( &stab_att_ref_euler)
-ref_quat = Int32Quat( &stab_att_ref_quat)
-ref_rate = Int32Rates( &stab_att_ref_rate)
-ref_accel = Int32Rates( &stab_att_ref_accel)
-
-
-def init():
- stabilization_attitude_ref_init()
-
-def enter():
- stabilization_attitude_ref_enter()
-
-def update():
- stabilization_attitude_ref_update()
+ property eulers:
+ def __get__(self):
+ euler = np.array([self.ref.euler.phi, self.ref.euler.theta, self.ref.euler.psi], dtype='d')
+ return euler / (1 << 20)
diff --git a/sw/misc/attitude_reference/Makefile b/sw/misc/attitude_reference/Makefile
new file mode 100644
index 0000000000..c6c52f502f
--- /dev/null
+++ b/sw/misc/attitude_reference/Makefile
@@ -0,0 +1,6 @@
+
+all:
+ make -C c_att_refs
+
+clean:
+ make -C c_att_refs clean
diff --git a/sw/misc/attitude_reference/README.md b/sw/misc/attitude_reference/README.md
new file mode 100644
index 0000000000..64ffb7c189
--- /dev/null
+++ b/sw/misc/attitude_reference/README.md
@@ -0,0 +1,5 @@
+Tools to test and compere attitude stabilization reference generation.
+
+In order to build the native C implementations, run `make` which will build them in the c_att_refs subdirectory.
+
+Then simply start ./att_ref_gui.py
diff --git a/sw/misc/attitude_reference/att_ref_gui.py b/sw/misc/attitude_reference/att_ref_gui.py
new file mode 100755
index 0000000000..4a1f4c2611
--- /dev/null
+++ b/sw/misc/attitude_reference/att_ref_gui.py
@@ -0,0 +1,311 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2014 Antoine Drouin
+#
+# This file is part of paparazzi.
+#
+# paparazzi is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# paparazzi is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with paparazzi; see the file COPYING. If not, write to
+# the Free Software Foundation, 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+"""
+This is a graphical user interface for playing with reference attitude
+"""
+# https://gist.github.com/zed/b966b5a04f2dfc16c98e
+# https://gist.github.com/nzjrs/51686
+# http://jakevdp.github.io/blog/2012/10/07/xkcd-style-plots-in-matplotlib/
+# http://chimera.labs.oreilly.com/books/1230000000393/ch12.html#_problem_208 <- threads
+
+# TODO:
+# -cancel workers
+#
+#
+#
+
+from __future__ import print_function
+
+from gi.repository import Gtk, GObject
+from matplotlib.figure import Figure
+from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCanvas
+import matplotlib.font_manager as fm
+
+import math, threading, numpy as np, scipy.signal, pdb, copy, logging
+
+import pat.utils as pu
+import pat.algebra as pa
+import control as ctl
+import gui
+
+
+class Reference(gui.Worker):
+
+ def __init__(self, sp, ref_impl=ctl.att_ref_default, omega=6., xi=0.8, max_vel=pu.rad_of_deg(100),
+ max_accel=pu.rad_of_deg(500)):
+ gui.Worker.__init__(self)
+ self.impl = ref_impl()
+ self.sp = sp
+ self.reset_outputs(sp)
+ self.update(sp, ref_impl, omega, xi, max_vel, max_accel)
+ self.do_work = True
+
+ def reset_outputs(self, sp):
+ self.euler = np.zeros((len(sp.time), pa.e_size))
+ self.quat = np.zeros((len(sp.time), pa.q_size))
+ self.vel = np.zeros((len(sp.time), pa.r_size))
+ self.accel = np.zeros((len(sp.time), pa.r_size))
+
+ def update_type(self, _type):
+ #print('update_type', _type)
+ self.impl = _type()
+ self.do_work = True
+ #self.recompute()
+
+ def update_param(self, p, v):
+ #print('update_param', p, v)
+ self.impl.set_param(p, v)
+ self.do_work = True
+ #self.recompute()
+
+ def update_sp(self, sp, ref_impl=None, omega=None, xi=None, max_vel=None, max_accel=None):
+ self.reset_outputs(sp)
+ self.update(sp, ref_impl, omega, xi, max_vel, max_accel)
+ self.do_work = True
+ #self.recompute()
+
+ def update(self, sp, ref_impl=None, omega=None, xi=None, max_vel=None, max_accel=None):
+ self.sp = sp
+ if ref_impl is not None:
+ self.impl = ref_impl()
+ if omega is not None:
+ self.impl.set_param('omega', omega)
+ if xi is not None:
+ self.impl.set_param('xi', xi)
+ if max_vel is not None:
+ self.impl.set_param('max_vel', max_vel)
+ if max_accel is not None:
+ self.impl.set_param('max_accel', max_accel)
+
+ def recompute(self):
+ #print("recomputing...")
+ self.start((self.sp,))
+
+ def _work_init(self, sp):
+ #print('_work_init ', self, self.impl, sp, sp.dt)
+ self.euler = np.zeros((len(sp.time), pa.e_size))
+ self.quat = np.zeros((len(sp.time), pa.q_size))
+ self.vel = np.zeros((len(sp.time), pa.r_size))
+ self.accel = np.zeros((len(sp.time), pa.r_size))
+ euler0 = [0.3, 0.1, 0.2]
+ self.impl.set_euler(np.array(euler0))
+ self.quat[0], self.euler[0], self.vel[0], self.accel[0] = self.impl.quat, self.impl.euler, self.impl.vel, self.impl.accel
+ self.n_iter_per_step = float(len(sp.time)) / self.n_step
+
+ def _work_step(self, i, sp):
+ start, stop = int(i * self.n_iter_per_step), int((i + 1) * self.n_iter_per_step)
+ # print('_work_step of %s: i %i, start %i, stop %i' % (self.impl, i, start, stop))
+ for j in range(start, stop):
+ self.impl.update_quat(sp.quat[j], sp.dt)
+ self.quat[j], self.vel[j], self.accel[j] = self.impl.quat, self.impl.vel, self.impl.accel
+ self.euler[j] = pa.euler_of_quat(self.quat[j])
+
+
+class Setpoint(object):
+ t_static, t_step_phi, t_step_theta, t_step_psi, t_step_random, t_nb = range(0, 6)
+ t_names = ["constant", "step phi", "step theta", "step psi", "step_random"]
+
+ def __init__(self, type=t_static, duration=10., step_duration=5., step_ampl=pu.rad_of_deg(10.)):
+ self.dt = 1. / 512
+ self.update(type, duration, step_duration, step_ampl)
+
+ def update(self, type, duration, step_duration, step_ampl):
+ self.type = type
+ self.duration, self.step_duration, self.step_ampl = duration, step_duration, step_ampl
+ self.time = np.arange(0., self.duration, self.dt)
+ self.euler = np.zeros((len(self.time), pa.e_size))
+ try:
+ i = [Setpoint.t_step_phi, Setpoint.t_step_theta, Setpoint.t_step_psi].index(self.type)
+ self.euler[:, i] = step_ampl / 2 * scipy.signal.square(math.pi / step_duration * self.time)
+ except Exception as e:
+ print(e)
+ pass
+
+ self.quat = np.zeros((len(self.time), pa.q_size))
+ for i in range(0, len(self.time)):
+ self.quat[i] = pa.quat_of_euler(self.euler[i])
+
+
+class GUI(object):
+ def __init__(self, sp, refs):
+ self.b = Gtk.Builder()
+ self.b.add_from_file("ressources/att_ref_gui.xml")
+ w = self.b.get_object("window")
+ w.connect("delete-event", Gtk.main_quit)
+ mb = self.b.get_object("main_vbox")
+ self.plot = Plot(sp, refs)
+ mb.pack_start(self.plot, True, True, 0)
+ mb = self.b.get_object("main_hbox")
+ ref_classes = [ctl.att_ref_default, ctl.att_ref_sat_naive, ctl.att_ref_sat_nested, ctl.att_ref_sat_nested2,
+ ctl.AttRefFloatNative, ctl.AttRefIntNative]
+ self.ref_views = [gui.AttRefParamView('Ref {}'.format(i+1), ref_classes=ref_classes,
+ active_impl=r.impl) for i, r in enumerate(refs)]
+ for r in self.ref_views:
+ mb.pack_start(r, True, True, 0)
+ w.show_all()
+
+
+class Plot(Gtk.Frame):
+ def __init__(self, sp, refs):
+ Gtk.Frame.__init__(self)
+ self.f = Figure()
+ self.canvas = FigureCanvas(self.f)
+ self.add(self.canvas)
+ self.set_size_request(1024, 600)
+ self.f.subplots_adjust(left=0.07, right=0.98, bottom=0.05, top=0.95,
+ hspace=0.2, wspace=0.2)
+ # self.buffer = self.canvas.get_snapshot()
+
+ def decorate(self, axis, title=None, ylab=None, legend=None):
+ # font_prop = fm.FontProperties(fname='Humor-Sans-1.0.ttf', size=14)
+ if title is not None:
+ axis.set_title(title) # , fontproperties=font_prop)
+ if ylab is not None:
+ axis.yaxis.set_label_text(ylab) # , fontproperties=font_prop)
+ if legend is not None:
+ axis.legend(legend) # , prop=font_prop)
+ axis.xaxis.grid(color='k', linestyle='-', linewidth=0.2)
+ axis.yaxis.grid(color='k', linestyle='-', linewidth=0.2)
+
+ def update(self, sp, refs):
+ title = [r'$\phi$', r'$\theta$', r'$\psi$']
+ legend = ['Ref1', 'Ref2', 'Setpoint']
+ for i in range(0, 3):
+ axis = self.f.add_subplot(331 + i)
+ axis.clear()
+ for ref in refs:
+ axis.plot(sp.time, pu.deg_of_rad(ref.euler[:, i]))
+ axis.plot(sp.time, pu.deg_of_rad(sp.euler[:, i]))
+ self.decorate(axis, title[i], *(('deg', legend) if i == 0 else (None, None)))
+
+ title = [r'$p$', r'$q$', r'$r$']
+ for i in range(0, 3):
+ axis = self.f.add_subplot(334 + i)
+ axis.clear()
+ for ref in refs:
+ axis.plot(sp.time, pu.deg_of_rad(ref.vel[:, i]))
+ self.decorate(axis, title[i], 'deg/s' if i == 0 else None)
+
+ title = [r'$\dot{p}$', r'$\dot{q}$', r'$\dot{r}$']
+ for i in range(0, 3):
+ axis = self.f.add_subplot(337 + i)
+ axis.clear()
+ for ref in refs:
+ axis.plot(sp.time, pu.deg_of_rad(ref.accel[:, i]))
+ self.decorate(axis, title[i], 'deg/s2' if i == 0 else None)
+
+ self.canvas.draw()
+
+
+class Application(object):
+ def __init__(self):
+ self.sp = Setpoint()
+ self.refs = [Reference(self.sp), Reference(self.sp, ref_impl=ctl.AttRefFloatNative)]
+ for nref, r in enumerate(self.refs):
+ r.connect("progress", self.on_ref_update_progress, nref + 1)
+ r.connect("completed", self.on_ref_update_completed, nref + 1)
+ self.gui = GUI(self.sp, self.refs)
+ self.register_gui()
+ self.recompute_sequentially()
+
+ def on_ref_update_progress(self, ref, v, nref):
+ #print('progress', nref, v)
+ self.gui.ref_views[nref - 1].progress.set_fraction(v)
+
+ def on_ref_update_completed(self, ref, nref):
+ #print('on_ref_update_completed', ref, nref)
+ self.gui.ref_views[nref - 1].progress.set_fraction(1.0)
+ # recompute remaining refs (if any)
+ self.recompute_sequentially()
+ self.gui.plot.update(self.sp, self.refs)
+
+ def register_gui(self):
+ self.register_setpoint()
+ for i in range(0, 2):
+ self.gui.ref_views[i].connect(self._on_ref_changed, self._on_ref_param_changed, self.refs[i], self.gui.ref_views[i])
+ self.gui.ref_views[i].update_view(self.refs[i].impl)
+
+ def register_setpoint(self):
+ b = self.gui.b
+ c_sp_type = b.get_object("combo_sp_type")
+ for n in Setpoint.t_names:
+ c_sp_type.append_text(n)
+ c_sp_type.set_active(self.sp.type)
+ c_sp_type.connect("changed", self.on_sp_changed)
+
+ names = ["spin_sp_duration", "spin_sp_step_duration", "spin_sp_step_amplitude"]
+ widgets = [b.get_object(name) for name in names]
+ adjs = [Gtk.Adjustment(self.sp.duration, 1, 100, 1, 10, 0),
+ Gtk.Adjustment(self.sp.step_duration, 0.1, 10., 0.1, 1., 0),
+ Gtk.Adjustment(pu.deg_of_rad(self.sp.step_ampl), 0.1, 180., 1, 10., 0)]
+ for i, w in enumerate(widgets):
+ w.set_adjustment(adjs[i])
+ w.update()
+ w.connect("value-changed", self.on_sp_changed)
+
+ def recompute_sequentially(self):
+ """
+ Somehow running two threads to update both references at the same time produces bogus data..
+ As a workaround we simply run them one after the other.
+ """
+ for r in self.refs:
+ if r.running:
+ return
+ for r in self.refs:
+ if r.do_work:
+ r.recompute()
+ return
+
+ def on_sp_changed(self, widget):
+ b = self.gui.b
+ _type = b.get_object("combo_sp_type").get_active()
+ names = ["spin_sp_duration", "spin_sp_step_duration", "spin_sp_step_amplitude"]
+ _duration, _step_duration, _step_amplitude = [b.get_object(name).get_value() for name in names]
+ #print('_on_sp_changed', _type, _duration, _step_duration, _step_amplitude)
+ _step_amplitude = pu.rad_of_deg(_step_amplitude)
+ self.sp.update(_type, _duration, _step_duration, _step_amplitude)
+ # somehow running two threads to update both references at the same time produces bogus data..
+ # as a workaround we simply run them one after the other
+ for r in self.refs:
+ r.update_sp(self.sp)
+ #r.recompute()
+ self.recompute_sequentially()
+
+ def _on_ref_changed(self, widget, ref, view):
+ #print('_on_ref_changed', widget, ref, view)
+ ref.update_type(view.get_selected_ref_class())
+ view.update_ref_params(ref.impl)
+ self.recompute_sequentially()
+
+ def _on_ref_param_changed(self, widget, p, ref, view):
+ #print("_on_ref_param_changed: %s %s=%s" % (ref.impl.name, p, val))
+ val = view.spin_cfg[p]['d2r'](widget.get_value())
+ ref.update_param(p, val)
+ self.recompute_sequentially()
+
+ def run(self):
+ Gtk.main()
+
+
+if __name__ == "__main__":
+ logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
+ Application().run()
diff --git a/sw/misc/attitude_reference/c_att_refs/.gitignore b/sw/misc/attitude_reference/c_att_refs/.gitignore
new file mode 100644
index 0000000000..c77768018e
--- /dev/null
+++ b/sw/misc/attitude_reference/c_att_refs/.gitignore
@@ -0,0 +1,4 @@
+*.so
+ref_quat_float.c
+ref_quat_int.c
+build
diff --git a/sw/misc/attitude_reference/c_att_refs/Makefile b/sw/misc/attitude_reference/c_att_refs/Makefile
new file mode 100644
index 0000000000..f05ebefd77
--- /dev/null
+++ b/sw/misc/attitude_reference/c_att_refs/Makefile
@@ -0,0 +1,6 @@
+
+all:
+ python setup.py build_ext --inplace
+
+clean:
+ rm -rf build *.so *.c
diff --git a/sw/misc/attitude_reference/c_att_refs/README.md b/sw/misc/attitude_reference/c_att_refs/README.md
new file mode 100644
index 0000000000..c9551f814c
--- /dev/null
+++ b/sw/misc/attitude_reference/c_att_refs/README.md
@@ -0,0 +1,7 @@
+Some Cython wrappers for stabilization reference generation testing.
+
+Tested with Cython 0.19 - 0.21
+
+To build execute in this directory:
+
+ python setup.py build_ext --inplace
diff --git a/sw/misc/attitude_reference/c_att_refs/__init__.py b/sw/misc/attitude_reference/c_att_refs/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/sw/misc/attitude_reference/c_att_refs/generated/airframe.h b/sw/misc/attitude_reference/c_att_refs/generated/airframe.h
new file mode 100644
index 0000000000..89e9d1b06b
--- /dev/null
+++ b/sw/misc/attitude_reference/c_att_refs/generated/airframe.h
@@ -0,0 +1,41 @@
+/* fake generated airframe file */
+
+#ifndef AIRFRAME_H
+#define AIRFRAME_H
+
+#define PERIODIC_FREQUENCY 512
+
+#if defined STABILIZATION_ATTITUDE_TYPE_FLOAT
+
+#define STABILIZATION_ATTITUDE_REF_OMEGA_P {RadOfDeg(400)}
+#define STABILIZATION_ATTITUDE_REF_ZETA_P {0.85}
+#define STABILIZATION_ATTITUDE_REF_MAX_P 6.981317
+#define STABILIZATION_ATTITUDE_REF_MAX_PDOT RadOfDeg(4000.)
+#define STABILIZATION_ATTITUDE_REF_OMEGA_Q {RadOfDeg(400)}
+#define STABILIZATION_ATTITUDE_REF_ZETA_Q {0.85}
+#define STABILIZATION_ATTITUDE_REF_MAX_Q 6.981317
+#define STABILIZATION_ATTITUDE_REF_MAX_QDOT RadOfDeg(4000.)
+#define STABILIZATION_ATTITUDE_REF_OMEGA_R {RadOfDeg(250)}
+#define STABILIZATION_ATTITUDE_REF_ZETA_R {0.85}
+#define STABILIZATION_ATTITUDE_REF_MAX_R 3.14159265
+#define STABILIZATION_ATTITUDE_REF_MAX_RDOT RadOfDeg(1800.)
+
+#elif defined STABILIZATION_ATTITUDE_TYPE_INT
+
+#define STABILIZATION_ATTITUDE_REF_OMEGA_P 6.981317
+#define STABILIZATION_ATTITUDE_REF_ZETA_P 0.85
+#define STABILIZATION_ATTITUDE_REF_MAX_P 6.981317
+#define STABILIZATION_ATTITUDE_REF_MAX_PDOT RadOfDeg(4000.)
+#define STABILIZATION_ATTITUDE_REF_OMEGA_Q 6.981317
+#define STABILIZATION_ATTITUDE_REF_ZETA_Q 0.85
+#define STABILIZATION_ATTITUDE_REF_MAX_Q 6.981317
+#define STABILIZATION_ATTITUDE_REF_MAX_QDOT RadOfDeg(4000.)
+#define STABILIZATION_ATTITUDE_REF_OMEGA_R 4.363323125
+#define STABILIZATION_ATTITUDE_REF_ZETA_R 0.85
+#define STABILIZATION_ATTITUDE_REF_MAX_R 3.14159265
+#define STABILIZATION_ATTITUDE_REF_MAX_RDOT RadOfDeg(1800.)
+
+#endif
+
+
+#endif // AIRFRAME_H
diff --git a/sw/misc/attitude_reference/c_att_refs/pprz_algebra_double_c.pxd b/sw/misc/attitude_reference/c_att_refs/pprz_algebra_double_c.pxd
new file mode 100644
index 0000000000..e2204d25b8
--- /dev/null
+++ b/sw/misc/attitude_reference/c_att_refs/pprz_algebra_double_c.pxd
@@ -0,0 +1,29 @@
+cdef extern from "math/pprz_algebra_double.h":
+
+ struct DoubleVect2
+ double x
+ double y
+
+ struct DoubleVect3
+ double x
+ double y
+ double z
+
+ struct DoubleEulers:
+ double phi
+ double theta
+ double psi
+
+ struct DoubleQuat:
+ double qi
+ double qx
+ double qy
+ double qz
+
+ struct DoubleRates:
+ double p
+ double q
+ double r
+
+ struct DoubleRMat:
+ double m[3*3]
diff --git a/sw/misc/attitude_reference/c_att_refs/pprz_algebra_float_c.pxd b/sw/misc/attitude_reference/c_att_refs/pprz_algebra_float_c.pxd
new file mode 100644
index 0000000000..287fe8ac39
--- /dev/null
+++ b/sw/misc/attitude_reference/c_att_refs/pprz_algebra_float_c.pxd
@@ -0,0 +1,32 @@
+cdef extern from "math/pprz_algebra_float.h":
+
+ struct FloatVect2:
+ float x
+ float y
+
+ struct FloatVect3:
+ float x
+ float y
+ float z
+
+ struct FloatEulers:
+ float phi
+ float theta
+ float psi
+
+ struct FloatQuat:
+ float qi
+ float qx
+ float qy
+ float qz
+
+ struct FloatRates:
+ float p
+ float q
+ float r
+
+ struct FloatRMat:
+ float m[3*3]
+
+ void float_eulers_of_quat(FloatEulers *e, FloatQuat *q)
+ void float_quat_of_eulers(FloatQuat *q, FloatEulers *e)
diff --git a/sw/misc/attitude_reference/c_att_refs/pprz_algebra_int_c.pxd b/sw/misc/attitude_reference/c_att_refs/pprz_algebra_int_c.pxd
new file mode 100644
index 0000000000..e4ca2f2d1e
--- /dev/null
+++ b/sw/misc/attitude_reference/c_att_refs/pprz_algebra_int_c.pxd
@@ -0,0 +1,37 @@
+from libc.stdint cimport uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t
+
+cdef extern from "math/pprz_algebra_int.h":
+
+ struct Int32Vect2:
+ int32_t x
+ int32_t y
+
+ struct Int32Vect3:
+ int32_t x
+ int32_t y
+ int32_t z
+
+ struct Int32Eulers:
+ int32_t phi
+ int32_t theta
+ int32_t psi
+
+ struct Int32Quat:
+ int32_t qi
+ int32_t qx
+ int32_t qy
+ int32_t qz
+
+ struct Int32Rates:
+ int32_t p
+ int32_t q
+ int32_t r
+
+ struct Int32RMat:
+ int32_t m[3*3]
+
+ void int32_quat_of_eulers(Int32Quat *q, Int32Eulers *e)
+ void int32_eulers_of_quat(Int32Eulers *e, Int32Quat *q)
+
+cdef extern from "math/pprz_trig_int.h":
+ int16_t pprz_trig_int[]
diff --git a/sw/misc/attitude_reference/c_att_refs/ref_quat_float.pxd b/sw/misc/attitude_reference/c_att_refs/ref_quat_float.pxd
new file mode 100644
index 0000000000..33607ecb40
--- /dev/null
+++ b/sw/misc/attitude_reference/c_att_refs/ref_quat_float.pxd
@@ -0,0 +1,21 @@
+from pprz_algebra_float_c cimport FloatQuat, FloatEulers, FloatRates
+
+cdef extern from "stabilization/stabilization_attitude_ref_quat_float.h":
+ struct FloatRefModel:
+ FloatRates omega
+ FloatRates zeta
+
+ struct AttRefQuatFloat:
+ FloatEulers euler
+ FloatQuat quat
+ FloatRates rate
+ FloatRates accel
+ FloatRefModel model[1]
+
+ void attitude_ref_quat_float_init(AttRefQuatFloat *ref)
+ void attitude_ref_quat_float_enter(AttRefQuatFloat *ref, float psi)
+ void attitude_ref_quat_float_update(AttRefQuatFloat *ref, FloatQuat *sp_quat, float dt)
+
+ void attitude_ref_quat_float_set_omega_p(AttRefQuatFloat *ref, float omega)
+ void attitude_ref_quat_float_set_omega_q(AttRefQuatFloat *ref, float omega)
+ void attitude_ref_quat_float_set_omega_r(AttRefQuatFloat *ref, float omega)
diff --git a/sw/misc/attitude_reference/c_att_refs/ref_quat_float.pyx b/sw/misc/attitude_reference/c_att_refs/ref_quat_float.pyx
new file mode 100644
index 0000000000..aea8988ae0
--- /dev/null
+++ b/sw/misc/attitude_reference/c_att_refs/ref_quat_float.pyx
@@ -0,0 +1,80 @@
+cimport ref_quat_float
+from pprz_algebra_float_c cimport FloatQuat, float_eulers_of_quat, float_quat_of_eulers
+import numpy as np
+
+cdef class RefQuatFloat:
+ cdef ref_quat_float.AttRefQuatFloat ref
+ cdef FloatQuat sp_quat
+
+ def __cinit__(self):
+ ref_quat_float.attitude_ref_quat_float_init(&self.ref)
+ self.setpoint = [1.0, 0, 0, 0]
+
+ cpdef update(self, dt, setpoint=None):
+ if setpoint is not None:
+ self.setpoint = setpoint
+ ref_quat_float.attitude_ref_quat_float_update(&self.ref, &self.sp_quat, dt)
+
+ cdef set_omega(self, omega):
+ ref_quat_float.attitude_ref_quat_float_set_omega_p(&self.ref, omega[0])
+ ref_quat_float.attitude_ref_quat_float_set_omega_q(&self.ref, omega[1])
+ ref_quat_float.attitude_ref_quat_float_set_omega_r(&self.ref, omega[2])
+
+ cdef set_zeta(self, zeta):
+ self.ref.model[0].zeta.p = zeta[0]
+ self.ref.model[0].zeta.q = zeta[1]
+ self.ref.model[0].zeta.r = zeta[2]
+
+ property setpoint:
+ def __get__(self):
+ return np.array([self.sp_quat.qi, self.sp_quat.qx, self.sp_quat.qy, self.sp_quat.qz])
+ def __set__(self, sp):
+ self.sp_quat.qi = sp[0]
+ self.sp_quat.qx = sp[1]
+ self.sp_quat.qy = sp[2]
+ self.sp_quat.qz = sp[3]
+
+ property euler:
+ def __get__(self):
+ return np.array([self.ref.euler.phi, self.ref.euler.theta, self.ref.euler.psi])
+ def __set__(self, euler):
+ self.ref.euler.phi = euler[0]
+ self.ref.euler.theta = euler[1]
+ self.ref.euler.psi = euler[2]
+ float_quat_of_eulers(&self.ref.quat, &self.ref.euler)
+
+ property quat:
+ def __get__(self):
+ return np.array([self.ref.quat.qi, self.ref.quat.qx, self.ref.quat.qy, self.ref.quat.qz], dtype='d')
+ def __set__(self, quat):
+ self.ref.quat.qi = quat[0]
+ self.ref.quat.qx = quat[1]
+ self.ref.quat.qy = quat[2]
+ self.ref.quat.qz = quat[3]
+ float_eulers_of_quat(&self.ref.euler, &self.ref.quat)
+
+ property rate:
+ def __get__(self):
+ return np.array([self.ref.rate.p, self.ref.rate.q, self.ref.rate.r])
+
+ property accel:
+ def __get__(self):
+ return np.array([self.ref.accel.p, self.ref.accel.q, self.ref.accel.r])
+
+ property zeta:
+ def __get__(self):
+ return np.array([self.ref.model[0].zeta.p, self.ref.model[0].zeta.q, self.ref.model[0].zeta.r])
+ def __set__(self, zeta):
+ if type(zeta) == float:
+ self.set_zeta(zeta * np.ones(3))
+ else:
+ self.set_zeta(zeta)
+
+ property omega:
+ def __get__(self):
+ return np.array([self.ref.model[0].omega.p, self.ref.model[0].omega.q, self.ref.model[0].omega.r])
+ def __set__(self, omega):
+ if type(omega) == float:
+ self.set_omega(omega * np.ones(3))
+ else:
+ self.set_omega(omega)
diff --git a/sw/misc/attitude_reference/c_att_refs/ref_quat_int.pxd b/sw/misc/attitude_reference/c_att_refs/ref_quat_int.pxd
new file mode 100644
index 0000000000..30aaa5a254
--- /dev/null
+++ b/sw/misc/attitude_reference/c_att_refs/ref_quat_int.pxd
@@ -0,0 +1,23 @@
+from libc.stdint cimport int32_t
+
+from pprz_algebra_int_c cimport Int32Quat, Int32Eulers, Int32Rates
+from pprz_algebra_float_c cimport FloatRates
+
+cdef extern from "stabilization/stabilization_attitude_ref_quat_int.h":
+ struct FloatRefModel:
+ FloatRates omega
+ FloatRates zeta
+
+ struct AttRefQuatInt:
+ Int32Eulers euler
+ Int32Quat quat
+ Int32Rates rate
+ Int32Rates accel
+ FloatRefModel model
+
+ void attitude_ref_quat_int_init(AttRefQuatInt *ref)
+ void attitude_ref_quat_int_enter(AttRefQuatInt *ref, int32_t psi)
+ void attitude_ref_quat_int_update(AttRefQuatInt *ref, Int32Quat *sp_quat, float dt)
+
+ void attitude_ref_quat_int_set_omega(AttRefQuatInt *ref, FloatRates *omega)
+ void attitude_ref_quat_int_set_zeta(AttRefQuatInt *ref, FloatRates *zeta)
diff --git a/sw/misc/attitude_reference/c_att_refs/ref_quat_int.pyx b/sw/misc/attitude_reference/c_att_refs/ref_quat_int.pyx
new file mode 100644
index 0000000000..100e80bf7e
--- /dev/null
+++ b/sw/misc/attitude_reference/c_att_refs/ref_quat_int.pyx
@@ -0,0 +1,99 @@
+cimport ref_quat_int
+from pprz_algebra_int_c cimport Int32Quat, Int32Eulers, int32_quat_of_eulers, int32_eulers_of_quat
+import numpy as np
+
+REF_ACCEL_FRAC = 12
+REF_RATE_FRAC = 16
+INT32_ANGLE_FRAC = 12
+INT32_QUAT_FRAC = 15
+
+cdef class RefQuatInt:
+ cdef ref_quat_int.AttRefQuatInt ref
+ cdef Int32Quat sp_quat
+
+ def __cinit__(self):
+ ref_quat_int.attitude_ref_quat_int_init(&self.ref)
+ self.setpoint = [1.0, 0, 0, 0]
+
+ cpdef Int32Quat quat_bfp_of_real(self, quat):
+ cdef Int32Quat quat_i
+ quat_i.qi = quat[0] * (1 << INT32_QUAT_FRAC)
+ quat_i.qx = quat[1] * (1 << INT32_QUAT_FRAC)
+ quat_i.qy = quat[2] * (1 << INT32_QUAT_FRAC)
+ quat_i.qz = quat[3] * (1 << INT32_QUAT_FRAC)
+ return quat_i
+
+ cpdef Int32Eulers euler_bfp_of_real(self, euler):
+ cdef Int32Eulers euler_i
+ euler_i.phi = euler[0] * (1 << INT32_ANGLE_FRAC)
+ euler_i.theta = euler[1] * (1 << INT32_ANGLE_FRAC)
+ euler_i.psi = euler[2] * (1 << INT32_ANGLE_FRAC)
+ return euler_i
+
+ cpdef update(self, dt, setpoint=None):
+ if setpoint is not None:
+ self.setpoint = setpoint
+ ref_quat_int.attitude_ref_quat_int_update(&self.ref, &self.sp_quat, dt)
+
+ cdef set_omega(self, omega):
+ cdef FloatRates c_omega
+ c_omega.p = omega[0]
+ c_omega.q = omega[1]
+ c_omega.r = omega[2]
+ ref_quat_int.attitude_ref_quat_int_set_omega(&self.ref, &c_omega)
+
+ cdef set_zeta(self, zeta):
+ cdef FloatRates c_zeta
+ c_zeta.p = zeta[0]
+ c_zeta.q = zeta[1]
+ c_zeta.r = zeta[2]
+ ref_quat_int.attitude_ref_quat_int_set_zeta(&self.ref, &c_zeta)
+
+ property setpoint:
+ def __get__(self):
+ quat = np.array([self.sp_quat.qi, self.sp_quat.qx, self.sp_quat.qy, self.sp_quat.qz], dtype='d')
+ return quat / (1 << INT32_QUAT_FRAC)
+ def __set__(self, sp):
+ self.sp_quat = self.quat_bfp_of_real(sp)
+
+ property euler:
+ def __get__(self):
+ euler = np.array([self.ref.euler.phi, self.ref.euler.theta, self.ref.euler.psi], dtype='d')
+ return euler / (1 << INT32_ANGLE_FRAC)
+ def __set__(self, euler):
+ self.ref.euler = self.euler_bfp_of_real(euler)
+ int32_quat_of_eulers(&self.ref.quat, &self.ref.euler)
+
+ property quat:
+ def __get__(self):
+ quat = np.array([self.ref.quat.qi, self.ref.quat.qx, self.ref.quat.qy, self.ref.quat.qz], dtype='d')
+ return quat / (1 << INT32_QUAT_FRAC)
+ def __set__(self, quat):
+ self.ref.quat = self.quat_bfp_of_real(quat)
+ int32_eulers_of_quat(&self.ref.euler, &self.ref.quat)
+
+ property rate:
+ def __get__(self):
+ return np.array([self.ref.rate.p, self.ref.rate.q, self.ref.rate.r], dtype='d') / (1 << REF_RATE_FRAC)
+
+ property accel:
+ def __get__(self):
+ return np.array([self.ref.accel.p, self.ref.accel.q, self.ref.accel.r], dtype='d') / (1 << REF_ACCEL_FRAC)
+
+ property zeta:
+ def __get__(self):
+ return np.array([self.ref.model.zeta.p, self.ref.model.zeta.q, self.ref.model.zeta.r])
+ def __set__(self, zeta):
+ if type(zeta) == float:
+ self.set_zeta(zeta * np.ones(3))
+ else:
+ self.set_zeta(zeta)
+
+ property omega:
+ def __get__(self):
+ return np.array([self.ref.model.omega.p, self.ref.model.omega.q, self.ref.model.omega.r])
+ def __set__(self, omega):
+ if type(omega) == float:
+ self.set_omega(omega * np.ones(3))
+ else:
+ self.set_omega(omega)
diff --git a/sw/misc/attitude_reference/c_att_refs/setup.py b/sw/misc/attitude_reference/c_att_refs/setup.py
new file mode 100644
index 0000000000..d49a34c2a5
--- /dev/null
+++ b/sw/misc/attitude_reference/c_att_refs/setup.py
@@ -0,0 +1,33 @@
+from distutils.core import setup, Extension
+from Cython.Build import cythonize
+from distutils.extension import Extension
+import numpy
+
+from os import path, getenv
+
+# if PAPARAZZI_SRC not set, then assume the tree containing this
+# file is a reasonable substitute
+pprz_src = getenv("PAPARAZZI_SRC", path.normpath(path.join(path.dirname(path.abspath(__file__)), '../../../../')))
+pprz_airborne = path.join(pprz_src, "sw/airborne")
+
+common_inc_dirs = ["./", path.join(pprz_src, "sw/include"), pprz_airborne, numpy.get_include()]
+
+includedirs = common_inc_dirs + [path.join(pprz_airborne, "firmwares/rotorcraft")]
+ext_quat_float = Extension("ref_quat_float",
+ sources=['ref_quat_float.pyx', path.join(pprz_airborne, 'math/pprz_algebra_float.c'),
+ path.join(pprz_airborne, "firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_float.c")],
+ include_dirs=includedirs,
+ extra_compile_args=["-std=c99", "-DSTABILIZATION_ATTITUDE_TYPE_FLOAT"])
+ext_quat_int = Extension("ref_quat_int",
+ sources=['ref_quat_int.pyx',
+ path.join(pprz_airborne, 'math/pprz_trig_int.c'),
+ path.join(pprz_airborne, 'math/pprz_algebra_int.c'),
+ path.join(pprz_airborne, "firmwares/rotorcraft/stabilization/stabilization_attitude_ref_quat_int.c")],
+ include_dirs=includedirs,
+ extra_compile_args=["-std=c99", "-DSTABILIZATION_ATTITUDE_TYPE_INT"])
+
+extensions = [ext_quat_float, ext_quat_int]
+
+setup(
+ ext_modules=cythonize(extensions)
+)
diff --git a/sw/misc/attitude_reference/control.py b/sw/misc/attitude_reference/control.py
new file mode 100644
index 0000000000..1acab6e5a5
--- /dev/null
+++ b/sw/misc/attitude_reference/control.py
@@ -0,0 +1,324 @@
+#
+# Copyright (C) 2014 Antoine Drouin
+#
+# This file is part of paparazzi.
+#
+# paparazzi is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# paparazzi is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with paparazzi; see the file COPYING. If not, write to
+# the Free Software Foundation, 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+"""
+This is a reference implementation of the control system to serve as specifications
+ for the C version
+"""
+
+import math, logging, pdb
+import numpy as np
+from scipy import integrate
+
+import pat.utils as pu
+import pat.algebra as pa
+import pat.control as pc
+
+from c_att_refs.ref_quat_float import RefQuatFloat
+from c_att_refs.ref_quat_int import RefQuatInt
+
+LOG = logging.getLogger('control')
+# LOG.setLevel(logging.ERROR)
+LOG.setLevel(logging.DEBUG)
+
+
+class AttitudeReference(object):
+ """Sort of abstract base class"""
+ def __init__(self, **kwargs):
+ self.omega = kwargs.get('omega', 6.)
+ self.xi = kwargs.get('xi', 0.8)
+ self.t = kwargs.get('t0', 0.)
+ for p in ['omega', 'xi']:
+ self.ensure_vect(p)
+
+ def ensure_vect(self, p):
+ if type(getattr(self, p)) == float:
+ setattr(self, p, getattr(self, p) * np.ones(3))
+
+ def set_param(self, p, v):
+ if hasattr(self, p):
+ #print("%s: setting param %s to %s" % (self.name, p, v))
+ if type(v) == float:
+ v = v * np.ones(3)
+ setattr(self, p, v)
+
+ def run(self, t, sp_euler=None, sp_quat=None):
+ dt = t - self.t
+ self.t = t
+ if sp_euler is not None:
+ self.update_euler(sp_euler, dt)
+ elif sp_quat is not None:
+ self.update_quat(sp_quat, dt)
+
+ def update_quat(self, setpoint, dt):
+ raise NotImplementedError("Should have implemented this")
+
+ def set_euler(self, euler):
+ raise NotImplementedError("Should have implemented this")
+
+
+class att_ref_default(AttitudeReference):
+ """Default second order attitude reference model, Python implementation"""
+ name = 'Python default'
+
+ def __init__(self, **kwargs):
+ super(att_ref_default, self).__init__(**kwargs)
+ self.euler, self.quat = np.zeros(3), pa.quat_zero()
+ self.vel, self.accel = np.zeros(3), np.zeros(3)
+
+ def set_quat(self, quat, vel=np.zeros(3), accel=np.zeros(3)):
+ self.quat = quat
+ self.vel = vel
+ self.accel = accel
+ self.euler = pa.euler_of_quat(self.quat)
+
+ def set_euler(self, euler, vel=np.zeros(3), accel=np.zeros(3)):
+ self.euler = euler
+ self.vel = vel
+ self.accel = accel
+ self.quat = pa.quat_of_euler(self.euler)
+
+ def update_quat(self, setpoint, dt):
+ self.quat = pa.quat_integrate(self.quat, self.vel, dt)
+ self.vel += dt * self.accel
+ err_quat = pa.quat_wrap_shortest(pa.quat_inv_comp(setpoint, self.quat))
+ self.accel = -2. * self.xi * self.omega * self.vel \
+ - 2. * self.omega * self.omega * err_quat[1:]
+ return self.quat, self.vel, self.accel
+
+ def update_euler(self, setpoint, dt):
+ self.update_quat(pa.quat_of_euler(setpoint), dt)
+ self.euler = pa.euler_of_quat(self.quat)
+
+
+class att_ref_sat_naive(att_ref_default):
+ """Attitude reference model with naive saturation"""
+ name = 'Python Sat Naive'
+
+ def __init__(self, **kwargs):
+ super(att_ref_sat_naive, self).__init__(**kwargs)
+ self.sat_vel = kwargs.get('sat_vel', pu.rad_of_deg(100))
+ self.sat_accel = kwargs.get('sat_accel', pu.rad_of_deg(500))
+ for p in ['sat_vel', 'sat_accel']:
+ self.ensure_vect(p)
+
+ def update_quat(self, setpoint, dt):
+ super(att_ref_sat_naive, self).update_quat(setpoint, dt)
+ self.accel = np.clip(self.accel, -self.sat_accel, self.sat_accel)
+ for i in range(0, 3):
+ if self.vel[i] >= self.sat_vel[i]:
+ self.vel[i] = self.sat_vel[i]
+ if self.accel[i] > 0:
+ self.accel[i] = 0
+ elif self.vel[i] <= -self.sat_vel[i]:
+ self.vel[i] = -self.sat_vel[i]
+ if self.accel[i] < 0:
+ self.accel[i] = 0
+ return self.quat, self.vel, self.accel
+
+
+class att_ref_sat_nested(att_ref_sat_naive):
+ """Nested saturation"""
+ name = 'Python Sat Nested'
+
+ def __init__(self, **kwargs):
+ super(att_ref_sat_nested, self).__init__(**kwargs)
+ self._compute_auxiliary()
+
+ def update_quat(self, sp, dt):
+ err_quat = 2. * np.array(pa.quat_wrap_shortest(pa.quat_inv_comp(sp, self.quat)))
+ self.e = [err_quat[1:], self.vel, self.accel]
+ self.quat = pa.quat_integrate(self.quat, self.vel, dt)
+ self.vel += dt * self.accel
+ self.accel = np.zeros(3)
+ self.accel = self.M[0] * np.clip(self.K[0] / self.CM[0] * self.e[0] + self.accel, -1., 1.)
+ self.accel = self.M[1] * np.clip(self.K[1] / self.CM[1] * self.e[1] + self.accel, -1., 1.)
+ # pdb.set_trace()
+ return self.quat, self.vel, self.accel
+
+ def set_param(self, p, v):
+ super(att_ref_sat_nested, self).set_param(p, v)
+ self._compute_auxiliary()
+
+ def _compute_auxiliary(self):
+ # self.K = pc.butterworth(2, self.omega[0])
+ omega, xi = self.omega[0], self.xi[0]
+ omega_d = omega * math.sqrt(1 - xi ** 2)
+ coefs = -np.poly([complex(-omega * xi, omega_d), complex(-omega * xi, -omega_d)])[::-1]
+ self.K = np.real(coefs[:-1])
+ LOG.debug('sat_nested.__init__ omega: {} K:{} poles:{} '.format(self.omega[0], self.K, pc.poles(self.K)))
+ self.sats = np.array([self.sat_vel, self.sat_accel])
+ LOG.debug(' sats:\n{}'.format(self.sats))
+ self.M = np.array(self.sats)
+ self.M[0] *= self.K[1]
+ self.M[0] /= np.prod(self.M[1:], axis=0)
+ LOG.debug(' M:\n{}'.format(self.M))
+ self.CM = np.cumprod(self.M[::-1], axis=0)[::-1]
+ LOG.debug(' CM:\n{}\n'.format(self.CM))
+
+
+def my_K(omega, xi=0.8):
+ omega_d = omega * math.sqrt(1 - xi ** 2)
+ p1 = complex(-omega * xi, omega_d)
+ p2 = complex(-omega * xi, -omega_d)
+ p3 = -1.5 * omega
+ poles = [p1, p2, p3]
+ coefs = -np.poly(poles)[::-1]
+ return np.real(coefs[:-1])
+
+
+class att_ref_sat_nested2(att_ref_sat_naive):
+ """Nested saturation"""
+ name = 'Python Sat Nested2'
+
+ def __init__(self, **kwargs):
+ super(att_ref_sat_nested2, self).__init__(**kwargs)
+ self.sat_jerk = kwargs.get('sat_jerk', pu.rad_of_deg(3000))
+ self.ensure_vect('sat_jerk')
+ self.jerk = np.zeros(3)
+ self._compute_auxiliary()
+
+ def update_quat(self, sp, dt):
+ err_quat = 2. * np.array(pa.quat_wrap_shortest(pa.quat_inv_comp(sp, self.quat)))
+ self.e = [err_quat[1:], self.vel, self.accel]
+
+ self.quat = pa.quat_integrate(self.quat, self.vel, dt)
+ self.vel += dt * self.accel
+ self.accel += dt * self.jerk
+ self.jerk = np.zeros(3)
+ self.jerk = self.M[0] * np.clip(self.K[0] / self.CM[0] * self.e[0] + self.jerk, -1., 1.)
+ self.jerk = self.M[1] * np.clip(self.K[1] / self.CM[1] * self.e[1] + self.jerk, -1., 1.)
+ self.jerk = self.M[2] * np.clip(self.K[2] / self.CM[2] * self.e[2] + self.jerk, -1., 1.)
+ # pdb.set_trace()
+ return self.quat, self.vel, self.accel
+
+ def set_param(self, p, v):
+ super(att_ref_sat_nested2, self).set_param(p, v)
+ self._compute_auxiliary()
+
+ def _compute_auxiliary(self):
+ # self.K = pc.butterworth(3, self.omega[0])
+ self.K = my_K(self.omega[0], self.xi[0])
+ LOG.debug('sat_nested.__init__ omega: {} K:{} poles:{} '.format(self.omega[0], self.K, pc.poles(self.K)))
+ self.sats = np.array([self.sat_vel, self.sat_accel, self.sat_jerk])
+ LOG.debug(' sats:\n{}'.format(self.sats))
+ self.M = np.array(self.sats)
+ # pdb.set_trace()
+ for i in range(0, 3):
+ self.M[0:-1, i] *= self.K[1:]
+ for j in range(0, 2):
+ self.M[1 - j, i] /= np.prod(self.M[2 - j:, i])
+ LOG.debug(' M:\n{}'.format(self.M))
+ self.CM = np.cumprod(self.M[::-1], axis=0)[::-1]
+ LOG.debug(' CM:\n{}\n'.format(self.CM))
+
+
+class AttRefNative(AttitudeReference):
+ """ Base class for native C implementations """
+ def __init__(self, **kwargs):
+ super(AttRefNative, self).__init__(**kwargs)
+
+ def update_quat(self, setpoint, dt):
+ self.setpoint = setpoint
+ self.update(dt)
+
+ def set_euler(self, euler):
+ self.euler = euler
+
+ @property
+ def vel(self):
+ """ alias for rate """
+ return self.rate
+
+ @property
+ def xi(self):
+ """ alias for zeta """
+ return self.zeta
+
+ @xi.setter
+ def xi(self, value):
+ self.zeta = value
+
+
+class AttRefFloatNative(AttRefNative, RefQuatFloat):
+ """ C implementation stabilization_attitude_ref_quat_float """
+ name = 'Native Quat Float'
+
+ def __init__(self, **kwargs):
+ super(AttRefFloatNative, self).__init__(**kwargs)
+
+
+class AttRefIntNative(AttRefNative, RefQuatInt):
+ """ C implementation stabilization_attitude_ref_quat_int """
+ name = 'Native Quat Int'
+
+ def __init__(self, **kwargs):
+ super(AttRefIntNative, self).__init__(**kwargs)
+
+
+class att_ref_analytic_disc(att_ref_default):
+ """ Scalar discrete time second order LTI"""
+
+ def __init__(self, axis=0):
+ super(att_ref_analytic_disc, self).__init__()
+ self.name = 'Scalar Analytic discrete time'
+ self.axis = axis
+
+ def update_euler(self, setpoint, dt):
+ omega, xi = self.omega[self.axis], self.xi[self.axis]
+ omega_d = omega * math.sqrt(1 - xi ** 2)
+ tan_phi = xi / math.sqrt(1 - xi ** 2)
+ omd_dt = omega_d * dt
+ s_omd_dt = math.sin(omd_dt)
+ c_omd_dt = math.cos(omd_dt)
+ a1 = tan_phi * s_omd_dt + c_omd_dt
+ a2 = 1. / omega_d * s_omd_dt
+ a3 = -omega / math.sqrt(1 - xi ** 2) * s_omd_dt
+ a4 = -tan_phi * s_omd_dt + c_omd_dt
+ emxiomdt = math.exp(-xi * omega * dt)
+ A = emxiomdt * np.array([[a1, a2], [a3, a4]])
+ B = np.array([[-emxiomdt * (tan_phi * s_omd_dt + c_omd_dt) + 1],
+ [omega / math.sqrt(1 - xi ** 2) * emxiomdt * s_omd_dt]])
+ Xi = np.array([[self.euler[self.axis]], [self.vel[self.axis]]])
+ Xi1 = np.dot(A, Xi) + np.dot(B, setpoint[self.axis])
+ self.euler[self.axis], self.vel[self.axis] = Xi1
+
+
+class att_ref_analytic_cont(att_ref_default):
+ """ Scalar continuous time second order LTI"""
+
+ def __init__(self, axis=0):
+ super(att_ref_analytic_cont, self).__init__(**kwargs)
+ self.name = 'Scalar Analytic continuous time'
+ self.axis = axis
+
+ def update_euler(self, setpoint, dt):
+ omega, xi = self.omega[self.axis], self.xi[self.axis]
+
+ def dyn_cont(X, t, U):
+ Ac = np.array([[0, 1], [-omega ** 2, -2. * xi * omega]])
+ Bc = np.array([[0], [omega ** 2]])
+ return np.dot(Ac, X) + np.dot(Bc, U)
+
+ Xi = np.array([self.euler[self.axis], self.vel[self.axis]])
+ foo, Xi1 = integrate.odeint(dyn_cont, Xi, [0., dt], args=([setpoint[self.axis]],))
+ self.euler[self.axis], self.vel[self.axis] = Xi1
+ Xi1d = dyn_cont(Xi1, 0., [setpoint[self.axis]])
+ self.accel[self.axis] = Xi1d[1]
diff --git a/sw/misc/attitude_reference/gui.py b/sw/misc/attitude_reference/gui.py
new file mode 100644
index 0000000000..8331a00049
--- /dev/null
+++ b/sw/misc/attitude_reference/gui.py
@@ -0,0 +1,132 @@
+from gi.repository import Gtk, GObject
+
+import threading
+
+import pat.utils as pu
+
+
+class Worker(GObject.GObject):
+ """a worker thread that avoid blocking the UI during long tasks"""
+ __gsignals__ = {
+ "progress": (
+ GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, [GObject.TYPE_FLOAT]),
+ "completed": (
+ GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, []),
+ "aborted": (
+ GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, [])
+ }
+
+ def __init__(self, n_step=100):
+ GObject.GObject.__init__(self)
+ self.running = False
+ self.canceled = False
+ self.do_work = False
+ self.n_step = n_step
+
+ def start(self, args):
+ if self.running:
+ self.cancel()
+ self.t = threading.Thread(target=self._work, args=args)
+ self.t.daemon = True
+ self.t.start()
+
+ def cancel(self, wait=True):
+ self.canceled = True
+ self.do_work = False
+ if wait:
+ self.t.join()
+
+ def _emit(self, *args):
+ GObject.idle_add(GObject.GObject.emit, self, *args)
+
+ def _work(self, args):
+ self.running = True
+ self.canceled = False
+ self.do_work = False
+ #print("starting new work thread with args %s\nnow calling work init" % args)
+ self._work_init(args)
+ for i in range(0, self.n_step):
+ if self.canceled:
+ self.running = False
+ self._emit("aborted")
+ return
+ self._work_step(i, args)
+ self._emit("progress", float(i) / self.n_step)
+ self.running = False
+ self._emit("completed")
+
+
+class AttRefParamView(Gtk.Frame):
+ """a graphical user interface for editing parameters of an attitude reference"""
+
+ def __init__(self, txt=None, ref_classes=[], active_impl=None):
+ Gtk.Frame.__init__(self)
+ if txt is not None:
+ lab = Gtk.Label()
+ lab.set_markup(txt)
+ self.set_label_widget(lab)
+ self.ref_classes = ref_classes
+ self.b = Gtk.Builder()
+ self.b.add_from_file("ressources/att_ref_param_view.xml")
+ self.b.get_object("main_grid").reparent(self)
+ self.combo_type = self.b.get_object("comboboxtext_references")
+ for c in self.ref_classes:
+ self.combo_type.append_text(c.name)
+ self.progress = self.b.get_object("progressbar")
+
+ self.spin_cfg = {
+ 'omega': {'range': (0.2, 20., 0.1, 1., 0.), 'r2d': lambda x: x, 'd2r': lambda x: x},
+ 'xi': {'range': (0.1, 1.5, 0.05, 0.2, 0.), 'r2d': lambda x: x, 'd2r': lambda x: x},
+ 'sat_vel': {'range': (1., 200., 1., 5., 0.), 'r2d': pu.deg_of_rad, 'd2r': pu.rad_of_deg},
+ 'sat_accel': {'range': (10., 1500., 10., 20., 0.), 'r2d': pu.deg_of_rad, 'd2r': pu.rad_of_deg},
+ 'sat_jerk': {'range': (10., 7500., 10., 20., 0.), 'r2d': pu.deg_of_rad, 'd2r': pu.rad_of_deg}
+ }
+ for n, c in self.spin_cfg.iteritems():
+ w = self.b.get_object("spin_{}".format(n))
+ adj = Gtk.Adjustment(0., *c['range'])
+ w.set_adjustment(adj)
+
+ if active_impl is not None:
+ self.update_view(active_impl)
+ else:
+ self.combo_type.set_active(0)
+
+ def connect(self, cbk_type_changed, cbk_param_changed, *args):
+ self.combo_type.connect("changed", cbk_type_changed, *args)
+ for n in self.spin_cfg.keys():
+ w = self.b.get_object("spin_{}".format(n))
+ self.spin_cfg[n]['handler'] = w.connect("value-changed", cbk_param_changed, n, *args)
+
+ def get_selected(self):
+ return self.combo_type.get_active()
+
+ def set_active(self, ref_class):
+ self.combo_type.set_active(self.ref_classes.index(ref_class))
+
+ def get_selected_ref_class(self):
+ return self.ref_classes[self.get_selected()]
+
+ def update_view(self, ref):
+ """ update view according to ref params """
+ self.set_active(ref.__class__)
+ for n, c in self.spin_cfg.iteritems():
+ w = self.b.get_object("spin_{}".format(n))
+ try:
+ w.set_value(c['r2d'](getattr(ref, n)[0]))
+ w.set_sensitive(True)
+ except AttributeError:
+ w.set_sensitive(False)
+
+ def update_ref_params(self, ref):
+ """" upate ref params from view by emitting value-changed.
+ if param was not sensitive, update view with current param from ref
+ """
+ for n, c in self.spin_cfg.iteritems():
+ w = self.b.get_object("spin_{}".format(n))
+ if hasattr(ref, n):
+ if not w.is_sensitive():
+ w.set_value(c['r2d'](getattr(ref, n)[0]))
+ w.emit('value-changed')
+ w.set_sensitive(True)
+ else:
+ w.set_sensitive(False)
diff --git a/sw/misc/attitude_reference/pat/__init__.py b/sw/misc/attitude_reference/pat/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/sw/misc/attitude_reference/pat/algebra.py b/sw/misc/attitude_reference/pat/algebra.py
new file mode 100644
index 0000000000..d3fa6efd42
--- /dev/null
+++ b/sw/misc/attitude_reference/pat/algebra.py
@@ -0,0 +1,271 @@
+import math
+import numpy as np
+import numpy.linalg
+
+# euler angles
+e_phi = 0
+e_theta = 1
+e_psi = 2
+e_size = 3
+
+# rotational velocities
+r_p = 0
+r_q = 1
+r_r = 2
+r_size = 3
+
+# quaternions
+q_i = 0
+q_x = 1
+q_y = 2
+q_z = 3
+q_size = 4
+
+# vectors
+v_x = 0
+v_y = 1
+v_z = 2
+v_size = 3
+
+
+def rmat_of_euler(e):
+ cphi = math.cos(e[e_phi])
+ sphi = math.sin(e[e_phi])
+ ctheta = math.cos(e[e_theta])
+ stheta = math.sin(e[e_theta])
+ cpsi = math.cos(e[e_psi])
+ spsi = math.sin(e[e_psi])
+ return np.array([[ctheta * cpsi, ctheta * spsi, -stheta],
+ [sphi * stheta * cpsi - cphi * spsi, sphi * stheta * spsi + cphi * cpsi, sphi * ctheta],
+ [cphi * stheta * cpsi + sphi * spsi, cphi * stheta * spsi - sphi * cpsi, cphi * ctheta]])
+
+
+def euler_of_quat(q):
+ dcm00 = 1.0 - 2. * (q[q_y] ** 2 + q[q_z] ** 2)
+ dcm01 = 2. * (q[q_x] * q[q_y] + q[q_i] * q[q_z])
+ dcm02 = 2. * (q[q_x] * q[q_z] - q[q_i] * q[q_y])
+ dcm12 = 2. * (q[q_y] * q[q_z] + q[q_i] * q[q_x])
+ dcm22 = 1.0 - 2. * (q[q_x] ** 2 + q[q_y] ** 2)
+ return [math.atan2(dcm12, dcm22),
+ -math.asin(dcm02),
+ math.atan2(dcm01, dcm00)]
+
+
+def euler_of_quat_v(q):
+ nr, nc = q.shape
+ eu = np.zeros((nr, e_size))
+ for i in range(0, nr):
+ eu[i] = euler_of_quat(q[i])
+ return eu
+
+
+#
+# bad (earth relative)
+#
+
+
+def rmat_of_euler_1(e):
+ cphi = math.cos(e[e_phi])
+ sphi = math.sin(e[e_phi])
+ ctheta = math.cos(e[e_theta])
+ stheta = math.sin(e[e_theta])
+ cpsi = math.cos(e[e_psi])
+ spsi = math.sin(e[e_psi])
+ return np.array([[ctheta * cpsi, -ctheta * spsi, -stheta],
+ [-sphi * stheta * cpsi + cphi * spsi, sphi * stheta * spsi + cphi * cpsi, -sphi * ctheta],
+ [cphi * stheta * cpsi + sphi * spsi, -cphi * stheta * spsi + sphi * cpsi, cphi * ctheta]])
+
+
+def rvel_of_eulerd_1(eu, eud):
+ sph = math.sin(eu[e_phi])
+ cph = math.cos(eu[e_phi])
+ sth = math.sin(eu[e_theta])
+ cth = math.cos(eu[e_theta])
+ a = 2 * (cph ** 2) - 1
+ return [eud[e_phi] - sth * eud[e_psi],
+ cph / a * eud[e_theta] - sph * cth / a * eud[e_psi],
+ -sph / a * eud[e_theta] + cph * cth / a * eud[e_psi]]
+
+
+def euler_derivatives_1(eu, om):
+ sph = math.sin(eu[e_phi])
+ cph = math.cos(eu[e_phi])
+ tth = math.tan(eu[e_theta])
+ cth = math.cos(eu[e_theta])
+ return [om[r_p] + sph * tth * om[r_q] + cph * tth * om[r_r],
+ cph * om[r_q] + sph * om[r_r],
+ sph / cth * om[r_q] + cph / cth * om[r_r]]
+
+
+#
+# good (body relative)
+#
+def rvel_of_eulerd(eu, eud):
+ sph = math.sin(eu[e_phi])
+ cph = math.cos(eu[e_phi])
+ sth = math.sin(eu[e_theta])
+ cth = math.cos(eu[e_theta])
+ return [eud[e_phi] - sth * eud[e_psi],
+ cph * eud[e_theta] + sph * cth * eud[e_psi],
+ -sph * eud[e_theta] + cph * cth * eud[e_psi]]
+
+
+def euler_derivatives(eu, om):
+ sph = math.sin(eu[e_phi])
+ cph = math.cos(eu[e_phi])
+ tth = math.tan(eu[e_theta])
+ cth = math.cos(eu[e_theta])
+
+ return [om[r_p] + sph * tth * om[r_q] + cph * tth * om[r_r],
+ cph * om[r_q] - sph * om[r_r],
+ sph / cth * om[r_q] + cph / cth * om[r_r]]
+
+
+#
+# Quaternions
+#
+
+def quat_zero():
+ return np.array([1., 0., 0., 0.])
+
+
+def quat_of_euler(e):
+ s_phi2 = math.sin(e[e_phi] / 2)
+ c_phi2 = math.cos(e[e_phi] / 2)
+ s_theta2 = math.sin(e[e_theta] / 2)
+ c_theta2 = math.cos(e[e_theta] / 2)
+ s_psi2 = math.sin(e[e_psi] / 2)
+ c_psi2 = math.cos(e[e_psi] / 2)
+
+ return [c_phi2 * c_theta2 * c_psi2 + s_phi2 * s_theta2 * s_psi2,
+ -c_phi2 * s_theta2 * s_psi2 + s_phi2 * c_theta2 * c_psi2,
+ c_phi2 * s_theta2 * c_psi2 + s_phi2 * c_theta2 * s_psi2,
+ c_phi2 * c_theta2 * s_psi2 - s_phi2 * s_theta2 * c_psi2]
+
+
+def quat_of_axis_angle(u, a):
+ sa2 = math.sin(a / 2.)
+ ca2 = math.cos(a / 2.)
+ return [ca2, sa2 * u[0], sa2 * u[1], sa2 * u[2]]
+
+
+def quat_comp(a2b, b2c):
+ return [
+ a2b[q_i] * b2c[q_i] - a2b[q_x] * b2c[q_x] - a2b[q_y] * b2c[q_y] - a2b[q_z] * b2c[q_z],
+ a2b[q_i] * b2c[q_x] + a2b[q_x] * b2c[q_i] + a2b[q_y] * b2c[q_z] - a2b[q_z] * b2c[q_y],
+ a2b[q_i] * b2c[q_y] - a2b[q_x] * b2c[q_z] + a2b[q_y] * b2c[q_i] + a2b[q_z] * b2c[q_x],
+ a2b[q_i] * b2c[q_z] + a2b[q_x] * b2c[q_y] - a2b[q_y] * b2c[q_x] + a2b[q_z] * b2c[q_i]]
+
+
+def quat_inv_comp(a2b, a2c):
+ return [
+ a2b[q_i] * a2c[q_i] + a2b[q_x] * a2c[q_x] + a2b[q_y] * a2c[q_y] + a2b[q_z] * a2c[q_z],
+ a2b[q_i] * a2c[q_x] - a2b[q_x] * a2c[q_i] - a2b[q_y] * a2c[q_z] + a2b[q_z] * a2c[q_y],
+ a2b[q_i] * a2c[q_y] + a2b[q_x] * a2c[q_z] - a2b[q_y] * a2c[q_i] - a2b[q_z] * a2c[q_x],
+ a2b[q_i] * a2c[q_z] - a2b[q_x] * a2c[q_y] + a2b[q_y] * a2c[q_x] - a2b[q_z] * a2c[q_i]]
+
+
+def quat_derivative(q, om):
+ return [
+ 0.5 * (-om[r_p] * q[q_x] - om[r_q] * q[q_y] - om[r_r] * q[q_z]),
+ 0.5 * (om[r_p] * q[q_i] + om[r_r] * q[q_y] - om[r_q] * q[q_z]),
+ 0.5 * (om[r_q] * q[q_i] - om[r_r] * q[q_x] + om[r_p] * q[q_z]),
+ 0.5 * (om[r_r] * q[q_i] + om[r_q] * q[q_x] - om[r_p] * q[q_y])
+ ]
+
+
+def quat_wrap_shortest(q):
+ if q[q_i] < 0:
+ return [-q[q_i], -q[q_x], -q[q_y], -q[q_z]]
+ else:
+ return q
+
+
+def quat_mormalize(q):
+ nq = np.linalg.norm(q)
+ return np.array(1. / nq * q)
+
+
+def quat_vmul(q, v):
+ qi2 = q[q_i] * q[q_i]
+ qiqx = q[q_i] * q[q_x]
+ qiqy = q[q_i] * q[q_y]
+ qiqz = q[q_i] * q[q_z]
+ qx2 = q[q_x] * q[q_x]
+ qxqy = q[q_x] * q[q_y]
+ qxqz = q[q_x] * q[q_z]
+ qy2 = q[q_y] * q[q_y]
+ qyqz = q[q_y] * q[q_z]
+ qz2 = q[q_z] * q[q_z]
+ m00 = qi2 + qx2 - qy2 - qz2
+ m01 = 2 * (qxqy + qiqz)
+ m02 = 2 * (qxqz - qiqy)
+ m10 = 2 * (qxqy - qiqz)
+ m11 = qi2 - qx2 + qy2 - qz2
+ m12 = 2 * (qyqz + qiqx)
+ m20 = 2 * (qxqz + qiqy)
+ m21 = 2 * (qyqz - qiqx)
+ m22 = qi2 - qx2 - qy2 + qz2
+
+ return [
+ m00 * v[v_x] + m01 * v[v_y] + m02 * v[v_z],
+ m10 * v[v_x] + m11 * v[v_y] + m12 * v[v_z],
+ m20 * v[v_x] + m21 * v[v_y] + m22 * v[v_z]]
+
+
+def quat_inv_vmul(q, v):
+ qi2 = q[q_i] * q[q_i]
+ qiqx = q[q_i] * q[q_x]
+ qiqy = q[q_i] * q[q_y]
+ qiqz = q[q_i] * q[q_z]
+ qx2 = q[q_x] * q[q_x]
+ qxqy = q[q_x] * q[q_y]
+ qxqz = q[q_x] * q[q_z]
+ qy2 = q[q_y] * q[q_y]
+ qyqz = q[q_y] * q[q_z]
+ qz2 = q[q_z] * q[q_z]
+ m00 = qi2 + qx2 - qy2 - qz2
+ m01 = 2 * (qxqy + qiqz)
+ m02 = 2 * (qxqz - qiqy)
+ m10 = 2 * (qxqy - qiqz)
+ m11 = qi2 - qx2 + qy2 - qz2
+ m12 = 2 * (qyqz + qiqx)
+ m20 = 2 * (qxqz + qiqy)
+ m21 = 2 * (qyqz - qiqx)
+ m22 = qi2 - qx2 - qy2 + qz2
+
+ return [
+ m00 * v[v_x] + m10 * v[v_y] + m20 * v[v_z],
+ m01 * v[v_x] + m11 * v[v_y] + m21 * v[v_z],
+ m02 * v[v_x] + m12 * v[v_y] + m22 * v[v_z]]
+
+
+def quat_integrate(q_im1, om_im1, dt):
+ no = np.linalg.norm(om_im1)
+ if no == 0.:
+ codt2 = 1.
+ sodt2o = 1.
+ else:
+ codt2 = math.cos(dt / 2. * no)
+ sodt2o = math.sin(dt / 2. * no) / no
+
+ p = -om_im1[0]
+ q = -om_im1[1]
+ r = -om_im1[2]
+ # WTF wrong formula. inverted signs instead
+ Phi = np.array([[codt2, p * sodt2o, q * sodt2o, r * sodt2o],
+ [-p * sodt2o, codt2, -r * sodt2o, q * sodt2o],
+ [-q * sodt2o, r * sodt2o, codt2, -p * sodt2o],
+ [-r * sodt2o, -q * sodt2o, p * sodt2o, codt2]])
+ q_i = np.dot(Phi, q_im1)
+ return q_i
+
+
+def cross_product(v1, v2):
+ return np.array([v1[v_y] * v2[v_z] - v1[v_z] * v2[v_y],
+ v1[v_z] * v2[v_x] - v1[v_x] * v2[v_z],
+ v1[v_x] * v2[v_y] - v1[v_y] * v2[v_x]])
+
+
+def dot_product(v1, v2):
+ return np.sum(v1 * v2)
diff --git a/sw/misc/attitude_reference/pat/control.py b/sw/misc/attitude_reference/pat/control.py
new file mode 100644
index 0000000000..9ff52bea97
--- /dev/null
+++ b/sw/misc/attitude_reference/pat/control.py
@@ -0,0 +1,112 @@
+from __future__ import division
+
+import math
+import numpy as np
+
+
+class LinRef:
+ """ Linear Reference Model (with first order integration)"""
+
+ def __init__(self, K):
+ """K: coefficients of the caracteristic polynomial, in ascending powers order,
+ highesr order ommited (normalized to -1)"""
+ self.K = K
+ self.order = len(K)
+ self.X = np.zeros(self.order + 1)
+
+ def run(self, dt, sp):
+ self.X[:self.order] += self.X[1:self.order + 1] * dt
+ e = np.array(self.X[:self.order])
+ e[0] -= sp
+ self.X[self.order] = np.sum(e * self.K)
+ return self.X
+
+
+class SatRef:
+ """ Nested Saturations Reference Model (with first order integration)"""
+
+ def __init__(self, K, sats):
+ """
+ K: coefficients of the caracteristic polynomial, in ascending power order,
+ highest power ommited (normalized to -1)
+ sats: saturations for each order in ascending order
+ """
+ self.K = K
+ self.M = np.array(sats)
+ self.M[0:-1] *= K[1:]
+ for i in range(0, len(self.M) - 1):
+ self.M[len(self.M) - 2 - i] /= np.prod(self.M[len(self.M) - 1 - i:])
+ self.CM = np.cumprod(self.M[::-1])[::-1]
+ print 'M', self.M, 'CM', self.CM
+ self.order = len(K)
+ self.X = np.zeros(self.order + 1)
+
+ def run(self, dt, sp):
+ self.X[:self.order] += self.X[1:self.order + 1] * dt
+ e = np.array(self.X[:self.order])
+ e[0] -= sp
+ self.X[self.order] = 0
+ for i in range(0, self.order):
+ self.X[self.order] = self.M[i] * np.clip(self.K[i] / self.CM[i] * e[i] + self.X[self.order], -1., 1.)
+ return self.X
+
+
+class SatRefNaiveSecOrder:
+ """ Second Order (brutally) Saturated Reference Model"""
+
+ def __init__(self, K, sats):
+ """
+ K: coefficients of the caracteristic polynomial, in ascending power order,
+ highest power ommited (normalized to -1)
+ sats: saturations for each order in ascending order
+ """
+ self.K = K
+ self.sats = sats
+ self.order = len(K)
+ self.X = np.zeros(self.order + 1)
+
+ def run(self, dt, sp):
+ self.X[:self.order] += self.X[1:self.order + 1] * dt
+ e = np.array(self.X[:self.order])
+ e[0] -= sp
+ self.X[self.order] = np.sum(e * self.K)
+ self.X[self.order] = np.clip(self.X[self.order], -self.sats[1], self.sats[1]) # saturate accel
+ if self.X[self.order - 1] >= self.sats[0]: # saturate vel, trim accel
+ self.X[self.order - 1] = self.sats[0]
+ if self.X[self.order] > 0:
+ self.X[self.order] = 0
+ elif self.X[self.order - 1] <= -self.sats[0]:
+ self.X[self.order - 1] = -self.sats[0]
+ if self.X[self.order] < 0:
+ self.X[self.order] = 0
+ return self.X
+
+
+def butterworth(n, omega=1):
+ """
+ returns the coefficients of a butterworth polynomial of order n in ascending powers order
+ see: http://en.wikipedia.org/wiki/Butterworth_filter
+ """
+ poles = [omega * np.exp(complex(0, 2 * k + n - 1) * math.pi / 2 / n) for k in range(1, n + 1)]
+ coefs = -np.poly(poles)[::-1]
+ return np.real(coefs[:-1])
+
+
+def bessel(n, omega=1):
+ """
+ returns the coefficients of a bessel polynomial of order n in ascending powers order
+ see http://en.wikipedia.org/wiki/Bessel_filter
+ """
+ coefs = [-math.factorial(2 * n - k) / (math.pow(2, n - k) * math.factorial(k) * math.factorial(n - k)) for k in
+ range(0, n)]
+ return coefs[::-1]
+
+
+def poles(K):
+ """ returns the roots of a polynomial whose coefficients are provided in ascending order,
+ highest power coefficients normalized to -1
+ """
+ p = np.zeros(len(K) + 1)
+ p[0] = -1
+ p[1:] = K[::-1]
+ return np.roots(p)
diff --git a/sw/misc/attitude_reference/pat/utils.py b/sw/misc/attitude_reference/pat/utils.py
new file mode 100644
index 0000000000..814555e591
--- /dev/null
+++ b/sw/misc/attitude_reference/pat/utils.py
@@ -0,0 +1,259 @@
+#
+# Copyright 2013-2014 Antoine Drouin (poinix@gmail.com)
+#
+# This file is part of PAT.
+#
+# PAT is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# PAT is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with PAT. If not, see .
+#
+
+"""
+Utility functions
+"""
+import math
+import numpy as np
+import numpy.linalg as linalg
+import pdb
+
+"""
+Unit convertions
+"""
+
+
+def rad_of_deg(d):
+ return d / 180. * math.pi
+
+
+def sqrad_of_sqdeg(d):
+ return d / (180. * math.pi) ** 2
+
+
+def deg_of_rad(r):
+ return r * 180. / math.pi
+
+
+def sqdeg_of_sqrad(r):
+ return r * (180. / math.pi) ** 2
+
+
+def rps_of_rpm(r):
+ return r * 2. * math.pi / 60.
+
+
+def rpm_of_rps(r):
+ return r / 2. / math.pi * 60.
+
+
+# http://en.wikipedia.org/wiki/Nautical_mile
+def m_of_NM(nm):
+ return nm * 1852.
+
+
+def NM_of_m(m):
+ return m / 1852.
+
+
+# http://en.wikipedia.org/wiki/Knot_(speed)
+def mps_of_kt(kt):
+ return kt * 0.514444
+
+
+def kt_of_mps(mps):
+ return mps / 0.514444
+
+
+# http://en.wikipedia.org/wiki/Foot_(unit)
+def m_of_ft(ft):
+ return ft * 0.3048
+
+
+def ft_of_m(m):
+ return m / 0.3048
+
+
+# feet per minute to/from meters per second
+def ftpm_of_mps(mps):
+ return mps * 60. * 3.28084
+
+
+def mps_of_ftpm(ftpm):
+ return ftpm / 60. / 3.28084
+
+
+"""
+Cliping
+"""
+
+
+def norm_angle_0_2pi(a):
+ while a > 2. * math.pi:
+ a -= 2. * math.pi
+ while a <= 0:
+ a += 2. * math.pi
+ return a
+
+
+def norm_angle_mpi_pi(a):
+ while a > math.pi:
+ a -= 2. * math.pi
+ while a <= -math.pi:
+ a += 2. * math.pi
+ return a
+
+
+#
+def saturate(_v, _min, _max):
+ if _v < _min:
+ return _min
+ if _v > _max:
+ return _max
+ return _v
+
+
+"""
+Plotting
+"""
+import matplotlib
+import matplotlib.pyplot as plt
+import matplotlib.gridspec as gridspec
+
+my_title_spec = {'color': 'k', 'fontsize': 20}
+
+
+def save_if(filename):
+ if filename: matplotlib.pyplot.savefig(filename, dpi=80)
+
+
+def prepare_fig(fig=None, window_title=None, figsize=(20.48, 10.24), margins=None):
+ if fig is None:
+ fig = plt.figure(figsize=figsize)
+ # else:
+ # plt.figure(fig.number)
+ if margins:
+ left, bottom, right, top, wspace, hspace = margins
+ fig.subplots_adjust(left=left, right=right, bottom=bottom, top=top,
+ hspace=hspace, wspace=wspace)
+ if window_title:
+ fig.canvas.set_window_title(window_title)
+ return fig
+
+
+def decorate(ax, title=None, xlab=None, ylab=None, legend=None, xlim=None, ylim=None):
+ ax.xaxis.grid(color='k', linestyle='-', linewidth=0.2)
+ ax.yaxis.grid(color='k', linestyle='-', linewidth=0.2)
+ if xlab:
+ ax.xaxis.set_label_text(xlab)
+ if ylab:
+ ax.yaxis.set_label_text(ylab)
+ if title:
+ ax.set_title(title, my_title_spec)
+ if legend is not None:
+ ax.legend(legend, loc='best')
+ if xlim is not None:
+ ax.set_xlim(xlim[0], xlim[1])
+ if ylim is not None:
+ ax.set_ylim(ylim[0], ylim[1])
+
+
+def ensure_ylim(ax, yspan):
+ ymin, ymax = ax.get_ylim()
+ if ymax - ymin < yspan:
+ ym = (ymin + ymax) / 2
+ ax.set_ylim(ym - yspan / 2, ym + yspan / 2)
+
+
+def write_text(nrows, ncols, plot_number, text, colspan=1, loc=[[0.5, 9.7]], filename=None):
+ # ax = plt.subplot(nrows, ncols, plot_number)
+ gs = gridspec.GridSpec(nrows, ncols)
+ row, col = divmod(plot_number - 1, ncols)
+ ax = plt.subplot(gs[row, col:col + colspan])
+ plt.axis([0, 10, 0, 10])
+ ax.get_xaxis().set_visible(False)
+ ax.get_yaxis().set_visible(False)
+ for i in range(0, len(text)):
+ plt.text(loc[i][0], loc[i][1], text[i], ha='left', va='top')
+ save_if(filename)
+
+
+def plot_in_grid(time, plots, ncol, figure=None, window_title="None", legend=None, filename=None,
+ margins=(0.04, 0.08, 0.93, 0.96, 0.20, 0.34)):
+ nrow = math.ceil(len(plots) / float(ncol))
+ figsize = (10.24 * ncol, 2.56 * nrow)
+ figure = prepare_fig(figure, window_title, figsize=figsize, margins=margins)
+ # pdb.set_trace()
+ for i, (title, ylab, data) in enumerate(plots):
+ ax = figure.add_subplot(nrow, ncol, i + 1)
+ ax.plot(time, data)
+ decorate(ax, title=title, ylab=ylab)
+ if legend is not None:
+ ax.legend(legend, loc='best')
+ save_if(filename)
+ return figure
+
+
+"""
+Misc
+"""
+
+
+def num_jacobian(X, U, P, dyn):
+ s_size = len(X)
+ i_size = len(U)
+ epsilonX = (0.1 * np.ones(s_size)).tolist()
+ dX = np.diag(epsilonX)
+ A = np.zeros((s_size, s_size))
+ for i in range(0, s_size):
+ dx = dX[i, :]
+ delta_f = dyn(X + dx / 2, 0, U, P) - dyn(X - dx / 2, 0, U, P)
+ delta_f = delta_f / dx[i]
+ # print delta_f
+ A[:, i] = delta_f
+
+ epsilonU = (0.1 * np.ones(i_size)).tolist()
+ dU = np.diag(epsilonU)
+ B = np.zeros((s_size, i_size))
+ for i in range(0, i_size):
+ du = dU[i, :]
+ delta_f = dyn(X, 0, U + du / 2, P) - dyn(X, 0, U - du / 2, P)
+ delta_f = delta_f / du[i]
+ B[:, i] = delta_f
+
+ return A, B
+
+
+def saturate(V, Sats):
+ Vsat = np.array(V)
+ for i in range(0, len(V)):
+ if Vsat[i] < Sats[i, 0]:
+ Vsat[i] = Sats[i, 0]
+ elif Vsat[i] > Sats[i, 1]:
+ Vsat[i] = Sats[i, 1]
+ return Vsat
+
+
+def print_lti_dynamics(A, B, txt=None, print_original_form=False, print_modal_form=False):
+ if txt:
+ print txt
+ if print_original_form:
+ print "A\n", A
+ print "B\n", B
+ w, M = np.linalg.eig(A)
+ print "modes \n", w
+ if print_modal_form:
+ # print "eigen vectors\n", M
+ # invM = np.linalg.inv(M)
+ # print "invM\n", invM
+ # Amod = np.dot(np.dot(invM, A), M)
+ # print "Amod\n", Amod
+ for i in range(len(w)):
+ print w[i], "->", M[:, i]
diff --git a/sw/misc/attitude_reference/ressources/att_ref_gui.xml b/sw/misc/attitude_reference/ressources/att_ref_gui.xml
new file mode 100644
index 0000000000..39bb73687e
--- /dev/null
+++ b/sw/misc/attitude_reference/ressources/att_ref_gui.xml
@@ -0,0 +1,237 @@
+
+
+
+
+
+
diff --git a/sw/misc/attitude_reference/ressources/att_ref_param_view.xml b/sw/misc/attitude_reference/ressources/att_ref_param_view.xml
new file mode 100644
index 0000000000..5ce312536a
--- /dev/null
+++ b/sw/misc/attitude_reference/ressources/att_ref_param_view.xml
@@ -0,0 +1,271 @@
+
+
+
+
+
+ False
+
+
+ True
+ False
+
+
+ True
+ False
+ 0
+ Type:
+
+
+ 0
+ 0
+ 1
+ 1
+
+
+
+
+ True
+ False
+
+
+ 1
+ 0
+ 2
+ 1
+
+
+
+
+ True
+ False
+ 0
+ Omega:
+
+
+ 0
+ 1
+ 1
+ 1
+
+
+
+
+ True
+ False
+ 0
+ Xi:
+
+
+ 0
+ 2
+ 1
+ 1
+
+
+
+
+ True
+ False
+ 0
+ MaxVel:
+
+
+ 0
+ 3
+ 1
+ 1
+
+
+
+
+ True
+ False
+ 0
+ MaxAccel:
+
+
+ 0
+ 4
+ 1
+ 1
+
+
+
+
+ True
+ False
+ rad/s
+
+
+ 2
+ 1
+ 1
+ 1
+
+
+
+
+ True
+ False
+ deg/s
+
+
+ 2
+ 3
+ 1
+ 1
+
+
+
+
+ True
+ False
+ deg/s2
+
+
+ 2
+ 4
+ 1
+ 1
+
+
+
+
+ True
+ False
+ deg/s3
+
+
+ 2
+ 5
+ 1
+ 1
+
+
+
+
+ True
+ True
+ ●
+ number
+ 2
+ True
+ if-valid
+
+
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+ True
+ True
+ ●
+ digits
+ 2
+ True
+ if-valid
+
+
+ 1
+ 2
+ 1
+ 1
+
+
+
+
+ True
+ True
+ ●
+ True
+ if-valid
+
+
+ 1
+ 3
+ 1
+ 1
+
+
+
+
+ True
+ True
+ ●
+ True
+ if-valid
+
+
+ 1
+ 4
+ 1
+ 1
+
+
+
+
+ True
+ True
+ ●
+ number
+ True
+ if-valid
+
+
+ 1
+ 5
+ 1
+ 1
+
+
+
+
+ True
+ False
+
+
+ 1
+ 6
+ 2
+ 1
+
+
+
+
+ True
+ False
+ 0
+ MaxJerk:
+
+
+ 0
+ 5
+ 1
+ 1
+
+
+
+
+ True
+ False
+ 0
+ Status:
+
+
+ 0
+ 6
+ 1
+ 1
+
+
+
+
+
+
+
+
+
diff --git a/sw/misc/attitude_reference/test_att_ref.py b/sw/misc/attitude_reference/test_att_ref.py
new file mode 100755
index 0000000000..267cb23090
--- /dev/null
+++ b/sw/misc/attitude_reference/test_att_ref.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2014 Antoine Drouin
+#
+# This file is part of paparazzi.
+#
+# paparazzi is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# paparazzi is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with paparazzi; see the file COPYING. If not, write to
+# the Free Software Foundation, 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+import math
+import numpy as np
+import scipy.signal
+import matplotlib.pyplot as plt
+
+import pat.utils as pu
+import pat.algebra as pa
+
+import control as ctl
+
+
+def random_setpoint(time, dt_step=2):
+ tf = time[0]
+ sp = np.zeros((len(time), 3))
+ sp_i = [0, 0, 0]
+ for i in range(0, len(time)):
+ if time[i] >= tf:
+ ui = np.random.rand(3) - [0.5, 0.5, 0.5];
+ ai = np.random.rand(1)
+ n = np.linalg.norm(ui)
+ if n > 0:
+ ui /= n
+ sp_i = pa.euler_of_quat(pa.quat_of_axis_angle(ui, ai))
+ tf += dt_step
+ sp[i] = sp_i
+ return sp
+
+
+def test_ref(r, time, setpoint):
+ ref = np.zeros((len(time), 9))
+ for i in range(1, time.size):
+ sp_quat = pa.quat_of_euler(setpoint[i])
+ r.update_quat(sp_quat, time[i] - time[i - 1])
+ euler = pa.euler_of_quat(r.quat)
+ ref[i] = np.concatenate((euler, r.vel, r.accel))
+ return ref
+
+
+def plot_ref(time, xref=None, sp=None, figure=None):
+ margins = (0.05, 0.05, 0.98, 0.96, 0.20, 0.34)
+ figure = pu.prepare_fig(figure, window_title='Reference', figsize=(20.48, 10.24), margins=margins)
+ plots = [("$\phi$", "deg"), ("$\\theta$", "deg"), ("$\\psi$", "deg"),
+ ("$p$", "deg/s"), ("$q$", "deg/s"), ("$r$", "deg/s"),
+ ("$\dot{p}$", "deg/s2"), ("$\dot{q}$", "deg/s2"), ("$\dot{r}$", "deg/s2")]
+ for i, (title, ylab) in enumerate(plots):
+ ax = plt.subplot(3, 3, i + 1)
+ if xref is not None: plt.plot(time, pu.deg_of_rad(xref[:, i]))
+ pu.decorate(ax, title=title, ylab=ylab)
+ if sp is not None and i < 3:
+ plt.plot(time, pu.deg_of_rad(sp[:, i]))
+ return figure
+
+
+dt = 1. / 512.
+time = np.arange(0., 4, dt)
+sp = np.zeros((len(time), 3))
+sp[:, 0] = pu.rad_of_deg(45.) * scipy.signal.square(math.pi / 2 * time + math.pi)
+# sp[:, 1] = pu.rad_of_deg(5.)*scipy.signal.square(math.pi/2*time)
+# sp[:, 2] = pu.rad_of_deg(45.)
+# sp = random_setpoint(time)
+
+# rs = [ctl.att_ref_analytic_disc(axis=0), ctl.att_ref_analytic_cont(axis=0), ctl.att_ref_default()]
+
+args = {'omega': 10., 'xi': 0.7, 'sat_vel': pu.rad_of_deg(150.), 'sat_accel': pu.rad_of_deg(1800),
+ 'sat_jerk': pu.rad_of_deg(27000)}
+rs = [ctl.att_ref_sat_naive(**args), ctl.att_ref_sat_nested(**args), ctl.att_ref_sat_nested2(**args)]
+# beware that the saturation parameters of the native implementations are currently defined at compile time!!
+# rs.append(ctl.AttRefIntNative(**args))
+rs.append(ctl.AttRefFloatNative(**args))
+
+xrs = [test_ref(r, time, sp) for r in rs]
+figure = None
+for xr in xrs:
+ figure = plot_ref(time, xr, None, figure)
+figure = plot_ref(time, None, sp, figure)
+legends = [r.name for r in rs] + ['Setpoint']
+plt.subplot(3, 3, 3)
+plt.legend(legends)
+plt.show()
diff --git a/sw/supervision/paparazzicenter.ml b/sw/supervision/paparazzicenter.ml
index 887bc0d21c..91b50e1901 100644
--- a/sw/supervision/paparazzicenter.ml
+++ b/sw/supervision/paparazzicenter.ml
@@ -210,7 +210,7 @@ let () =
let ac_combo = AC.parse_conf_xml gui#vbox_ac
and target_combo = Gtk_tools.combo ~width:50 ["sim";"fbw";"ap"] gui#vbox_target
- and flash_combo = Gtk_tools.combo ~width:50 ["Default mode"] gui#vbox_flash in
+ and flash_combo = Gtk_tools.combo ~width:50 ["Default"] gui#vbox_flash in
(Gtk_tools.combo_widget target_combo)#misc#set_sensitive false;
(Gtk_tools.combo_widget flash_combo)#misc#set_sensitive false;
diff --git a/sw/supervision/pc_aircraft.ml b/sw/supervision/pc_aircraft.ml
index 38b2a7d7f8..516cc196b1 100644
--- a/sw/supervision/pc_aircraft.ml
+++ b/sw/supervision/pc_aircraft.ml
@@ -228,7 +228,7 @@ let get_targets_list = fun ac_xml ->
(** Parse Airframe File for Targets **)
let parse_ac_targets = fun target_combo ac_file (log:string->unit) ->
(* remember last target *)
- let last_target = Gtk_tools.combo_value target_combo in
+ let last_target = try Gtk_tools.combo_value target_combo with _ -> "" in
(* Clear ComboBox *)
let (store, column) = Gtk_tools.combo_model target_combo in
store#clear ();
@@ -243,7 +243,9 @@ let parse_ac_targets = fun target_combo ac_file (log:string->unit) ->
Gtk_tools.add_to_combo target_combo "sim"
end;
Gtk_tools.select_in_combo target_combo last_target
- with _ -> log (sprintf "Error while parsing targets from file %s\n" ac_file)
+ with _ ->
+ log (sprintf "Error while parsing targets from file %s\n" ac_file);
+ raise Not_found
(* Parse AC file for flash mode *)
let parse_ac_flash = fun target flash_combo ac_file ->
@@ -268,7 +270,8 @@ let parse_ac_flash = fun target flash_combo ac_file ->
Gtk_tools.select_in_combo flash_combo last_flash_mode
with _ ->
(* not a valid airframe file *)
- (Gtk_tools.combo_widget flash_combo)#misc#set_sensitive false
+ (Gtk_tools.combo_widget flash_combo)#misc#set_sensitive false;
+ raise Not_found
(* Link A/C to airframe & flight_plan labels *)
let ac_combo_handler = fun gui (ac_combo:Gtk_tools.combo) target_combo flash_combo (log:string->unit) ->
@@ -301,8 +304,19 @@ let ac_combo_handler = fun gui (ac_combo:Gtk_tools.combo) target_combo flash_com
let aircraft = Hashtbl.find Utils.aircrafts ac_name in
let sample = aircraft_sample ac_name "42" in
(* update list of modules settings *)
+ let af_file = (Env.paparazzi_home // "conf" // (Xml.attrib aircraft "airframe")) in
+ let af_xml = try Xml.parse_file af_file
+ with
+ | Xml.File_not_found x ->
+ gui#label_airframe#set_text "";
+ gui#button_clean#misc#set_sensitive false;
+ gui#button_build#misc#set_sensitive false;
+ (Gtk_tools.combo_widget target_combo)#misc#set_sensitive false;
+ (Gtk_tools.combo_widget flash_combo)#misc#set_sensitive false;
+ log (sprintf "Error airframe file not found: %s\n" x);
+ Xml.Element ("airframe", [], []);
+ in
let settings_modules = try
- let af_xml = Xml.parse_file (Env.paparazzi_home // "conf" // (Xml.attrib aircraft "airframe")) in
get_settings_modules af_xml (ExtXml.attrib_or_default aircraft "settings_modules" "")
with
| Failure x -> prerr_endline x; []
@@ -326,23 +340,33 @@ let ac_combo_handler = fun gui (ac_combo:Gtk_tools.combo) target_combo flash_com
and gui_color = ExtXml.attrib_or_default aircraft "gui_color" "white" in
gui#button_clean#misc#set_sensitive true;
gui#button_build#misc#set_sensitive true;
+ gui#button_upload#misc#set_sensitive true;
gui#eventbox_gui_color#misc#modify_bg [`NORMAL, `NAME gui_color];
current_color := gui_color;
gui#entry_ac_id#set_text ac_id;
(Gtk_tools.combo_widget target_combo)#misc#set_sensitive true;
(Gtk_tools.combo_widget flash_combo)#misc#set_sensitive true;
- let last_flash_mode = Gtk_tools.combo_value flash_combo in
- parse_ac_targets target_combo (ExtXml.attrib aircraft "airframe") log;
- parse_ac_flash (Gtk_tools.combo_value target_combo) flash_combo (ExtXml.attrib aircraft "airframe");
+ let last_flash_mode = try Gtk_tools.combo_value flash_combo with _ -> "Default" in
+ begin
+ (* try parsing target from airframe file, may fail if not valid *)
+ try parse_ac_targets target_combo (ExtXml.attrib aircraft "airframe") log with _ ->
+ (Gtk_tools.combo_widget target_combo)#misc#set_sensitive false;
+ gui#button_build#misc#set_sensitive false
+ end;
+ begin
+ try parse_ac_flash (Gtk_tools.combo_value target_combo) flash_combo (ExtXml.attrib aircraft "airframe") with _ ->
+ (Gtk_tools.combo_widget flash_combo)#misc#set_sensitive false;
+ gui#button_upload#misc#set_sensitive false
+ end;
Gtk_tools.select_in_combo flash_combo last_flash_mode;
with
Not_found ->
- gui#label_airframe#set_text "";
- gui#label_flight_plan#set_text "";
- gui#button_clean#misc#set_sensitive false;
+ (* Not found in aircrafts hashtbl *)
gui#button_build#misc#set_sensitive false;
+ gui#button_clean#misc#set_sensitive false;
(Gtk_tools.combo_widget target_combo)#misc#set_sensitive false;
- (Gtk_tools.combo_widget flash_combo)#misc#set_sensitive false
+ (Gtk_tools.combo_widget flash_combo)#misc#set_sensitive false;
+ log (sprintf "Aircraft %s not in conf\n" ac_name)
in
Gtk_tools.combo_connect ac_combo update_params;