...
From the highest level, most sensor drivers (though not all), will belong to 2 independent threads. One is whatever the thread you need the data in, which is, by design, exclusively SensorFusion, while the second is the thread who’s whose exclusive job is to sample the sensor at a regular interval. The reason that second thread is required is that the process of collecting data from the sensor via SPI, I2C or whatever else, takes time. If we were only using a single thread, that thread would have to wait for that transfer to occur before it could move on , which is unacceptable for, for example, the state machines, which need to run at a very strict rate. The second thread ensures we can begin the transaction with the sensor so that by the time the data is needed by the first thread, it can be directly picked up without having to wait. The reason this isn’t the case with all sensors is that some sensors are always spewing data regardless of whether of whether we’re asking for it (gps for example) and others might be analog, meaning their data is always available to read at our ADCs (airspeed for example).The rest of this page details that general design by referring to this sample.
Sample sensor interface
Code Block | ||||
---|---|---|---|---|
| ||||
/** * AltimeterIMU Sensor Functions and Part Number Selection. * Available IMU driver(s): BMX160 * AuthorsAuthor(s): Lucy Gong, Dhruv Rawat, SahilAnthony KaleBerbari */ #ifndef ALTIMETERIMU_HPP #define ALTIMETERIMU_HPP #include <cstdint> /*********************************************************************************************************************** * Definitions struct AltimeterData**********************************************************************************************************************/ struct IMUData_t { float pressure, altitude, temp;magx, magy, magz; // TODO although the BMX 160 has a magnetometer, it seems to produce bizarre results.More investigation needs to be done. Figuring out what the RHall register does is likely a part of that. float accx, accy, accz; float gyrx, gyry, gyrz; float temp; bool isDataNew; int statussensorStatus; //TBD but probably 0 = SUCCESS, -1 = FAIL, 1 = BUSY }; class Altimeter/*********************************************************************************************************************** * Prototypes *********************************************************************************************************************/ class IMU { public: /** * Triggers interrupt for new altimeter measurement - stores raw data in variablesBegins a transaction with the IMU. * This function is non blocking and returns right away, data will be stored inside the module as it arrives. * To achieve synchronous data, this function must be called synchronously. * */ virtual void Begin_Measuring() = 0; /***GetResult should: * Retrieves any data already received by the imu. * 1. Reset dataIsNew flag If no new data is available, the appropriate flag will be set in the return struct. * 2. Transfers raw data from variables to structAll contents of the return struct, apart from the isDataNew flag, are undefined unless isDataNew is set to 1. * 3. Updates utcTime and status values in struct as well This function is non blocking and returns right away. * @param[in] Data reference to the results struct. * */ virtual void GetResult(AltimeterDataIMUData_t *&Data) = 0; // }; class MS5637 BMX160: public Altimeter IMU{ public: /** MS5637(const MS5637*) = delete; //Apparently if you try This module is built as a singleton. Thus to copyaccess a singletonBMX160 object, this function must be called. * Only a single BMX160 object will give you errors? ever be created and will be shared by all callers of this function. * @return IMU reference to the singleton object. static* MS5637*/ GetInstance(); static void Begin_MeasuringIMU& getInstance(); /** void GetResult(AltimeterData_t *Data); Deletes the constructor to private:disallow users to instantiate objects. MS5637(); //Constructor can never be called* muwhahaha*/ staticBMX160(const MS5637BMX160* s_Instance) = delete; void beginCollectingTemperatureBegin_Measuring(); void beginCollectingPressure(GetResult(IMUData_t &Data); private: uint32_t getNewestMeasurement BMX160(); uint32_t readFromMS5637(uint8_t commandToWrite void SetAllPowerModesToNormal(void); void getRawPressureAndTemperature(float *displayPressure, float *displayTemperature, float *displayAltitudeConfigAcc(void); void ConfigGyro(void); uint32_tvoid getCurrentTimeConfigMag(void); uint32void SetMagConfig(uint8_t timeOfResult; regAddr, uint8_t data); bool dataIsNew = falsevoid PrepareMagForDataMode(void); float altitudeMeasured = 0, pressureMeasured = 0, temperatureMeasured = 0void Bmx160WriteReg(uint8_t reg, uint8_t val); void Bmx160ReadReg(uint8_t const regAddr, uint8_t *pData, uint8_t len); // various offsets and calibration parameters read from device. Used in internal math but God only knows what each one means. void Calibrate(void); //Variables uint8_t rawImuData[21]; uint16IMUData_t c1, c2, c3, c4, c5, c6; ImuCalibration; IMUData_t ImuCalibrationFinal; }; #endif |
User’s perspective
...