SPI slave program to enable communication between the FPGA and the STM32L432 board.

Dependencies:   mbed

IMUs.cpp

Committer:
Zbyszek
Date:
2019-05-05
Revision:
14:7bbaafa22f8d
Parent:
13:c7e8e277f884
Child:
15:791f35b0f220

File content as of revision 14:7bbaafa22f8d:

#include "CustomDatatypes.h"
#include "Quaternions.h"
#include "IMUs.h"
#include "mbed.h"

//IMU Class Constructor
IMU::IMU(char IMU_ID, double OffsetAX, double OffsetAY, double OffsetAZ, double OffsetGX, double OffsetGY, double OffsetGZ, char SSFA, char SSFG) {

    AccelerometerOffset.x = OffsetAX;
    AccelerometerOffset.y = OffsetAY;
    AccelerometerOffset.z = OffsetAZ;

    GyroscopeOffset.x = OffsetGX;
    GyroscopeOffset.y = OffsetGY;
    GyroscopeOffset.z = OffsetGZ;
    
    
    IMU_Identifier = IMU_ID;
    
    switch(SSFA) {
     case 0:
        accelSSF = 0.00006103515625f;     
     break;
     case 1:
        accelSSF = 0.0001220703125f;
     break;
     case 2:
         accelSSF = 0.000244140625f; 
     break;
     case 3:
        accelSSF = 0.00048828125f; 
     break;
     default:
     break;   
    }
    
    switch(SSFG) {
     case 0:
        gyroSSF = 0.00763358778625954198473282442748f;     
     break;
     case 1:
        gyroSSF = 0.01526717557251908396946564885496f;
     break;
     case 2:
         gyroSSF = 0.03048780487804878048780487804878f; 
     break;
     case 3:
        gyroSSF = 0.06097560975609756097560975609756f; 
     break;
     default:
     break;   
    }
    
    this->t.start();     
    
}

//void IMU::CFAngle() {
    
    
    
//}

