Skip to content

Commit 61906b4

Browse files
Merge pull request #53 from larus-breeze/add_fine_tune_orientation
Add fine tune sensor orientation
2 parents 31a9ab9 + 784c4eb commit 61906b4

File tree

3 files changed

+137
-63
lines changed

3 files changed

+137
-63
lines changed

Generic_Algorithms/quaternion.h

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -78,28 +78,6 @@ template <class datatype > class quaternion: public vector <datatype, 4>
7878
return _euler;
7979
}
8080

81-
//! quaternion chaining, multiplication
82-
quaternion<datatype> operator *( const quaternion<datatype> right) const
83-
{
84-
quaternion<datatype> result;
85-
datatype w1 = vector<datatype, 4>::e[0];
86-
datatype x1 = vector<datatype, 4>::e[1];
87-
datatype y1 = vector<datatype, 4>::e[2];
88-
datatype z1 = vector<datatype, 4>::e[3];
89-
90-
datatype w2 = right[0];
91-
datatype x2 = right[1];
92-
datatype y2 = right[2];
93-
datatype z2 = right[3];
94-
95-
result[0] = w1*w2 - x1*x2 - y1*y2 - z1*z2;
96-
result[1] = w1*x2 + x1*w2 + y1*z2 - z1*y2;
97-
result[2] = w1*y2 - x1*z2 + y1*w2 + z1*x2;
98-
result[3] = w1*z2 + x1*y2 - y1*x2 + z1*w2;
99-
100-
return result;
101-
}
102-
10381
//! get north component of attitude
10482
inline datatype get_north( void) const
10583
{
@@ -208,13 +186,19 @@ template <class datatype > class quaternion: public vector <datatype, 4>
208186
datatype re1=right.e[1];
209187
datatype re2=right.e[2];
210188
datatype re3=right.e[3];
211-
result.e[0] = e0 * re0 - e1 * re1 - e2 * re2 + e3 * re3;
189+
result.e[0] = e0 * re0 - e1 * re1 - e2 * re2 - e3 * re3;
212190
result.e[1] = e1 * re0 + e2 * re3 - e3 * re2 + e0 * re1;
213191
result.e[2] = e3 * re1 + e0 * re2 - e1 * re3 + e2 * re0;
214192
result.e[3] = e1 * re2 - e2 * re1 + e0 * re3 + e3 * re0;
215193
return result;
216194
}
217195

196+
quaternion <datatype> operator *= ( const quaternion <datatype> & right) //!< quaternion multiplication
197+
{
198+
*this = *this * right;
199+
return *this;
200+
}
201+
218202
void from_rotation_matrix( matrix<datatype, 3> &rotm) //!< rotation matrix -> quaternion transformation
219203
{
220204
float tmp;
@@ -229,5 +213,16 @@ template <class datatype > class quaternion: public vector <datatype, 4>
229213
this->e[3] = tmp * (rotm.e[1][0] - rotm.e[0][1]);
230214
normalize(); // compensate computational inaccuracies
231215
};
216+
217+
quaternion <datatype> inverse( void)
218+
{
219+
quaternion <datatype> retv;
220+
retv[0] = this->e[0];
221+
retv[1] = -this->e[1];
222+
retv[2] = -this->e[2];
223+
retv[3] = -this->e[3];
224+
retv.normalize();
225+
return retv;
226+
}
232227
};
233228
#endif // QUATERNION_H

NAV_Algorithms/organizer.h

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,21 @@ class organizer_t
6464
u_front_sensor.normalize();
6565

6666
// calculate the new rotation matrix using our calibration data
67-
sensor_mapping.e[0][0]=u_front_sensor[0];
68-
sensor_mapping.e[0][1]=u_front_sensor[1];
69-
sensor_mapping.e[0][2]=u_front_sensor[2];
67+
float3matrix new_sensor_mapping;
68+
new_sensor_mapping.e[0][0]=u_front_sensor[0];
69+
new_sensor_mapping.e[0][1]=u_front_sensor[1];
70+
new_sensor_mapping.e[0][2]=u_front_sensor[2];
7071

