http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/9dbad3bd/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUGD20M303DLHC.cpp ---------------------------------------------------------------------- diff --git a/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUGD20M303DLHC.cpp b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUGD20M303DLHC.cpp new file mode 100644 index 0000000..d8ab502 --- /dev/null +++ b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUGD20M303DLHC.cpp @@ -0,0 +1,537 @@ +//////////////////////////////////////////////////////////////////////////// +// +// This file is part of RTIMULib +// +// Copyright (c) 2014-2015, richards-tech, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +// Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#include "RTIMUGD20M303DLHC.h" +#include "RTIMUSettings.h" + +// this sets the learning rate for compass running average calculation + +#define COMPASS_ALPHA 0.2f + +RTIMUGD20M303DLHC::RTIMUGD20M303DLHC(RTIMUSettings *settings) : RTIMU(settings) +{ + m_sampleRate = 100; +} + +RTIMUGD20M303DLHC::~RTIMUGD20M303DLHC() +{ +} + +bool RTIMUGD20M303DLHC::IMUInit() +{ + unsigned char result; + +#ifdef GD20M303DLHC_CACHE_MODE + m_firstTime = true; + m_cacheIn = m_cacheOut = m_cacheCount = 0; +#endif + // set validity flags + + m_imuData.fusionPoseValid = false; + m_imuData.fusionQPoseValid = false; + m_imuData.gyroValid = true; + m_imuData.accelValid = true; + m_imuData.compassValid = true; + m_imuData.pressureValid = false; + m_imuData.temperatureValid = false; + m_imuData.humidityValid = false; + + // configure IMU + + m_gyroSlaveAddr = m_settings->m_I2CSlaveAddress; + m_accelSlaveAddr = LSM303DLHC_ACCEL_ADDRESS; + m_compassSlaveAddr = LSM303DLHC_COMPASS_ADDRESS; + + setCalibrationData(); + + // enable the I2C bus + + if (!m_settings->HALOpen()) + return false; + + // Set up the gyro + + if (!m_settings->HALWrite(m_gyroSlaveAddr, L3GD20_CTRL5, 0x80, "Failed to boot L3GD20")) + return false; + + if (!m_settings->HALRead(m_gyroSlaveAddr, L3GD20_WHO_AM_I, 1, &result, "Failed to read L3GD20 id")) + return false; + + if (result != L3GD20_ID) { + HAL_ERROR1("Incorrect L3GD20 id %d\n", result); + return false; + } + + if (!setGyroSampleRate()) + return false; + + if (!setGyroCTRL2()) + return false; + + if (!setGyroCTRL4()) + return false; + + // Set up the accel + + if (!setAccelCTRL1()) + return false; + + if (!setAccelCTRL4()) + return false; + + // Set up the compass + + if (!setCompassCRA()) + return false; + + if (!setCompassCRB()) + return false; + + if (!setCompassCRM()) + return false; + +#ifdef GD20M303DLHC_CACHE_MODE + + // turn on gyro fifo + + if (!m_settings->HALWrite(m_gyroSlaveAddr, L3GD20_FIFO_CTRL, 0x3f, "Failed to set L3GD20 FIFO mode")) + return false; +#endif + + if (!setGyroCTRL5()) + return false; + + gyroBiasInit(); + + HAL_INFO("GD20M303DLHC init complete\n"); + return true; +} + +bool RTIMUGD20M303DLHC::setGyroSampleRate() +{ + unsigned char ctrl1; + + switch (m_settings->m_GD20M303DLHCGyroSampleRate) { + case L3GD20_SAMPLERATE_95: + ctrl1 = 0x0f; + m_sampleRate = 95; + break; + + case L3GD20_SAMPLERATE_190: + ctrl1 = 0x4f; + m_sampleRate = 190; + break; + + case L3GD20_SAMPLERATE_380: + ctrl1 = 0x8f; + m_sampleRate = 380; + break; + + case L3GD20_SAMPLERATE_760: + ctrl1 = 0xcf; + m_sampleRate = 760; + break; + + default: + HAL_ERROR1("Illegal L3GD20 sample rate code %d\n", m_settings->m_GD20M303DLHCGyroSampleRate); + return false; + } + + m_sampleInterval = (uint64_t)1000000 / m_sampleRate; + + switch (m_settings->m_GD20M303DLHCGyroBW) { + case L3GD20_BANDWIDTH_0: + ctrl1 |= 0x00; + break; + + case L3GD20_BANDWIDTH_1: + ctrl1 |= 0x10; + break; + + case L3GD20_BANDWIDTH_2: + ctrl1 |= 0x20; + break; + + case L3GD20_BANDWIDTH_3: + ctrl1 |= 0x30; + break; + + } + + return (m_settings->HALWrite(m_gyroSlaveAddr, L3GD20_CTRL1, ctrl1, "Failed to set L3GD20 CTRL1")); +} + +bool RTIMUGD20M303DLHC::setGyroCTRL2() +{ + if ((m_settings->m_GD20M303DLHCGyroHpf < L3GD20_HPF_0) || (m_settings->m_GD20M303DLHCGyroHpf > L3GD20_HPF_9)) { + HAL_ERROR1("Illegal L3GD20 high pass filter code %d\n", m_settings->m_GD20M303DLHCGyroHpf); + return false; + } + return m_settings->HALWrite(m_gyroSlaveAddr, L3GD20_CTRL2, m_settings->m_GD20M303DLHCGyroHpf, "Failed to set L3GD20 CTRL2"); +} + +bool RTIMUGD20M303DLHC::setGyroCTRL4() +{ + unsigned char ctrl4; + + switch (m_settings->m_GD20M303DLHCGyroFsr) { + case L3GD20_FSR_250: + ctrl4 = 0x00; + m_gyroScale = (RTFLOAT)0.00875 * RTMATH_DEGREE_TO_RAD; + break; + + case L3GD20_FSR_500: + ctrl4 = 0x10; + m_gyroScale = (RTFLOAT)0.0175 * RTMATH_DEGREE_TO_RAD; + break; + + case L3GD20_FSR_2000: + ctrl4 = 0x20; + m_gyroScale = (RTFLOAT)0.07 * RTMATH_DEGREE_TO_RAD; + break; + + default: + HAL_ERROR1("Illegal L3GD20 FSR code %d\n", m_settings->m_GD20M303DLHCGyroFsr); + return false; + } + + return m_settings->HALWrite(m_gyroSlaveAddr, L3GD20_CTRL4, ctrl4, "Failed to set L3GD20 CTRL4"); +} + + +bool RTIMUGD20M303DLHC::setGyroCTRL5() +{ + unsigned char ctrl5; + + // Turn on hpf + + ctrl5 = 0x10; + +#ifdef GD20M303DLHC_CACHE_MODE + // turn on fifo + + ctrl5 |= 0x40; +#endif + + return m_settings->HALWrite(m_gyroSlaveAddr, L3GD20_CTRL5, ctrl5, "Failed to set L3GD20 CTRL5"); +} + + +bool RTIMUGD20M303DLHC::setAccelCTRL1() +{ + unsigned char ctrl1; + + if ((m_settings->m_GD20M303DLHCAccelSampleRate < 1) || (m_settings->m_GD20M303DLHCAccelSampleRate > 7)) { + HAL_ERROR1("Illegal LSM303DLHC accel sample rate code %d\n", m_settings->m_GD20M303DLHCAccelSampleRate); + return false; + } + + ctrl1 = (m_settings->m_GD20M303DLHCAccelSampleRate << 4) | 0x07; + + return m_settings->HALWrite(m_accelSlaveAddr, LSM303DLHC_CTRL1_A, ctrl1, "Failed to set LSM303D CTRL1"); +} + +bool RTIMUGD20M303DLHC::setAccelCTRL4() +{ + unsigned char ctrl4; + + switch (m_settings->m_GD20M303DLHCAccelFsr) { + case LSM303DLHC_ACCEL_FSR_2: + m_accelScale = (RTFLOAT)0.001 / (RTFLOAT)16; + break; + + case LSM303DLHC_ACCEL_FSR_4: + m_accelScale = (RTFLOAT)0.002 / (RTFLOAT)16; + break; + + case LSM303DLHC_ACCEL_FSR_8: + m_accelScale = (RTFLOAT)0.004 / (RTFLOAT)16; + break; + + case LSM303DLHC_ACCEL_FSR_16: + m_accelScale = (RTFLOAT)0.012 / (RTFLOAT)16; + break; + + default: + HAL_ERROR1("Illegal LSM303DLHC accel FSR code %d\n", m_settings->m_GD20M303DLHCAccelFsr); + return false; + } + + ctrl4 = 0x80 + (m_settings->m_GD20M303DLHCAccelFsr << 4); + + return m_settings->HALWrite(m_accelSlaveAddr, LSM303DLHC_CTRL4_A, ctrl4, "Failed to set LSM303DLHC CTRL4"); +} + + +bool RTIMUGD20M303DLHC::setCompassCRA() +{ + unsigned char cra; + + if ((m_settings->m_GD20M303DLHCCompassSampleRate < 0) || (m_settings->m_GD20M303DLHCCompassSampleRate > 7)) { + HAL_ERROR1("Illegal LSM303DLHC compass sample rate code %d\n", m_settings->m_GD20M303DLHCCompassSampleRate); + return false; + } + + cra = (m_settings->m_GD20M303DLHCCompassSampleRate << 2); + + return m_settings->HALWrite(m_compassSlaveAddr, LSM303DLHC_CRA_M, cra, "Failed to set LSM303DLHC CRA_M"); +} + +bool RTIMUGD20M303DLHC::setCompassCRB() +{ + unsigned char crb; + + // convert FSR to uT + + switch (m_settings->m_GD20M303DLHCCompassFsr) { + case LSM303DLHC_COMPASS_FSR_1_3: + crb = 0x20; + m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)1100; + m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)980; + break; + + case LSM303DLHC_COMPASS_FSR_1_9: + crb = 0x40; + m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)855; + m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)760; + break; + + case LSM303DLHC_COMPASS_FSR_2_5: + crb = 0x60; + m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)670; + m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)600; + break; + + case LSM303DLHC_COMPASS_FSR_4: + crb = 0x80; + m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)450; + m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)400; + break; + + case LSM303DLHC_COMPASS_FSR_4_7: + crb = 0xa0; + m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)400; + m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)355; + break; + + case LSM303DLHC_COMPASS_FSR_5_6: + crb = 0xc0; + m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)330; + m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)295; + break; + + case LSM303DLHC_COMPASS_FSR_8_1: + crb = 0xe0; + m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)230; + m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)205; + break; + + default: + HAL_ERROR1("Illegal LSM303DLHC compass FSR code %d\n", m_settings->m_GD20M303DLHCCompassFsr); + return false; + } + + return m_settings->HALWrite(m_compassSlaveAddr, LSM303DLHC_CRB_M, crb, "Failed to set LSM303DLHC CRB_M"); +} + +bool RTIMUGD20M303DLHC::setCompassCRM() +{ + return m_settings->HALWrite(m_compassSlaveAddr, LSM303DLHC_CRM_M, 0x00, "Failed to set LSM303DLHC CRM_M"); +} + + +int RTIMUGD20M303DLHC::IMUGetPollInterval() +{ + return (400 / m_sampleRate); +} + +bool RTIMUGD20M303DLHC::IMURead() +{ + unsigned char status; + unsigned char gyroData[6]; + unsigned char accelData[6]; + unsigned char compassData[6]; + + +#ifdef GD20M303DLHC_CACHE_MODE + int count; + + if (!m_settings->HALRead(m_gyroSlaveAddr, L3GD20_FIFO_SRC, 1, &status, "Failed to read L3GD20 fifo status")) + return false; + + if ((status & 0x40) != 0) { + HAL_INFO("L3GD20 fifo overrun\n"); + if (!m_settings->HALWrite(m_gyroSlaveAddr, L3GD20_CTRL5, 0x10, "Failed to set L3GD20 CTRL5")) + return false; + + if (!m_settings->HALWrite(m_gyroSlaveAddr, L3GD20_FIFO_CTRL, 0x0, "Failed to set L3GD20 FIFO mode")) + return false; + + if (!m_settings->HALWrite(m_gyroSlaveAddr, L3GD20_FIFO_CTRL, 0x3f, "Failed to set L3GD20 FIFO mode")) + return false; + + if (!setGyroCTRL5()) + return false; + + m_imuData.timestamp += m_sampleInterval * 32; + return false; + } + + // get count of samples in fifo + count = status & 0x1f; + + if ((m_cacheCount == 0) && (count > 0) && (count < GD20M303DLHC_FIFO_THRESH)) { + // special case of a small fifo and nothing cached - just handle as simple read + + if (!m_settings->HALRead(m_gyroSlaveAddr, 0x80 | L3GD20_OUT_X_L, 6, gyroData, "Failed to read L3GD20 data")) + return false; + + if (!m_settings->HALRead(m_accelSlaveAddr, 0x80 | LSM303DLHC_OUT_X_L_A, 6, accelData, "Failed to read LSM303DLHC accel data")) + return false; + + if (!m_settings->HALRead(m_compassSlaveAddr, 0x80 | LSM303DLHC_OUT_X_H_M, 6, compassData, "Failed to read LSM303DLHC compass data")) + return false; + + if (m_firstTime) + m_imuData.timestamp = RTMath::currentUSecsSinceEpoch(); + else + m_imuData.timestamp += m_sampleInterval; + + m_firstTime = false; + } else { + if (count >= GD20M303DLHC_FIFO_THRESH) { + // need to create a cache block + + if (m_cacheCount == GD20M303DLHC_CACHE_BLOCK_COUNT) { + // all cache blocks are full - discard oldest and update timestamp to account for lost samples + m_imuData.timestamp += m_sampleInterval * m_cache[m_cacheOut].count; + if (++m_cacheOut == GD20M303DLHC_CACHE_BLOCK_COUNT) + m_cacheOut = 0; + m_cacheCount--; + } + + if (!m_settings->HALRead(m_gyroSlaveAddr, 0x80 | L3GD20_OUT_X_L, GD20M303DLHC_FIFO_CHUNK_SIZE * GD20M303DLHC_FIFO_THRESH, + m_cache[m_cacheIn].data, "Failed to read L3GD20 fifo data")) + return false; + + if (!m_settings->HALRead(m_accelSlaveAddr, 0x80 | LSM303DLHC_OUT_X_L_A, 6, + m_cache[m_cacheIn].accel, "Failed to read LSM303DLHC accel data")) + return false; + + if (!m_settings->HALRead(m_compassSlaveAddr, 0x80 | LSM303DLHC_OUT_X_H_M, 6, + m_cache[m_cacheIn].compass, "Failed to read LSM303DLHC compass data")) + return false; + + m_cache[m_cacheIn].count = GD20M303DLHC_FIFO_THRESH; + m_cache[m_cacheIn].index = 0; + + m_cacheCount++; + if (++m_cacheIn == GD20M303DLHC_CACHE_BLOCK_COUNT) + m_cacheIn = 0; + + } + + // now fifo has been read if necessary, get something to process + + if (m_cacheCount == 0) + return false; + + memcpy(gyroData, m_cache[m_cacheOut].data + m_cache[m_cacheOut].index, GD20M303DLHC_FIFO_CHUNK_SIZE); + memcpy(accelData, m_cache[m_cacheOut].accel, 6); + memcpy(compassData, m_cache[m_cacheOut].compass, 6); + + m_cache[m_cacheOut].index += GD20M303DLHC_FIFO_CHUNK_SIZE; + + if (--m_cache[m_cacheOut].count == 0) { + // this cache block is now empty + + if (++m_cacheOut == GD20M303DLHC_CACHE_BLOCK_COUNT) + m_cacheOut = 0; + m_cacheCount--; + } + if (m_firstTime) + m_imuData.timestamp = RTMath::currentUSecsSinceEpoch(); + else + m_imuData.timestamp += m_sampleInterval; + + m_firstTime = false; + } + +#else + if (!m_settings->HALRead(m_gyroSlaveAddr, L3GD20_STATUS, 1, &status, "Failed to read L3GD20 status")) + return false; + + if ((status & 0x8) == 0) + return false; + + if (!m_settings->HALRead(m_gyroSlaveAddr, 0x80 | L3GD20_OUT_X_L, 6, gyroData, "Failed to read L3GD20 data")) + return false; + + m_imuData.timestamp = RTMath::currentUSecsSinceEpoch(); + + if (!m_settings->HALRead(m_accelSlaveAddr, 0x80 | LSM303DLHC_OUT_X_L_A, 6, accelData, "Failed to read LSM303DLHC accel data")) + return false; + + if (!m_settings->HALRead(m_compassSlaveAddr, 0x80 | LSM303DLHC_OUT_X_H_M, 6, compassData, "Failed to read LSM303DLHC compass data")) + return false; + +#endif + + RTMath::convertToVector(gyroData, m_imuData.gyro, m_gyroScale, false); + RTMath::convertToVector(accelData, m_imuData.accel, m_accelScale, false); + + m_imuData.compass.setX((RTFLOAT)((int16_t)(((uint16_t)compassData[0] << 8) | (uint16_t)compassData[1])) * m_compassScaleXY); + m_imuData.compass.setY((RTFLOAT)((int16_t)(((uint16_t)compassData[2] << 8) | (uint16_t)compassData[3])) * m_compassScaleXY); + m_imuData.compass.setZ((RTFLOAT)((int16_t)(((uint16_t)compassData[4] << 8) | (uint16_t)compassData[5])) * m_compassScaleZ); + + // sort out gyro axes + + m_imuData.gyro.setX(m_imuData.gyro.x()); + m_imuData.gyro.setY(-m_imuData.gyro.y()); + m_imuData.gyro.setZ(-m_imuData.gyro.z()); + + // sort out accel data; + + m_imuData.accel.setX(-m_imuData.accel.x()); + + // sort out compass axes + + RTFLOAT temp; + + temp = m_imuData.compass.z(); + m_imuData.compass.setZ(-m_imuData.compass.y()); + m_imuData.compass.setY(-temp); + + // now do standard processing + + handleGyroBias(); + calibrateAverageCompass(); + calibrateAccel(); + + // now update the filter + + updateFusion(); + + return true; +}
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/9dbad3bd/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUGD20M303DLHC.h ---------------------------------------------------------------------- diff --git a/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUGD20M303DLHC.h b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUGD20M303DLHC.h new file mode 100644 index 0000000..6d2aa9c --- /dev/null +++ b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUGD20M303DLHC.h @@ -0,0 +1,97 @@ +//////////////////////////////////////////////////////////////////////////// +// +// This file is part of RTIMULib +// +// Copyright (c) 2014-2015, richards-tech, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +// Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#ifndef _RTIMUGD20M303DLHC_H +#define _RTIMUGD20M303DLHC_H + +#include "RTIMU.h" + +// Define this symbol to use cache mode + +//#define GD20M303DLHC_CACHE_MODE // not reliable at the moment + +#ifdef GD20M303DLHC_CACHE_MODE + +// Cache defs + +#define GD20M303DLHC_FIFO_CHUNK_SIZE 6 // 6 bytes of gyro data +#define GD20M303DLHC_FIFO_THRESH 16 // threshold point in fifo +#define GD20M303DLHC_CACHE_BLOCK_COUNT 16 // number of cache blocks + +typedef struct +{ + unsigned char data[GD20M303DLHC_FIFO_THRESH * GD20M303DLHC_FIFO_CHUNK_SIZE]; + int count; // number of chunks in the cache block + int index; // current index into the cache + unsigned char accel[6]; // the raw accel readings for the block + unsigned char compass[6]; // the raw compass readings for the block + +} GD20M303DLHC_CACHE_BLOCK; + +#endif + +class RTIMUGD20M303DLHC : public RTIMU +{ +public: + RTIMUGD20M303DLHC(RTIMUSettings *settings); + ~RTIMUGD20M303DLHC(); + + virtual const char *IMUName() { return "L3GD20 + LSM303DLHC"; } + virtual int IMUType() { return RTIMU_TYPE_GD20M303DLHC; } + virtual bool IMUInit(); + virtual int IMUGetPollInterval(); + virtual bool IMURead(); + +private: + bool setGyroSampleRate(); + bool setGyroCTRL2(); + bool setGyroCTRL4(); + bool setGyroCTRL5(); + bool setAccelCTRL1(); + bool setAccelCTRL4(); + bool setCompassCRA(); + bool setCompassCRB(); + bool setCompassCRM(); + + unsigned char m_gyroSlaveAddr; // I2C address of L3GD20 + unsigned char m_accelSlaveAddr; // I2C address of LSM303DLHC accel + unsigned char m_compassSlaveAddr; // I2C address of LSM303DLHC compass + + RTFLOAT m_gyroScale; + RTFLOAT m_accelScale; + RTFLOAT m_compassScaleXY; + RTFLOAT m_compassScaleZ; + +#ifdef GD20M303DLHC_CACHE_MODE + bool m_firstTime; // if first sample + + GD20M303DLHC_CACHE_BLOCK m_cache[GD20M303DLHC_CACHE_BLOCK_COUNT]; // the cache itself + int m_cacheIn; // the in index + int m_cacheOut; // the out index + int m_cacheCount; // number of used cache blocks + +#endif +}; + +#endif // _RTIMUGD20M303DLHC_H http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/9dbad3bd/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS0.cpp ---------------------------------------------------------------------- diff --git a/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS0.cpp b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS0.cpp new file mode 100644 index 0000000..676d111 --- /dev/null +++ b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS0.cpp @@ -0,0 +1,538 @@ +//////////////////////////////////////////////////////////////////////////// +// +// This file is part of RTIMULib +// +// Copyright (c) 2014-2015, richards-tech, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +// Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#include "RTIMULSM9DS0.h" +#include "RTIMUSettings.h" + +// this sets the learning rate for compass running average calculation + +#define COMPASS_ALPHA 0.2f + +RTIMULSM9DS0::RTIMULSM9DS0(RTIMUSettings *settings) : RTIMU(settings) +{ + m_sampleRate = 100; +} + +RTIMULSM9DS0::~RTIMULSM9DS0() +{ +} + +bool RTIMULSM9DS0::IMUInit() +{ + unsigned char result; + +#ifdef LSM9DS0_CACHE_MODE + m_firstTime = true; + m_cacheIn = m_cacheOut = m_cacheCount = 0; +#endif + // set validity flags + + m_imuData.fusionPoseValid = false; + m_imuData.fusionQPoseValid = false; + m_imuData.gyroValid = true; + m_imuData.accelValid = true; + m_imuData.compassValid = true; + m_imuData.pressureValid = false; + m_imuData.temperatureValid = false; + m_imuData.humidityValid = false; + + // configure IMU + + m_gyroSlaveAddr = m_settings->m_I2CSlaveAddress; + + // work out accelmag address + + if (m_settings->HALRead(LSM9DS0_ACCELMAG_ADDRESS0, LSM9DS0_WHO_AM_I, 1, &result, "")) { + if (result == LSM9DS0_ACCELMAG_ID) { + m_accelCompassSlaveAddr = LSM9DS0_ACCELMAG_ADDRESS0; + } + } else { + m_accelCompassSlaveAddr = LSM9DS0_ACCELMAG_ADDRESS1; + } + + setCalibrationData(); + + // enable the I2C bus + + if (!m_settings->HALOpen()) + return false; + + // Set up the gyro + + if (!m_settings->HALWrite(m_gyroSlaveAddr, LSM9DS0_GYRO_CTRL5, 0x80, "Failed to boot LSM9DS0")) + return false; + + if (!m_settings->HALRead(m_gyroSlaveAddr, LSM9DS0_GYRO_WHO_AM_I, 1, &result, "Failed to read LSM9DS0 gyro id")) + return false; + + if (result != LSM9DS0_GYRO_ID) { + HAL_ERROR1("Incorrect LSM9DS0 gyro id %d\n", result); + return false; + } + + if (!setGyroSampleRate()) + return false; + + if (!setGyroCTRL2()) + return false; + + if (!setGyroCTRL4()) + return false; + + // Set up the accel + + if (!m_settings->HALRead(m_accelCompassSlaveAddr, LSM9DS0_WHO_AM_I, 1, &result, "Failed to read LSM9DS0 accel/mag id")) + return false; + + if (result != LSM9DS0_ACCELMAG_ID) { + HAL_ERROR1("Incorrect LSM9DS0 accel/mag id %d\n", result); + return false; + } + + if (!setAccelCTRL1()) + return false; + + if (!setAccelCTRL2()) + return false; + + if (!setCompassCTRL5()) + return false; + + if (!setCompassCTRL6()) + return false; + + if (!setCompassCTRL7()) + return false; + +#ifdef LSM9DS0_CACHE_MODE + + // turn on gyro fifo + + if (!m_settings->HALWrite(m_gyroSlaveAddr, LSM9DS0_GYRO_FIFO_CTRL, 0x3f, "Failed to set LSM9DS0 FIFO mode")) + return false; +#endif + + if (!setGyroCTRL5()) + return false; + + gyroBiasInit(); + + HAL_INFO("LSM9DS0 init complete\n"); + return true; +} + +bool RTIMULSM9DS0::setGyroSampleRate() +{ + unsigned char ctrl1; + + switch (m_settings->m_LSM9DS0GyroSampleRate) { + case LSM9DS0_GYRO_SAMPLERATE_95: + ctrl1 = 0x0f; + m_sampleRate = 95; + break; + + case LSM9DS0_GYRO_SAMPLERATE_190: + ctrl1 = 0x4f; + m_sampleRate = 190; + break; + + case LSM9DS0_GYRO_SAMPLERATE_380: + ctrl1 = 0x8f; + m_sampleRate = 380; + break; + + case LSM9DS0_GYRO_SAMPLERATE_760: + ctrl1 = 0xcf; + m_sampleRate = 760; + break; + + default: + HAL_ERROR1("Illegal LSM9DS0 gyro sample rate code %d\n", m_settings->m_LSM9DS0GyroSampleRate); + return false; + } + + m_sampleInterval = (uint64_t)1000000 / m_sampleRate; + + switch (m_settings->m_LSM9DS0GyroBW) { + case LSM9DS0_GYRO_BANDWIDTH_0: + ctrl1 |= 0x00; + break; + + case LSM9DS0_GYRO_BANDWIDTH_1: + ctrl1 |= 0x10; + break; + + case LSM9DS0_GYRO_BANDWIDTH_2: + ctrl1 |= 0x20; + break; + + case LSM9DS0_GYRO_BANDWIDTH_3: + ctrl1 |= 0x30; + break; + + } + + return (m_settings->HALWrite(m_gyroSlaveAddr, LSM9DS0_GYRO_CTRL1, ctrl1, "Failed to set LSM9DS0 gyro CTRL1")); +} + +bool RTIMULSM9DS0::setGyroCTRL2() +{ + if ((m_settings->m_LSM9DS0GyroHpf < LSM9DS0_GYRO_HPF_0) || (m_settings->m_LSM9DS0GyroHpf > LSM9DS0_GYRO_HPF_9)) { + HAL_ERROR1("Illegal LSM9DS0 gyro high pass filter code %d\n", m_settings->m_LSM9DS0GyroHpf); + return false; + } + return m_settings->HALWrite(m_gyroSlaveAddr, LSM9DS0_GYRO_CTRL2, m_settings->m_LSM9DS0GyroHpf, "Failed to set LSM9DS0 gyro CTRL2"); +} + +bool RTIMULSM9DS0::setGyroCTRL4() +{ + unsigned char ctrl4; + + switch (m_settings->m_LSM9DS0GyroFsr) { + case LSM9DS0_GYRO_FSR_250: + ctrl4 = 0x00; + m_gyroScale = (RTFLOAT)0.00875 * RTMATH_DEGREE_TO_RAD; + break; + + case LSM9DS0_GYRO_FSR_500: + ctrl4 = 0x10; + m_gyroScale = (RTFLOAT)0.0175 * RTMATH_DEGREE_TO_RAD; + break; + + case LSM9DS0_GYRO_FSR_2000: + ctrl4 = 0x20; + m_gyroScale = (RTFLOAT)0.07 * RTMATH_DEGREE_TO_RAD; + break; + + default: + HAL_ERROR1("Illegal LSM9DS0 gyro FSR code %d\n", m_settings->m_LSM9DS0GyroFsr); + return false; + } + + return m_settings->HALWrite(m_gyroSlaveAddr, LSM9DS0_GYRO_CTRL4, ctrl4, "Failed to set LSM9DS0 gyro CTRL4"); +} + + +bool RTIMULSM9DS0::setGyroCTRL5() +{ + unsigned char ctrl5; + + // Turn on hpf + + ctrl5 = 0x10; + +#ifdef LSM9DS0_CACHE_MODE + // turn on fifo + + ctrl5 |= 0x40; +#endif + + return m_settings->HALWrite(m_gyroSlaveAddr, LSM9DS0_GYRO_CTRL5, ctrl5, "Failed to set LSM9DS0 gyro CTRL5"); +} + + +bool RTIMULSM9DS0::setAccelCTRL1() +{ + unsigned char ctrl1; + + if ((m_settings->m_LSM9DS0AccelSampleRate < 0) || (m_settings->m_LSM9DS0AccelSampleRate > 10)) { + HAL_ERROR1("Illegal LSM9DS0 accel sample rate code %d\n", m_settings->m_LSM9DS0AccelSampleRate); + return false; + } + + ctrl1 = (m_settings->m_LSM9DS0AccelSampleRate << 4) | 0x07; + + return m_settings->HALWrite(m_accelCompassSlaveAddr, LSM9DS0_CTRL1, ctrl1, "Failed to set LSM9DS0 accell CTRL1"); +} + +bool RTIMULSM9DS0::setAccelCTRL2() +{ + unsigned char ctrl2; + + if ((m_settings->m_LSM9DS0AccelLpf < 0) || (m_settings->m_LSM9DS0AccelLpf > 3)) { + HAL_ERROR1("Illegal LSM9DS0 accel low pass fiter code %d\n", m_settings->m_LSM9DS0AccelLpf); + return false; + } + + switch (m_settings->m_LSM9DS0AccelFsr) { + case LSM9DS0_ACCEL_FSR_2: + m_accelScale = (RTFLOAT)0.000061; + break; + + case LSM9DS0_ACCEL_FSR_4: + m_accelScale = (RTFLOAT)0.000122; + break; + + case LSM9DS0_ACCEL_FSR_6: + m_accelScale = (RTFLOAT)0.000183; + break; + + case LSM9DS0_ACCEL_FSR_8: + m_accelScale = (RTFLOAT)0.000244; + break; + + case LSM9DS0_ACCEL_FSR_16: + m_accelScale = (RTFLOAT)0.000732; + break; + + default: + HAL_ERROR1("Illegal LSM9DS0 accel FSR code %d\n", m_settings->m_LSM9DS0AccelFsr); + return false; + } + + ctrl2 = (m_settings->m_LSM9DS0AccelLpf << 6) | (m_settings->m_LSM9DS0AccelFsr << 3); + + return m_settings->HALWrite(m_accelCompassSlaveAddr, LSM9DS0_CTRL2, ctrl2, "Failed to set LSM9DS0 accel CTRL2"); +} + + +bool RTIMULSM9DS0::setCompassCTRL5() +{ + unsigned char ctrl5; + + if ((m_settings->m_LSM9DS0CompassSampleRate < 0) || (m_settings->m_LSM9DS0CompassSampleRate > 5)) { + HAL_ERROR1("Illegal LSM9DS0 compass sample rate code %d\n", m_settings->m_LSM9DS0CompassSampleRate); + return false; + } + + ctrl5 = (m_settings->m_LSM9DS0CompassSampleRate << 2); + +#ifdef LSM9DS0_CACHE_MODE + // enable fifo + + ctrl5 |= 0x40; +#endif + + return m_settings->HALWrite(m_accelCompassSlaveAddr, LSM9DS0_CTRL5, ctrl5, "Failed to set LSM9DS0 compass CTRL5"); +} + +bool RTIMULSM9DS0::setCompassCTRL6() +{ + unsigned char ctrl6; + + // convert FSR to uT + + switch (m_settings->m_LSM9DS0CompassFsr) { + case LSM9DS0_COMPASS_FSR_2: + ctrl6 = 0; + m_compassScale = (RTFLOAT)0.008; + break; + + case LSM9DS0_COMPASS_FSR_4: + ctrl6 = 0x20; + m_compassScale = (RTFLOAT)0.016; + break; + + case LSM9DS0_COMPASS_FSR_8: + ctrl6 = 0x40; + m_compassScale = (RTFLOAT)0.032; + break; + + case LSM9DS0_COMPASS_FSR_12: + ctrl6 = 0x60; + m_compassScale = (RTFLOAT)0.0479; + break; + + default: + HAL_ERROR1("Illegal LSM9DS0 compass FSR code %d\n", m_settings->m_LSM9DS0CompassFsr); + return false; + } + + return m_settings->HALWrite(m_accelCompassSlaveAddr, LSM9DS0_CTRL6, ctrl6, "Failed to set LSM9DS0 compass CTRL6"); +} + +bool RTIMULSM9DS0::setCompassCTRL7() +{ + return m_settings->HALWrite(m_accelCompassSlaveAddr, LSM9DS0_CTRL7, 0x60, "Failed to set LSM9DS0CTRL7"); +} + + + +int RTIMULSM9DS0::IMUGetPollInterval() +{ + return (400 / m_sampleRate); +} + +bool RTIMULSM9DS0::IMURead() +{ + unsigned char status; + unsigned char gyroData[6]; + unsigned char accelData[6]; + unsigned char compassData[6]; + + +#ifdef LSM9DS0_CACHE_MODE + int count; + + if (!m_settings->HALRead(m_gyroSlaveAddr, LSM9DS0_GYRO_FIFO_SRC, 1, &status, "Failed to read LSM9DS0 gyro fifo status")) + return false; + + if ((status & 0x40) != 0) { + HAL_INFO("LSM9DS0 gyro fifo overrun\n"); + if (!m_settings->HALWrite(m_gyroSlaveAddr, LSM9DS0_GYRO_CTRL5, 0x10, "Failed to set LSM9DS0 gyro CTRL5")) + return false; + + if (!m_settings->HALWrite(m_gyroSlaveAddr, LSM9DS0_GYRO_FIFO_CTRL, 0x0, "Failed to set LSM9DS0 gyro FIFO mode")) + return false; + + if (!m_settings->HALWrite(m_gyroSlaveAddr, LSM9DS0_GYRO_FIFO_CTRL, 0x3f, "Failed to set LSM9DS0 gyro FIFO mode")) + return false; + + if (!setGyroCTRL5()) + return false; + + m_imuData.timestamp += m_sampleInterval * 32; + return false; + } + + // get count of samples in fifo + count = status & 0x1f; + + if ((m_cacheCount == 0) && (count > 0) && (count < LSM9DS0_FIFO_THRESH)) { + // special case of a small fifo and nothing cached - just handle as simple read + + if (!m_settings->HALRead(m_gyroSlaveAddr, 0x80 | LSM9DS0_GYRO_OUT_X_L, 6, gyroData, "Failed to read LSM9DS0 gyro data")) + return false; + + if (!m_settings->HALRead(m_accelCompassSlaveAddr, 0x80 | LSM9DS0_OUT_X_L_A, 6, accelData, "Failed to read LSM9DS0 accel data")) + return false; + + if (!m_settings->HALRead(m_accelCompassSlaveAddr, 0x80 | LSM9DS0_OUT_X_L_M, 6, compassData, "Failed to read LSM9DS0 compass data")) + return false; + + if (m_firstTime) + m_imuData.timestamp = RTMath::currentUSecsSinceEpoch(); + else + m_imuData.timestamp += m_sampleInterval; + + m_firstTime = false; + } else { + if (count >= LSM9DS0_FIFO_THRESH) { + // need to create a cache block + + if (m_cacheCount == LSM9DS0_CACHE_BLOCK_COUNT) { + // all cache blocks are full - discard oldest and update timestamp to account for lost samples + m_imuData.timestamp += m_sampleInterval * m_cache[m_cacheOut].count; + if (++m_cacheOut == LSM9DS0_CACHE_BLOCK_COUNT) + m_cacheOut = 0; + m_cacheCount--; + } + + if (!m_settings->HALRead(m_gyroSlaveAddr, 0x80 | LSM9DS0_GYRO_OUT_X_L, LSM9DS0_FIFO_CHUNK_SIZE * LSM9DS0_FIFO_THRESH, + m_cache[m_cacheIn].data, "Failed to read LSM9DS0 fifo data")) + return false; + + if (!m_settings->HALRead(m_accelCompassSlaveAddr, 0x80 | LSM9DS0_OUT_X_L_A, 6, + m_cache[m_cacheIn].accel, "Failed to read LSM9DS0 accel data")) + return false; + + if (!m_settings->HALRead(m_accelCompassSlaveAddr, 0x80 | LSM9DS0_OUT_X_L_M, 6, + m_cache[m_cacheIn].compass, "Failed to read LSM9DS0 compass data")) + return false; + + m_cache[m_cacheIn].count = LSM9DS0_FIFO_THRESH; + m_cache[m_cacheIn].index = 0; + + m_cacheCount++; + if (++m_cacheIn == LSM9DS0_CACHE_BLOCK_COUNT) + m_cacheIn = 0; + + } + + // now fifo has been read if necessary, get something to process + + if (m_cacheCount == 0) + return false; + + memcpy(gyroData, m_cache[m_cacheOut].data + m_cache[m_cacheOut].index, LSM9DS0_FIFO_CHUNK_SIZE); + memcpy(accelData, m_cache[m_cacheOut].accel, 6); + memcpy(compassData, m_cache[m_cacheOut].compass, 6); + + m_cache[m_cacheOut].index += LSM9DS0_FIFO_CHUNK_SIZE; + + if (--m_cache[m_cacheOut].count == 0) { + // this cache block is now empty + + if (++m_cacheOut == LSM9DS0_CACHE_BLOCK_COUNT) + m_cacheOut = 0; + m_cacheCount--; + } + if (m_firstTime) + m_imuData.timestamp = RTMath::currentUSecsSinceEpoch(); + else + m_imuData.timestamp += m_sampleInterval; + + m_firstTime = false; + } + +#else + if (!m_settings->HALRead(m_gyroSlaveAddr, LSM9DS0_GYRO_STATUS, 1, &status, "Failed to read LSM9DS0 status")) + return false; + + if ((status & 0x8) == 0) + return false; + + if (!m_settings->HALRead(m_gyroSlaveAddr, 0x80 | LSM9DS0_GYRO_OUT_X_L, 6, gyroData, "Failed to read LSM9DS0 gyro data")) + return false; + + m_imuData.timestamp = RTMath::currentUSecsSinceEpoch(); + + if (!m_settings->HALRead(m_accelCompassSlaveAddr, 0x80 | LSM9DS0_OUT_X_L_A, 6, accelData, "Failed to read LSM9DS0 accel data")) + return false; + + if (!m_settings->HALRead(m_accelCompassSlaveAddr, 0x80 | LSM9DS0_OUT_X_L_M, 6, compassData, "Failed to read LSM9DS0 compass data")) + return false; + +#endif + + RTMath::convertToVector(gyroData, m_imuData.gyro, m_gyroScale, false); + RTMath::convertToVector(accelData, m_imuData.accel, m_accelScale, false); + RTMath::convertToVector(compassData, m_imuData.compass, m_compassScale, false); + + // sort out gyro axes and correct for bias + + m_imuData.gyro.setX(m_imuData.gyro.x()); + m_imuData.gyro.setY(-m_imuData.gyro.y()); + m_imuData.gyro.setZ(-m_imuData.gyro.z()); + + // sort out accel data; + + m_imuData.accel.setX(-m_imuData.accel.x()); + + // sort out compass axes + + m_imuData.compass.setY(-m_imuData.compass.y()); + + // now do standard processing + + handleGyroBias(); + calibrateAverageCompass(); + calibrateAccel(); + + // now update the filter + + updateFusion(); + + return true; +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/9dbad3bd/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS0.h ---------------------------------------------------------------------- diff --git a/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS0.h b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS0.h new file mode 100644 index 0000000..814bd3f --- /dev/null +++ b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS0.h @@ -0,0 +1,95 @@ +//////////////////////////////////////////////////////////////////////////// +// +// This file is part of RTIMULib +// +// Copyright (c) 2014-2015, richards-tech, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +// Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#ifndef _RTIMULSM9DS0_H +#define _RTIMULSM9DS0_H + +#include "RTIMU.h" + +// Define this symbol to use cache mode + +//#define LSM9DS0_CACHE_MODE // not reliable at the moment + +#ifdef LSM9DS0_CACHE_MODE + +// Cache defs + +#define LSM9DS0_FIFO_CHUNK_SIZE 6 // 6 bytes of gyro data +#define LSM9DS0_FIFO_THRESH 16 // threshold point in fifo +#define LSM9DS0_CACHE_BLOCK_COUNT 16 // number of cache blocks + +typedef struct +{ + unsigned char data[LSM9DS0_FIFO_THRESH * LSM9DS0_FIFO_CHUNK_SIZE]; + int count; // number of chunks in the cache block + int index; // current index into the cache + unsigned char accel[6]; // the raw accel readings for the block + unsigned char compass[6]; // the raw compass readings for the block + +} LSM9DS0_CACHE_BLOCK; + +#endif + +class RTIMULSM9DS0 : public RTIMU +{ +public: + RTIMULSM9DS0(RTIMUSettings *settings); + ~RTIMULSM9DS0(); + + virtual const char *IMUName() { return "LSM9DS0"; } + virtual int IMUType() { return RTIMU_TYPE_LSM9DS0; } + virtual bool IMUInit(); + virtual int IMUGetPollInterval(); + virtual bool IMURead(); + +private: + bool setGyroSampleRate(); + bool setGyroCTRL2(); + bool setGyroCTRL4(); + bool setGyroCTRL5(); + bool setAccelCTRL1(); + bool setAccelCTRL2(); + bool setCompassCTRL5(); + bool setCompassCTRL6(); + bool setCompassCTRL7(); + + unsigned char m_gyroSlaveAddr; // I2C address of gyro + unsigned char m_accelCompassSlaveAddr; // I2C address of accel and mag + + RTFLOAT m_gyroScale; + RTFLOAT m_accelScale; + RTFLOAT m_compassScale; + +#ifdef LSM9DS0_CACHE_MODE + bool m_firstTime; // if first sample + + LSM9DS0_CACHE_BLOCK m_cache[LSM9DS0_CACHE_BLOCK_COUNT]; // the cache itself + int m_cacheIn; // the in index + int m_cacheOut; // the out index + int m_cacheCount; // number of used cache blocks + +#endif +}; + +#endif // _RTIMULSM9DS0_H http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/9dbad3bd/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS1.cpp ---------------------------------------------------------------------- diff --git a/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS1.cpp b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS1.cpp new file mode 100644 index 0000000..b84b6b7 --- /dev/null +++ b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS1.cpp @@ -0,0 +1,408 @@ +//////////////////////////////////////////////////////////////////////////// +// +// This file is part of RTIMULib +// +// Copyright (c) 2014-2015, richards-tech, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +// Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#include "RTIMULSM9DS1.h" +#include "RTIMUSettings.h" + +// this sets the learning rate for compass running average calculation + +#define COMPASS_ALPHA 0.2f + +RTIMULSM9DS1::RTIMULSM9DS1(RTIMUSettings *settings) : RTIMU(settings) +{ + m_sampleRate = 100; +} + +RTIMULSM9DS1::~RTIMULSM9DS1() +{ +} + +bool RTIMULSM9DS1::IMUInit() +{ + unsigned char result; + + // set validity flags + + m_imuData.fusionPoseValid = false; + m_imuData.fusionQPoseValid = false; + m_imuData.gyroValid = true; + m_imuData.accelValid = true; + m_imuData.compassValid = true; + m_imuData.pressureValid = false; + m_imuData.temperatureValid = false; + m_imuData.humidityValid = false; + + // configure IMU + + m_accelGyroSlaveAddr = m_settings->m_I2CSlaveAddress; + + // work outmag address + + if (m_settings->HALRead(LSM9DS1_MAG_ADDRESS0, LSM9DS1_MAG_WHO_AM_I, 1, &result, "")) { + if (result == LSM9DS1_MAG_ID) { + m_magSlaveAddr = LSM9DS1_MAG_ADDRESS0; + } + } else if (m_settings->HALRead(LSM9DS1_MAG_ADDRESS1, LSM9DS1_MAG_WHO_AM_I, 1, &result, "")) { + if (result == LSM9DS1_MAG_ID) { + m_magSlaveAddr = LSM9DS1_MAG_ADDRESS1; + } + } else if (m_settings->HALRead(LSM9DS1_MAG_ADDRESS2, LSM9DS1_MAG_WHO_AM_I, 1, &result, "")) { + if (result == LSM9DS1_MAG_ID) { + m_magSlaveAddr = LSM9DS1_MAG_ADDRESS2; + } + } else if (m_settings->HALRead(LSM9DS1_MAG_ADDRESS3, LSM9DS1_MAG_WHO_AM_I, 1, &result, "")) { + if (result == LSM9DS1_MAG_ID) { + m_magSlaveAddr = LSM9DS1_MAG_ADDRESS3; + } + } + + setCalibrationData(); + + // enable the I2C bus + + if (!m_settings->HALOpen()) + return false; + + // Set up the gyro/accel + + if (!m_settings->HALWrite(m_accelGyroSlaveAddr, LSM9DS1_CTRL8, 0x80, "Failed to boot LSM9DS1")) + return false; + + m_settings->delayMs(100); + + if (!m_settings->HALRead(m_accelGyroSlaveAddr, LSM9DS1_WHO_AM_I, 1, &result, "Failed to read LSM9DS1 accel/gyro id")) + return false; + + if (result != LSM9DS1_ID) { + HAL_ERROR1("Incorrect LSM9DS1 gyro id %d\n", result); + return false; + } + + if (!setGyroSampleRate()) + return false; + + if (!setGyroCTRL3()) + return false; + + // Set up the mag + + if (!m_settings->HALRead(m_magSlaveAddr, LSM9DS1_MAG_WHO_AM_I, 1, &result, "Failed to read LSM9DS1 accel/mag id")) + return false; + + if (result != LSM9DS1_MAG_ID) { + HAL_ERROR1("Incorrect LSM9DS1 accel/mag id %d\n", result); + return false; + } + + if (!setAccelCTRL6()) + return false; + + if (!setAccelCTRL7()) + return false; + + if (!setCompassCTRL1()) + return false; + + if (!setCompassCTRL2()) + return false; + + if (!setCompassCTRL3()) + return false; + + gyroBiasInit(); + + HAL_INFO("LSM9DS1 init complete\n"); + return true; +} + +bool RTIMULSM9DS1::setGyroSampleRate() +{ + unsigned char ctrl1; + + switch (m_settings->m_LSM9DS1GyroSampleRate) { + case LSM9DS1_GYRO_SAMPLERATE_14_9: + ctrl1 = 0x20; + m_sampleRate = 15; + break; + + case LSM9DS1_GYRO_SAMPLERATE_59_5: + ctrl1 = 0x40; + m_sampleRate = 60; + break; + + case LSM9DS1_GYRO_SAMPLERATE_119: + ctrl1 = 0x60; + m_sampleRate = 119; + break; + + case LSM9DS1_GYRO_SAMPLERATE_238: + ctrl1 = 0x80; + m_sampleRate = 238; + break; + + case LSM9DS1_GYRO_SAMPLERATE_476: + ctrl1 = 0xa0; + m_sampleRate = 476; + break; + + case LSM9DS1_GYRO_SAMPLERATE_952: + ctrl1 = 0xc0; + m_sampleRate = 952; + break; + + default: + HAL_ERROR1("Illegal LSM9DS1 gyro sample rate code %d\n", m_settings->m_LSM9DS1GyroSampleRate); + return false; + } + + m_sampleInterval = (uint64_t)1000000 / m_sampleRate; + + switch (m_settings->m_LSM9DS1GyroBW) { + case LSM9DS1_GYRO_BANDWIDTH_0: + ctrl1 |= 0x00; + break; + + case LSM9DS1_GYRO_BANDWIDTH_1: + ctrl1 |= 0x01; + break; + + case LSM9DS1_GYRO_BANDWIDTH_2: + ctrl1 |= 0x02; + break; + + case LSM9DS1_GYRO_BANDWIDTH_3: + ctrl1 |= 0x03; + break; + } + + switch (m_settings->m_LSM9DS1GyroFsr) { + case LSM9DS1_GYRO_FSR_250: + ctrl1 |= 0x00; + m_gyroScale = (RTFLOAT)0.00875 * RTMATH_DEGREE_TO_RAD; + break; + + case LSM9DS1_GYRO_FSR_500: + ctrl1 |= 0x08; + m_gyroScale = (RTFLOAT)0.0175 * RTMATH_DEGREE_TO_RAD; + break; + + case LSM9DS1_GYRO_FSR_2000: + ctrl1 |= 0x18; + m_gyroScale = (RTFLOAT)0.07 * RTMATH_DEGREE_TO_RAD; + break; + + default: + HAL_ERROR1("Illegal LSM9DS1 gyro FSR code %d\n", m_settings->m_LSM9DS1GyroFsr); + return false; + } + return (m_settings->HALWrite(m_accelGyroSlaveAddr, LSM9DS1_CTRL1, ctrl1, "Failed to set LSM9DS1 gyro CTRL1")); +} + +bool RTIMULSM9DS1::setGyroCTRL3() +{ + unsigned char ctrl3; + + if ((m_settings->m_LSM9DS1GyroHpf < LSM9DS1_GYRO_HPF_0) || (m_settings->m_LSM9DS1GyroHpf > LSM9DS1_GYRO_HPF_9)) { + HAL_ERROR1("Illegal LSM9DS1 gyro high pass filter code %d\n", m_settings->m_LSM9DS1GyroHpf); + return false; + } + ctrl3 = m_settings->m_LSM9DS1GyroHpf; + + // Turn on hpf + ctrl3 |= 0x40; + + return m_settings->HALWrite(m_accelGyroSlaveAddr, LSM9DS1_CTRL3, ctrl3, "Failed to set LSM9DS1 gyro CTRL3"); +} + +bool RTIMULSM9DS1::setAccelCTRL6() +{ + unsigned char ctrl6; + + if ((m_settings->m_LSM9DS1AccelSampleRate < 0) || (m_settings->m_LSM9DS1AccelSampleRate > 6)) { + HAL_ERROR1("Illegal LSM9DS1 accel sample rate code %d\n", m_settings->m_LSM9DS1AccelSampleRate); + return false; + } + + ctrl6 = (m_settings->m_LSM9DS1AccelSampleRate << 5); + + if ((m_settings->m_LSM9DS1AccelLpf < 0) || (m_settings->m_LSM9DS1AccelLpf > 3)) { + HAL_ERROR1("Illegal LSM9DS1 accel low pass fiter code %d\n", m_settings->m_LSM9DS1AccelLpf); + return false; + } + + switch (m_settings->m_LSM9DS1AccelFsr) { + case LSM9DS1_ACCEL_FSR_2: + m_accelScale = (RTFLOAT)0.000061; + break; + + case LSM9DS1_ACCEL_FSR_4: + m_accelScale = (RTFLOAT)0.000122; + break; + + case LSM9DS1_ACCEL_FSR_8: + m_accelScale = (RTFLOAT)0.000244; + break; + + case LSM9DS1_ACCEL_FSR_16: + m_accelScale = (RTFLOAT)0.000732; + break; + + default: + HAL_ERROR1("Illegal LSM9DS1 accel FSR code %d\n", m_settings->m_LSM9DS1AccelFsr); + return false; + } + + ctrl6 |= (m_settings->m_LSM9DS1AccelLpf) | (m_settings->m_LSM9DS1AccelFsr << 3); + + return m_settings->HALWrite(m_accelGyroSlaveAddr, LSM9DS1_CTRL6, ctrl6, "Failed to set LSM9DS1 accel CTRL6"); +} + +bool RTIMULSM9DS1::setAccelCTRL7() +{ + unsigned char ctrl7; + + ctrl7 = 0x00; + //Bug: Bad things happen. + //ctrl7 = 0x05; + + return m_settings->HALWrite(m_accelGyroSlaveAddr, LSM9DS1_CTRL7, ctrl7, "Failed to set LSM9DS1 accel CTRL7"); +} + + +bool RTIMULSM9DS1::setCompassCTRL1() +{ + unsigned char ctrl1; + + if ((m_settings->m_LSM9DS1CompassSampleRate < 0) || (m_settings->m_LSM9DS1CompassSampleRate > 5)) { + HAL_ERROR1("Illegal LSM9DS1 compass sample rate code %d\n", m_settings->m_LSM9DS1CompassSampleRate); + return false; + } + + ctrl1 = (m_settings->m_LSM9DS1CompassSampleRate << 2); + + return m_settings->HALWrite(m_magSlaveAddr, LSM9DS1_MAG_CTRL1, ctrl1, "Failed to set LSM9DS1 compass CTRL5"); +} + +bool RTIMULSM9DS1::setCompassCTRL2() +{ + unsigned char ctrl2; + + // convert FSR to uT + + switch (m_settings->m_LSM9DS1CompassFsr) { + case LSM9DS1_COMPASS_FSR_4: + ctrl2 = 0; + m_compassScale = (RTFLOAT)0.014; + break; + + case LSM9DS1_COMPASS_FSR_8: + ctrl2 = 0x20; + m_compassScale = (RTFLOAT)0.029; + break; + + case LSM9DS1_COMPASS_FSR_12: + ctrl2 = 0x40; + m_compassScale = (RTFLOAT)0.043; + break; + + case LSM9DS1_COMPASS_FSR_16: + ctrl2 = 0x60; + m_compassScale = (RTFLOAT)0.058; + break; + + default: + HAL_ERROR1("Illegal LSM9DS1 compass FSR code %d\n", m_settings->m_LSM9DS1CompassFsr); + return false; + } + + return m_settings->HALWrite(m_magSlaveAddr, LSM9DS1_MAG_CTRL2, ctrl2, "Failed to set LSM9DS1 compass CTRL6"); +} + +bool RTIMULSM9DS1::setCompassCTRL3() +{ + return m_settings->HALWrite(m_magSlaveAddr, LSM9DS1_MAG_CTRL3, 0x00, "Failed to set LSM9DS1 compass CTRL3"); +} + +int RTIMULSM9DS1::IMUGetPollInterval() +{ + return (400 / m_sampleRate); +} + +bool RTIMULSM9DS1::IMURead() +{ + unsigned char status; + unsigned char gyroData[6]; + unsigned char accelData[6]; + unsigned char compassData[6]; + + if (!m_settings->HALRead(m_accelGyroSlaveAddr, LSM9DS1_STATUS, 1, &status, "Failed to read LSM9DS1 status")) + return false; + + if ((status & 0x3) == 0) + return false; + + for (int i = 0; i<6; i++){ + if (!m_settings->HALRead(m_accelGyroSlaveAddr, LSM9DS1_OUT_X_L_G + i, 1, &gyroData[i], "Failed to read LSM9DS1 gyro data")) + return false; + + if (!m_settings->HALRead(m_accelGyroSlaveAddr, LSM9DS1_OUT_X_L_XL + i, 1, &accelData[i], "Failed to read LSM9DS1 accel data")) + return false; + + if (!m_settings->HALRead(m_magSlaveAddr, LSM9DS1_MAG_OUT_X_L + i, 1, &compassData[i], "Failed to read LSM9DS1 compass data")) + return false; + } + + + m_imuData.timestamp = RTMath::currentUSecsSinceEpoch(); + + RTMath::convertToVector(gyroData, m_imuData.gyro, m_gyroScale, false); + RTMath::convertToVector(accelData, m_imuData.accel, m_accelScale, false); + RTMath::convertToVector(compassData, m_imuData.compass, m_compassScale, false); + + // sort out gyro axes and correct for bias + + m_imuData.gyro.setZ(-m_imuData.gyro.z()); + + // sort out accel data; + + m_imuData.accel.setX(-m_imuData.accel.x()); + m_imuData.accel.setY(-m_imuData.accel.y()); + + // sort out compass axes + + m_imuData.compass.setX(-m_imuData.compass.x()); + m_imuData.compass.setZ(-m_imuData.compass.z()); + + // now do standard processing + + handleGyroBias(); + calibrateAverageCompass(); + calibrateAccel(); + + // now update the filter + + updateFusion(); + + return true; +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/9dbad3bd/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS1.h ---------------------------------------------------------------------- diff --git a/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS1.h b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS1.h new file mode 100644 index 0000000..7f4feda --- /dev/null +++ b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMULSM9DS1.h @@ -0,0 +1,93 @@ +//////////////////////////////////////////////////////////////////////////// +// +// This file is part of RTIMULib +// +// Copyright (c) 2014-2015, richards-tech, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +// Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#ifndef _RTIMULSM9DS1_H +#define _RTIMULSM9DS1_H + +#include "RTIMU.h" + +// Define this symbol to use cache mode + +//#define LSM9DS1_CACHE_MODE // not reliable at the moment + +#ifdef LSM9DS1_CACHE_MODE + +// Cache defs + +#define LSM9DS1_FIFO_CHUNK_SIZE 6 // 6 bytes of gyro data +#define LSM9DS1_FIFO_THRESH 16 // threshold point in fifo +#define LSM9DS1_CACHE_BLOCK_COUNT 16 // number of cache blocks + +typedef struct +{ + unsigned char data[LSM9DS1_FIFO_THRESH * LSM9DS1_FIFO_CHUNK_SIZE]; + int count; // number of chunks in the cache block + int index; // current index into the cache + unsigned char accel[6]; // the raw accel readings for the block + unsigned char compass[6]; // the raw compass readings for the block + +} LSM9DS1_CACHE_BLOCK; + +#endif + +class RTIMULSM9DS1 : public RTIMU +{ +public: + RTIMULSM9DS1(RTIMUSettings *settings); + ~RTIMULSM9DS1(); + + virtual const char *IMUName() { return "LSM9DS1"; } + virtual int IMUType() { return RTIMU_TYPE_LSM9DS1; } + virtual bool IMUInit(); + virtual int IMUGetPollInterval(); + virtual bool IMURead(); + +private: + bool setGyroSampleRate(); + bool setGyroCTRL3(); + bool setAccelCTRL6(); + bool setAccelCTRL7(); + bool setCompassCTRL1(); + bool setCompassCTRL2(); + bool setCompassCTRL3(); + + unsigned char m_accelGyroSlaveAddr; // I2C address of accel andgyro + unsigned char m_magSlaveAddr; // I2C address of mag + + RTFLOAT m_gyroScale; + RTFLOAT m_accelScale; + RTFLOAT m_compassScale; + +#ifdef LSM9DS1_CACHE_MODE + bool m_firstTime; // if first sample + + LSM9DS1_CACHE_BLOCK m_cache[LSM9DS1_CACHE_BLOCK_COUNT]; // the cache itself + int m_cacheIn; // the in index + int m_cacheOut; // the out index + int m_cacheCount; // number of used cache blocks + +#endif +}; + +#endif // _RTIMULSM9DS1_H http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/9dbad3bd/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUMPU9150.cpp ---------------------------------------------------------------------- diff --git a/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUMPU9150.cpp b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUMPU9150.cpp new file mode 100644 index 0000000..59d3f31 --- /dev/null +++ b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUMPU9150.cpp @@ -0,0 +1,633 @@ +//////////////////////////////////////////////////////////////////////////// +// +// This file is part of RTIMULib +// +// Copyright (c) 2014-2015, richards-tech, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +// Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#include "RTIMUMPU9150.h" +#include "RTIMUSettings.h" + +RTIMUMPU9150::RTIMUMPU9150(RTIMUSettings *settings) : RTIMU(settings) +{ + +} + +RTIMUMPU9150::~RTIMUMPU9150() +{ +} + +bool RTIMUMPU9150::setLpf(unsigned char lpf) +{ + switch (lpf) { + case MPU9150_LPF_256: + case MPU9150_LPF_188: + case MPU9150_LPF_98: + case MPU9150_LPF_42: + case MPU9150_LPF_20: + case MPU9150_LPF_10: + case MPU9150_LPF_5: + m_lpf = lpf; + return true; + + default: + HAL_ERROR1("Illegal MPU9150 lpf %d\n", lpf); + return false; + } +} + + +bool RTIMUMPU9150::setSampleRate(int rate) +{ + if ((rate < MPU9150_SAMPLERATE_MIN) || (rate > MPU9150_SAMPLERATE_MAX)) { + HAL_ERROR1("Illegal sample rate %d\n", rate); + return false; + } + m_sampleRate = rate; + m_sampleInterval = (uint64_t)1000000 / m_sampleRate; + return true; +} + +bool RTIMUMPU9150::setCompassRate(int rate) +{ + if ((rate < MPU9150_COMPASSRATE_MIN) || (rate > MPU9150_COMPASSRATE_MAX)) { + HAL_ERROR1("Illegal compass rate %d\n", rate); + return false; + } + m_compassRate = rate; + return true; +} + +bool RTIMUMPU9150::setGyroFsr(unsigned char fsr) +{ + switch (fsr) { + case MPU9150_GYROFSR_250: + m_gyroFsr = fsr; + m_gyroScale = RTMATH_PI / (131.0 * 180.0); + return true; + + case MPU9150_GYROFSR_500: + m_gyroFsr = fsr; + m_gyroScale = RTMATH_PI / (62.5 * 180.0); + return true; + + case MPU9150_GYROFSR_1000: + m_gyroFsr = fsr; + m_gyroScale = RTMATH_PI / (32.8 * 180.0); + return true; + + case MPU9150_GYROFSR_2000: + m_gyroFsr = fsr; + m_gyroScale = RTMATH_PI / (16.4 * 180.0); + return true; + + default: + HAL_ERROR1("Illegal MPU9150 gyro fsr %d\n", fsr); + return false; + } +} + +bool RTIMUMPU9150::setAccelFsr(unsigned char fsr) +{ + switch (fsr) { + case MPU9150_ACCELFSR_2: + m_accelFsr = fsr; + m_accelScale = 1.0/16384.0; + return true; + + case MPU9150_ACCELFSR_4: + m_accelFsr = fsr; + m_accelScale = 1.0/8192.0; + return true; + + case MPU9150_ACCELFSR_8: + m_accelFsr = fsr; + m_accelScale = 1.0/4096.0; + return true; + + case MPU9150_ACCELFSR_16: + m_accelFsr = fsr; + m_accelScale = 1.0/2048.0; + return true; + + default: + HAL_ERROR1("Illegal MPU9150 accel fsr %d\n", fsr); + return false; + } +} + + +bool RTIMUMPU9150::IMUInit() +{ + unsigned char result; + + m_firstTime = true; + +#ifdef MPU9150_CACHE_MODE + m_cacheIn = m_cacheOut = m_cacheCount = 0; +#endif + + // set validity flags + + m_imuData.fusionPoseValid = false; + m_imuData.fusionQPoseValid = false; + m_imuData.gyroValid = true; + m_imuData.accelValid = true; + m_imuData.compassValid = true; + m_imuData.pressureValid = false; + m_imuData.temperatureValid = false; + m_imuData.humidityValid = false; + + // configure IMU + + m_slaveAddr = m_settings->m_I2CSlaveAddress; + + setSampleRate(m_settings->m_MPU9150GyroAccelSampleRate); + setCompassRate(m_settings->m_MPU9150CompassSampleRate); + setLpf(m_settings->m_MPU9150GyroAccelLpf); + setGyroFsr(m_settings->m_MPU9150GyroFsr); + setAccelFsr(m_settings->m_MPU9150AccelFsr); + + setCalibrationData(); + + // enable the I2C bus + + if (!m_settings->HALOpen()) + return false; + + // reset the MPU9150 + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_PWR_MGMT_1, 0x80, "Failed to initiate MPU9150 reset")) + return false; + + m_settings->delayMs(100); + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_PWR_MGMT_1, 0x00, "Failed to stop MPU9150 reset")) + return false; + + if (!m_settings->HALRead(m_slaveAddr, MPU9150_WHO_AM_I, 1, &result, "Failed to read MPU9150 id")) + return false; + + if (result != MPU9150_ID) { + HAL_ERROR1("Incorrect MPU9150 id %d\n", result); + return false; + } + + // now configure the various components + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_LPF_CONFIG, m_lpf, "Failed to set lpf")) + return false; + + if (!setSampleRate()) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_GYRO_CONFIG, m_gyroFsr, "Failed to set gyro fsr")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_ACCEL_CONFIG, m_accelFsr, "Failed to set accel fsr")) + return false; + + // now configure compass + + if (!configureCompass()) + return false; + + // enable the sensors + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_PWR_MGMT_1, 1, "Failed to set pwr_mgmt_1")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_PWR_MGMT_2, 0, "Failed to set pwr_mgmt_2")) + return false; + + // select the data to go into the FIFO and enable + + if (!resetFifo()) + return false; + + gyroBiasInit(); + + HAL_INFO("MPU9150 init complete\n"); + return true; +} + +bool RTIMUMPU9150::configureCompass() +{ + unsigned char asa[3]; + unsigned char id; + + m_compassIs5883 = false; + m_compassDataLength = 8; + + bypassOn(); + + // get fuse ROM data + + if (!m_settings->HALWrite(AK8975_ADDRESS, AK8975_CNTL, 0, "Failed to set compass in power down mode 1")) { + bypassOff(); + return false; + } + + if (!m_settings->HALWrite(AK8975_ADDRESS, AK8975_CNTL, 0x0f, "Failed to set compass in fuse ROM mode")) { + bypassOff(); + return false; + } + + if (!m_settings->HALRead(AK8975_ADDRESS, AK8975_ASAX, 3, asa, "")) { + + // check to see if an HMC5883L is fitted + + if (!m_settings->HALRead(HMC5883_ADDRESS, HMC5883_ID, 1, &id, "Failed to find 5883")) { + bypassOff(); + + // this is returning true so that MPU-6050 by itself will work + + HAL_INFO("Detected MPU-6050 without compass\n"); + + m_imuData.compassValid = false; + return true; + } + if (id != 0x48) { // incorrect id for HMC5883L + + bypassOff(); + + // this is returning true so that MPU-6050 by itself will work + + HAL_INFO("Detected MPU-6050 without compass\n"); + + m_imuData.compassValid = false; + return true; + } + + // HMC5883 is present - use that + + if (!m_settings->HALWrite(HMC5883_ADDRESS, HMC5883_CONFIG_A, 0x38, "Failed to set HMC5883 config A")) { + bypassOff(); + return false; + } + + if (!m_settings->HALWrite(HMC5883_ADDRESS, HMC5883_CONFIG_B, 0x20, "Failed to set HMC5883 config B")) { + bypassOff(); + return false; + } + + if (!m_settings->HALWrite(HMC5883_ADDRESS, HMC5883_MODE, 0x00, "Failed to set HMC5883 mode")) { + bypassOff(); + return false; + } + + HAL_INFO("Detected MPU-6050 with HMC5883\n"); + + m_compassDataLength = 6; + m_compassIs5883 = true; + } else { + + // convert asa to usable scale factor + + m_compassAdjust[0] = ((float)asa[0] - 128.0) / 256.0 + 1.0f; + m_compassAdjust[1] = ((float)asa[1] - 128.0) / 256.0 + 1.0f; + m_compassAdjust[2] = ((float)asa[2] - 128.0) / 256.0 + 1.0f; + + if (!m_settings->HALWrite(AK8975_ADDRESS, AK8975_CNTL, 0, "Failed to set compass in power down mode 2")) { + bypassOff(); + return false; + } + } + + bypassOff(); + + // now set up MPU9150 to talk to the compass chip + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_I2C_MST_CTRL, 0x40, "Failed to set I2C master mode")) + return false; + + if (m_compassIs5883) { + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_I2C_SLV0_ADDR, 0x80 | HMC5883_ADDRESS, "Failed to set slave 0 address")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_I2C_SLV0_REG, HMC5883_DATA_X_HI, "Failed to set slave 0 reg")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_I2C_SLV0_CTRL, 0x86, "Failed to set slave 0 ctrl")) + return false; + } else { + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_I2C_SLV0_ADDR, 0x80 | AK8975_ADDRESS, "Failed to set slave 0 address")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_I2C_SLV0_REG, AK8975_ST1, "Failed to set slave 0 reg")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_I2C_SLV0_CTRL, 0x88, "Failed to set slave 0 ctrl")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_I2C_SLV1_ADDR, AK8975_ADDRESS, "Failed to set slave 1 address")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_I2C_SLV1_REG, AK8975_CNTL, "Failed to set slave 1 reg")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_I2C_SLV1_CTRL, 0x81, "Failed to set slave 1 ctrl")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_I2C_SLV1_DO, 0x1, "Failed to set slave 1 DO")) + return false; + + } + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_I2C_MST_DELAY_CTRL, 0x3, "Failed to set mst delay")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_YG_OFFS_TC, 0x80, "Failed to set yg offs tc")) + return false; + + if (!setCompassRate()) + return false; + + return true; +} + +bool RTIMUMPU9150::resetFifo() +{ + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_INT_ENABLE, 0, "Writing int enable")) + return false; + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_FIFO_EN, 0, "Writing fifo enable")) + return false; + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_USER_CTRL, 0, "Writing user control")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_USER_CTRL, 0x04, "Resetting fifo")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_USER_CTRL, 0x60, "Enabling the fifo")) + return false; + + m_settings->delayMs(50); + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_INT_ENABLE, 1, "Writing int enable")) + return false; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_FIFO_EN, 0x78, "Failed to set FIFO enables")) + return false; + + return true; +} + +bool RTIMUMPU9150::bypassOn() +{ + unsigned char userControl; + + if (!m_settings->HALRead(m_slaveAddr, MPU9150_USER_CTRL, 1, &userControl, "Failed to read user_ctrl reg")) + return false; + + userControl &= ~0x20; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_USER_CTRL, 1, &userControl, "Failed to write user_ctrl reg")) + return false; + + m_settings->delayMs(50); + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_INT_PIN_CFG, 0x82, "Failed to write int_pin_cfg reg")) + return false; + + m_settings->delayMs(50); + return true; +} + + +bool RTIMUMPU9150::bypassOff() +{ + unsigned char userControl; + + if (!m_settings->HALRead(m_slaveAddr, MPU9150_USER_CTRL, 1, &userControl, "Failed to read user_ctrl reg")) + return false; + + userControl |= 0x20; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_USER_CTRL, 1, &userControl, "Failed to write user_ctrl reg")) + return false; + + m_settings->delayMs(50); + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_INT_PIN_CFG, 0x80, "Failed to write int_pin_cfg reg")) + return false; + + m_settings->delayMs(50); + return true; +} + +bool RTIMUMPU9150::setSampleRate() +{ + int clockRate = 1000; + + if (m_lpf == MPU9150_LPF_256) + clockRate = 8000; + + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_SMPRT_DIV, (unsigned char)(clockRate / m_sampleRate - 1), + "Failed to set sample rate")) + return false; + + return true; +} + +bool RTIMUMPU9150::setCompassRate() +{ + int rate; + + rate = m_sampleRate / m_compassRate - 1; + + if (rate > 31) + rate = 31; + if (!m_settings->HALWrite(m_slaveAddr, MPU9150_I2C_SLV4_CTRL, rate, "Failed to set slave ctrl 4")) + return false; + return true; +} + +int RTIMUMPU9150::IMUGetPollInterval() +{ + return (400 / m_sampleRate); +} + +bool RTIMUMPU9150::IMURead() +{ + unsigned char fifoCount[2]; + unsigned int count; + unsigned char fifoData[12]; + unsigned char compassData[8]; + + if (!m_settings->HALRead(m_slaveAddr, MPU9150_FIFO_COUNT_H, 2, fifoCount, "Failed to read fifo count")) + return false; + + count = ((unsigned int)fifoCount[0] << 8) + fifoCount[1]; + + if (count == 1024) { + HAL_INFO("MPU9150 fifo has overflowed"); + resetFifo(); + m_imuData.timestamp += m_sampleInterval * (1024 / MPU9150_FIFO_CHUNK_SIZE + 1); // try to fix timestamp + return false; + } + + +#ifdef MPU9150_CACHE_MODE + if ((m_cacheCount == 0) && (count >= MPU9150_FIFO_CHUNK_SIZE) && (count < (MPU9150_CACHE_SIZE * MPU9150_FIFO_CHUNK_SIZE))) { + // special case of a small fifo and nothing cached - just handle as simple read + + if (!m_settings->HALRead(m_slaveAddr, MPU9150_FIFO_R_W, MPU9150_FIFO_CHUNK_SIZE, fifoData, "Failed to read fifo data")) + return false; + + if (!m_settings->HALRead(m_slaveAddr, MPU9150_EXT_SENS_DATA_00, m_compassDataLength, compassData, "Failed to read compass data")) + return false; + } else { + if (count >= (MPU9150_CACHE_SIZE * MPU9150_FIFO_CHUNK_SIZE)) { + if (m_cacheCount == MPU9150_CACHE_BLOCK_COUNT) { + // all cache blocks are full - discard oldest and update timestamp to account for lost samples + m_imuData.timestamp += m_sampleInterval * m_cache[m_cacheOut].count; + if (++m_cacheOut == MPU9150_CACHE_BLOCK_COUNT) + m_cacheOut = 0; + m_cacheCount--; + } + + int blockCount = count / MPU9150_FIFO_CHUNK_SIZE; // number of chunks in fifo + + if (blockCount > MPU9150_CACHE_SIZE) + blockCount = MPU9150_CACHE_SIZE; + + if (!m_settings->HALRead(m_slaveAddr, MPU9150_FIFO_R_W, MPU9150_FIFO_CHUNK_SIZE * blockCount, + m_cache[m_cacheIn].data, "Failed to read fifo data")) + return false; + + if (!m_settings->HALRead(m_slaveAddr, MPU9150_EXT_SENS_DATA_00, 8, m_cache[m_cacheIn].compass, "Failed to read compass data")) + return false; + + m_cache[m_cacheIn].count = blockCount; + m_cache[m_cacheIn].index = 0; + + m_cacheCount++; + if (++m_cacheIn == MPU9150_CACHE_BLOCK_COUNT) + m_cacheIn = 0; + + } + + // now fifo has been read if necessary, get something to process + + if (m_cacheCount == 0) + return false; + + memcpy(fifoData, m_cache[m_cacheOut].data + m_cache[m_cacheOut].index, MPU9150_FIFO_CHUNK_SIZE); + memcpy(compassData, m_cache[m_cacheOut].compass, 8); + + m_cache[m_cacheOut].index += MPU9150_FIFO_CHUNK_SIZE; + + if (--m_cache[m_cacheOut].count == 0) { + // this cache block is now empty + + if (++m_cacheOut == MPU9150_CACHE_BLOCK_COUNT) + m_cacheOut = 0; + m_cacheCount--; + } + } + +#else + + if (count > MPU9150_FIFO_CHUNK_SIZE * 40) { + // more than 40 samples behind - going too slowly so discard some samples but maintain timestamp correctly + while (count >= MPU9150_FIFO_CHUNK_SIZE * 10) { + if (!m_settings->HALRead(m_slaveAddr, MPU9150_FIFO_R_W, MPU9150_FIFO_CHUNK_SIZE, fifoData, "Failed to read fifo data")) + return false; + count -= MPU9150_FIFO_CHUNK_SIZE; + m_imuData.timestamp += m_sampleInterval; + } + } + + if (count < MPU9150_FIFO_CHUNK_SIZE) + return false; + + if (!m_settings->HALRead(m_slaveAddr, MPU9150_FIFO_R_W, MPU9150_FIFO_CHUNK_SIZE, fifoData, "Failed to read fifo data")) + return false; + + if (!m_settings->HALRead(m_slaveAddr, MPU9150_EXT_SENS_DATA_00, m_compassDataLength, compassData, "Failed to read compass data")) + return false; + +#endif + + RTMath::convertToVector(fifoData, m_imuData.accel, m_accelScale, true); + RTMath::convertToVector(fifoData + 6, m_imuData.gyro, m_gyroScale, true); + + if (m_compassIs5883) + RTMath::convertToVector(compassData, m_imuData.compass, 0.092f, true); + else + RTMath::convertToVector(compassData + 1, m_imuData.compass, 0.3f, false); + + // sort out gyro axes + + m_imuData.gyro.setX(m_imuData.gyro.x()); + m_imuData.gyro.setY(-m_imuData.gyro.y()); + m_imuData.gyro.setZ(-m_imuData.gyro.z()); + + // sort out accel data; + + m_imuData.accel.setX(-m_imuData.accel.x()); + + + if (m_compassIs5883) { + // sort out compass axes + + float temp; + + temp = m_imuData.compass.y(); + m_imuData.compass.setY(-m_imuData.compass.z()); + m_imuData.compass.setZ(-temp); + + } else { + + // use the compass fuse data adjustments + + m_imuData.compass.setX(m_imuData.compass.x() * m_compassAdjust[0]); + m_imuData.compass.setY(m_imuData.compass.y() * m_compassAdjust[1]); + m_imuData.compass.setZ(m_imuData.compass.z() * m_compassAdjust[2]); + + // sort out compass axes + + float temp; + + temp = m_imuData.compass.x(); + m_imuData.compass.setX(m_imuData.compass.y()); + m_imuData.compass.setY(-temp); + } + + + // now do standard processing + + handleGyroBias(); + calibrateAverageCompass(); + calibrateAccel(); + + if (m_firstTime) + m_imuData.timestamp = RTMath::currentUSecsSinceEpoch(); + else + m_imuData.timestamp += m_sampleInterval; + + m_firstTime = false; + + // now update the filter + + updateFusion(); + + return true; +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/9dbad3bd/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUMPU9150.h ---------------------------------------------------------------------- diff --git a/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUMPU9150.h b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUMPU9150.h new file mode 100644 index 0000000..396a632 --- /dev/null +++ b/thirdparty/RTIMULib/RTIMULib/IMUDrivers/RTIMUMPU9150.h @@ -0,0 +1,110 @@ +//////////////////////////////////////////////////////////////////////////// +// +// This file is part of RTIMULib +// +// Copyright (c) 2014-2015, richards-tech, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +// Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#ifndef _RTIMUMPU9150_H +#define _RTIMUMPU9150_H + +#include "RTIMU.h" + +// Define this symbol to use cache mode + +#define MPU9150_CACHE_MODE + +// FIFO transfer size + +#define MPU9150_FIFO_CHUNK_SIZE 12 // gyro and accels take 12 bytes + +#ifdef MPU9150_CACHE_MODE + +// Cache mode defines + +#define MPU9150_CACHE_SIZE 16 // number of chunks in a block +#define MPU9150_CACHE_BLOCK_COUNT 16 // number of cache blocks + +typedef struct +{ + unsigned char data[MPU9150_FIFO_CHUNK_SIZE * MPU9150_CACHE_SIZE]; + int count; // number of chunks in the cache block + int index; // current index into the cache + unsigned char compass[8]; // the raw compass readings for the block + +} MPU9150_CACHE_BLOCK; + +#endif + + +class RTIMUMPU9150 : public RTIMU +{ +public: + RTIMUMPU9150(RTIMUSettings *settings); + ~RTIMUMPU9150(); + + bool setLpf(unsigned char lpf); + bool setSampleRate(int rate); + bool setCompassRate(int rate); + bool setGyroFsr(unsigned char fsr); + bool setAccelFsr(unsigned char fsr); + + virtual const char *IMUName() { return "MPU-9150"; } + virtual int IMUType() { return RTIMU_TYPE_MPU9150; } + virtual bool IMUInit(); + virtual bool IMURead(); + virtual int IMUGetPollInterval(); + +private: + bool configureCompass(); // configures the compass + bool bypassOn(); // talk to compass + bool bypassOff(); // talk to MPU9150 + bool setSampleRate(); + bool setCompassRate(); + bool resetFifo(); + + bool m_firstTime; // if first sample + + unsigned char m_slaveAddr; // I2C address of MPU9150 + + unsigned char m_lpf; // low pass filter setting + int m_compassRate; // compass sample rate in Hz + unsigned char m_gyroFsr; + unsigned char m_accelFsr; + + RTFLOAT m_gyroScale; + RTFLOAT m_accelScale; + + bool m_compassIs5883; // if it is an MPU-6050/HMC5883 combo + int m_compassDataLength; // 8 for MPU-9150, 6 for HMC5883 + RTFLOAT m_compassAdjust[3]; // the compass fuse ROM values converted for use + +#ifdef MPU9150_CACHE_MODE + + MPU9150_CACHE_BLOCK m_cache[MPU9150_CACHE_BLOCK_COUNT]; // the cache itself + int m_cacheIn; // the in index + int m_cacheOut; // the out index + int m_cacheCount; // number of used cache blocks + +#endif + +}; + +#endif // _RTIMUMPU9150_H