
SPI slave program to enable communication between the FPGA and the STM32L432 board.
IMUs.cpp
- Committer:
- Zbyszek
- Date:
- 2019-05-15
- Revision:
- 15:791f35b0f220
- Parent:
- 14:7bbaafa22f8d
File content as of revision 15:791f35b0f220:
#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) { this->AccelerometerOffset.x = OffsetAX; this->AccelerometerOffset.y = OffsetAY; this->AccelerometerOffset.z = OffsetAZ; this->GyroscopeOffset.x = OffsetGX; this->GyroscopeOffset.y = OffsetGY; this->GyroscopeOffset.z = OffsetGZ; IMU_Identifier = IMU_ID; //Accelerometer Sensitvity Scale Factor reciprocals switch(SSFA) { case 0: accelSSF = 0.00006103515625f; //Sensitivity Scale Factor setting 0 reciprocal break; case 1: accelSSF = 0.0001220703125f; //Sensitivity Scale Factor setting 1 reciprocal break; case 2: accelSSF = 0.000244140625f; //Sensitivity Scale Factor setting 2 reciprocal break; case 3: accelSSF = 0.00048828125f; //Sensitivity Scale Factor setting 3 reciprocal break; default: break; } //Gyroscope Sensitivity Scale Factor reciprocals switch(SSFG) { case 0: gyroSSF = 0.00763358778625954198473282442748f; //Sensitivity Scale Factor setting 0 reciprocal break; case 1: gyroSSF = 0.01526717557251908396946564885496f; //Sensitivity Scale Factor setting 1 reciprocal break; case 2: gyroSSF = 0.03048780487804878048780487804878f; //Sensitivity Scale Factor setting 2 reciprocal break; case 3: gyroSSF = 0.06097560975609756097560975609756f; //Sensitivity Scale Factor setting 3 reciprocal 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) + this->AccelerometerOffset.x; //Combine Accelerometer x-axis data and apply offset cancellation value break; case 1: LocalD.Ay = (MSB + LSB) + this->AccelerometerOffset.y; //Combine Accelerometer y-axis data and apply offset cancellation value break; case 2: LocalD.Az = (MSB + LSB) + this->AccelerometerOffset.z; //Combine Accelerometer z-axis data and apply offset cancellation value break; case 3: LocalD.Gx = (MSB + LSB) + this->GyroscopeOffset.x; //Combine Gyroscope x-axis data and apply offset cancellation value break; case 4: LocalD.Gy = (MSB + LSB) + this->GyroscopeOffset.y; //Combine Gyroscope y-axis data and apply offset cancellation value break; case 5: LocalD.Gz = (MSB + LSB) + this->GyroscopeOffset.z; //Combine Gyroscope z-axis data and apply offset cancellation value 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; //Multiply the raw data by sensitivity scale factor to convert: //Accelerometer data to gravity in g. localD.Ax = RawData.Ax * this->accelSSF; localD.Ay = RawData.Ay * this->accelSSF; localD.Az = RawData.Az * this->accelSSF; //angular velocity to degrees per second localD.Gx = RawData.Gx * this->gyroSSF; localD.Gy = RawData.Gy * this->gyroSSF; localD.Gz = RawData.Gz * this->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; //use trig functions to calculate tilt angles based on accelerometer values //The function returns data in radains and therefore convert to angle by multiplying by 57.295..... 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 //Integrate with respect to time to get change in angle. AngleData.Gx = (newValues.Gx * dt); AngleData.Gy = (newValues.Gy * dt); AngleData.Gz = (newValues.Gz * dt); //return the data 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; } //---------------------------------------------------------------------------------------------------------------------------------------------------------- //Complementary filter calculation function vector IMU::CalculateCFAngles(int16_t SamplesPieces[12]) { IMU_Data ConcatenatedValues,NewAngle, SSFValues; float deltaT; static vector pureGANGLE; this->t.stop(); //Stop timer deltaT = this->t.read(); //read how much time has passed since last sample i.e sample period ConcatenatedValues = this->concatenateData(SamplesPieces); //Get Sample pieces and join together to from actual useful value SSFValues = this->SSFmultiply(ConcatenatedValues); //Multiply the values by sensitivity scale factor to get angular velocity in deg per sec and acceleration of gravity in g NewAngle = this->getAngles(SSFValues, deltaT); //calculate the accelerometer angles and the change in angle from the new gyroscope data this->CFAngle.x = 0.98f*(CFAngle.x + NewAngle.Gx) + 0.02f*NewAngle.Ax; //Complementary filter for x-axis this->CFAngle.y = 0.98f*(CFAngle.y + NewAngle.Gy) + 0.02f*NewAngle.Ay; //Complementary filter for y-axis this->CFAngle.z = 0.98f*(CFAngle.z + NewAngle.Gz) + 0.02f*NewAngle.Az; //This in fact will just return the z-axis angle to zero all the time as accelerometer tilt in this axis is zero this->t.reset(); //reset timer to count until next sample arrives this->t.start(); //Start the timer again to start counting return CFAngle; //Return the calculated complementary filter angles } 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; }