ROME2 Robot Firmware

IMU.cpp

Committer:
boro
Date:
2021-03-09
Revision:
3:6fe17b8a6d62
Parent:
0:4beb2ea291ec

File content as of revision 3:6fe17b8a6d62:

/*
 * Main.cpp
 * Copyright (c) 2018, ZHAW
 * All rights reserved.
 */

#include "IMU.h"
#include "mbed.h"



using namespace std;

const float IMU::M_PI = 3.14159265358979323846f;    // the mathematical constant PI
const float IMU::SAMPLE_TIME = 0.001f;
const float IMU::STD_ALPHA = 0.02f; // standard deviation Measurement noise sensor gx - R
const float IMU::STD_OMEGA = 0.034f; // standard deviation Measurement noise sensor gx - R


/**
 * Creates an IMU object.
 * @param spi a reference to an spi controller to use.
 * @param csAG the chip select output for the accelerometer and the gyro sensor.
 * @param csM the chip select output for the magnetometer.
 */
IMU::IMU(SPI& spi, DigitalOut& csAG, DigitalOut& csM) : 
        spi(spi), csAG(csAG), csM(csM)
{

    // initialize SPI interface

    spi.format(8, 3);
    spi.frequency(100000); //90000000

    // reset chip select lines to logical high

    csAG = 1;
    csM = 1;

    // initialize accelerometer and gyro

    writeRegister(csAG, CTRL_REG1_G, 0xCB);     // ODR 952 Hz, full scale 245 deg/s
    writeRegister(csAG, CTRL_REG2_G, 0x00);     // disable interrupt generation
    writeRegister(csAG, CTRL_REG3_G, 0x00);     // disable low power mode, disable high pass filter, high pass cutoff frequency 57 Hz
    writeRegister(csAG, CTRL_REG4, 0x38);       // enable gyro in all 3 axis
    writeRegister(csAG, CTRL_REG5_XL, 0x38);    // no decimation, enable accelerometer in all 3 axis
    writeRegister(csAG, CTRL_REG6_XL, 0xC0);    // ODR 952 Hz, full scale 2g
    writeRegister(csAG, CTRL_REG7_XL, 0x00);    // high res mode disabled, filter bypassed
    writeRegister(csAG, CTRL_REG8, 0x00);       // 4-wire SPI interface, LSB at lower address
    writeRegister(csAG, CTRL_REG9, 0x04);       // disable gyro sleep mode, disable I2C interface, disable FIFO
    writeRegister(csAG, CTRL_REG10, 0x00);      // self test disabled

    // initialize magnetometer

    writeRegister(csM, CTRL_REG1_M, 0x10);      // temperature not compensated, low power mode for x & y axis, data rate 10 Hz
    writeRegister(csM, CTRL_REG2_M, 0x00);      // full scale 4 gauss
    writeRegister(csM, CTRL_REG3_M, 0x80);      // disable I2C interface, low power mode, SPI write only, continuous conversion mode
    writeRegister(csM, CTRL_REG4_M, 0x00);      // low power mode for z axis, LSB at lower address
    writeRegister(csM, CTRL_REG5_M, 0x00);      // fast read disabled

    gainAx = 0.9921997f;
    gainAy = 1.0f;
    gainAz = 1.0f;
    gainGx = 2.391f; //2.4648f
    gainGy = 2.3896f;
    gainGz = 2.4f;

    offsGx = -0.1162f; //-0.0057f
    offsGy = -0.0374f;
    offsGz = -0.0087f;
    offsAx = 0.0925285f;
    offsAy = 0.0f;
    offsAz = 0.0f;
}

/**
 * Deletes the IMU object.
 */
IMU::~IMU() {}

/**
 * This private method allows to write a register value.
 * @param cs the chip select output to use, either csAG or csM.
 * @param address the 7 bit address of the register.
 * @param value the value to write into the register.
 */
void IMU::writeRegister(DigitalOut& cs, uint8_t address, uint8_t value)
{

    cs = 0;

    spi.write(0x7F & address);
    spi.write(value & 0xFF);

    cs = 1;
}

/**
 * This private method allows to read a register value.
 * @param cs the chip select output to use, either csAG or csM.
 * @param address the 7 bit address of the register.
 * @return the value read from the register.
 */
uint8_t IMU::readRegister(DigitalOut& cs, uint8_t address)
{

    cs = 0;

    spi.write(0x80 | address);
    int32_t value = spi.write(0xFF);

    cs = 1;

    return static_cast<uint8_t>(value & 0xFF);
}

/**
 * Reads the gyroscope about the x-axis.
 * @return the rotational speed about the x-axis given in [rad/s].
 */
