test angle measurement LSM6DS3

Dependencies:   ESC IMUfilter LSM6DS3 mbed

main.cpp

Committer:
rsmits
Date:
2018-02-10
Revision:
3:78cf56b8eb21
Parent:
2:405f8e1a01d3

File content as of revision 3:78cf56b8eb21:

#include "mbed.h"
#include "esc.h" 
#include "LSM6DS3.h"
#include "IMUfilter.h"

// refresh time. set to 500 for part 2 and 50 for part 4
#define REFRESH_TIME_MS 100
//Gravity at Earth's surface in m/s/s
#define g0 9.812865328f
//Convert from degrees to radians. radians = (degrees*pi)/180
#define toRadians(x) (x * 0.01745329252f)
//Convert from radians to degrees.
#define toDegrees(x) (x * 57.2957795)
//Number of samples to average.
#define SAMPLES 4
//Number of samples to be averaged for a null bias calculation
//during calibration.
#define CALIBRATION_SAMPLES 128
//Sampling gyroscope at 200Hz.
#define GYRO_RATE   0.005
//Sampling accelerometer at 200Hz.
#define ACC_RATE    0.005
//Updating filter at 40Hz.
#define FILTER_RATE 0.1
const int   LSM6DS3_ADDRESS = 0xD4;
//const int   LSM6DS3_ADDRESS = 0x69;

Serial      pc(SERIAL_TX, SERIAL_RX); 
AnalogIn    PRESSURE_SENSOR(PA_0);
LSM6DS3     imu(PB_9, PB_8, LSM6DS3_ADDRESS);
//At rest the gyroscope is centred around 0 and goes between about
//-5 and 5 counts. As 1 degrees/sec is ~15 LSB, error is roughly
//5/15 = 0.3 degrees/sec.
IMUfilter   imuFilter(FILTER_RATE, 0.3);
Ticker      filterTicker;
Ticker      ScreenTicker; 

//Offsets for the gyroscope.
//The readings we take when the gyroscope is stationary won't be 0, so we'll
//average a set of readings we do get when the gyroscope is stationary and
//take those away from subsequent readings to ensure the gyroscope is offset
//or "biased" to 0.
float w_xBias;
float w_yBias;
float w_zBias;
 
//Offsets for the accelerometer.
//Same as with the gyroscope.
float a_xBias;
float a_yBias;
float a_zBias;
 
//Accumulators used for oversampling and then averaging.
volatile float a_xAccumulator = 0;
volatile float a_yAccumulator = 0;
volatile float a_zAccumulator = 0;
volatile float w_xAccumulator = 0;
volatile float w_yAccumulator = 0;
volatile float w_zAccumulator = 0;
 
//Accelerometer and gyroscope readings for x, y, z axes.
volatile float a_x;
volatile float a_y;
volatile float a_z;
volatile float w_x;
volatile float w_y;
volatile float w_z;
 
//Buffer for accelerometer readings.
float readings[3];
//Number of accelerometer samples we're on.
int accelerometerSamples = 0;
//Number of gyroscope samples we're on.
int gyroscopeSamples = 0;
 
/**
 * Prototypes
 */
//Calculate the null bias.
void calibrateAccelerometer(void);
//Take a set of samples and average them.
void sampleAccelerometer(void);
//Calculate the null bias.
void calibrateGyroscope(void);
//Take a set of samples and average them.
void sampleGyroscope(void);
//Update the filter and calculate the Euler angles.
void filter(void);

//Init Serial port and LSM6DS3 chip
void setup_LSM6DS3()
{
    // Use the begin() function to initialize the LSM9DS0 library.
    // You can either call it with no parameters (the easy way):
    // SLEEP
//    uint16_t status = imu.begin(imu.G_SCALE_245DPS, imu.A_SCALE_2G,
//                                imu.G_POWER_DOWN, imu.A_POWER_DOWN);
    // LOWEST
//    uint16_t status = imu.begin(imu.G_SCALE_245DPS, imu.A_SCALE_2G,
//                                imu.G_ODR_13_BW_0, imu.A_ODR_13);
    // HIGHEST
//    uint16_t status = imu.begin(imu.G_SCALE_2000DPS, imu.A_SCALE_8G,
//                                imu.G_ODR_1660, imu.A_ODR_6660);
                                
    uint16_t status = imu.begin(imu.G_SCALE_245DPS, imu.A_SCALE_2G,
                                imu.G_ODR_1660, imu.A_ODR_6660);
 
    //Make sure communication is working
    pc.printf("LSM6DS3 WHO_AM_I's returned: 0x%X\r\n", status);
    pc.printf("Should be 0x69\r\n");
}

void screenUpdate(){    
    pc.printf("%f,%f,%f\r\n",toDegrees(imuFilter.getRoll()),
          toDegrees(imuFilter.getPitch()),
          toDegrees(imuFilter.getYaw()));
}

