Program Listing for File mpu6500.hpp
↰ Return to documentation for file (src/tap/communication/sensors/imu/mpu6500/mpu6500.hpp
)
/*
* Copyright (c) 2020-2022 Advanced Robotics at the University of Washington <robomstr@uw.edu>
*
* This file is part of Taproot.
*
* Taproot is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Taproot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Taproot. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef TAPROOT_MPU6500_HPP_
#define TAPROOT_MPU6500_HPP_
#include <cstdint>
#include "tap/algorithms/MahonyAHRS.h"
#include "tap/architecture/timeout.hpp"
#include "tap/communication/sensors/imu/imu_interface.hpp"
#include "tap/communication/sensors/imu_heater/imu_heater.hpp"
#include "tap/util_macros.hpp"
#include "modm/math/geometry.hpp"
#include "modm/processing/protothread.hpp"
#define LITTLE_ENDIAN_INT16_TO_FLOAT(buff) \
(static_cast<float>(static_cast<int16_t>((*(buff) << 8) | *(buff + 1))))
namespace tap
{
class Drivers;
}
namespace tap::communication::sensors::imu::mpu6500
{
class Mpu6500 final_mockable : public ::modm::pt::Protothread, public ImuInterface
{
public:
static constexpr uint8_t ACC_GYRO_TEMPERATURE_BUFF_RX_SIZE = 14;
struct RawData
{
modm::Vector3f accel;
modm::Vector3f gyro;
uint16_t temperature = 0;
modm::Vector3f accelOffset;
modm::Vector3f gyroOffset;
};
using ProcessRawMpu6500DataFn = void (*)(
const uint8_t (&)[ACC_GYRO_TEMPERATURE_BUFF_RX_SIZE],
modm::Vector3f &accel,
modm::Vector3f &gyro);
Mpu6500(Drivers *drivers);
DISALLOW_COPY_AND_ASSIGN(Mpu6500)
mockable ~Mpu6500() = default;
mockable void init(float sampleFrequency, float mahonyKp, float mahonyKi);
mockable void periodicIMUUpdate();
mockable bool read();
bool run() { return this->read(); }
mockable inline ImuState getImuState() const { return imuState; }
virtual inline const char *getName() const { return "mpu6500"; }
inline float validateReading(float reading)
{
if (imuState == ImuState::IMU_CALIBRATED)
{
return reading;
}
else if (imuState == ImuState::IMU_NOT_CALIBRATED)
{
errorState |= 1 << static_cast<uint8_t>(ImuState::IMU_NOT_CALIBRATED);
return reading;
}
else if (imuState == ImuState::IMU_CALIBRATING)
{
errorState |= 1 << static_cast<uint8_t>(ImuState::IMU_CALIBRATING);
return 0.0f;
}
else
{
errorState |= 1 << static_cast<uint8_t>(ImuState::IMU_NOT_CONNECTED);
return 0.0f;
}
}
inline float getAx() final_mockable
{
return validateReading(
static_cast<float>(raw.accel.x - raw.accelOffset.x) * ACCELERATION_GRAVITY /
ACCELERATION_SENSITIVITY);
}
inline float getAy() final_mockable
{
return validateReading(
static_cast<float>(raw.accel.y - raw.accelOffset.y) * ACCELERATION_GRAVITY /
ACCELERATION_SENSITIVITY);
}
inline float getAz() final_mockable
{
return validateReading(
static_cast<float>(raw.accel.z - raw.accelOffset.z) * ACCELERATION_GRAVITY /
ACCELERATION_SENSITIVITY);
}
inline float getGx() final_mockable
{
return validateReading(
static_cast<float>(raw.gyro.x - raw.gyroOffset.x) / LSB_D_PER_S_TO_D_PER_S);
}
inline float getGy() final_mockable
{
return validateReading(
static_cast<float>(raw.gyro.y - raw.gyroOffset.y) / LSB_D_PER_S_TO_D_PER_S);
}
inline float getGz() final_mockable
{
return validateReading(
static_cast<float>(raw.gyro.z - raw.gyroOffset.z) / LSB_D_PER_S_TO_D_PER_S);
}
inline float getTemp() final_mockable
{
return 21.0f + static_cast<float>(raw.temperature) / 333.87f;
}
inline float getYaw() final_mockable { return validateReading(mahonyAlgorithm.getYaw()); }
inline float getPitch() final_mockable { return validateReading(mahonyAlgorithm.getPitch()); }
inline float getRoll() final_mockable { return validateReading(mahonyAlgorithm.getRoll()); }
mockable inline uint32_t getPrevIMUDataReceivedTime() const { return prevIMUDataReceivedTime; }
mockable float getTiltAngle();
mockable void requestCalibration();
void attachProcessRawMpu6500DataFn(ProcessRawMpu6500DataFn fn) { processRawMpu6500DataFn = fn; }
static constexpr float LSB_D_PER_S_TO_D_PER_S = 16.384f;
inline void setCalibrationSamples(float samples) { MPU6500_OFFSET_SAMPLES = samples; }
inline void setTargetTemperature(float temperatureC)
{
imuHeater.setDesiredTemperature(temperatureC);
}
private:
static constexpr float ACCELERATION_GRAVITY = 9.80665f;
static constexpr float ACCELERATION_SENSITIVITY = 4096.0f;
float MPU6500_OFFSET_SAMPLES = 1000;
static constexpr int NONBLOCKING_TIME_TO_READ_REG = 450;
static constexpr uint32_t MAX_WAIT_FOR_IMU_TEMPERATURE_STABALIZE = 10'000;
static constexpr uint32_t WAIT_TIME_AFTER_CALIBRATION = 10'000;
static constexpr uint8_t MPU6500_READ_BIT = 0x80;
Drivers *drivers;
ProcessRawMpu6500DataFn processRawMpu6500DataFn;
int delayBtwnCalcAndReadReg = 2000 - NONBLOCKING_TIME_TO_READ_REG;
ImuState imuState = ImuState::IMU_NOT_CONNECTED;
tap::arch::MicroTimeout readRegistersTimeout;
uint8_t tx = 0;
uint8_t rx = 0;
RawData raw;
Mahony mahonyAlgorithm;
imu_heater::ImuHeater imuHeater;
float tiltAngle = 0.0f;
bool tiltAngleCalculated = false;
uint8_t txBuff[ACC_GYRO_TEMPERATURE_BUFF_RX_SIZE] = {0};
uint8_t rxBuff[ACC_GYRO_TEMPERATURE_BUFF_RX_SIZE] = {0};
int calibrationSample = 0;
uint8_t errorState = 0;
uint32_t prevIMUDataReceivedTime = 0;
// Functions for interacting with hardware directly.
void mpuNssLow();
void mpuNssHigh();
void spiWriteRegister(uint8_t reg, uint8_t data);
uint8_t spiReadRegister(uint8_t reg);
void spiReadRegisters(uint8_t regAddr, uint8_t *pData, uint8_t len);
void addValidationErrors();
static void defaultProcessRawMpu6500Data(
const uint8_t (&rxBuff)[ACC_GYRO_TEMPERATURE_BUFF_RX_SIZE],
modm::Vector3f &accel,
modm::Vector3f &gyro);
};
} // namespace tap::communication::sensors::imu::mpu6500
#endif // TAPROOT_MPU6500_HPP_