Subversion Repositories Projects

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

/*
MPU6050.cpp - Class file for the MPU6050 Triple Axis Gyroscope & Accelerometer Arduino Library.

Version: 1.0.3
(c) 2014-2015 Korneliusz Jarzebski
www.jarzebski.pl

This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.

This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/


//#if ARDUINO >= 100
//#include "Arduino.h"
//#else
//#include "WProgram.h"
//#endif
//
//#include <Wire.h>
#include <math.h>
#include <inttypes.h>
#include <util/delay.h>
#include <stdlib.h>
#include "MPU6050.h"
#include "Wire.h"

bool InitMPU6050(mpu6050_dps_t scale, mpu6050_range_t range, int mpua)
{
    // Set Address
    mpuAddress = mpua;


    Wire_begin();

    // Reset calibrate values
    dg.XAxis = 0;
    dg.YAxis = 0;
    dg.ZAxis = 0;
    useCalibrate = false;

    // Reset threshold values
    tg.XAxis = 0;
    tg.YAxis = 0;
    tg.ZAxis = 0;
    actualThreshold = 0;

    // Check MPU6050 Who Am I Register
    if (fastRegister8(MPU6050_REG_WHO_AM_I) != 0x68)
    {
        return (false);
    }

    // Set Clock Source
    setClockSource(MPU6050_CLOCK_PLL_XGYRO);

    // Set Scale & Range
    setScale(scale);
    setRange(range);

    // Disable Sleep Mode
    setSleepEnabled(false);

    return (true);
}

void setScale(mpu6050_dps_t scale)
{
    uint8_t value;

    switch (scale)
    {
        case MPU6050_SCALE_250DPS:
            dpsPerDigit = .007633f;
            break;
        case MPU6050_SCALE_500DPS:
            dpsPerDigit = .015267f;
            break;
        case MPU6050_SCALE_1000DPS:
            dpsPerDigit = .030487f;
            break;
        case MPU6050_SCALE_2000DPS:
            dpsPerDigit = .060975f;
            break;
        default:
            break;
    }

    value = readRegister8(MPU6050_REG_GYRO_CONFIG);
    value &= 0b11100111;
    value |= (scale << 3);
    writeRegister8(MPU6050_REG_GYRO_CONFIG, value);
}

mpu6050_dps_t getScale(void)
{
    uint8_t value;
    value = readRegister8(MPU6050_REG_GYRO_CONFIG);
    value &= 0b00011000;
    value >>= 3;
    return ((mpu6050_dps_t)value);
}

void setRange(mpu6050_range_t range)
{
    uint8_t value;

    switch (range)
    {
        case MPU6050_RANGE_2G:
            rangePerDigit = .000061f;
            break;
        case MPU6050_RANGE_4G:
            rangePerDigit = .000122f;
            break;
        case MPU6050_RANGE_8G:
            rangePerDigit = .000244f;
            break;
        case MPU6050_RANGE_16G:
            rangePerDigit = .0004882f;
            break;
        default:
            break;
    }

    value = readRegister8(MPU6050_REG_ACCEL_CONFIG);
    value &= 0b11100111;
    value |= (range << 3);
    writeRegister8(MPU6050_REG_ACCEL_CONFIG, value);
}

mpu6050_range_t getRange(void)
{
    uint8_t value;
    value = readRegister8(MPU6050_REG_ACCEL_CONFIG);
    value &= 0b00011000;
    value >>= 3;
    return ((mpu6050_range_t)value);
}

void setDHPFMode(mpu6050_dhpf_t dhpf)
{
    uint8_t value;
    value = readRegister8(MPU6050_REG_ACCEL_CONFIG);
    value &= 0b11111000;
    value |= dhpf;
    writeRegister8(MPU6050_REG_ACCEL_CONFIG, value);
}

void setDLPFMode(mpu6050_dlpf_t dlpf)
{
    uint8_t value;
    value = readRegister8(MPU6050_REG_CONFIG);
    value &= 0b11111000;
    value |= dlpf;
    writeRegister8(MPU6050_REG_CONFIG, value);
}

void setClockSource(mpu6050_clockSource_t source)
{
    uint8_t value;
    value = readRegister8(MPU6050_REG_PWR_MGMT_1);
    value &= 0b11111000;
    value |= source;
    writeRegister8(MPU6050_REG_PWR_MGMT_1, value);
}

mpu6050_clockSource_t getClockSource(void)
{
    uint8_t value;
    value = readRegister8(MPU6050_REG_PWR_MGMT_1);
    value &= 0b00000111;
    return ((mpu6050_clockSource_t)value);
}

bool getSleepEnabled(void)
{
    return (readRegisterBit(MPU6050_REG_PWR_MGMT_1, 6));
}

void setSleepEnabled(bool state)
{
    writeRegisterBit(MPU6050_REG_PWR_MGMT_1, 6, state);
}

bool getIntZeroMotionEnabled(void)
{
    return (readRegisterBit(MPU6050_REG_INT_ENABLE, 5));
}

void setIntZeroMotionEnabled(bool state)
{
    writeRegisterBit(MPU6050_REG_INT_ENABLE, 5, state);
}

bool getIntMotionEnabled(void)
{
    return (readRegisterBit(MPU6050_REG_INT_ENABLE, 6));
}

void setIntMotionEnabled(bool state)
{
    writeRegisterBit(MPU6050_REG_INT_ENABLE, 6, state);
}

bool getIntFreeFallEnabled(void)
{
    return (readRegisterBit(MPU6050_REG_INT_ENABLE, 7));
}

void setIntFreeFallEnabled(bool state)
{
    writeRegisterBit(MPU6050_REG_INT_ENABLE, 7, state);
}

uint8_t getMotionDetectionThreshold(void)
{
    return (readRegister8(MPU6050_REG_MOT_THRESHOLD));
}

void setMotionDetectionThreshold(uint8_t threshold)
{
    writeRegister8(MPU6050_REG_MOT_THRESHOLD, threshold);
}

uint8_t getMotionDetectionDuration(void)
{
    return (readRegister8(MPU6050_REG_MOT_DURATION));
}

void setMotionDetectionDuration(uint8_t duration)
{
    writeRegister8(MPU6050_REG_MOT_DURATION, duration);
}

uint8_t getZeroMotionDetectionThreshold(void)
{
    return (readRegister8(MPU6050_REG_ZMOT_THRESHOLD));
}

void setZeroMotionDetectionThreshold(uint8_t threshold)
{
    writeRegister8(MPU6050_REG_ZMOT_THRESHOLD, threshold);
}

uint8_t getZeroMotionDetectionDuration(void)
{
    return (readRegister8(MPU6050_REG_ZMOT_DURATION));
}

void setZeroMotionDetectionDuration(uint8_t duration)
{
    writeRegister8(MPU6050_REG_ZMOT_DURATION, duration);
}

uint8_t getFreeFallDetectionThreshold(void)
{
    return (readRegister8(MPU6050_REG_FF_THRESHOLD));
}

void setFreeFallDetectionThreshold(uint8_t threshold)
{
    writeRegister8(MPU6050_REG_FF_THRESHOLD, threshold);
}

uint8_t getFreeFallDetectionDuration(void)
{
    return (readRegister8(MPU6050_REG_FF_DURATION));
}

void setFreeFallDetectionDuration(uint8_t duration)
{
    writeRegister8(MPU6050_REG_FF_DURATION, duration);
}

bool getI2CMasterModeEnabled(void)
{
    return (readRegisterBit(MPU6050_REG_USER_CTRL, 5));
}

void setI2CMasterModeEnabled(bool state)
{
    writeRegisterBit(MPU6050_REG_USER_CTRL, 5, state);
}

void setI2CBypassEnabled(bool state)
{
    return (writeRegisterBit(MPU6050_REG_INT_PIN_CFG, 1, state));
}

bool getI2CBypassEnabled(void)
{
    return (readRegisterBit(MPU6050_REG_INT_PIN_CFG, 1));
}

void setAccelPowerOnDelay(mpu6050_onDelay_t delay)
{
    uint8_t value;
    value = readRegister8(MPU6050_REG_MOT_DETECT_CTRL);
    value &= 0b11001111;
    value |= (delay << 4);
    writeRegister8(MPU6050_REG_MOT_DETECT_CTRL, value);
}

mpu6050_onDelay_t getAccelPowerOnDelay(void)
{
    uint8_t value;
    value = readRegister8(MPU6050_REG_MOT_DETECT_CTRL);
    value &= 0b00110000;
    return ((mpu6050_onDelay_t)(value >> 4));
}

uint8_t getIntStatus(void)
{
    return (readRegister8(MPU6050_REG_INT_STATUS));
}

Activites readActivites(void)
{
    uint8_t data = readRegister8(MPU6050_REG_INT_STATUS);

    a.isOverflow = ((data >> 4) & 1);
    a.isFreeFall = ((data >> 7) & 1);
    a.isInactivity = ((data >> 5) & 1);
    a.isActivity = ((data >> 6) & 1);
    a.isDataReady = ((data >> 0) & 1);

    data = readRegister8(MPU6050_REG_MOT_DETECT_STATUS);

    a.isNegActivityOnX = ((data >> 7) & 1);
    a.isPosActivityOnX = ((data >> 6) & 1);

    a.isNegActivityOnY = ((data >> 5) & 1);
    a.isPosActivityOnY = ((data >> 4) & 1);

    a.isNegActivityOnZ = ((data >> 3) & 1);
    a.isPosActivityOnZ = ((data >> 2) & 1);

    return (a);
}

Vector readRawAccel(void)
{
    Wire_beginTransmission_int(mpuAddress);
//    #if ARDUINO >= 100
        Wire_write(MPU6050_REG_ACCEL_XOUT_H);
//    #else
//      Wire.send(MPU6050_REG_ACCEL_XOUT_H);
//    #endif
    Wire_endTransmission();

    Wire_beginTransmission_int(mpuAddress);
    Wire_requestFrom_int(mpuAddress, 6);

    while (Wire_available() < 6);

//    #if ARDUINO >= 100
        uint8_t xha = Wire_read();
        uint8_t xla = Wire_read();
        uint8_t yha = Wire_read();
        uint8_t yla = Wire_read();
        uint8_t zha = Wire_read();
        uint8_t zla = Wire_read();
//    #else
//      uint8_t xha = Wire.receive();
//      uint8_t xla = Wire.receive();
//      uint8_t yha = Wire.receive();
//      uint8_t yla = Wire.receive();
//      uint8_t zha = Wire.receive();
//      uint8_t zla = Wire.receive();
//    #endif

    ra.XAxis = xha << 8 | xla;
    ra.YAxis = yha << 8 | yla;
    ra.ZAxis = zha << 8 | zla;

    return (ra);
}

Vector readNormalizeAccel(void)
{
    readRawAccel();

    na.XAxis = ra.XAxis * rangePerDigit * 9.80665f;
    na.YAxis = ra.YAxis * rangePerDigit * 9.80665f;
    na.ZAxis = ra.ZAxis * rangePerDigit * 9.80665f;

    return (na);
}

Vector readScaledAccel(void)
{
    readRawAccel();

    na.XAxis = ra.XAxis * rangePerDigit;
    na.YAxis = ra.YAxis * rangePerDigit;
    na.ZAxis = ra.ZAxis * rangePerDigit;

    return (na);
}


Vector readRawGyro(void)
{
    Wire_beginTransmission_int(mpuAddress);
//    #if ARDUINO >= 100
        Wire_write(MPU6050_REG_GYRO_XOUT_H);
//    #else
//      Wire.send(MPU6050_REG_GYRO_XOUT_H);
//    #endif
    Wire_endTransmission();

    Wire_beginTransmission_int(mpuAddress);
    Wire_requestFrom_int(mpuAddress, 6);

    while (Wire_available() < 6);

//    #if ARDUINO >= 100
        uint8_t xha = Wire_read();
        uint8_t xla = Wire_read();
        uint8_t yha = Wire_read();
        uint8_t yla = Wire_read();
        uint8_t zha = Wire_read();
        uint8_t zla = Wire_read();
//    #else
//      uint8_t xha = Wire.receive();
//      uint8_t xla = Wire.receive();
//      uint8_t yha = Wire.receive();
//      uint8_t yla = Wire.receive();
//      uint8_t zha = Wire.receive();
//      uint8_t zla = Wire.receive();
//    #endif

    rg.XAxis = xha << 8 | xla;
    rg.YAxis = yha << 8 | yla;
    rg.ZAxis = zha << 8 | zla;

    return (rg);
}

Vector readNormalizeGyro(void)
{
    readRawGyro();

    if (useCalibrate)
    {
        ng.XAxis = (rg.XAxis - dg.XAxis) * dpsPerDigit;
        ng.YAxis = (rg.YAxis - dg.YAxis) * dpsPerDigit;
        ng.ZAxis = (rg.ZAxis - dg.ZAxis) * dpsPerDigit;
    } else
    {
        ng.XAxis = rg.XAxis * dpsPerDigit;
        ng.YAxis = rg.YAxis * dpsPerDigit;
        ng.ZAxis = rg.ZAxis * dpsPerDigit;
    }

    if (actualThreshold)
    {
        if (abs(ng.XAxis) < tg.XAxis) ng.XAxis = 0;
        if (abs(ng.YAxis) < tg.YAxis) ng.YAxis = 0;
        if (abs(ng.ZAxis) < tg.ZAxis) ng.ZAxis = 0;
    }

    return (ng);
}

float readTemperature(void)
{
    int16_t T;
    T = readRegister16(MPU6050_REG_TEMP_OUT_H);
    return ((float)T/340 + 36.53);
}

int16_t getGyroOffsetX(void)
{
    return (readRegister16(MPU6050_REG_GYRO_XOFFS_H));
}

int16_t getGyroOffsetY(void)
{
    return (readRegister16(MPU6050_REG_GYRO_YOFFS_H));
}

int16_t getGyroOffsetZ(void)
{
    return (readRegister16(MPU6050_REG_GYRO_ZOFFS_H));
}

void setGyroOffsetX(int16_t offset)
{
    writeRegister16(MPU6050_REG_GYRO_XOFFS_H, offset);
}

void setGyroOffsetY(int16_t offset)
{
    writeRegister16(MPU6050_REG_GYRO_YOFFS_H, offset);
}

void setGyroOffsetZ(int16_t offset)
{
    writeRegister16(MPU6050_REG_GYRO_ZOFFS_H, offset);
}

int16_t getAccelOffsetX(void)
{
    return (readRegister16(MPU6050_REG_ACCEL_XOFFS_H));
}

int16_t getAccelOffsetY(void)
{
    return (readRegister16(MPU6050_REG_ACCEL_YOFFS_H));
}

int16_t getAccelOffsetZ(void)
{
    return (readRegister16(MPU6050_REG_ACCEL_ZOFFS_H));
}

void setAccelOffsetX(int16_t offset)
{
    writeRegister16(MPU6050_REG_ACCEL_XOFFS_H, offset);
}

void setAccelOffsetY(int16_t offset)
{
    writeRegister16(MPU6050_REG_ACCEL_YOFFS_H, offset);
}

void setAccelOffsetZ(int16_t offset)
{
    writeRegister16(MPU6050_REG_ACCEL_ZOFFS_H, offset);
}




// Set treshold value
void setThreshold(uint8_t multiple)
{
    if (multiple > 0)
    {
        // If not calibrated, need calibrate
        if (!useCalibrate)
        {
            calibrateGyro(50);
        }

        // Calculate threshold vectors
        tg.XAxis = th.XAxis * multiple;
        tg.YAxis = th.YAxis * multiple;
        tg.ZAxis = th.ZAxis * multiple;
    } else
    {
        // No threshold
        tg.XAxis = 0;
        tg.YAxis = 0;
        tg.ZAxis = 0;
    }

    // Remember old threshold value
    actualThreshold = multiple;
}



// Calibrate algorithm
void calibrateGyro(uint8_t samples)
{
    // Set calibrate
    useCalibrate = true;

    // Reset values
    float sumX = 0;
    float sumY = 0;
    float sumZ = 0;
    float sigmaX = 0;
    float sigmaY = 0;
    float sigmaZ = 0;

    // Read n-samples
    for (uint8_t i = 0; i < samples; ++i)
    {
        readRawGyro();
        sumX += rg.XAxis;
        sumY += rg.YAxis;
        sumZ += rg.ZAxis;

        sigmaX += rg.XAxis * rg.XAxis;
        sigmaY += rg.YAxis * rg.YAxis;
        sigmaZ += rg.ZAxis * rg.ZAxis;

        _delay_ms(5);
    }

    // Calculate delta vectors
    dg.XAxis = sumX / samples;
    dg.YAxis = sumY / samples;
    dg.ZAxis = sumZ / samples;

    // Calculate threshold vectors
    th.XAxis = sqrt((sigmaX / 50) - (dg.XAxis * dg.XAxis));
    th.YAxis = sqrt((sigmaY / 50) - (dg.YAxis * dg.YAxis));
    th.ZAxis = sqrt((sigmaZ / 50) - (dg.ZAxis * dg.ZAxis));

    // If already set threshold, recalculate threshold vectors
    if (actualThreshold > 0)
    {
        setThreshold(actualThreshold);
    }
}

// Get current threshold value
uint8_t getThreshold(void)
{
    return (actualThreshold);
}



// Fast read 8-bit from register
uint8_t fastRegister8(uint8_t reg)
{
    uint8_t value;

    Wire_beginTransmission_int(mpuAddress);
//    #if ARDUINO >= 100
        Wire_write(reg);
//    #else
//      Wire.send(reg);
//    #endif
    Wire_endTransmission();

    Wire_beginTransmission_int(mpuAddress);
    Wire_requestFrom_int(mpuAddress, 1);
//    #if ARDUINO >= 100
        value = Wire_read();
//    #else
//      value = Wire.receive();
//    #endif;
    Wire_endTransmission();

    return (value);
}

// Read 8-bit from register
uint8_t readRegister8(uint8_t reg)
{
    uint8_t value;

    Wire_beginTransmission_int(mpuAddress);
//    #if ARDUINO >= 100
        Wire_write(reg);
//    #else
//      Wire.send(reg);
//    #endif
    Wire_endTransmission();

    Wire_beginTransmission_int(mpuAddress);
    Wire_requestFrom_int(mpuAddress, 1);
    while(!Wire_available()) {};
//    #if ARDUINO >= 100
        value = Wire_read();
//    #else
//      value = Wire.receive();
//    #endif;
    Wire_endTransmission();

    return (value);
}

// Write 8-bit to register
void writeRegister8(uint8_t reg, uint8_t value)
{
    Wire_beginTransmission_int(mpuAddress);

//    #if ARDUINO >= 100
        Wire_write(reg);
        Wire_write(value);
//    #else
//      Wire.send(reg);
//      Wire.send(value);
//    #endif
    Wire_endTransmission();
}

int16_t readRegister16(uint8_t reg)
{
    int16_t value;
    Wire_beginTransmission_int(mpuAddress);
//    #if ARDUINO >= 100
        Wire_write(reg);
//    #else
//        Wire.send(reg);
//    #endif
    Wire_endTransmission();

    Wire_beginTransmission_int(mpuAddress);
    Wire_requestFrom_int(mpuAddress, 2);
    while(!Wire_available()) {};
//    #if ARDUINO >= 100
        uint8_t vha = Wire_read();
        uint8_t vla = Wire_read();
//    #else
//        uint8_t vha = Wire.receive();
//        uint8_t vla = Wire.receive();
//    #endif;
    Wire_endTransmission();

    value = vha << 8 | vla;

    return (value);
}

void writeRegister16(uint8_t reg, int16_t value)
{
    Wire_beginTransmission_int(mpuAddress);

//    #if ARDUINO >= 100
        Wire_write(reg);
        Wire_write((uint8_t)(value >> 8));
        Wire_write((uint8_t)value);
//    #else
//      Wire.send(reg);
//      Wire.send((uint8_t)(value >> 8));
//      Wire.send((uint8_t)value);
//    #endif
    Wire_endTransmission();
}

// Read register bit
bool readRegisterBit(uint8_t reg, uint8_t pos)
{
    uint8_t value;
    value = readRegister8(reg);
    return ((value >> pos) & 1);
}

// Write register bit
void writeRegisterBit(uint8_t reg, uint8_t pos, bool state)
{
    uint8_t value;
    value = readRegister8(reg);

    if (state)
    {
        value |= (1 << pos);
    } else
    {
        value &= ~(1 << pos);
    }

    writeRegister8(reg, value);
}