//----------------------------------------------------------------------------------------------------------------------------------------------------------
IMU_Data IMU::concatenateData(int16_t SamplesPieces[12]) {
//Local-Variables------Local-Variables------Local-Variables------Local-Variables

    int16_t MSB = 0;                                                            //Store Most Significant Byte of data piece in this variable for processing
    int16_t LSB = 0;                                                            //Store Least Significant Byte of data piece in this variable for processing
    char    arrPointer = 0;                                                     //Array Pointer
    
    IMU_Data LocalD;
    
//Procedure--------------Procedure------------Procedure-------------Procedure---      
        for(char x = 0; x <= 5; x++) {
        MSB = SamplesPieces[arrPointer];                                        //Odd data pieces are MSBs
        MSB &= ~(255<<8);                                                       //Mask the MSB bits as they are not part of data
        MSB = MSB << 8;                                                         //Shift the Value as its the MSB of the data piece
        arrPointer++;                                                           //Increment array pointer
        LSB = SamplesPieces[arrPointer];                                        //Even data pieces are LSBs
        LSB &= ~(255 << 8);                                                     //Mask the MSB bits as they are not part of data
        arrPointer++;                                                           //Increment array pointer
        
        switch(x) {
            case 0:
                LocalD.Ax = (MSB + LSB) + AccelerometerOffset.x;                 //Combine Accelerometer x-axis data
            break;
            case 1:
                LocalD.Ay = (MSB + LSB) + AccelerometerOffset.y;                 //Combine Accelerometer y-axis data
            break;
            case 2:
                LocalD.Az = (MSB + LSB) + AccelerometerOffset.z;                 //Combine Accelerometer z-axis data
            break;
            case 3:
                LocalD.Gx = (MSB + LSB) + GyroscopeOffset.x;                      //Combine Gyroscope x-axis data
            break;
            case 4:
                LocalD.Gy = (MSB + LSB) + GyroscopeOffset.y;                      //Combine Gyroscope y-axis data
            break;
            case 5:
                LocalD.Gz = (MSB + LSB) + GyroscopeOffset.z;                      //Combine Gyroscope z-axis data
            break;
            default:
            break; 
        }//switch(x) 
    }//for(char x = 0; x <= 5; x++)
    
    //printf("Accel X: %+2f,    Accel Y: %+2f,    Accel Z: %+2f,    Gyro X: %+2f,    Gyro Y: %+2f,    Gyro Z: %+2f\n\r", LocalD.Ax, LocalD.Ay, LocalD.Az, LocalD.Gx, LocalD.Gy, LocalD.Gz);
             
    return LocalD;
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------





//----------------------------------------------------------------------------------------------------------------------------------------------------------
IMU_Data IMU::SSFmultiply(IMU_Data RawData) {
    
    IMU_Data localD;  
    

    localD.Ax = RawData.Ax * accelSSF;
    localD.Ay = RawData.Ay * accelSSF;
    localD.Az = RawData.Az * accelSSF;
    
    localD.Gx = RawData.Gx * gyroSSF;
    localD.Gy = RawData.Gy * gyroSSF;
    localD.Gz = RawData.Gz * gyroSSF;
        
        //printf("Accel X: %+2f,    Accel Y: %+2f,    Accel Z: %+2f,    Gyro X: %+2f,    Gyro Y: %+2f,    Gyro Z: %+2f\n\r", LocalD.Ax, LocalD.Ay, LocalD.Az, LocalD.Gx, LocalD.Gy, LocalD.Gz);
    return localD;
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------





//----------------------------------------------------------------------------------------------------------------------------------------------------------
IMU_Data IMU::getAngles(IMU_Data SSF_Format_Values, float dt) {
    
    IMU_Data newValues, AngleData;
    
    newValues = SSF_Format_Values;
    
    AngleData.Ax = (atan2f(newValues.Ay, newValues.Az) * 57.29577951f); 
    AngleData.Ay = (atan2f((-newValues.Ax), sqrt(pow(newValues.Ay, 2) + pow(newValues.Az, 2) )) * 57.29577951f);
    AngleData.Az = 0;                                                           //Cannot calculate angle for this one as it remains constant all the time
    
    AngleData.Gx = (newValues.Gx * dt);
    AngleData.Gy = (newValues.Gy * dt);
    AngleData.Gz = (newValues.Gz * dt);
    
        //printf("Accel X: %+2f,    Accel Y: %+2f,    Accel Z: %+2f,    Gyro X: %+2f,    Gyro Y: %+2f,    Gyro Z: %+2f    dt: %2f\n\r", AngleData.Ax, AngleData.Ay, AngleData.Az, AngleData.Gx, AngleData.Gy, AngleData.Gz, dt);
    return AngleData;
    
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------





//----------------------------------------------------------------------------------------------------------------------------------------------------------
vector IMU::getAccelAngles(vector SSF_Accel) {
    
    vector newValues, AngleData;
    
    newValues = SSF_Accel;
    
    AngleData.x = (atan2f(newValues.y, newValues.z) * 57.29577951f); 
    AngleData.y = (atan2f((-newValues.x), sqrt(pow(newValues.y, 2) + pow(newValues.z, 2) )) * 57.29577951f);
    //AngleData.z = 0;                                                           //Cannot calculate angle for this one as it remains constant all the time
    
        //printf("Accel X: %+2f,    Accel Y: %+2f,    Accel Z: %+2f,    Gyro X: %+2f,    Gyro Y: %+2f,    Gyro Z: %+2f    dt: %2f\n\r", AngleData.Ax, AngleData.Ay, AngleData.Az, AngleData.Gx, AngleData.Gy, AngleData.Gz, dt);
    return AngleData;
    
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------








//----------------------------------------------------------------------------------------------------------------------------------------------------------
IMU_Data IMU::CalculateAngles(int16_t SamplesPieces[12]){
    
    IMU_Data ConcatenatedValues, SSFValues, SimpleAngles;
    static IMU_Data PrevSimpleAngles;
    float deltaT;
    
    ConcatenatedValues = this->concatenateData(SamplesPieces);
    SSFValues = this->SSFmultiply(ConcatenatedValues);
    
    this->t.stop();
    deltaT = this->t.read();
    SimpleAngles = this->getAngles(SSFValues, deltaT);
    
    PrevSimpleAngles.Gx = PrevSimpleAngles.Gx + SimpleAngles.Gx;
    PrevSimpleAngles.Gy = PrevSimpleAngles.Gy + SimpleAngles.Gy;
    PrevSimpleAngles.Gz = PrevSimpleAngles.Gz + SimpleAngles.Gz;
    
    this->t.reset();
    this->t.start();
    
        //printf("Accel X: %+2f,    Accel Y: %+2f,    Accel Z: %+2f,    Gyro X: %+2f,    Gyro Y: %+2f,    Gyro Z: %+2f\n\r", PrevSimpleAngles.Ax, PrevSimpleAngles.Ay, PrevSimpleAngles.Az, PrevSimpleAngles.Gx, PrevSimpleAngles.Gy, PrevSimpleAngles.Gz);
    return PrevSimpleAngles;
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------


vector IMU::CalculateCFAngles(int16_t SamplesPieces[12]) {
    
    IMU_Data ConcatenatedValues,NewAngle, SSFValues;
    float deltaT;
    
    
    this->t.stop();
    deltaT = this->t.read();
    ConcatenatedValues = this->concatenateData(SamplesPieces);
    SSFValues          = this->SSFmultiply(ConcatenatedValues);
    NewAngle           = this->getAngles(SSFValues, deltaT);
    
    this->CFAngle.x = 0.98f*(CFAngle.x + NewAngle.Gx) + 0.02f*NewAngle.Ax;
    this->CFAngle.y = 0.98f*(CFAngle.y + NewAngle.Gy) + 0.02f*NewAngle.Ay;
    this->CFAngle.z = 0.98f*(CFAngle.z + NewAngle.Gz) + 0.02f*NewAngle.Az;
    
    t.reset();
    t.start();
    
        //printf("Accel X: %+2f,    Accel Y: %+2f,    Accel Z: %+2f,  dt: %+2f\n\r", CFAngle.x, CFAngle.y, CFAngle.z, deltaT);
        //printf("%+2f,%+2f,%+2f\n\r", CFAngle.x, CFAngle.y, CFAngle.z);
    return CFAngle;
    
}



vector IMU::CalculateQCFAngles(int16_t SamplesPieces[12]) {
    
    IMU_Data ConcatenatedValues,NewAngle, SSFValues;
    float deltaT;
    static Quaternion CF = {.w = 1.0f, .x = 0.0001f, .y = 0.0001f, .z = 0.0001f};
    vector Accel_Angles, Eangles, accelSSFVals, SSFAngularRate, QuaternionAngles;
    
       
    this->t.stop();
    deltaT = this->t.read();
    ConcatenatedValues = this->concatenateData(SamplesPieces);
    SSFValues          = this->SSFmultiply(ConcatenatedValues);                                        
    
    //convert to radians per second
    SSFValues.Gx *= 0.0174533f;
    SSFValues.Gy *= 0.0174533f; 
    SSFValues.Gz *= 0.0174533f;  
    
    //Angular rates used for Quaternion gyro integration
    SSFAngularRate.x = SSFValues.Gx;
    SSFAngularRate.y = SSFValues.Gy;
    SSFAngularRate.z = SSFValues.Gz;    
    
    CF = updateQuaternion(CF, SSFAngularRate, deltaT); 
    CF = normaliseQuaternion(CF);
    Eangles = eulerA(CF);
    
    
    //Get accel ssf values into vector format
    accelSSFVals.x = SSFValues.Ax;
    accelSSFVals.y = SSFValues.Ay;
    accelSSFVals.z = SSFValues.Az;
    Accel_Angles = getAccelAngles(accelSSFVals);                                //Convert Accel data to angle
        
    
    CF.x = 0.98f*(Eangles.x) + 0.02f*Accel_Angles.x;
    CF.y = 0.98f*(Eangles.y) + 0.02f*Accel_Angles.y;
    CF.z = 0.98f*(Eangles.z) + 0.02f*Accel_Angles.z;
   
    QuaternionAngles.x = CF.x;
    QuaternionAngles.y = CF.y;
    QuaternionAngles.z = CF.z;
    
    //Convert back to radians 
    CF.x *= 0.0174533f;             
    CF.y *= 0.0174533f;
    CF.z *= 0.0174533f;
    
    CF = euler2Quaternion(CF);                                                  //Conver CF angle back to quaternion for next iteration
    CF = normaliseQuaternion(CF);                                               //Normalise the quaternion
    
    this->t.reset();
    this->t.start();
    
    printf("Quat Angle X: %+2f,    Quat Angle Y: %+2f,    Quat Angle Z: %+2f,  dt: %+2f\n\r", QuaternionAngles.x, QuaternionAngles.y, QuaternionAngles.z, deltaT);
    return QuaternionAngles;
    
}