void calibrateAccelerometer(void) {
 
    a_xAccumulator = 0;
    a_yAccumulator = 0;
    a_zAccumulator = 0;
    
    //Take a number of readings and average them
    //to calculate the zero g offset.
    for (int i = 0; i < CALIBRATION_SAMPLES; i++) {

        imu.readAccel();
        a_xAccumulator += imu.ax;
        a_yAccumulator += imu.ay;
        a_zAccumulator += imu.az;  
 
        wait(ACC_RATE);
    }
 
    a_xAccumulator /= CALIBRATION_SAMPLES;
    a_yAccumulator /= CALIBRATION_SAMPLES;
    a_zAccumulator /= CALIBRATION_SAMPLES;
 
    a_xBias = a_xAccumulator;
    a_yBias = a_yAccumulator;
    // When laying on the table, default a_z is 1g
    a_zBias = (a_zAccumulator - 1.0f);
 
    a_xAccumulator = 0;
    a_yAccumulator = 0;
    a_zAccumulator = 0;
}

void sampleAccelerometer(void) {
 
    //Have we taken enough samples?
    if (accelerometerSamples == SAMPLES) {
 
        //Average the samples, remove the bias and convert to m/s/s.
        a_x = ((a_xAccumulator / SAMPLES) - a_xBias) * g0;
        a_y = ((a_yAccumulator / SAMPLES) - a_yBias) * g0;
        a_z = ((a_zAccumulator / SAMPLES) - a_zBias) * g0;
 
        a_xAccumulator = 0;
        a_yAccumulator = 0;
        a_zAccumulator = 0;
        accelerometerSamples = 0;
 
    } else {
        //Take another sample.
        imu.readAccel();
        a_xAccumulator += imu.ax;
        a_yAccumulator += imu.ay;
        a_zAccumulator += imu.az;        
 
        accelerometerSamples++;
    }
}

void calibrateGyroscope(void) {
 
    w_xAccumulator = 0;
    w_yAccumulator = 0;
    w_zAccumulator = 0;
 
    //Take a number of readings and average them
    //to calculate the gyroscope bias offset.
    for (int i = 0; i < CALIBRATION_SAMPLES; i++) {

        imu.readGyro();
        w_xAccumulator += imu.gx;
        w_yAccumulator += imu.gy;
        w_zAccumulator += imu.gz;
        
        wait(GYRO_RATE);
    }
 
    //Average the samples.
    w_xAccumulator /= CALIBRATION_SAMPLES;
    w_yAccumulator /= CALIBRATION_SAMPLES;
    w_zAccumulator /= CALIBRATION_SAMPLES;
 
    w_xBias = w_xAccumulator;
    w_yBias = w_yAccumulator;
    w_zBias = w_zAccumulator;
 
    w_xAccumulator = 0;
    w_yAccumulator = 0;
    w_zAccumulator = 0;
}
 
void sampleGyroscope(void) {
 
    //Have we taken enough samples?
    if (gyroscopeSamples == SAMPLES) {
 
        //Average the samples, remove the bias, and calculate the angular
        //velocity in rad/s.
        w_x = toRadians(((w_xAccumulator / SAMPLES) - w_xBias));
        w_y = toRadians(((w_yAccumulator / SAMPLES) - w_yBias));
        w_z = toRadians(((w_zAccumulator / SAMPLES) - w_zBias));
 
        w_xAccumulator = 0;
        w_yAccumulator = 0;
        w_zAccumulator = 0;
        gyroscopeSamples = 0;
 
    } else {
        //Take another sample.
        imu.readGyro();
        w_xAccumulator += imu.gx;
        w_yAccumulator += imu.gy;
        w_zAccumulator += imu.gz;
 
        gyroscopeSamples++;
    }
}
 
void filter(void) {
 
    //Update the filter variables.
    imuFilter.updateFilter(w_y, w_x, w_z, a_y, a_x, a_z);
    //Calculate the new Euler angles.
    imuFilter.computeEuler();
 
}
 
int main()
{
    bool started = false;
    while (true){
        
        if(PRESSURE_SENSOR > 0.9f){
            
            if (not started){
                setup_LSM6DS3();  //Setup sensor and Serial
                pc.printf("\r\n------ LSM6DS3 Demo -----------\r\n");
                started=true;
                
                calibrateAccelerometer();
                calibrateGyroscope();
                pc.printf("\r\n------ Calibrated -----------\r\n");
                
                //Set up timers.
                filterTicker.attach(&filter, FILTER_RATE);
                ScreenTicker.attach(&screenUpdate, FILTER_RATE);
            }
            
            wait(0.005);
            sampleAccelerometer();
            sampleGyroscope();
               
        }
        else {
            started=false;
            imuFilter.reset();
            filterTicker.detach();
            ScreenTicker.detach();
        }
    }
}