Merge pull request #494 'guidance_h_quat'

Don't pretend that the commands from guidance_h are actually real euler angles.
Compose a roll/pitch quaternion from simultaneous rotation of roll/pitch,
then rotate around resulting body z-axis to align the heading.

This should "fix" the setpoint passed to the attitude stabilization if in HOVER or NAV
at large angles and in cases of where heading_sp != current heading.
This commit is contained in:
Felix Ruess
2013-09-01 17:06:40 +02:00
9 changed files with 152 additions and 21 deletions
@@ -253,12 +253,12 @@ void guidance_h_run(bool_t in_flight) {
guidance_h_nav_enter();
if (horizontal_mode == HORIZONTAL_MODE_ATTITUDE) {
struct Int32Eulers sp_euler_i;
sp_euler_i.phi = nav_roll;
sp_euler_i.theta = nav_pitch;
struct Int32Eulers sp_cmd_i;
sp_cmd_i.phi = nav_roll;
sp_cmd_i.theta = nav_pitch;
/* FIXME: heading can't be set via attitude block yet, use current heading for now */
sp_euler_i.psi = stateGetNedToBodyEulers_i()->psi;
stabilization_attitude_set_from_eulers_i(&sp_euler_i);
sp_cmd_i.psi = stateGetNedToBodyEulers_i()->psi;
stabilization_attitude_set_cmd_i(&sp_cmd_i);
}
else {
INT32_VECT2_NED_OF_ENU(guidance_h_pos_sp, navigation_carrot);
@@ -267,6 +267,7 @@ void guidance_h_run(bool_t in_flight) {
/* set psi command */
guidance_h_command_body.psi = nav_heading;
INT32_ANGLE_NORMALIZE(guidance_h_command_body.psi);
/* compute roll and pitch commands and set final attitude setpoint */
guidance_h_traj_run(in_flight);
}
@@ -362,8 +363,8 @@ static void guidance_h_traj_run(bool_t in_flight) {
guidance_h_command_body.phi += guidance_h_rc_sp.phi;
guidance_h_command_body.theta += guidance_h_rc_sp.theta;
/* Set attitude setpoint from pseudo-eulers */
stabilization_attitude_set_from_eulers_i(&guidance_h_command_body);
/* Set attitude setpoint from pseudo-euler commands */
stabilization_attitude_set_cmd_i(&guidance_h_command_body);
}
static void guidance_h_hover_enter(void) {
@@ -217,6 +217,7 @@ void guidance_v_run(bool_t in_flight) {
if (fms.enabled && fms.input.v_mode == GUIDANCE_V_MODE_HOVER)
guidance_v_z_sp = fms.input.v_sp.height;
#endif
guidance_v_zd_sp = 0;
gv_update_ref_from_z_sp(guidance_v_z_sp);
run_hover_loop(in_flight);
#if NO_RC_THRUST_LIMIT
@@ -231,6 +232,7 @@ void guidance_v_run(bool_t in_flight) {
{
if (vertical_mode == VERTICAL_MODE_ALT) {
guidance_v_z_sp = -nav_flight_altitude;
guidance_v_zd_sp = 0;
gv_update_ref_from_z_sp(guidance_v_z_sp);
run_hover_loop(in_flight);
}
@@ -34,7 +34,7 @@ extern void stabilization_attitude_init(void);
extern void stabilization_attitude_read_rc(bool_t in_flight);
extern void stabilization_attitude_enter(void);
extern void stabilization_attitude_set_failsafe_setpoint(void);
extern void stabilization_attitude_set_from_eulers_i(struct Int32Eulers *sp_euler);
extern void stabilization_attitude_set_cmd_i(struct Int32Eulers *sp_cmd);
extern void stabilization_attitude_run(bool_t in_flight);
@@ -86,8 +86,8 @@ void stabilization_attitude_set_failsafe_setpoint(void) {
stab_att_sp_euler.psi = stateGetNedToBodyEulers_f()->psi;
}
void stabilization_attitude_set_from_eulers_i(struct Int32Eulers *sp_euler) {
EULERS_FLOAT_OF_BFP(stab_att_sp_euler, *sp_euler);
void stabilization_attitude_set_cmd_i(struct Int32Eulers *sp_cmd) {
EULERS_FLOAT_OF_BFP(stab_att_sp_euler, *sp_cmd);
}
@@ -102,8 +102,8 @@ void stabilization_attitude_set_failsafe_setpoint(void) {
stab_att_sp_euler.psi = stateGetNedToBodyEulers_i()->psi;
}
void stabilization_attitude_set_from_eulers_i(struct Int32Eulers *sp_euler) {
memcpy(&stab_att_sp_euler, sp_euler, sizeof(struct Int32Eulers));
void stabilization_attitude_set_cmd_i(struct Int32Eulers *sp_cmd) {
memcpy(&stab_att_sp_euler, sp_cmd, sizeof(struct Int32Eulers));
}
@@ -78,7 +78,7 @@ void stabilization_attitude_set_failsafe_setpoint(void) {
stab_att_sp_euler.psi = stateGetNedToBodyEulers_i()->psi;
}
void stabilization_attitude_set_from_eulers_i(struct Int32Eulers *sp_euler) {
memcpy(&stab_att_sp_euler, sp_euler, sizeof(struct Int32Eulers));
void stabilization_attitude_set_cmd_i(struct Int32Eulers *sp_cmd) {
memcpy(&stab_att_sp_euler, sp_cmd, sizeof(struct Int32Eulers));
}
@@ -142,9 +142,61 @@ void stabilization_attitude_set_failsafe_setpoint(void) {
stab_att_sp_quat.qz = sinf(heading2);
}
void stabilization_attitude_set_from_eulers_i(struct Int32Eulers *sp_euler) {
EULERS_FLOAT_OF_BFP(stab_att_sp_euler, *sp_euler);
FLOAT_QUAT_OF_EULERS(stab_att_sp_quat, stab_att_sp_euler);
void stabilization_attitude_set_cmd_i(struct Int32Eulers *sp_cmd) {
EULERS_FLOAT_OF_BFP(stab_att_sp_euler, *sp_cmd);
/* orientation vector describing simultaneous rotation of roll/pitch */
struct FloatVect3 ov;
ov.x = stab_att_sp_euler.phi;
ov.y = stab_att_sp_euler.theta;
ov.z = 0.0;
/* quaternion from that orientation vector */
struct FloatQuat q_rp;
FLOAT_QUAT_OF_ORIENTATION_VECT(q_rp, ov);
/// @todo optimize yaw angle calculation
/*
* Instead of using the psi setpoint angle to rotate around the body z-axis,
* calculate the real angle needed to align the projection of the body x-axis
* onto the horizontal plane with the psi setpoint.
*
* angle between two vectors a and b:
* angle = atan2(norm(cross(a,b)), dot(a,b))
*/
const struct FloatVect3 xaxis = {1.0, 0.0, 0.0};
const struct FloatVect3 zaxis = {0.0, 0.0, 1.0};
struct FloatVect3 a;
FLOAT_QUAT_VMULT(a, q_rp, xaxis);
// desired heading vect in earth x-y plane
struct FloatVect3 psi_vect;
psi_vect.x = cosf(stab_att_sp_euler.psi);
psi_vect.y = sinf(stab_att_sp_euler.psi);
psi_vect.z = 0.0;
struct FloatVect3 normal;
FLOAT_QUAT_VMULT(normal, q_rp, zaxis);
// projection of desired heading onto body x-y plane
// b = v - dot(v,n)*n
float dot = FLOAT_VECT3_DOT_PRODUCT(psi_vect, normal);
struct FloatVect3 dotn;
FLOAT_VECT3_SMUL(dotn, normal, dot);
struct FloatVect3 b;
FLOAT_VECT3_DIFF(b, psi_vect, dotn);
dot = FLOAT_VECT3_DOT_PRODUCT(a, b);
struct FloatVect3 cross;
VECT3_CROSS_PRODUCT(cross, a, b);
// norm of the cross product
float nc = FLOAT_VECT3_NORM(cross);
float yaw2 = atan2(nc, dot) / 2.0;
/* quaternion with yaw command */
struct FloatQuat q_yaw;
QUAT_ASSIGN(q_yaw, cosf(yaw2), 0.0, 0.0, sinf(yaw2));
/* final setpoint: apply roll/pitch, then yaw around resulting body z-axis */
FLOAT_QUAT_COMP(stab_att_sp_quat, q_yaw, q_rp);
FLOAT_QUAT_WRAP_SHORTEST(stab_att_sp_quat);
}
@@ -92,11 +92,71 @@ void stabilization_attitude_set_failsafe_setpoint(void) {
PPRZ_ITRIG_SIN(stab_att_sp_quat.qz, heading2);
}
void stabilization_attitude_set_from_eulers_i(struct Int32Eulers *sp_euler) {
void stabilization_attitude_set_cmd_i(struct Int32Eulers *sp_cmd) {
// copy euler setpoint for debugging
memcpy(&stab_att_sp_euler, sp_euler, sizeof(struct Int32Eulers));
INT32_QUAT_OF_EULERS(stab_att_sp_quat, *sp_euler);
INT32_QUAT_WRAP_SHORTEST(stab_att_sp_quat);
memcpy(&stab_att_sp_euler, sp_cmd, sizeof(struct Int32Eulers));
/// @todo calc sp_quat in fixed-point
/* orientation vector describing simultaneous rotation of roll/pitch */
struct FloatVect3 ov;
ov.x = ANGLE_FLOAT_OF_BFP(sp_cmd->phi);
ov.y = ANGLE_FLOAT_OF_BFP(sp_cmd->theta);
ov.z = 0.0;
/* quaternion from that orientation vector */
struct FloatQuat q_rp;
FLOAT_QUAT_OF_ORIENTATION_VECT(q_rp, ov);
const float psi_sp = ANGLE_FLOAT_OF_BFP(sp_cmd->psi);
/// @todo optimize yaw angle calculation
/*
* Instead of using the psi setpoint angle to rotate around the body z-axis,
* calculate the real angle needed to align the projection of the body x-axis
* onto the horizontal plane with the psi setpoint.
*
* angle between two vectors a and b:
* angle = atan2(norm(cross(a,b)), dot(a,b))
*/
const struct FloatVect3 xaxis = {1.0, 0.0, 0.0};
const struct FloatVect3 zaxis = {0.0, 0.0, 1.0};
struct FloatVect3 a;
FLOAT_QUAT_VMULT(a, q_rp, xaxis);
// desired heading vect in earth x-y plane
struct FloatVect3 psi_vect;
psi_vect.x = cosf(psi_sp);
psi_vect.y = sinf(psi_sp);
psi_vect.z = 0.0;
struct FloatVect3 normal;
FLOAT_QUAT_VMULT(normal, q_rp, zaxis);
// projection of desired heading onto body x-y plane
// b = v - dot(v,n)*n
float dot = FLOAT_VECT3_DOT_PRODUCT(psi_vect, normal);
struct FloatVect3 dotn;
FLOAT_VECT3_SMUL(dotn, normal, dot);
struct FloatVect3 b;
FLOAT_VECT3_DIFF(b, psi_vect, dotn);
dot = FLOAT_VECT3_DOT_PRODUCT(a, b);
struct FloatVect3 cross;
VECT3_CROSS_PRODUCT(cross, a, b);
// norm of the cross product
float nc = FLOAT_VECT3_NORM(cross);
float yaw2 = atan2(nc, dot) / 2.0;
/* quaternion with yaw command */
struct FloatQuat q_yaw;
QUAT_ASSIGN(q_yaw, cosf(yaw2), 0.0, 0.0, sinf(yaw2));
/* final setpoint: apply roll/pitch, then yaw around resulting body z-axis */
struct FloatQuat q_sp;
FLOAT_QUAT_COMP(q_sp, q_yaw, q_rp);
FLOAT_QUAT_WRAP_SHORTEST(q_sp);
/* convert to fixed point */
QUAT_BFP_OF_REAL(stab_att_sp_quat, q_sp);
}
#define OFFSET_AND_ROUND(_a, _b) (((_a)+(1<<((_b)-1)))>>(_b))
+16
View File
@@ -647,6 +647,22 @@ static inline float float_rmat_reorthogonalize(struct FloatRMat* rm) {
(_q).qz = san * (_uv).z; \
}
#define FLOAT_QUAT_OF_ORIENTATION_VECT(_q, _ov) { \
const float ov_norm = sqrtf((_ov).x*(_ov).x + (_ov).y*(_ov).y + (_ov).z*(_ov).z); \
if (ov_norm < 1e-8) { \
(_q).qi = 1; \
(_q).qx = 0; \
(_q).qy = 0; \
(_q).qz = 0; \
} else { \
const float s2_normalized = sinf(ov_norm/2.0) / ov_norm; \
(_q).qi = cosf(ov_norm/2.0); \
(_q).qx = (_ov).x * s2_normalized; \
(_q).qy = (_ov).y * s2_normalized; \
(_q).qz = (_ov).z * s2_normalized; \
} \
}
#define FLOAT_QUAT_OF_RMAT(_q, _r) { \
const float tr = RMAT_TRACE((_r)); \
if (tr > 0) { \