Sensor Fusion Library 0.6.1
Orientation sensing for Espressif (ESP32, ESP8266) processors
Loading...
Searching...
No Matches
sensor_fusion.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
12#include <stdio.h>
13
14#include "sensor_fusion.h"
15
16#include "control.h"
17#include "fusion.h"
18#include "hal_i2c.h"
19#include "hal_timer.h"
20#include "status.h"
21
25{
26 sfg->pStatusSubsystem->set(sfg->pStatusSubsystem, status);
27}
28
32{
33 return sfg->pStatusSubsystem->get(sfg->pStatusSubsystem);
34}
35
39{
40 sfg->pStatusSubsystem->queue(sfg->pStatusSubsystem, status);
41}
42
46{
47 sfg->pStatusSubsystem->update(sfg->pStatusSubsystem);
48}
49
50void testStatus(SensorFusionGlobals *sfg)
51{
52 sfg->pStatusSubsystem->test(sfg->pStatusSubsystem);
53}
54
57 StatusSubsystem *pStatusSubsystem,
58 ControlSubsystem *pControlSubsystem)
59{
60 sfg->iFlags = // all of the following defines are either 0x0000 or a 1-bit value (2, 4, 8 ...) and are defined in build.h
66 F_ALL_SENSORS | // refers to all applicable sensor types for the given physical unit
67 F_1DOF_P_BASIC | // 1DOF pressure (altitude) and temperature: (pressure)
68 F_3DOF_G_BASIC | // 3DOF accel tilt: (accel)
69 F_3DOF_B_BASIC | // 3DOF mag eCompass (vehicle): (mag)
70 F_3DOF_Y_BASIC | // 3DOF gyro integration: (gyro)
71 F_6DOF_GB_BASIC | // 6DOF accel and mag eCompass)
72 F_6DOF_GY_KALMAN | // 6DOF accel and gyro (Kalman): (accel + gyro)
73 F_9DOF_GBY_KALMAN ; // 9DOF accel, mag and gyro (Kalman): (accel + mag + gyro)
74
75 sfg->pControlSubsystem = pControlSubsystem;
76 sfg->pStatusSubsystem = pStatusSubsystem;
77 sfg->loopcounter = 0; // counter incrementing each iteration of sensor fusion (typically 25Hz)
78 sfg->systick_I2C = 0; // systick counter to benchmark I2C reads
79 sfg->systick_Spare = 0; // systick counter for counts spare waiting for timing interrupt
80 sfg->iPerturbation = 0; // no perturbation to be applied
81 sfg->installSensor = installSensor; // function for installing a new sensor into the structures
82 sfg->initializeFusionEngine = initializeFusionEngine; // initializes fusion variables
83 sfg->readSensors = readSensors; // function for reading a sensor
84 sfg->runFusion = runFusion; // function for running fusion algorithms
85 sfg->applyPerturbation = ApplyPerturbation; // function used for step function testing
86 sfg->conditionSensorReadings = conditionSensorReadings; // function does averaging, HAL adjustments, etc.
87 sfg->clearFIFOs = clearFIFOs; // function to clear FIFO flags sfg->applyPerturbation = ApplyPerturbation; // function used for step function testing
88 sfg->setStatus = setStatus; // function to immediately set status change
89 sfg->getStatus = getStatus; // function to report status
90 sfg->queueStatus = queueStatus; // function to queue status change
91 sfg->updateStatus = updateStatus; // function to promote queued status change
92 sfg->testStatus = testStatus; // function for unit testing the status subsystem
93 sfg->pSensors = NULL; // pointer to linked list of physical sensors
94// put error value into whoAmI as initial value
95#if F_USING_ACCEL
96 sfg->Accel.iWhoAmI = 0;
97#endif
98#if F_USING_MAG
99 sfg->Mag.iWhoAmI = 0;
100#endif
101#if F_USING_GYRO
102 sfg->Gyro.iWhoAmI = 0;
103#endif
104#if F_USING_PRESSURE
105 sfg->Pressure.iWhoAmI = 0;
106#endif
107} // end initSensorFusionGlobals()
108
112int8_t installSensor(
114 struct PhysicalSensor *pSensor,
115 uint16_t addr,
116 uint16_t schedule,
117 registerDeviceInfo_t *busInfo,
118 initializeSensor_t *initialize,
119 readSensor_t *read)
120{
121 if (sfg && pSensor && initialize && read)
122 {
123 /* was pSensor->deviceInfo.deviceInstance = busInfo->deviceInstance;
124 pSensor->deviceInfo.functionParam = busInfo->functionParam;
125 pSensor->deviceInfo.idleFunction = busInfo->idleFunction;
126 but these aren't used. Instead of changing structs everywhere,
127 we just set to zero. */
128 pSensor->deviceInfo.deviceInstance = 0;
129 pSensor->deviceInfo.functionParam = NULL;
130 pSensor->deviceInfo.idleFunction = NULL;
131
132 pSensor->initialize = initialize; // The initialization function is responsible for putting the sensor
133 // into the proper mode for sensor fusion.
134 pSensor->read = read; // The read function is responsible for taking sensor readings and
135 // loading them into the sensor fusion input structures.
136 pSensor->addr = addr; // I2C address if applicable
137 pSensor->schedule = schedule;
138 // Now add the new sensor at the head of the linked list
139 pSensor->next = sfg->pSensors;
140 sfg->pSensors = pSensor;
141 return (0);
142 }
143 else
144 {
145 return (1);
146 }
147} // end installSensor()
148
149// The initializeSensors function traverses the linked list of physical sensor
150// types and calls the initialization function for each one.
151int8_t initializeSensors(SensorFusionGlobals *sfg)
152{
153 struct PhysicalSensor *pSensor;
154 int8_t s;
155 int8_t status = 0;
156 for (pSensor = sfg->pSensors; pSensor != NULL; pSensor = pSensor->next)
157 {
158 s = pSensor->initialize(pSensor, sfg);
159 if (status == 0) status = s; // will return 1st error flag, but try all sensors
160 }
161 return (status);
162} // end initializeSensors()
163
164// process<Sensor>Data routines do post processing for HAL and averaging. They
165// are called from the readSensors() function below.
166#if F_USING_ACCEL
167void processAccelData(SensorFusionGlobals *sfg)
168{
169 int32_t iSum[3]; // channel sums
170 int16_t i, j; // counters
171 if (sfg->Accel.iFIFOExceeded > 0) {
172 sfg->setStatus(sfg, SOFT_FAULT);
173 }
174
175 ApplyAccelHAL(&(sfg->Accel)); // This function is board-dependent
176
177 // calculate the average HAL-corrected measurement
178 for (j = CHX; j <= CHZ; j++) iSum[j] = 0;
179 for (i = 0; i < sfg->Accel.iFIFOCount; i++)
180 for (j = CHX; j <= CHZ; j++) iSum[j] += sfg->Accel.iGsFIFO[i][j];
181 if (sfg->Accel.iFIFOCount > 0)
182 {
183 for (j = CHX; j <= CHZ; j++)
184 {
185 sfg->Accel.iGs[j] = (int16_t)(iSum[j] / (int32_t) sfg->Accel.iFIFOCount);
186 sfg->Accel.fGs[j] = (float)sfg->Accel.iGs[j] * sfg->Accel.fgPerCount;
187 }
188 }
189
190 // apply precision accelerometer calibration (offset V, inverse gain invW and rotation correction R^T)
191 // to map fGs onto fGc (g), iGc (counts)
192 fInvertAccelCal(&(sfg->Accel), &(sfg->AccelCal));
193
194 // update the precision accelerometer data buffer
195 fUpdateAccelBuffer(&(sfg->AccelCal),
196 &(sfg->AccelBuffer),
197 &(sfg->Accel),
198 &(sfg->pControlSubsystem->AccelCalPacketOn));
199 return;
200} // end processAccelData()
201#endif
202
203#if F_USING_MAG
204void processMagData(SensorFusionGlobals *sfg)
205{
206 int32_t iSum[3]; // channel sums
207 int16_t i, j; // counters
208
209 if (sfg->Mag.iFIFOExceeded > 0) {
210 sfg->setStatus(sfg, SOFT_FAULT);
211 }
212
213 ApplyMagHAL(&(sfg->Mag)); // This function is board-dependent
214
215 // calculate the average HAL-corrected measurement
216 for (j = CHX; j <= CHZ; j++) iSum[j] = 0;
217 for (i = 0; i < sfg->Mag.iFIFOCount; i++)
218 for (j = CHX; j <= CHZ; j++) iSum[j] += sfg->Mag.iBsFIFO[i][j];
219 if (sfg->Mag.iFIFOCount > 0)
220 {
221 for (j = CHX; j <= CHZ; j++)
222 {
223 sfg->Mag.iBs[j] = (int16_t)(iSum[j] / (int32_t) sfg->Mag.iFIFOCount);
224 sfg->Mag.fBs[j] = (float)sfg->Mag.iBs[j] * sfg->Mag.fuTPerCount;
225 }
226 }
227
228 // remove hard and soft iron terms from fBs (uT) to get calibrated data fBc (uT), iBc (counts) and
229 // update magnetic buffer avoiding a write while a magnetic calibration is in progress.
230 // run one iteration of the time sliced magnetic calibration
231 fInvertMagCal(&(sfg->Mag), &(sfg->MagCal));
232 if (!sfg->MagCal.iMagBufferReadOnly)
233 iUpdateMagBuffer(&(sfg->MagBuffer), &(sfg->Mag), sfg->loopcounter);
234 fRunMagCalibration(&(sfg->MagCal), &(sfg->MagBuffer), &(sfg->Mag),
235 sfg->loopcounter);
236
237 return;
238} // end processMagData()
239#endif
240
241#if F_USING_GYRO
242void processGyroData(SensorFusionGlobals *sfg)
243{
244 int32_t iSum[3]; // channel sums
245 int16_t i, j; // counters
246 if (sfg->Gyro.iFIFOExceeded > 0) {
247 sfg->setStatus(sfg, SOFT_FAULT);
248 }
249
250 ApplyGyroHAL(&(sfg->Gyro)); // This function is board-dependent
251
252 // calculate the average HAL-corrected measurement. This is used for offset
253 // initialization, display purposes and in the 3-axis gyro-only algorithm.
254 // The Kalman filters both do the full incremental rotation integration
255 // right in the filters themselves.
256 for (j = CHX; j <= CHZ; j++) iSum[j] = 0;
257 for (i = 0; i < sfg->Gyro.iFIFOCount; i++)
258 for (j = CHX; j <= CHZ; j++)
259 iSum[j] += sfg->Gyro.iYsFIFO[i][j];
260 if (sfg->Gyro.iFIFOCount > 0)
261 {
262 for (j = CHX; j <= CHZ; j++)
263 {
264 sfg->Gyro.iYs[j] = (int16_t)(iSum[j] / (int32_t) sfg->Gyro.iFIFOCount);
265 sfg->Gyro.fYs[j] = (float)sfg->Gyro.iYs[j] * sfg->Gyro.fDegPerSecPerCount;
266 }
267 }
268 return;
269} // end processGyroData()
270#endif
271
277int8_t readSensors(
279 uint8_t read_loop_counter
280 )
281{
282 struct PhysicalSensor *pSensor;
283 int8_t s;
284 int8_t status = SENSOR_ERROR_NONE;
285
286 pSensor = sfg->pSensors;
287
288 for (pSensor = sfg->pSensors; pSensor != NULL; pSensor = pSensor->next)
289 { if (pSensor->isInitialized) {
290 if ( 0 == (read_loop_counter % pSensor->schedule)) {
291 //read the sensor if it is its turn (per loop_counter)
292 s = pSensor->read(pSensor, sfg);
293 if(s != SENSOR_ERROR_NONE) {
294 //sensor reported error, so mark it uninitialized.
295 //If it becomes reinitialized next loop, init function will set flag back to sensor type
296 pSensor->isInitialized = F_USING_NONE;
297 }
298 if (status == SENSOR_ERROR_NONE) status = s; // will return 1st error flag, but try all sensors
299 }
300 }else {
301 //sensor not initialized. Make one attempt to init it.
302 //If init succeeds, next time through a sensor read will be attempted
303 s = pSensor->initialize(pSensor, sfg);
304 if (s != SENSOR_ERROR_NONE) {
305 //note that there is still an error
306 status = s;
307 }
308 }
309 }
310 if (status == SENSOR_ERROR_NONE) {
311 //change (or keep) status to NORMAL on next regular status update
312 sfg->queueStatus(sfg, NORMAL);
313 } else {
314 // flag that we have problem reading sensor, which may clear later
315 sfg->setStatus(sfg, SOFT_FAULT);
316 }
317 return (status);
318} // end readSensors()
319
326#if F_USING_ACCEL
327 if (sfg->Accel.isEnabled) processAccelData(sfg);
328#endif
329
330#if F_USING_MAG
331 if (sfg->Mag.isEnabled) processMagData(sfg);
332#endif
333
334#if F_USING_GYRO
335 if (sfg->Gyro.isEnabled) processGyroData(sfg);
336#endif
337 return;
338} // end conditionSensorReadings()
339
340void zeroArray(StatusSubsystem *pStatus, void* data, uint16_t size, uint16_t numElements, uint8_t check) {
341 uint16_t i;
342 uint8_t *d8;
343 uint16_t *d16;
344 uint32_t *d32;
345 switch(size) {
346 case 8:
347 d8 = data;
348 for (i=0; i<numElements; i++) d8[i]=0;
349 break;
350 case 16:
351 d16 = data;
352 for (i=0; i<numElements; i++) d16[i]=0;
353 break;
354 case 32:
355 d32 = data;
356 for (i=0; i<numElements; i++) d32[i]=0;
357 break;
358 default:
359 pStatus->set(pStatus, HARD_FAULT);
360 }
361 if (check) {
362 switch(size) {
363 case 8:
364 d8 = data;
365 for (i=0; i<numElements; i++)
366 if (d8[i]!=0) pStatus->set(pStatus, HARD_FAULT);
367 break;
368 case 16:
369 d16 = data;
370 for (i=0; i<numElements; i++)
371 if (d16[i]!=0) pStatus->set(pStatus, HARD_FAULT);
372 break;
373 case 32:
374 d32 = data;
375 for (i=0; i<numElements; i++)
376 if (d32[i]!=0) pStatus->set(pStatus, HARD_FAULT);
377 break;
378 }
379 return;
380 }
381} // end zeroArray()
382
385 // We only clear FIFOs if the sensors are enabled. This allows us
386 // to continue to use these values when we've shut higher power consumption
387 // sensors down during periods of no activity.
388#if F_USING_ACCEL
389 sfg->Accel.iFIFOCount=0;
390 sfg->Accel.iFIFOExceeded = false;
391#endif
392#if F_USING_MAG
393 sfg->Mag.iFIFOCount=0;
394 sfg->Mag.iFIFOExceeded = false;
395#endif
396#if F_USING_GYRO
397 sfg->Gyro.iFIFOCount=0;
398 sfg->Gyro.iFIFOExceeded = false;
399#endif
400} // end clearFIFOs()
401
407void runFusion(SensorFusionGlobals *sfg)
408{
409 struct SV_1DOF_P_BASIC *pSV_1DOF_P_BASIC;
410 struct SV_3DOF_G_BASIC *pSV_3DOF_G_BASIC;
411 struct SV_3DOF_B_BASIC *pSV_3DOF_B_BASIC;
412 struct SV_3DOF_Y_BASIC *pSV_3DOF_Y_BASIC;
413 struct SV_6DOF_GB_BASIC *pSV_6DOF_GB_BASIC;
414 struct SV_6DOF_GY_KALMAN *pSV_6DOF_GY_KALMAN;
415 struct SV_9DOF_GBY_KALMAN *pSV_9DOF_GBY_KALMAN;
416 struct AccelSensor *pAccel;
417 struct MagSensor *pMag;
418 struct GyroSensor *pGyro;
419 struct PressureSensor *pPressure;
420 struct MagCalibration *pMagCal;
421#if F_1DOF_P_BASIC
422 pSV_1DOF_P_BASIC = &(sfg->SV_1DOF_P_BASIC);
423#else
424 pSV_1DOF_P_BASIC = NULL;
425#endif
426#if F_3DOF_G_BASIC
427 pSV_3DOF_G_BASIC = &(sfg->SV_3DOF_G_BASIC) ;
428#else
429 pSV_3DOF_G_BASIC = NULL;
430#endif
431#if F_3DOF_B_BASIC
432 pSV_3DOF_B_BASIC = &(sfg->SV_3DOF_B_BASIC);
433#else
434 pSV_3DOF_B_BASIC = NULL;
435#endif
436#if F_3DOF_Y_BASIC
437 pSV_3DOF_Y_BASIC = &(sfg->SV_3DOF_Y_BASIC);
438#else
439 pSV_3DOF_Y_BASIC = NULL;
440#endif
441#if F_6DOF_GB_BASIC
442 pSV_6DOF_GB_BASIC = &(sfg->SV_6DOF_GB_BASIC);
443#else
444 pSV_6DOF_GB_BASIC = NULL;
445#endif
446#if F_6DOF_GY_KALMAN
447 pSV_6DOF_GY_KALMAN = &(sfg->SV_6DOF_GY_KALMAN);
448#else
449 pSV_6DOF_GY_KALMAN = NULL;
450#endif
451#if F_9DOF_GBY_KALMAN
452 pSV_9DOF_GBY_KALMAN = &(sfg->SV_9DOF_GBY_KALMAN);
453#else
454 pSV_9DOF_GBY_KALMAN = NULL;
455#endif
456#if F_USING_ACCEL
457 pAccel = &(sfg->Accel);
458#else
459 pAccel = NULL;
460#endif
461#if F_USING_MAG
462 pMag = &(sfg->Mag);
463 pMagCal = &(sfg->MagCal);
464#else
465 pMag = NULL;
466 pMagCal = NULL;
467#endif
468#if F_USING_GYRO
469 pGyro = &(sfg->Gyro);
470#else
471 pGyro = NULL;
472#endif
473#if F_USING_PRESSURE
474 pPressure = &(sfg->Pressure);
475#else
476 pPressure = NULL;
477#endif
478
479 // conditionSensorReadings(sfg); must be called prior to this function
480 // fuse the sensor data
481 fFuseSensors(pSV_1DOF_P_BASIC, pSV_3DOF_G_BASIC,
482 pSV_3DOF_B_BASIC, pSV_3DOF_Y_BASIC,
483 pSV_6DOF_GB_BASIC, pSV_6DOF_GY_KALMAN,
484 pSV_9DOF_GBY_KALMAN, pAccel, pMag, pGyro,
485 pPressure, pMagCal);
486 clearFIFOs(sfg);
487} // end runFusion()
488
497void initializeFusionEngine(SensorFusionGlobals *sfg, int pin_i2c_sda, int pin_i2c_scl)
498{
499 int16_t status = SENSOR_ERROR_NONE;
500 struct ControlSubsystem *pComm;
501 pComm = sfg->pControlSubsystem;
502
503 sfg->setStatus(sfg, INITIALIZING);
504 if( ! I2CInitialize(pin_i2c_sda, pin_i2c_scl) ) {
505 sfg->setStatus(sfg, HARD_FAULT); // Never returns
506 }
507 status = initializeSensors(sfg);
508 if (status!=SENSOR_ERROR_NONE) { // fault condition found - will try again later
509 sfg->setStatus(sfg, SOFT_FAULT);
510 }
511
512 // recall: typedef enum quaternion {Q3, Q3M, Q3G, Q6MA, Q6AG, Q9} quaternion_type;
513 // Set the default quaternion to the most sophisticated supported by this build
514 pComm->DefaultQuaternionPacketType = Q3;
515 if (sfg->iFlags & F_3DOF_B_BASIC) pComm->DefaultQuaternionPacketType = Q3M;
516 if (sfg->iFlags & F_3DOF_Y_BASIC) pComm->DefaultQuaternionPacketType = Q3G;
517 if (sfg->iFlags & F_6DOF_GB_BASIC) pComm->DefaultQuaternionPacketType = Q6MA;
518 if (sfg->iFlags & F_6DOF_GY_KALMAN) pComm->DefaultQuaternionPacketType = Q6AG;
519 if (sfg->iFlags & F_9DOF_GBY_KALMAN) pComm->DefaultQuaternionPacketType = Q9;
520 pComm->QuaternionPacketType = pComm->DefaultQuaternionPacketType ;
521
522 // initialize the sensor fusion algorithms
523 fInitializeFusion(sfg);
524
525 // reset the loop counter to zero for first iteration
526 sfg->loopcounter = 0;
527
528 // initialize the magnetic calibration and magnetometer data buffer
529#if F_USING_MAG
530 fInitializeMagCalibration(&sfg->MagCal, &sfg->MagBuffer);
531#endif
532
533 // initialize the precision accelerometer calibration and accelerometer data buffer
534#if F_USING_ACCEL
535 fInitializeAccelCalibration(&sfg->AccelCal, &sfg->AccelBuffer, &sfg->pControlSubsystem->AccelCalPacketOn );
536#endif
537
538 clearFIFOs(sfg);
539
540 if( status == SENSOR_ERROR_NONE ) {
541 //nothing went wrong, so set status to normal
542 sfg->setStatus(sfg, NORMAL);
543 }
544
545} // end initializeFusionEngine()
546
547void conditionSample(int16_t sample[3])
548{
549 // This function should be called for every 16 bit sample read from sensor hardware.
550 // It is responsible for making sure that we never pass on the value of -32768.
551 // That value cannot be properly negated using 16-bit twos complement math.
552 // The ability to be later negated is required for general compatibility
553 // with possible HAL (Hardware abstraction logic) which is run later in
554 // the processing pipeline.
555 if (sample[CHX] == -32768) sample[CHX]++;
556 if (sample[CHY] == -32768) sample[CHY]++;
557 if (sample[CHZ] == -32768) sample[CHZ]++;
558} // end conditionSample()
559
560void addToFifo(union FifoSensor *sensor, uint16_t maxFifoSize, int16_t sample[3])
561{
562 // Note that FifoSensor is a union of GyroSensor, MagSensor and AccelSensor.
563 // All contain FIFO structures in the same location. We use the Accel
564 // structure to index here.
565
566 // example usage: if (status==SENSOR_ERROR_NONE) addToFifo((FifoSensor*) &(sfg->Mag), MAG_FIFO_SIZE, sample);
567 uint8_t fifoCount = sensor->Accel.iFIFOCount;
568 if (fifoCount < maxFifoSize) {
569 // we have room for the new sample
570 sensor->Accel.iGsFIFO[fifoCount][CHX] = sample[CHX];
571 sensor->Accel.iGsFIFO[fifoCount][CHY] = sample[CHY];
572 sensor->Accel.iGsFIFO[fifoCount][CHZ] = sample[CHZ];
573 sensor->Accel.iFIFOCount += 1;
574 sensor->Accel.iFIFOExceeded = 0;
575 } else {
576 //there is no room for a new sample
577 sensor->Accel.iFIFOExceeded += 1;
578 }
579} // end addToFifo()
580
#define F_USING_TEMPERATURE
nominally 0x0010 if temp sensor is to be used, 0x0000 otherwise
Definition build.h:52
#define F_9DOF_GBY_KALMAN
9DOF accel, mag and gyro algorithm selector - 0x4000 to include, 0x0000 otherwise/*#end#*‍/
Definition build.h:72
#define F_ALL_SENSORS
refers to all applicable sensor types for the given physical unit
Definition build.h:53
#define F_6DOF_GY_KALMAN
6DOF accel and gyro (Kalman) algorithm selector - 0x2000 to include, 0x0000 otherwise/*#end#*‍/
Definition build.h:70
#define F_1DOF_P_BASIC
1DOF pressure (altitude) and temperature algorithm selector - 0x0100 to include, 0x0000 otherwise/*#e...
Definition build.h:60
#define F_USING_MAG
nominally 0x0002 if an magnetometer is to be used, 0x0000 otherwise
Definition build.h:49
#define F_USING_ACCEL
nominally 0x0001 if an accelerometer is to be used, 0x0000 otherwise
Definition build.h:48
#define F_3DOF_Y_BASIC
3DOF gyro integration algorithm selector - 0x0800 to include, 0x0000 otherwise/*#end#*‍/
Definition build.h:66
#define F_6DOF_GB_BASIC
6DOF accel and mag eCompass algorithm selector - 0x1000 to include, 0x0000 otherwise/*#end#*‍/
Definition build.h:68
#define F_USING_PRESSURE
nominally 0x0008 if altimeter is to be used, 0x0000 otherwise
Definition build.h:51
#define F_3DOF_G_BASIC
3DOF accel tilt (accel) algorithm selector - 0x0200 to include, 0x0000 otherwise/*#end#*‍/
Definition build.h:62
#define F_USING_NONE
0x0000 indicates a sensor is unavailable / unconfigured.
Definition build.h:47
#define F_USING_GYRO
nominally 0x0004 if a gyro is to be used, 0x0000 otherwise
Definition build.h:50
#define F_3DOF_B_BASIC
3DOF mag eCompass (vehicle/mag) algorithm selector - 0x0400 to include, 0x0000 otherwise/*#end#*‍/
Definition build.h:64
Defines control sub-system.
Lower level sensor fusion interface.
void ApplyMagHAL(struct MagSensor *Mag)
Apply the magnetometer Hardware Abstraction Layer.
void ApplyGyroHAL(struct GyroSensor *Gyro)
Apply the gyroscope Hardware Abstraction Layer.
void ApplyAccelHAL(struct AccelSensor *Accel)
Apply the accelerometer Hardware Abstraction Layer.
bool I2CInitialize(int pin_sda, int pin_scl)
Initialize the I2C system at max clock rate supported by sensors. pin_sda and pin_scl indicate the pi...
Definition hal_i2c.cc:37
The hal_i2c.h file declares low-level interface functions for reading and writing sensor registers us...
Wrapper for Hardware Abstraction Layer (HAL) Contains replacements for hardware-specific functions Cu...
void fRunMagCalibration(struct MagCalibration *pthisMagCal, struct MagBuffer *pthisMagBuffer, struct MagSensor *pthisMag, int32_t loopcounter)
Run the magnetic calibration. Calibration is done in time-slices, to avoid excessive CPU load during ...
Definition magnetic.c:352
void fUpdateAccelBuffer(AccelCalibration *pthisAccelCal, AccelBuffer *pthisAccelBuffer, struct AccelSensor *pthisAccel, volatile int8_t *AccelCalPacketOn)
Update the buffer used to store samples used for accelerometer calibration.
void fInvertAccelCal(struct AccelSensor *pthisAccel, AccelCalibration *pthisAccelCal)
function maps the accelerometer data fGs (g) onto precision calibrated and de-rotated data fGc (g),...
void fInitializeAccelCalibration(AccelCalibration *pthisAccelCal, AccelBuffer *pthisAccelBuffer, volatile int8_t *AccelCalPacketOn)
Initialize the accelerometer calibration functions.
void conditionSample(int16_t sample[3])
conditionSample ensures that we never encounter the maximum negative two's complement value for a 16-...
void initSensorFusionGlobals(SensorFusionGlobals *sfg, StatusSubsystem *pStatusSubsystem, ControlSubsystem *pControlSubsystem)
utility function to insert default values in the top level structure
fusion_status_t getStatus(SensorFusionGlobals *sfg)
void setStatus(SensorFusionGlobals *sfg, fusion_status_t status)
void clearFIFOs(SensorFusionGlobals *sfg)
Function to clear FIFO at the end of each fusion computation.
void updateStatus(SensorFusionGlobals *sfg)
void zeroArray(StatusSubsystem *pStatus, void *data, uint16_t size, uint16_t numElements, uint8_t check)
void addToFifo(union FifoSensor *sensor, uint16_t maxFifoSize, int16_t sample[3])
addToFifo is called from within sensor driver read functions
void queueStatus(SensorFusionGlobals *sfg, fusion_status_t status)
void conditionSensorReadings(SensorFusionGlobals *sfg)
The sensor_fusion.h file implements the top level programming interface.
#define CHX
Used to access X-channel entries in various data data structures.
@ Q6MA
Quaternion derived from 3-axis accel + 3 axis mag (eCompass)
@ Q3
Quaternion derived from 3-axis accel (tilt)
@ Q6AG
Quaternion derived from 3-axis accel + 3-axis gyro (gaming)
@ Q9
Quaternion derived from full 9-axis sensor fusion.
@ Q3M
Quaternion derived from 3-axis mag only (auto compass algorithm)
@ Q3G
Quaternion derived from 3-axis gyro only (rotation)
fusion_status_t
Application-specific serial communications system.
@ HARD_FAULT
Non-recoverable FAULT = something went very wrong.
@ NORMAL
Operation is Nominal.
@ INITIALIZING
Initializing sensors and algorithms.
@ SOFT_FAULT
Recoverable FAULT = something went wrong, but we can keep going.
#define CHY
Used to access Y-channel entries in various data data structures.
#define CHZ
Used to access Z-channel entries in various data data structures.
applyPerturbation_t ApplyPerturbation
ApplyPerturbation is a reverse unit-step test function.
Application-specific status subsystem.
The AccelSensor structure stores raw and processed measurements for a 3-axis accelerometer.
uint8_t iFIFOCount
number of measurements read from FIFO
uint16_t iFIFOExceeded
Number of samples received in excess of software FIFO size.
int16_t iGsFIFO[ACCEL_FIFO_SIZE][3]
FIFO measurements (counts)
The ControlSubsystem encapsulates command and data streaming functions.
Definition control.h:51
The GyroSensor structure stores raw and processed measurements for a 3-axis gyroscope.
Magnetic Calibration Structure.
Definition magnetic.h:61
int8_t iMagBufferReadOnly
flag to denote that the magnetic measurement buffer is temporarily read only
Definition magnetic.h:88
The MagSensor structure stores raw and processed measurements for a 3-axis magnetic sensor.
uint8_t iFIFOCount
number of measurements read from FIFO
float fuTPerCount
uT per count
float fBs[3]
averaged un-calibrated measurement (uT)
uint8_t iWhoAmI
sensor whoami
int16_t iBsFIFO[MAG_FIFO_SIZE][3]
FIFO measurements (counts)
uint16_t iFIFOExceeded
Number of samples received in excess of software FIFO size.
bool isEnabled
true if the device is sampling
int16_t iBs[3]
averaged uncalibrated measurement (counts)
An instance of PhysicalSensor structure type should be allocated for each physical sensors (combo dev...
registerDeviceInfo_t deviceInfo
I2C device context.
readSensor_t * read
pointer to function to read sensor using the supplied drivers
uint16_t addr
I2C address if applicable.
initializeSensor_t * initialize
pointer to function to initialize sensor using the supplied drivers
uint16_t isInitialized
Bitfields to indicate sensor is active (use SensorBitFields from build.h)
struct PhysicalSensor * next
pointer to next sensor in this linked list
uint8_t schedule
Parameter to control sensor sampling rate.
The PressureSensor structure stores raw and processed measurements for an altimeter.
The SV_1DOF_P_BASIC structure contains state information for a pressure sensor/altimeter.
This is the 3DOF basic magnetometer state vector structure/.
This is the 3DOF basic accelerometer state vector structure.
SV_3DOF_Y_BASIC structure is the 3DOF basic gyroscope state vector structure.
SV_6DOF_GB_BASIC is the 6DOF basic accelerometer and magnetometer state vector structure.
SV_6DOF_GY_KALMAN is the 6DOF Kalman filter accelerometer and gyroscope state vector structure.
SV_9DOF_GBY_KALMAN is the 9DOF Kalman filter accelerometer, magnetometer and gyroscope state vector s...
The top level fusion structure.
struct MagCalibration MagCal
mag cal storage
initializeFusionEngine_t * initializeFusionEngine
set sensor fusion structures to initial values
clearFIFOs_t * clearFIFOs
clear sensor FIFOs
installSensor_t * installSensor
function for installing a new sensor
struct PhysicalSensor * pSensors
a linked list of physical sensors
int32_t systick_I2C
systick counter to benchmark I2C reads
updateStatus_t * testStatus
increment to next enumerated status value (test only)
applyPerturbation_t * applyPerturbation
apply step function for testing purposes
setStatus_t * queueStatus
queue status change for next regular interval
conditionSensorReadings_t * conditionSensorReadings
preprocessing step for sensor fusion
struct MagBuffer MagBuffer
mag cal constellation points
getStatus_t * getStatus
fetch the current status from the Status Subsystem
struct MagSensor Mag
magnetometer storage
int32_t systick_Spare
systick counter for counts spare waiting for timing interrupt
int32_t loopcounter
counter incrementing each iteration of sensor fusion (typically 25Hz)
runFusion_t * runFusion
run the fusion routines
volatile uint8_t iPerturbation
test perturbation to be applied
readSensors_t * readSensors
read all physical sensors
setStatus_t * setStatus
change status indicator immediately
updateStatus_t * updateStatus
status=next status
uint32_t iFlags
a bit-field of sensors and algorithms used
StatusSubsystem() provides an object-like interface for communicating status to the user.
Definition status.h:26
ssUpdateStatus_t * update
make pending status active/visible
Definition status.h:35
ssUpdateStatus_t * test
unit test which simply increments to next state
Definition status.h:36
ssSetStatus_t * set
change status immediately - no delay
Definition status.h:32
ssSetStatus_t * queue
queue status change for next regular interval
Definition status.h:34
ssGetStatus_t * get
return status
Definition status.h:33
This structure defines the device specific info required by register I/O.
The FifoSensor union allows us to use common pointers for Accel, Mag & Gyro logical sensor structures...