Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of virgo3_imuHandler_Orion_PCB by
imuHandler.cpp
- Committer:
- akashvibhute
- Date:
- 2016-04-26
- Revision:
- 1:927f1b3e4bf4
- Parent:
- 0:88de7b3bd889
- Child:
- 2:3ab5d5ee2160
- Child:
- 3:d7a72ce26117
File content as of revision 1:927f1b3e4bf4:
/* * Copyright (C) 2016 Akash Vibhute <akash.roboticist@gmail.com> * * Wrapper to handle all quirks of MPU9250 and BNO055 IMU on Virgo 3 robot. * Based off various user libraries * * * Initial Release: Apr/26/2016 * */ #include "imuHandler.h" /*** MPU6050 ***/ IMU_MPU6050::IMU_MPU6050(): imu_mpu6050(i2c_SDA, i2c_SCL) { unsigned int movWindowSize_Pose = Pose_MWindowSize; unsigned int movWindowSize_GyroAcc = GyroAcc_MWindowSize; unstable_readings = MPU6050_StabilizationReadings; imu_stabilized=false; if(movWindowSize_Pose <= movWindow_lenMax) movWindow_len_Pose = movWindowSize_Pose; else movWindow_len_Pose = movWindow_lenMax; if(movWindow_len_GyroAcc <= movWindow_lenMax) movWindow_len_GyroAcc = movWindowSize_GyroAcc; else movWindow_len_GyroAcc = movWindow_lenMax; movWindow_index_Pose=0; movWindow_index_GyroAcc=0; for(int i=0; i<3; i++) PoseCorrection[i]=0; } bool IMU_MPU6050::imuInit() { //debug_printf("MPU6050 initializing.\n"); imu_mpu6050.initialize(); if (imu_mpu6050.testConnection()) { //debug_printf("MPU6050 test connection passed.\n"); } else { //debug_printf("MPU6050 test connection failed.\n"); return false; } if (imu_mpu6050.dmpInitialize() == 0) { //debug_printf("succeed in MPU6050 DMP Initializing.\n"); } else { //debug_printf("failed in MPU6050 DMP Initializing.\n"); return false; } imu_mpu6050.setXAccelOffset(MPU6050_Offset_Ax); imu_mpu6050.setYAccelOffset(MPU6050_Offset_Ay); imu_mpu6050.setZAccelOffset(MPU6050_Offset_Az); imu_mpu6050.setFullScaleGyroRange(MPU6050_GYRO_FS); imu_mpu6050.setFullScaleAccelRange(MPU6050_ACCEL_FS); imu_mpu6050.setXGyroOffsetUser(MPU6050_Offset_Gx); imu_mpu6050.setYGyroOffsetUser(MPU6050_Offset_Gy); imu_mpu6050.setZGyroOffsetUser(MPU6050_Offset_Gz); imu_mpu6050.setDMPEnabled(true); // Enable DMP packetSize = imu_mpu6050.dmpGetFIFOPacketSize(); //debug_printf("Init finish!\n"); return true; } void IMU_MPU6050::imuUpdate() { mpuIntStatus = imu_mpu6050.getIntStatus(); fifoCount = imu_mpu6050.getFIFOCount(); // Check that this interrupt is a FIFO buffer overflow interrupt. if ((mpuIntStatus & 0x10) || fifoCount == 1024) { /*imu_mpu6050.resetFIFO(); debug_printf("FIFO overflow!\n");*/ return; // Check that this interrupt is a Data Ready interrupt. } else if (mpuIntStatus & 0x02) { while (fifoCount < packetSize) fifoCount = imu_mpu6050.getFIFOCount(); if(unstable_readings >= 1) { imu_mpu6050.getFIFOBytes(fifoBuffer, packetSize); imu_mpu6050.dmpGetQuaternion(&imu_Data.q, fifoBuffer); imu_mpu6050.dmpGetGravity(&imu_Data.gravity, &imu_Data.q); imu_mpu6050.dmpGetAccel(&imu_Data.aa, fifoBuffer); imu_mpu6050.dmpGetLinearAccel(&imu_Data.aaReal, &imu_Data.aa, &imu_Data.gravity); imu_mpu6050.dmpGetLinearAccelInWorld(&imu_Data.aaWorld, &imu_Data.aaReal, &imu_Data.q); if((generalFunctions::abs_f(imu_Data.aaWorld.x) <= 8) && (generalFunctions::abs_f(imu_Data.aaWorld.y) <= 8)) { if(unstable_readings > 1) unstable_readings --; else { imu_mpu6050.dmpGetYawPitchRoll(imu_initialAngles, &imu_Data.q, &imu_Data.gravity); mpu_timer.start(); unstable_readings --; imu_stabilized = true; //debug_printf("\nIMU stabilized\n"); } } } else { float yawPitchRoll[3]; int16_t raw_gyro[3]; imu_mpu6050.getFIFOBytes(fifoBuffer, packetSize); imu_mpu6050.dmpGetQuaternion(&imu_Data.q, fifoBuffer); imu_mpu6050.dmpGetGravity(&imu_Data.gravity, &imu_Data.q); imu_mpu6050.dmpGetYawPitchRoll(yawPitchRoll, &imu_Data.q, &imu_Data.gravity); //debug_printf("DEBUG>> got YPR data\n"); if(mpu_timer.read() > 2100) { //reset as timer is close to overflow mpu_timer.reset(); imuTime_s[0] = imuTime_s[1]; } else imuTime_s[1] = imuTime_s[0] + mpu_timer.read(); time_s = imuTime_s[1]; //imu timestamp imu_Data.posePRY[2] = -1*(yawPitchRoll[0] - imu_initialAngles[0]- DRIFT_CORRECTION(imuTime_s[1])) - PoseCorrection[0]; imu_Data.posePRY[1] = yawPitchRoll[1] - imu_initialAngles[1] - PoseCorrection[1]; imu_Data.posePRY[0] = yawPitchRoll[2] - imu_initialAngles[2] - PoseCorrection[2]; //convert angles to 0 to 2pi range for(int i=0; i<3; i++) { if(imu_Data.posePRY[i] > 2*M_PI) imu_Data.posePRY[i] -= 2*M_PI; if(imu_Data.posePRY[i] < 0) imu_Data.posePRY[i] += 2*M_PI; } //moving window average of pose angle for(int i=0; i<3; i++) { movWindow_Pose[i][movWindow_index_Pose] = RAD_TO_DEG(imu_Data.posePRY[i]); Pose[i] = generalFunctions::moving_window(movWindow_Pose[i]/**/, movWindow_len_Pose); /****** PROBABLY WILL BREAK HERE!!! ******/ } /** Todo: offset->filter quaternion, use this quaternion to generate gravity vector, and consequently aaReal and aaWorld **/ //convert filtered pose to quaternion here Quat[0]= imu_Data.q.w; Quat[1]= imu_Data.q.x; Quat[2]= imu_Data.q.y; Quat[3]= imu_Data.q.z; //imu_mpu6050.dmpGetGravity(&imu_Data.gravity, &imu_Data.q /* filtered quaternion */); /***************************************/ imu_mpu6050.dmpGetAccel(&imu_Data.aa, fifoBuffer); imu_mpu6050.dmpGetGyro(raw_gyro, fifoBuffer); imu_mpu6050.dmpGetLinearAccel(&imu_Data.aaReal, &imu_Data.aa, &imu_Data.gravity); imu_mpu6050.dmpGetLinearAccelInWorld(&imu_Data.aaWorld, &imu_Data.aaReal, &imu_Data.q); imu_Data.accW.x = (float) imu_Data.aaWorld.x * (9806.0/8192); imu_Data.accW.y = (float) imu_Data.aaWorld.y * (9806.0/8192); imu_Data.accW.z = (float) imu_Data.aaWorld.z * (9806.0/8192); imu_Data.gyro.x = (float) raw_gyro[0]; imu_Data.gyro.y = (float) raw_gyro[1]; imu_Data.gyro.z = (float) raw_gyro[2]; //moving window average of gyro velocities movWindow_AngVel[0][movWindow_index_GyroAcc] = imu_Data.gyro.x; movWindow_AngVel[1][movWindow_index_GyroAcc] = imu_Data.gyro.y; movWindow_AngVel[2][movWindow_index_GyroAcc] = imu_Data.gyro.z; movWindow_LinAcc[0][movWindow_index_GyroAcc] = imu_Data.accW.x; movWindow_LinAcc[1][movWindow_index_GyroAcc] = imu_Data.accW.y; movWindow_LinAcc[2][movWindow_index_GyroAcc] = imu_Data.accW.z; for(int i=0; i<3; i++) { AngVel[i] = generalFunctions::moving_window(movWindow_AngVel[i]/**/, movWindow_index_GyroAcc); /****** PROBABLY WILL BREAK HERE!!! ******/ LinAcc[i] = generalFunctions::moving_window(movWindow_LinAcc[i]/**/, movWindow_index_GyroAcc); /****** PROBABLY WILL BREAK HERE!!! ******/ } movWindow_index_Pose++; if(movWindow_index_Pose >= movWindow_len_Pose) movWindow_index_Pose=0; movWindow_index_GyroAcc++; if(movWindow_index_GyroAcc >= movWindow_len_GyroAcc) movWindow_index_GyroAcc=0; //debug_printf("Roll:%6.2fdeg, Pitch:%6.2fdeg, Yaw:%6.2fdeg\n", RAD_TO_DEG(imu_Data.roll), RAD_TO_DEG(imu_Data.pitch), RAD_TO_DEG(imu_Data.yaw)); } } } void IMU_MPU6050::getPose(float *pose[3]) { //pitch about X, roll about Y, yaw about Z for(int i=0; i<3; i++) *pose[i]=Pose[i]; } void IMU_MPU6050::getQuat(float *quaternion[4]) { for(int i=0; i<4; i++) *quaternion[i]=Quat[i]; } void IMU_MPU6050::getAngVel(float *angVelocity[3]) { for(int i=0; i<3; i++) *angVelocity[i]=AngVel[i]; } void IMU_MPU6050::getLinAcc(float *linAcc[3]) { for(int i=0; i<3; i++) *linAcc[i]=LinAcc[i]; } float IMU_MPU6050::getTime() { return(imuTime_s[1]); } void IMU_MPU6050::setPose(float pose_in[3]) { IMU_MPU6050::imuUpdate(); //refresh imu before updating Pose //pitch about X, roll about Y, yaw about Z for(int i=0; i<3; i++) PoseCorrection[i]=(Pose[i] - pose_in[i]); } /*** ***/ /*** BNO055 ***/ IMU_BNO055::IMU_BNO055(): imu_BNO055(i2c_SDA, i2c_SCL) { unsigned int movWindowSize_Pose = Pose_MWindowSize; unsigned int movWindowSize_GyroAcc = GyroAcc_MWindowSize; unstable_readings = BNO055_StabilizationReadings; //imu_stabilized[0] =0; imu_stabilized[0] =1; //for imu mode no need to calibrate imu_stabilized[1] =0; if(movWindowSize_Pose <= movWindow_lenMax) movWindow_len_Pose = movWindowSize_Pose; else movWindow_len_Pose = movWindow_lenMax; if(movWindow_len_GyroAcc <= movWindow_lenMax) movWindow_len_GyroAcc = movWindowSize_GyroAcc; else movWindow_len_GyroAcc = movWindow_lenMax; movWindow_index_Pose=0; movWindow_index_GyroAcc=0; for(int i=0; i<3; i++) PoseCorrection[i]=0; bno_timer.start(); } bool IMU_BNO055::imuInit() { imu_BNO055.reset(); if (imu_BNO055.check()) { //load default calib parameters offset_acc[0] =10; offset_acc[1] =509; offset_acc[2] =500; offset_mag[0] =409; offset_mag[1] =487; offset_mag[2] =290; offset_gyr[0] =4; offset_gyr[0] =0; offset_gyr[2] =1; radius_acc = 235; radius_mag = 165; writeCalibrationData(); imu_BNO055.set_mapping(2); imu_BNO055.setmode(OPERATION_MODE_IMUPLUS); imu_BNO055.get_calib(); calibration_status = (imu_BNO055.calib & 0xc0) >> 6; //upper 2 MSB's denoting calibration status return(true); } else return(false); //debug_printf("Init finish!\n"); } void IMU_BNO055::imuUpdate() { imu_BNO055.get_calib(); imu_BNO055.get_angles(); imu_BNO055.get_lia(); //imu_BNO055.get_accel(); imu_BNO055.get_gyro(); //imu_BNO055.get_mag(); imu_BNO055.get_quat(); //imu_BNO055.get_grv(); float posePRY[3]; //debug_printf("DEBUG>> got YPR data\n"); if(bno_timer.read() > 2100) { //reset as timer is close to overflow bno_timer.reset(); imuTime_s[0] = imuTime_s[1]; } else imuTime_s[1] = imuTime_s[0] + bno_timer.read(); time_s = imuTime_s[1]; //imu timestamp calib_stat[4] = imu_BNO055.calib; calib_stat[3] = (calib_stat[4] & 0xc0) >> 6; calib_stat[2] = (calib_stat[4] & 0x30) >> 4; calib_stat[1] = (calib_stat[4] & 0x0c) >> 2; calib_stat[0] = (calib_stat[4] & 0x03); calibration_status = (imu_BNO055.calib & 0xc0) >> 6; //upper 2 MSB's denoting calibration status //if((calib_stat[4] >= 193) && (imu_stabilized[1] == 0)) { if(imu_stabilized[1] == 0) { //for imu only mode if(imu_stabilized[0] == 0) imu_stabilized[0] = 1; if( ((generalFunctions::abs_f(imu_BNO055.lia.x) - initialAcc[0])* 9.81*1000 <= 5.0) && ((generalFunctions::abs_f(imu_BNO055.lia.y) - initialAcc[1])* 9.81*1000 <= 5.0) && ((generalFunctions::abs_f(imu_BNO055.lia.z) - initialAcc[2])* 9.81*1000 <= 5.0)) { unstable_readings--; } initialAcc[0] = generalFunctions::abs_f(imu_BNO055.lia.x); initialAcc[1] = generalFunctions::abs_f(imu_BNO055.lia.y); initialAcc[2] = generalFunctions::abs_f(imu_BNO055.lia.z); if(unstable_readings <= 1) { //imu_initialAngles[0] = imu_BNO055.euler.pitch; //imu_initialAngles[1] = imu_BNO055.euler.roll; imu_initialAngles[2] = 2*RAD_TO_DEG(M_PI) - imu_BNO055.euler.yaw; imu_initialAngles[0] = 0; imu_initialAngles[1] = 0; imu_stabilized[1] =1; bno_timer.reset(); } } posePRY[0] = imu_BNO055.euler.pitch - imu_initialAngles[0] - PoseCorrection[0]; posePRY[1] = imu_BNO055.euler.roll - imu_initialAngles[1] - PoseCorrection[1]; //posePRY[2] = -1.0*(imu_BNO055.euler.yaw - imu_initialAngles[0]- DRIFT_CORRECTION(imuTime_s[1])) - PoseCorrection[2]; //posePRY[2] = -1.0*(imu_BNO055.euler.yaw - imu_initialAngles[0]) - PoseCorrection[2]; posePRY[2] = (2*RAD_TO_DEG(M_PI) - imu_BNO055.euler.yaw) - imu_initialAngles[2]; //convert angles to 0 to 2pi range for(int i=0; i<3; i++) { if(posePRY[i] > 2*RAD_TO_DEG(M_PI)) posePRY[i] -= 2*RAD_TO_DEG(M_PI); if(posePRY[i] < 0.0) posePRY[i] += 2*RAD_TO_DEG(M_PI); } //moving window average of pose angle for(int i=0; i<3; i++) { movWindow_Pose[i][movWindow_index_Pose] = posePRY[i]; Pose[i] = generalFunctions::moving_window(movWindow_Pose[i], movWindow_len_Pose); } /** Todo: offset->filter quaternion, use this quaternion to generate gravity vector, and consequently aaReal and aaWorld **/ Quat[0]= imu_BNO055.quat.w; Quat[1]= imu_BNO055.quat.x; Quat[2]= imu_BNO055.quat.y; Quat[3]= imu_BNO055.quat.z; //moving window average of gyro velocities movWindow_AngVel[0][movWindow_index_GyroAcc] = imu_BNO055.gyro.x; movWindow_AngVel[1][movWindow_index_GyroAcc] = imu_BNO055.gyro.y; movWindow_AngVel[2][movWindow_index_GyroAcc] = imu_BNO055.gyro.z; movWindow_LinAcc[0][movWindow_index_GyroAcc] = imu_BNO055.lia.x; movWindow_LinAcc[1][movWindow_index_GyroAcc] = imu_BNO055.lia.y; movWindow_LinAcc[2][movWindow_index_GyroAcc] = imu_BNO055.lia.z; for(int i=0; i<3; i++) { AngVel[i] = generalFunctions::moving_window(movWindow_AngVel[i]/**/, movWindow_index_GyroAcc); /****** PROBABLY WILL BREAK HERE!!! ******/ LinAcc[i] = generalFunctions::moving_window(movWindow_LinAcc[i]/**/, movWindow_index_GyroAcc); /****** PROBABLY WILL BREAK HERE!!! ******/ } movWindow_index_Pose++; if(movWindow_index_Pose >= movWindow_len_Pose) movWindow_index_Pose=0; movWindow_index_GyroAcc++; if(movWindow_index_GyroAcc >= movWindow_len_GyroAcc) movWindow_index_GyroAcc=0; //debug_printf("Roll:%6.2fdeg, Pitch:%6.2fdeg, Yaw:%6.2fdeg\n", RAD_TO_DEG(imu_Data.roll), RAD_TO_DEG(imu_Data.pitch), RAD_TO_DEG(imu_Data.yaw)); } void IMU_BNO055::getPose(float *pose[3]) { //pitch about X, roll about Y, yaw about Z for(int i=0; i<3; i++) *pose[i]=Pose[i]; } void IMU_BNO055::getQuat(float *quaternion[4]) { for(int i=0; i<4; i++) *quaternion[i]=Quat[i]; } void IMU_BNO055::getAngVel(float *angVelocity[3]) { for(int i=0; i<3; i++) *angVelocity[i]=AngVel[i]; } void IMU_BNO055::getLinAcc(float *linAcc[3]) { for(int i=0; i<3; i++) *linAcc[i]=LinAcc[i]; } float IMU_BNO055::getTime() { return(imuTime_s[1]); } void IMU_BNO055::setPose(float pose_in[3]) { IMU_BNO055::imuUpdate(); //refresh imu before updating Pose //pitch about X, roll about Y, yaw about Z for(int i=0; i<3; i++) PoseCorrection[i]=(Pose[i] - pose_in[i]); } void IMU_BNO055::readCalibrationData() { //imu_BNO055.get_calib(); imu_BNO055.read_calibration_data(); for(int i=0; i<22; i++) calibration_regs[i]=imu_BNO055.calibration[i]; offset_acc[0] = (calibration_regs[1] + calibration_regs[0]); offset_acc[1] = (calibration_regs[3] + calibration_regs[2]); offset_acc[2] = (calibration_regs[5] + calibration_regs[4]); offset_mag[0] = (calibration_regs[7] + calibration_regs[6]); offset_mag[1] = (calibration_regs[9] + calibration_regs[8]); offset_mag[2] = (calibration_regs[11] + calibration_regs[10]); offset_gyr[0] = (calibration_regs[13] + calibration_regs[12]); offset_gyr[1] = (calibration_regs[15] + calibration_regs[14]); offset_gyr[2] = (calibration_regs[17] + calibration_regs[16]); radius_acc = (calibration_regs[19] + calibration_regs[18]); radius_mag = (calibration_regs[21] + calibration_regs[20]); } void IMU_BNO055::writeCalibrationData() { //acc calibration_regs[0] = offset_acc[0] & 0b00001111; calibration_regs[1] = offset_acc[0] & 0b11110000; calibration_regs[2] = offset_acc[1] & 0b00001111; calibration_regs[3] = offset_acc[1] & 0b11110000; calibration_regs[4] = offset_acc[2] & 0b00001111; calibration_regs[5] = offset_acc[2] & 0b11110000; //mag calibration_regs[6] = offset_mag[0] & 0b00001111; calibration_regs[7] = offset_mag[0] & 0b11110000; calibration_regs[8] = offset_mag[1] & 0b00001111; calibration_regs[9] = offset_mag[1] & 0b11110000; calibration_regs[10] = offset_mag[2] & 0b00001111; calibration_regs[11] = offset_mag[2] & 0b11110000; //gyro calibration_regs[12] = offset_gyr[0] & 0b00001111; calibration_regs[13] = offset_gyr[0] & 0b11110000; calibration_regs[14] = offset_gyr[1] & 0b00001111; calibration_regs[15] = offset_gyr[1] & 0b11110000; calibration_regs[16] = offset_gyr[2] & 0b00001111; calibration_regs[17] = offset_gyr[2] & 0b11110000; //acc_radius calibration_regs[18] = radius_acc & 0b00001111; calibration_regs[19] = radius_acc & 0b11110000; //mag_radius calibration_regs[20] = radius_mag & 0b00001111; calibration_regs[21] = radius_mag & 0b11110000; for(int i=0; i<22; i++) imu_BNO055.calibration[i] = calibration_regs[i]; imu_BNO055.write_calibration_data(); } /*** ***/