I am trying to implement quaternions and i am using CC2650 sensortag board from TI. This board has MPU9250 from invensense which has Digital Motion Processor (DMP) in it. This DMP gives quaternion, but for my understanding i implemented my own quaternion. I used Gyroscope and acceleorometer values coming out of DMP (which are calibrated ) to calculate angle of rotation. I feed this angle, in 3 directions (x,y,z), to my quaternion. I am not able to match my quaternion values with DMP quaternion values. In fact it's way off, so wondering what I have done wrong.
Following are detailed steps that i did :
1) Tapped Gyro sensor values from function “read_from_mpl”.
2) Converted gyro values in to float by diving by 2^16. As gyro values are in Q16 format.
3) Now used Gyro values of 3 axis and found out resultant using formula : Gr = sqrt(Gx^2+Gy^2+Gz^2) Where Gx,Gy and Gz are Gyro values along x-axis,y-axis and z-axis respectively.
4) Now Angle is derived using above found resultant Gr by : *Angle = Gr*1/sample_rate* Where sample_rate is found using API call ,mpu_get_sample_rate(&sample_rate)
5) This Angle is fed to angle_to_quater function which basically converts angle to axis and then quaternion multiplication.
/* Angle to axis and quaternion multiplication: */
temp.w = cos((Angle*1.0/RAD_TO_DEG)/2);
temp.x = sin((Angle*1.0/RAD_TO_DEG)/2);
temp.y = sin((Angle*1.0/RAD_TO_DEG)/2);
temp.z = sin((Angle*1.0/RAD_TO_DEG)/2);
temp.x = temp.x *gyro_axis[0];//gyro_axis[0]=Gx
temp.y = temp.x *gyro_axis[1]; //gyro_axis[0]=Gy
temp.z = temp.x *gyro_axis[2]; //gyro_axis[0]=Gz
/* quaternion multiplication and normalization */
res = quat_mul(*qt,temp);
quat_normalize(&res);
*qt = res;*
6) I also added doing angle calculations from accelerometer as follows : Here also accelerometer is converted to float by dividing by 2^16, as acceleorometer values also in Q16 format.
*//acc_data[0]->Ax, acc_data[1]->Ay, acc_data[2]->Az
temp = (acc_data[0]*acc_data[0]) + (acc_data[1]*acc_data[1]);
acc_angle[0]=atan2(acc_data[2],temp)*RAD_TO_DEG;
temp = (acc_data[1]*acc_data[1]) + (acc_data[2]*acc_data[2]);
acc_angle[1]=atan2(acc_data[0],temp)*RAD_TO_DEG;
temp = (acc_data[1]*acc_data[1]) + (acc_data[0]*acc_data[0]);
acc_angle[2]=atan2(acc_data[1],temp)*RAD_TO_DEG;*
*Find resultant angle of this also as :
inst_acc_angle = (sqrt(acc_angle[0]*acc_angle[0] + acc_angle[1]*acc_angle[1] + acc_angle[2]*acc_angle[2]));*
7) Then complimentary filter is : *FinalAngle = 0.96*Angle + 0.04*inst_acc_angle; This Final Angle is fed to step 5 to get quaternion.*
Quaternion multiplication is done as below and then normailized to get new quaternion (q).
quater_mul :
q3.w = -q1.x * q2.x - q1.y * q2.y - q1.z * q2.z + q1.w * q2.w;
q3.x = q1.x * q2.w + q1.y * q2.z - q1.z * q2.y + q1.w * q2.x;
q3.y = -q1.x * q2.z + q1.y * q2.w + q1.z * q2.x + q1.w * q2.y;
q3.z = q1.x * q2.y - q1.y * q2.x + q1.z * q2.w + q1.w * q2.z;
quat_normalize:
double mag = pow(q->w,2) + pow(q->x,2) + pow(q->y,2) + pow(q->z,2);
mag = sqrt(mag);
q->w = q->w/mag;
q->x = q->x/mag;
q->y = q->y/mag;
q->z = q->z/mag;
When i check my quaternion values with DMP, they are WAY off. Can you please provide some insights in to what could be wrong here.
Source code :
acc_data[0]=data[0]/65536.0;
acc_data[1]=data[1]/65536.0;
acc_data[2]=data[2]/65536.0;
double temp = (acc_data[0]*acc_data[0]) + (acc_data[1]*acc_data[1]);
acc_angle[0]=atan2(acc_data[2],temp)*RAD_TO_DEG;
temp = (acc_data[1]*acc_data[1]) + (acc_data[2]*acc_data[2]);
acc_angle[1]=atan2(acc_data[0],temp)*RAD_TO_DEG;
temp = (acc_data[1]*acc_data[1]) + (acc_data[0]*acc_data[0]);
acc_angle[2]=atan2(acc_data[1],temp)*RAD_TO_DEG;*
gyro_rate_data[0]=data[0]/65536.0;
gyro_rate_data[1]=data[1]/65536.0;
gyro_rate_data[2]=data[2]/65536.0;
float inst_angle = (sqrt(gyro_rate_data[0]*gyro_rate_data[0] + gyro_rate_data[1]*gyro_rate_data[1] + gyro_rate_data[2]*gyro_rate_data[2]));
gyro_rate_data[0] = gyro_rate_data[0]/inst_angle;
gyro_rate_data[1] = gyro_rate_data[1]/inst_angle;
gyro_rate_data[2] = gyro_rate_data[2]/inst_angle;
inst_angle = inst_angle *1.0/sam_rate;
float inst_acc_angle = (sqrt(acc_angle[0]*acc_angle[0] + acc_angle[1]*acc_angle[1] + acc_angle[2]*acc_angle[2]));
inst_angle = WT*inst_angle + (1.0-WT)*inst_acc_angle;
angle_to_quat(inst_angle,gyro_rate_data,&q);
/* The function for angle to quaterinion and multiplication,normalization */
void angle_to_quat(float Angle,float *gyro_axis,struct quat *qt)
{
struct quat temp;
struct quat res;
temp.w = cos((Angle*1.0/RAD_TO_DEG)/2);
temp.x = sin((Angle*1.0/RAD_TO_DEG)/2);
temp.y = sin((Angle*1.0/RAD_TO_DEG)/2);
temp.z = sin((Angle*1.0/RAD_TO_DEG)/2);
temp.x = temp.x *gyro_axis[0];
temp.y = temp.x *gyro_axis[1];
temp.z = temp.x *gyro_axis[2];
res = quat_mul(*qt,temp);
quat_normalize(&res);
*qt = res;
}
This variation is coming when i am keeping my device stationary.
Y-Axis : Resultant of all 3 gyro axis.
X-axis : The number of samples. (have not converted them to time)
Sample_rate is 3Hz.