1
1
#include " imu.h"
2
2
3
+ #include < MadgwickAHRS.h>
4
+
3
5
#define IMU_DEFAULT_CALIBRATION_TIME_MS 3000
4
6
7
+ #define IMU_MADGWICK_LOOP_FREQ_HZ 25
8
+
5
9
namespace xrp {
6
10
7
11
unsigned long _imuUpdatePeriod = 1000 / IMU_UPDATE_RATE_HZ;
@@ -12,14 +16,27 @@ bool _imuEnabled = false;
12
16
unsigned long _lastIMUUpdateTime = 0 ;
13
17
bool _imuOnePassComplete = false ;
14
18
15
- float _gyroOffsetsDegPerSec[3 ] = {0 , 0 , 0 };
16
- float _gyroRatesDegPerSec[3 ] = {0 , 0 , 0 };
19
+ float _accelOffsetsG[3 ] = {0 , 0 , 0 };
20
+ float _accelG[3 ] = {0 , 0 , 0 };
21
+
22
+ float _gyroOffsetsDPS[3 ] = {0 , 0 , 0 };
23
+ float _gyroRatesDPS[3 ] = {0 , 0 , 0 };
17
24
float _gyroAnglesDeg[3 ] = {0 , 0 , 0 };
18
25
26
+ float _ahrsOffsets[3 ] = {0 , 0 , 0 };
27
+
28
+ Madgwick _ahrsFilter;
29
+ bool _filterStarted = false ;
30
+ unsigned long _microsPerReading, _microsPrevious;
31
+
19
32
float _radToDeg (float angleRad) {
20
33
return angleRad * 180.0 / PI;
21
34
}
22
35
36
+ float _accelToG (float accelMS2) {
37
+ return accelMS2 / 9.80665 ;
38
+ }
39
+
23
40
bool imuIsReady () {
24
41
return _imuReady;
25
42
}
@@ -96,6 +113,8 @@ void imuCalibrate(unsigned long calibrationTimeMs) {
96
113
Serial.printf (" [IMU] Beginning calibration. Running for %u ms\n " , calibrationTimeMs);
97
114
98
115
float gyroAvgValues[3 ] = {0 , 0 , 0 };
116
+ float accelAvgValues[3 ] = {0 , 0 , 0 };
117
+
99
118
int numVals = 0 ;
100
119
101
120
bool ledBlinkState = true ;
@@ -119,7 +138,13 @@ void imuCalibrate(unsigned long calibrationTimeMs) {
119
138
sensors_event_t temp;
120
139
121
140
_lsm6.getEvent (&accel, &gyro, &temp);
141
+
142
+ // Accelerometer averages
143
+ accelAvgValues[0 ] += _accelToG (accel.acceleration .x );
144
+ accelAvgValues[1 ] += _accelToG (accel.acceleration .y );
145
+ accelAvgValues[2 ] += _accelToG (accel.acceleration .z );
122
146
147
+ // Gyro averages
123
148
gyroAvgValues[0 ] += _radToDeg (gyro.gyro .x );
124
149
gyroAvgValues[1 ] += _radToDeg (gyro.gyro .y );
125
150
gyroAvgValues[2 ] += _radToDeg (gyro.gyro .z );
@@ -128,91 +153,235 @@ void imuCalibrate(unsigned long calibrationTimeMs) {
128
153
delay (loopDelayTime);
129
154
}
130
155
131
- _gyroOffsetsDegPerSec[0 ] = gyroAvgValues[0 ] / numVals;
132
- _gyroOffsetsDegPerSec[1 ] = gyroAvgValues[1 ] / numVals;
133
- _gyroOffsetsDegPerSec[2 ] = gyroAvgValues[2 ] / numVals;
134
-
135
- Serial.printf (" [IMU] Offsets: X(%f) Y(%f) Z(%f)\n " ,
136
- _gyroOffsetsDegPerSec[0 ],
137
- _gyroOffsetsDegPerSec[1 ],
138
- _gyroOffsetsDegPerSec[2 ]);
156
+ _accelOffsetsG[0 ] = accelAvgValues[0 ] / numVals;
157
+ _accelOffsetsG[1 ] = accelAvgValues[1 ] / numVals;
158
+ _accelOffsetsG[2 ] = accelAvgValues[2 ] / numVals;
159
+
160
+ _gyroOffsetsDPS[0 ] = gyroAvgValues[0 ] / numVals;
161
+ _gyroOffsetsDPS[1 ] = gyroAvgValues[1 ] / numVals;
162
+ _gyroOffsetsDPS[2 ] = gyroAvgValues[2 ] / numVals;
163
+
164
+ Serial.printf (" [IMU] Gyro Offsets(dps): X(%f) Y(%f) Z(%f), Accel Offsets(g): X(%f) Y(%f) Z(%f)\n " ,
165
+ _gyroOffsetsDPS[0 ],
166
+ _gyroOffsetsDPS[1 ],
167
+ _gyroOffsetsDPS[2 ],
168
+ _accelOffsetsG[0 ],
169
+ _accelOffsetsG[1 ],
170
+ _accelOffsetsG[2 ]);
139
171
Serial.println (" [IMU] Calibration Complete" );
140
172
141
173
digitalWrite (LED_BUILTIN, LOW);
142
174
}
143
175
144
- bool imuPeriodic () {
176
+ void imuPeriodic () {
177
+ // Initialize the filter if this is the first time we are running through the periodic
178
+ if (!_filterStarted) {
179
+ Serial.printf (" [IMU] Starting Madgwick filter at %u hz\n " , IMU_MADGWICK_LOOP_FREQ_HZ);
180
+ _microsPerReading = 1000000 / IMU_MADGWICK_LOOP_FREQ_HZ;
181
+ _microsPrevious = micros ();
182
+ _ahrsFilter.begin (IMU_MADGWICK_LOOP_FREQ_HZ);
183
+ _filterStarted = true ;
184
+ return ;
185
+ }
186
+
187
+ unsigned long microsNow = micros ();
188
+ if (microsNow - _microsPrevious >= _microsPerReading) {
189
+ // Read data
190
+ sensors_event_t accel;
191
+ sensors_event_t gyro;
192
+ sensors_event_t temp;
193
+
194
+ _lsm6.getEvent (&accel, &gyro, &temp);
195
+
196
+ _gyroRatesDPS[0 ] = _radToDeg (gyro.gyro .x ) - _gyroOffsetsDPS[0 ];
197
+ _gyroRatesDPS[1 ] = _radToDeg (gyro.gyro .y ) - _gyroOffsetsDPS[1 ];
198
+ _gyroRatesDPS[2 ] = _radToDeg (gyro.gyro .z ) - _gyroOffsetsDPS[2 ];
199
+
200
+ _accelG[0 ] = _accelToG (accel.acceleration .x ) - _accelOffsetsG[0 ];
201
+ _accelG[1 ] = _accelToG (accel.acceleration .y ) - _accelOffsetsG[1 ];
202
+ _accelG[2 ] = _accelToG (accel.acceleration .z ) - _accelOffsetsG[2 ];
203
+
204
+ // Update the filter, which will compute orientation
205
+ _ahrsFilter.updateIMU (_accelG[0 ], _accelG[1 ], _accelG[2 ], _gyroRatesDPS[0 ], _gyroRatesDPS[1 ], _gyroRatesDPS[2 ]);
206
+
207
+ // Increment the previous time so that we keep proper pace
208
+ _microsPrevious = _microsPrevious + _microsPerReading;
209
+ }
210
+ }
211
+
212
+ /* *
213
+ * Determine if we have data ready to send upstream
214
+ */
215
+ bool imuDataReady () {
145
216
if (!_imuReady) return false ;
146
217
if (!_imuEnabled) return false ;
147
218
148
219
unsigned long currTime = millis ();
149
220
unsigned long dt = currTime - _lastIMUUpdateTime;
150
221
151
- // Send the IMU data at the specified IMU_UPDATE_RATE_HZ
152
222
if (dt < _imuUpdatePeriod) return false ;
153
223
154
- // Get IMU data
155
- sensors_event_t accel;
156
- sensors_event_t gyro;
157
- sensors_event_t temp;
158
-
159
- _lsm6.getEvent (&accel, &gyro, &temp);
160
-
161
- float rateX = _radToDeg (gyro.gyro .x );
162
- float rateY = _radToDeg (gyro.gyro .y );
163
- float rateZ = _radToDeg (gyro.gyro .z );
164
- _gyroRatesDegPerSec[0 ] = rateX - _gyroOffsetsDegPerSec[0 ];
165
- _gyroRatesDegPerSec[1 ] = rateY - _gyroOffsetsDegPerSec[1 ];
166
- _gyroRatesDegPerSec[2 ] = rateZ - _gyroOffsetsDegPerSec[2 ];
167
-
168
- // We can't integrate with only a single value, so bail out
169
- if (!_imuOnePassComplete) {
170
- _imuOnePassComplete = true ;
171
- _lastIMUUpdateTime = currTime;
172
- return false ;
173
- }
224
+ _lastIMUUpdateTime = currTime;
225
+ return true ;
226
+ }
227
+
228
+ // bool imuPeriodic() {
229
+ // if (!_imuReady) return false;
230
+ // if (!_imuEnabled) return false;
231
+
232
+ // unsigned long currTime = millis();
233
+ // unsigned long dt = currTime - _lastIMUUpdateTime;
234
+
235
+ // // Send the IMU data at the specified IMU_UPDATE_RATE_HZ
236
+ // if (dt < _imuUpdatePeriod) return false;
237
+
238
+ // // Get IMU data
239
+ // sensors_event_t accel;
240
+ // sensors_event_t gyro;
241
+ // sensors_event_t temp;
242
+
243
+ // _lsm6.getEvent(&accel, &gyro, &temp);
244
+
245
+ // float rateX = _radToDeg(gyro.gyro.x);
246
+ // float rateY = _radToDeg(gyro.gyro.y);
247
+ // float rateZ = _radToDeg(gyro.gyro.z);
248
+ // _gyroRatesDPS[0] = rateX - _gyroOffsetsDPS[0];
249
+ // _gyroRatesDPS[1] = rateY - _gyroOffsetsDPS[1];
250
+ // _gyroRatesDPS[2] = rateZ - _gyroOffsetsDPS[2];
251
+
252
+ // // We can't integrate with only a single value, so bail out
253
+ // if (!_imuOnePassComplete) {
254
+ // _imuOnePassComplete = true;
255
+ // _lastIMUUpdateTime = currTime;
256
+ // return false;
257
+ // }
174
258
175
- float dtInSeconds = dt / 1000.0 ;
259
+ // float dtInSeconds = dt / 1000.0;
260
+
261
+ // for (int i = 0; i < 3; i++) {
262
+ // _gyroAnglesDeg[i] = _gyroAnglesDeg[i] + (_gyroRatesDPS[i] * dtInSeconds);
263
+ // }
264
+
265
+ // _lastIMUUpdateTime = currTime;
266
+ // return true;
267
+ // }
268
+
269
+ // ===============================
270
+ // AHRS Values
271
+ // ===============================
272
+
273
+ /* *
274
+ * Get acceleration in the X axis
275
+ *
276
+ * @return Acceleration in X (in G)
277
+ */
278
+ float imuGetAccelX () {
279
+ return _accelG[0 ];
280
+ }
176
281
177
- for (int i = 0 ; i < 3 ; i++) {
178
- _gyroAnglesDeg[i] = _gyroAnglesDeg[i] + (_gyroRatesDegPerSec[i] * dtInSeconds);
179
- }
282
+ /* *
283
+ * Get acceleration in the Y axis
284
+ *
285
+ * @return Acceleration in Y (in G)
286
+ */
287
+ float imuGetAccelY () {
288
+ return _accelG[1 ];
289
+ }
180
290
181
- _lastIMUUpdateTime = currTime;
182
- return true ;
291
+ /* *
292
+ * Get acceleration in the Z axis
293
+ *
294
+ * @return Acceleration in Z (in G)
295
+ */
296
+ float imuGetAccelZ () {
297
+ return _accelG[2 ];
183
298
}
184
299
185
- float gyroGetAngleX () {
186
- return _gyroAnglesDeg[0 ];
300
+ /* *
301
+ * Get gyro rate in the X axis
302
+ *
303
+ * @return Gyro rate in X (in DPS)
304
+ */
305
+ float imuGetGyroRateX () {
306
+ return _gyroRatesDPS[0 ];
187
307
}
188
308
189
- float gyroGetRateX () {
190
- return _gyroRatesDegPerSec[0 ];
309
+ /* *
310
+ * Get gyro rate in the Y axis
311
+ *
312
+ * @return Gyro rate in Y (in DPS)
313
+ */
314
+ float imuGetGyroRateY () {
315
+ return _gyroRatesDPS[1 ];
191
316
}
192
317
193
- float gyroGetAngleY () {
194
- return _gyroAnglesDeg[1 ];
318
+ /* *
319
+ * Get gyro rate in the Z axis
320
+ *
321
+ * @return Gyro rate in Z (in DPS)
322
+ */
323
+ float imuGetGyroRateZ () {
324
+ return _gyroRatesDPS[2 ];
195
325
}
196
326
197
- float gyroGetRateY () {
198
- return _gyroRatesDegPerSec[1 ];
327
+ /* *
328
+ * Get current roll angle
329
+ *
330
+ * @return Current roll angle (in degrees)
331
+ */
332
+ float imuGetRoll () {
333
+ return _ahrsFilter.getRoll () - _ahrsOffsets[0 ];
199
334
}
200
335
201
- float gyroGetAngleZ () {
202
- return _gyroAnglesDeg[2 ];
336
+ /* *
337
+ * Get current pitch angle
338
+ *
339
+ * @return Current pitch angle (in degrees)
340
+ */
341
+ float imuGetPitch () {
342
+ return _ahrsFilter.getPitch () - _ahrsOffsets[1 ];
203
343
}
204
344
205
- float gyroGetRateZ () {
206
- return _gyroRatesDegPerSec[2 ];
345
+ /* *
346
+ * Get current yaw angle
347
+ *
348
+ * @return Current yaw angle (in degrees)
349
+ */
350
+ float imuGetYaw () {
351
+ return _ahrsFilter.getYaw () - _ahrsOffsets[2 ];
207
352
}
208
353
209
- void gyroReset () {
210
- for (int i = 0 ; i < 3 ; i++) {
211
- _gyroRatesDegPerSec[i] = 0 ;
212
- _gyroAnglesDeg[i] = 0 ;
213
- }
354
+ /* *
355
+ * Reset the roll angle.
356
+ *
357
+ * The AHRS filter always runs, so this basically sets an offset value
358
+ */
359
+ void imuResetRoll () {
360
+ _ahrsOffsets[0 ] = _ahrsFilter.getRoll ();
361
+ }
362
+
363
+ /* *
364
+ * Reset the pitch angle.
365
+ *
366
+ * The AHRS filter always runs, so this basically sets an offset value
367
+ */
368
+ void imuResetPitch () {
369
+ _ahrsOffsets[1 ] = _ahrsFilter.getPitch ();
370
+ }
214
371
215
- _imuOnePassComplete = false ;
372
+ /* *
373
+ * Reset the yaw angle.
374
+ *
375
+ * The AHRS filter always runs, so this basically sets an offset value
376
+ */
377
+ void imuResetYaw () {
378
+ _ahrsOffsets[2 ] = _ahrsFilter.getYaw ();
379
+ }
380
+
381
+ void gyroReset () {
382
+ imuResetRoll ();
383
+ imuResetPitch ();
384
+ imuResetYaw ();
216
385
}
217
386
218
387
} // namespace xrp
0 commit comments