-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAP_Inertial_Nav.c
225 lines (182 loc) · 8.36 KB
/
AP_Inertial_Nav.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#include "Vector3f.h"
#include "Matrix3f.h"
#include "AP_AHRS_DCM.h"
#include "AP_Baro.h"
#include "AP_BufferFloat.h"
#include "confige.h"
#include "AP_Math.h"
#include <string.h>
#include <stdio.h>
#include "AP_Inertial_Nav.h"
void ap_inertial_nav_check_baro(AP_Inertial_Nav *ap_inertial_nav);
void ap_inertial_nav_correct_with_baro(AP_Inertial_Nav *ap_inertial_nav, float baro_alt, float dt);
void ap_inertial_nav_set_altitude(AP_Inertial_Nav *ap_inertial_nav, float new_altitude);
//
// Private methods
//
// update_gains - update gains from time constant (given in seconds)
void ap_inertial_nav_update_gains(AP_Inertial_Nav *ap_inertial_nav);
// set_velocity_z - get latest climb rate (in cm/s)
void ap_inertial_nav_set_velocity_z(AP_Inertial_Nav *ap_inertial_nav, float z );
// init - initialise library
void ap_inertial_nav_init(AP_Inertial_Nav *ap_inertial_nav, AP_AHRS_DCM *ap_ahrs_dcm, AP_Baro *ap_baro)
{
ap_inertial_nav->accel_correction.x = ap_inertial_nav->accel_correction.y
= ap_inertial_nav->accel_correction.z = 0.0F;
ap_inertial_nav->_ahrs = ap_ahrs_dcm;
ap_inertial_nav->_baro = ap_baro;
ap_inertial_nav->_time_constant_z = AP_INTERTIALNAV_TC_Z;
ap_inertial_nav_update_gains(ap_inertial_nav);
ap_inertial_nav->_baro_last_update = 0;
ap_bufferfloat_init(&ap_inertial_nav->_hist_position_estimate_z, 15);
ap_inertial_nav->_first_read_baro = 0;
ap_inertial_nav->_position_base.x = ap_inertial_nav->_position_base.y
= ap_inertial_nav->_position_base.z = 0;
ap_inertial_nav->_position_correction.x = ap_inertial_nav->_position_correction.y
= ap_inertial_nav->_position_correction.z = 0;
ap_inertial_nav->_velocity.x = ap_inertial_nav->_velocity.y
= ap_inertial_nav->_velocity.z = 0;
}
// update - updates velocities and positions using latest info from ahrs, ins and barometer if new data is available;
void ap_inertial_nav_update(AP_Inertial_Nav *ap_inertial_nav, float dt)
{
Vector3f acc_corr = ap_inertial_nav->accel_correction;
Vector3f accel_ef;
Vector3f velocity_increase;
Matrix3f dcm;
Vector3f vector3f_tmp;
// discard samples where dt is too large
if( dt > 0.1 ) {
return;
}
// check barometer
ap_inertial_nav_check_baro(ap_inertial_nav);
// convert accelerometer readings to earth frame
dcm = ap_inertial_nav->_ahrs->dcm_matrix;
accel_ef = ap_inertial_nav->_ahrs->_accel_ef;
// remove influence of gravity
accel_ef.z += GRAVITY;
accel_ef = vector3f_multiply_by_coefficient(&accel_ef, 100.0F);
// get earth frame accelerometer correction
ap_inertial_nav->accel_correction_ef = matrix3f_mul_transpose(&dcm, &acc_corr);
// calculate velocity increase adding new acceleration from accelerometers
//velocity_increase = (-accel_ef + accel_correction_ef) * dt;
vector3f_tmp = vector3f_multiply_by_coefficient(&accel_ef, -1);
vector3f_tmp = vector3f_plus(&vector3f_tmp, &ap_inertial_nav->accel_correction_ef);
velocity_increase = vector3f_multiply_by_coefficient(&vector3f_tmp, dt);
// calculate new estimate of position
//_position_base += (_velocity + velocity_increase*0.5) * dt;
vector3f_tmp = vector3f_multiply_by_coefficient(&velocity_increase, 0.5);
vector3f_tmp = vector3f_plus(&ap_inertial_nav->_velocity, &vector3f_tmp);
vector3f_tmp = vector3f_multiply_by_coefficient(&vector3f_tmp, dt);
ap_inertial_nav->_position_base = vector3f_plus(&ap_inertial_nav->_position_base, &vector3f_tmp);
// calculate new velocity
//_velocity += velocity_increase;
ap_inertial_nav->_velocity = vector3f_plus(&ap_inertial_nav->_velocity, &velocity_increase);
// store 3rd order estimate (i.e. estimated vertical position) for future use
//_hist_position_estimate_z.add(_position_base.z);
ap_bufferfloat_add(&ap_inertial_nav->_hist_position_estimate_z, ap_inertial_nav->_position_base.z);
}
//
// Z Axis methods
//
// check_baro - check if new baro readings have arrived and use them to correct vertical accelerometer offsets
void ap_inertial_nav_check_baro(AP_Inertial_Nav *ap_inertial_nav)
{
unsigned long baro_update_time;
if( ap_inertial_nav->_baro == NULL )
return;
// calculate time since last baro reading
baro_update_time = ap_inertial_nav->_baro->last_update;
if( baro_update_time != ap_inertial_nav->_baro_last_update ) {
float dt = (float)(baro_update_time - ap_inertial_nav->_baro_last_update) / 1000.0F;
// call correction method
ap_inertial_nav_correct_with_baro(ap_inertial_nav, ap_inertial_nav->_baro->altitude, dt);
ap_inertial_nav->_baro_last_update = baro_update_time;
}
}
// correct_with_baro - modifies accelerometer offsets using barometer. dt is time since last baro reading
void ap_inertial_nav_correct_with_baro(AP_Inertial_Nav *ap_inertial_nav, float baro_alt, float dt)
{
float hist_position_base_z;
float accel_ef_z_correction;
Matrix3f dcm;
Vector3f accel_corr;
float err;
// discard samples where dt is too large
if( dt > 0.5 ) {
return;
}
// discard first 10 reads but perform some initialisation
if( ap_inertial_nav->_first_read_baro <= 10 ) {
ap_inertial_nav_set_altitude(ap_inertial_nav, baro_alt);
ap_inertial_nav->_first_read_baro++;
}
// get dcm matrix
dcm = ap_inertial_nav->_ahrs->dcm_matrix;
// 3rd order samples (i.e. position from baro) are delayed by 150ms (15 iterations at 100hz)
// so we should calculate error using historical estimates
if( ap_inertial_nav->_hist_position_estimate_z.num_items >= 15 ) {
hist_position_base_z = ap_bufferfloat_peek(&ap_inertial_nav->_hist_position_estimate_z, 14);
}else{
hist_position_base_z = ap_inertial_nav->_position_base.z;
}
// calculate error in position from baro with our estimate
err = baro_alt - (hist_position_base_z + ap_inertial_nav->_position_correction.z);
// retrieve the existing accelerometer corrections
accel_corr = ap_inertial_nav->accel_correction;
// calculate the accelerometer correction from this iteration in the earth frame
accel_ef_z_correction = err * ap_inertial_nav->_k3_z * dt;
// rotate the correction into the body frame (note: this is a shortened form of dcm.mul_transpose(..) because we have only one axis
accel_corr.x += accel_ef_z_correction * dcm.c.x;
accel_corr.y += accel_ef_z_correction * dcm.c.y;
accel_corr.z += accel_ef_z_correction * dcm.c.z;
// ensure corrections are reasonable
accel_corr.x = constrain(accel_corr.x,-AP_INTERTIALNAV_ACCEL_CORR_MAX,AP_INTERTIALNAV_ACCEL_CORR_MAX);
accel_corr.y = constrain(accel_corr.y,-AP_INTERTIALNAV_ACCEL_CORR_MAX,AP_INTERTIALNAV_ACCEL_CORR_MAX);
accel_corr.z = constrain(accel_corr.z,-AP_INTERTIALNAV_ACCEL_CORR_MAX,AP_INTERTIALNAV_ACCEL_CORR_MAX);
// set the parameter to include the corrections
ap_inertial_nav->accel_correction = accel_corr;
// correct velocity
ap_inertial_nav->_velocity.z += (err * ap_inertial_nav->_k2_z) * dt;
// correct position
ap_inertial_nav->_position_correction.z += err * ap_inertial_nav->_k1_z * dt;
}
// set_altitude - set base altitude estimate in cm
void ap_inertial_nav_set_altitude(AP_Inertial_Nav *ap_inertial_nav, float new_altitude)
{
ap_inertial_nav->_position_base.z = new_altitude;
ap_inertial_nav->_position_correction.z = 0;
}
//
// Private methods
//
// update_gains - update gains from time constant (given in seconds)
void ap_inertial_nav_update_gains(AP_Inertial_Nav *ap_inertial_nav)
{
// Z axis time constant
if( ap_inertial_nav->_time_constant_z == 0 ) {
ap_inertial_nav->_k1_z = ap_inertial_nav->_k2_z = ap_inertial_nav->_k3_z = 0;
}else{
ap_inertial_nav->_k1_z = 3 / ap_inertial_nav->_time_constant_z;
ap_inertial_nav->_k2_z = 3 / (ap_inertial_nav->_time_constant_z * ap_inertial_nav->_time_constant_z);
ap_inertial_nav->_k3_z = 1 / (ap_inertial_nav->_time_constant_z * ap_inertial_nav->_time_constant_z
* ap_inertial_nav->_time_constant_z);
}
}
// set_velocity_z - get latest climb rate (in cm/s)
void ap_inertial_nav_set_velocity_z(AP_Inertial_Nav *ap_inertial_nav, float z )
{
ap_inertial_nav->_velocity.z = z;
}
// void ap_inertial_nav_print(AP_Inertial_Nav *ap_inertial_nav)
// {
// Vector3f *pos_base = &ap_inertial_nav->_position_base;
// Vector3f *pos_corr = &ap_inertial_nav->_position_correction;
// Vector3f *v = &ap_inertial_nav->_velocity;
// printf("=================AP_INERTIAL_NAV===============\n");
// printf("position_base: [%f, %f, %f]\n", pos_base->x, pos_base->y, pos_base->z);
// printf("position_correction: [%f, %f, %f]\n", pos_corr->x, pos_corr->y, pos_corr->z);
// printf("velocity: [%f, %f, %f]\n", v->x, v->y, v->z);
// printf("================================================\n");
// }