71-
sensor_mapping.e[1][0]=u_right_sensor[0];
72-
sensor_mapping.e[1][1]=u_right_sensor[1];
73-
sensor_mapping.e[1][2]=u_right_sensor[2];
72+
new_sensor_mapping.e[1][0]=u_right_sensor[0];
73+
new_sensor_mapping.e[1][1]=u_right_sensor[1];
74+
new_sensor_mapping.e[1][2]=u_right_sensor[2];
7475

75-
sensor_mapping.e[2][0]=u_down_sensor[0];
76-
sensor_mapping.e[2][1]=u_down_sensor[1];
77-
sensor_mapping.e[2][2]=u_down_sensor[2];
76+
new_sensor_mapping.e[2][0]=u_down_sensor[0];
77+
new_sensor_mapping.e[2][1]=u_down_sensor[1];
78+
new_sensor_mapping.e[2][2]=u_down_sensor[2];
7879

7980
quaternion<float> q;
80-
q.from_rotation_matrix( sensor_mapping);
81+
q.from_rotation_matrix( new_sensor_mapping);
8182
eulerangle<float> euler = q;
8283

8384
// make the change permanent
@@ -88,6 +89,34 @@ class organizer_t
8889
lock_EEPROM( true);
8990
}
9091

92+
void fine_tune_sensor_orientation( const vector_average_collection_t & values)
93+
{
94+
float3vector observed_body_acc = sensor_mapping * values.acc_observed_level;
95+
float pitch_correction = - ATAN2( - observed_body_acc[FRONT], - observed_body_acc[DOWN]);
96+
float roll_correction = + ATAN2( - observed_body_acc[RIGHT], - observed_body_acc[DOWN]);
97+
98+
quaternion<float> q_correction;
99+
q_correction.from_euler( roll_correction, pitch_correction, ZERO);
100+
101+
quaternion<float> q_present_setting;
102+
q_present_setting.from_euler (
103+
configuration (SENS_TILT_ROLL),
104+
configuration (SENS_TILT_PITCH),
105+
configuration (SENS_TILT_YAW));
106+
107+
quaternion<float> q_new_setting;
108+
q_new_setting = q_correction * q_present_setting;
109+
110+
eulerangle<float> new_euler = q_new_setting;
111+
112+
// make the change permanent
113+
lock_EEPROM( false);
114+
write_EEPROM_value( SENS_TILT_ROLL, new_euler.roll);
115+
write_EEPROM_value( SENS_TILT_PITCH, new_euler.pitch);
116+
write_EEPROM_value( SENS_TILT_YAW, new_euler.yaw);
117+
lock_EEPROM( true);
118+
}
119+
91120
void initialize_before_measurement( void)
92121
{
93122
pitot_offset= configuration (PITOT_OFFSET);

NAV_Algorithms/setup_tester.cpp

Lines changed: 80 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "float3vector.h"
22
#include "float3matrix.h"
33
#include "quaternion.h"
4+
#include "AHRS.h"
45

56
const float ldi[]={0.1f, +0.25f, -10.0f}; // left wing down
67
const float rdi[]={0.1f, -0.15f, -10.0f}; // right wing down
@@ -18,73 +19,122 @@ void setup_tester(void)
1819
float3vector horiz_body( hi);
1920

2021
// setup the sensor orientation to test
21-
quaternion<float>sensor_q;
22+
quaternion<float>q_sensor_2_body;
23+
// q_sensor_2_body.from_euler( 0 * M_PI/180.0, 0 * M_PI/180.0, 13 * M_PI/180.0);
24+
q_sensor_2_body.from_euler( 90 * M_PI/180.0, 180.0 * M_PI/180.0, -30 * M_PI/180.0);
2225
// sensor_q.from_euler( 45.0 * M_PI/180.0, 135.0 * M_PI/180.0, -30.0 * M_PI/180.0);
2326
// sensor_q.from_euler( -135.0 * M_PI/180.0, 45.0 * M_PI/180.0, 150.0 * M_PI/180.0);
2427
// sensor_q.from_euler( -10.0 * M_PI/180.0, 75.0 * M_PI/180.0, -45.0 * M_PI/180.0);
25-
sensor_q.from_euler( 10.0 * M_PI/180.0, -75.0 * M_PI/180.0, +125.0 * M_PI/180.0);
28+
// sensor_q.from_euler( 10.0 * M_PI/180.0, -75.0 * M_PI/180.0, +125.0 * M_PI/180.0);
2629

27-
float3matrix sensor_2_body_assumption;
28-
sensor_q.get_rotation_matrix(sensor_2_body_assumption);
30+
float3matrix m_sensor_2_body_assumption;
31+
q_sensor_2_body.get_rotation_matrix( m_sensor_2_body_assumption);
2932

3033
//check if we get the rotation angles using the matrix given
31-
quaternion<float> qin;
32-
qin.from_rotation_matrix(sensor_2_body_assumption);
33-
eulerangle<float> euler_in = qin;
34+
quaternion<float> q_sensor_2_body_assumption;
35+
q_sensor_2_body_assumption.from_rotation_matrix(m_sensor_2_body_assumption);
36+
eulerangle<float> euler_in = q_sensor_2_body_assumption;
3437
euler_in.roll *= 180/M_PI;
3538
euler_in.pitch *= 180/M_PI;
3639
euler_in.yaw *= 180/M_PI;
3740

3841
// map measurements into the sensor frame
39-
float3vector left_down_sensor = sensor_2_body_assumption.reverse_map( left_down_body);
40-
float3vector right_down_sensor= sensor_2_body_assumption.reverse_map( right_down_body);
41-
float3vector horiz_sensor = sensor_2_body_assumption.reverse_map( horiz_body);
42+
float3vector v_left_down_sensor = m_sensor_2_body_assumption.reverse_map( left_down_body);
43+
float3vector v_right_down_sensor= m_sensor_2_body_assumption.reverse_map( right_down_body);
44+
float3vector v_horiz_sensor = m_sensor_2_body_assumption.reverse_map( horiz_body);
4245

4346
// resolve sensor orientation using measurements
44-
float3vector front_down_sensor_helper = right_down_sensor.vector_multiply(left_down_sensor);
45-
float3vector u_right_sensor = front_down_sensor_helper.vector_multiply(horiz_sensor);
47+
float3vector front_down_sensor_helper = v_right_down_sensor.vector_multiply(v_left_down_sensor);
48+
float3vector u_right_sensor = front_down_sensor_helper.vector_multiply(v_horiz_sensor);
4649
u_right_sensor.normalize();
4750

48-
float3vector u_down_sensor = horiz_sensor * -1.0f;
51+
float3vector u_down_sensor = v_horiz_sensor * -1.0f;
4952
u_down_sensor.normalize();
5053

5154
float3vector u_front_sensor=u_right_sensor.vector_multiply(u_down_sensor);
5255
u_front_sensor.normalize();
5356

5457
// calculate the rotation matrix using our calibration data
55-
float3matrix sensor_2_body;
56-
sensor_2_body.e[0][0]=u_front_sensor[0];
57-
sensor_2_body.e[0][1]=u_front_sensor[1];
58-
sensor_2_body.e[0][2]=u_front_sensor[2];
58+
float3matrix m_sensor_2_body;
59+
m_sensor_2_body.e[FRONT][0]=u_front_sensor[0];
60+
m_sensor_2_body.e[FRONT][1]=u_front_sensor[1];
61+
m_sensor_2_body.e[FRONT][2]=u_front_sensor[2];
5962

60-
sensor_2_body.e[1][0]=u_right_sensor[0];
61-
sensor_2_body.e[1][1]=u_right_sensor[1];
62-
sensor_2_body.e[1][2]=u_right_sensor[2];
63+
m_sensor_2_body.e[RIGHT][0]=u_right_sensor[0];
64+
m_sensor_2_body.e[RIGHT][1]=u_right_sensor[1];
65+
m_sensor_2_body.e[RIGHT][2]=u_right_sensor[2];
6366

64-
sensor_2_body.e[2][0]=u_down_sensor[0];
65-
sensor_2_body.e[2][1]=u_down_sensor[1];
66-
sensor_2_body.e[2][2]=u_down_sensor[2];
67+
m_sensor_2_body.e[DOWN][0]=u_down_sensor[0];
68+
m_sensor_2_body.e[DOWN][1]=u_down_sensor[1];
69+
m_sensor_2_body.e[DOWN][2]=u_down_sensor[2];
6770

6871
// test if the rotation matrix recovers the body frame data
69-
float3vector test_left_down_body = sensor_2_body * left_down_sensor;
70-
float3vector test_right_down_body = sensor_2_body * right_down_sensor;
71-
float3vector test_horiz_body = sensor_2_body * horiz_sensor;
72+
float3vector test_left_down_body = m_sensor_2_body * v_left_down_sensor;
73+
float3vector test_right_down_body = m_sensor_2_body * v_right_down_sensor;
74+
float3vector test_horiz_body = m_sensor_2_body * v_horiz_sensor;
7275

7376
// test if the matrix provides pure rotation
74-
float3vector vtest1 = sensor_2_body * float3vector( test1);
77+
float3vector vtest1 = m_sensor_2_body * float3vector( test1);
7578
float test1_abs=vtest1.abs();
76-
float3vector vtest2 = sensor_2_body * float3vector( test2);
79+
float3vector vtest2 = m_sensor_2_body * float3vector( test2);
7780
float test2_abs=vtest2.abs();
78-
float3vector vtest3 = sensor_2_body * float3vector( test3);
81+
float3vector vtest3 = m_sensor_2_body * float3vector( test3);
7982
float test3_abs=vtest3.abs();
8083

8184
//check if we get the rotation angles using the matrix we have calculated
8285
quaternion<float> q;
83-
q.from_rotation_matrix(sensor_2_body);
86+
q.from_rotation_matrix(m_sensor_2_body);
8487
eulerangle<float> euler = q;
8588
euler.roll *= 180/M_PI;
8689
euler.pitch *= 180/M_PI;
8790
euler.yaw *= 180/M_PI;
91+
92+
////////////////////////////////////////////////////////////////////////////////////////////////
93+
94+
// pitch and roll axis fine tuning
95+
float pitch_angle = 0.5f; // sensor nose is higher than configured
96+
float roll_angle = -0.3f; // sensor is looking more left than configured
97+
quaternion<float>q_sensor_ideal_2_misaligned;
98+
q_sensor_ideal_2_misaligned.from_euler( roll_angle, pitch_angle, ZERO);
99+
100+
quaternion<float>q_body_2_world; // looking NE horizontally
101+
q_body_2_world.from_euler( ZERO, ZERO, 45.0f * M_PI_F / 180.0f);
102+
// q_body_2_world.from_euler( ZERO, ZERO, -145.0f * M_PI_F / 180.0f);
103+
104+
// provide simulated measurement
105+
quaternion <float> q_misaligned_sensor_2_world = q_sensor_ideal_2_misaligned;
106+
q_misaligned_sensor_2_world *= q_sensor_2_body;
107+
q_misaligned_sensor_2_world *= q_body_2_world;
108+
109+
euler = q_misaligned_sensor_2_world;
110+
euler.roll *= 180/M_PI;
111+
euler.pitch *= 180/M_PI;
112+
euler.yaw *= 180/M_PI;
113+
114+
float3matrix m_misaligned_sensor_to_world;
115+
q_misaligned_sensor_2_world.get_rotation_matrix( m_misaligned_sensor_to_world);
116+
117+
// simulate measurement
118+
float3vector v_down;
119+
v_down[DOWN] = -10.0f;
120+
float3vector v_measurement_sensor = m_misaligned_sensor_to_world.reverse_map( v_down);
121+
122+
q_sensor_2_body.get_rotation_matrix( m_sensor_2_body);
123+
124+
float3vector v_measurement_body = m_sensor_2_body * v_measurement_sensor;
125+
126+
float3matrix m_body_2_world;
127+
q_body_2_world.get_rotation_matrix(m_body_2_world);
128+
float3vector v_measurement_world = m_body_2_world * v_measurement_body;
129+
130+
float pitch_angle_measured = ATAN2( -v_measurement_world[0], -v_measurement_world[2]);
131+
float roll_angle_measured = ATAN2( -v_measurement_world[1], -v_measurement_world[2]);
132+
133+
// compute corrected sensor alignment quaternion
134+
quaternion <float> q_correction;
135+
q_correction.from_euler( roll_angle_measured, pitch_angle_measured, ZERO);
136+
137+
quaternion<float> q_corrected_sensor_orientation;
88138
}
89139

90140

0 commit comments

Comments
 (0)