float IMU::readGyroX()
{

    uint8_t low = readRegister(csAG, OUT_X_L_G);
    uint8_t high = readRegister(csAG, OUT_X_H_G);

    int16_t value = static_cast<int16_t>((static_cast<uint16_t>(high) << 8) | static_cast<uint16_t>(low));

    return static_cast<float>(value)/32768.0f*245.0f*M_PI/180.0f*gainGx + offsGx; // --> Fullscale +-500 (bevor: +-245) + scale factor: 2.4648
}

/**
 * Reads the gyroscope about the y-axis.
 * @return the rotational speed about the y-axis given in [rad/s].
 */
float IMU::readGyroY()
{
    uint8_t low = readRegister(csAG, OUT_Y_L_G);
    uint8_t high = readRegister(csAG, OUT_Y_H_G);

    int16_t value = static_cast<int16_t>((static_cast<uint16_t>(high) << 8) | static_cast<uint16_t>(low));

    return static_cast<float>(value)/32768.0f*245.0f*M_PI/180.0f*gainGy + offsGy; // --> Fullscale +-500 (bevor: +-245) + scale factor: 2.3896
}

/**
 * Reads the gyroscope about the z-axis.
 * @return the rotational speed about the z-axis given in [rad/s].
 */
float IMU::readGyroZ()
{

    uint8_t low = readRegister(csAG, OUT_Z_L_G);
    uint8_t high = readRegister(csAG, OUT_Z_H_G);

    int16_t value = static_cast<int16_t>((static_cast<uint16_t>(high) << 8) | static_cast<uint16_t>(low));

    return static_cast<float>(value)/32768.0f*245.0f*M_PI/180.0f*gainGz + offsGz;
}

/**
 * Reads the acceleration in x-direction.
 * @return the acceleration in x-direction, given in [m/s2].
 */
float IMU::readAccelerationX()
{

    uint8_t low = readRegister(csAG, OUT_X_L_XL);
    uint8_t high = readRegister(csAG, OUT_X_H_XL);

    int16_t value = static_cast<int16_t>((static_cast<uint16_t>(high) << 8) | static_cast<uint16_t>(low));

    return static_cast<float>(value)/32768.0f*2.0f*9.81f*gainAx + offsAx; // added scale factor 0.9911414 and offset -0.3793863
}

/**
 * Reads the acceleration in y-direction.
 * @return the acceleration in y-direction, given in [m/s2].
 */
float IMU::readAccelerationY()
{

    uint8_t low = readRegister(csAG, OUT_Y_L_XL);
    uint8_t high = readRegister(csAG, OUT_Y_H_XL);

    int16_t value = static_cast<int16_t>((static_cast<uint16_t>(high) << 8) | static_cast<uint16_t>(low));

    return static_cast<float>(value)/32768.0f*2.0f*9.81f*gainAy + offsAy; // added scale factor 1.0011989 and offset -0.0116007
}

/**
 * Reads the acceleration in z-direction.
 * @return the acceleration in z-direction, given in [m/s2].
 */
float IMU::readAccelerationZ()
{

    uint8_t low = readRegister(csAG, OUT_Z_L_XL);
    uint8_t high = readRegister(csAG, OUT_Z_H_XL);

    int16_t value = static_cast<int16_t>((static_cast<uint16_t>(high) << 8) | static_cast<uint16_t>(low));

    return static_cast<float>(value)/32768.0f*2.0f*9.81f*gainAz + offsAz; // added scale factor 0.9921997 and offset -0.0925285f
}

/**
 * Reads the magnetic field in x-direction.
 * @return the magnetic field in x-direction, given in [Gauss].
 */
float IMU::readMagnetometerX()
{

    uint8_t low = readRegister(csM, OUT_X_L_M);
    uint8_t high = readRegister(csM, OUT_X_H_M);

    int16_t value = static_cast<int16_t>((static_cast<uint16_t>(high) << 8) | static_cast<uint16_t>(low));

    return static_cast<float>(value)/32768.0f*4.0f;
}

/**
 * Reads the magnetic field in x-direction.
 * @return the magnetic field in x-direction, given in [Gauss].
 */
float IMU::readMagnetometerY()
{

    uint8_t low = readRegister(csM, OUT_Y_L_M);
    uint8_t high = readRegister(csM, OUT_Y_H_M);

    int16_t value = static_cast<int16_t>((static_cast<uint16_t>(high) << 8) | static_cast<uint16_t>(low));

    return static_cast<float>(value)/32768.0f*4.0f;
}

/**
 * Reads the magnetic field in x-direction.
 * @return the magnetic field in x-direction, given in [Gauss].
 */
float IMU::readMagnetometerZ()
{

    uint8_t low = readRegister(csM, OUT_Z_L_M);
    uint8_t high = readRegister(csM, OUT_Z_H_M);

    int16_t value = static_cast<int16_t>((static_cast<uint16_t>(high) << 8) | static_cast<uint16_t>(low));

    return static_cast<float>(value)/32768.0f*4.0f;
}