I am using the HMC-5983 magnetometer module to obtain the compass heading of a autonomous car I am building using the arduino platform.I'musing the Z axis and X axis to obtain the heading.
However when the headingFiltered variable is at 359 and the car turns to Zero,the headingFiltered becomes to 0 via all the values between 0 and 360 rather than just becoming 0.This causes my car be constantly steering side to side when heading in this relevant direction. Also if there is anyway that this function could be improved,I'm open to suggestions.
The function I'm using is as follows.
void chead() {
//---- X-Axis
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mX1);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1);
if(Wire.available()<=1)
{
mX0 = Wire.read();
}
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mX0);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1);
if(Wire.available()<=1)
{
mX1 = Wire.read();
}
//---- Y-Axis
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mY1);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1);
if(Wire.available()<=1)
{
mY0 = Wire.read();
}
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mY0);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1);
if(Wire.available()<=1)
{
mY1 = Wire.read();
}
//---- Z-Axis
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mZ1);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1);
if(Wire.available()<=1)
{
mZ0 = Wire.read();
}
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mZ0);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1);
if(Wire.available()<=1)
{
mZ1 = Wire.read();
}
//---- X-Axis
mX1=mX1<<8;
mX_out =mX0+mX1; // Raw data
// From the datasheet: 0.92 mG/digit
Xm = mX_out*0.00092; // Gauss unit
//* Earth magnetic field ranges from 0.25 to 0.65 Gauss, so these are the values that we need to get approximately.
//---- Y-Axis
mY1=mY1<<8;
mY_out =mY0+mY1;
Ym = mY_out*0.00092;
//---- Z-Axis
mZ1=mZ1<<8;
mZ_out =mZ0+mZ1;
Zm = mZ_out*0.00092;
// ==============================
//Calculating Heading
heading = atan2(Zm, Xm);// arc tangent of z/x
// Correcting the heading with the declination angle depending on your location
declination = 0.03717551307 ;
heading += declination;
// Correcting when signs are reveresed
if(heading <0) heading += 2*PI;
// Correcting due to the addition of the declination angle
if(heading > 2*PI)heading -= 2*PI;
headingDegrees = heading * 180/PI; // The heading in Degrees unit
// Smoothing the output angle / Low pass filter
headingFiltered = headingFiltered*0.85 + headingDegrees*0.15;
//Sending the heading value through the Serial Port to Processing IDE
//this was done to fix an error.which was when the compass was made to turn by 180° the reading obtained did not change by 180°.
if(headingFiltered >= 0 && headingFiltered <= 89){
c_head=map(headingFiltered,0,90,270,359);
}
if(headingFiltered > 89 && headingFiltered <= 204){
c_head=map(headingFiltered,90,204,0,90);
}
if(headingFiltered > 204 && headingFiltered <= 290){
c_head=map(headingFiltered,205,290,91,180);
}
if(headingFiltered > 290){
c_head=map(headingFiltered,291,359,181,269);
}
//Further calibration
if(c_head>=0 && c_head<8){
c_head=352+c_head;
}
if(c_head>=8){
c_head=c_head-8;
}
// Serial.print("Degrees - ");
// Serial.println(c_head);
float teta1 = radians(clatval);
float teta2 = radians(dlatval);
float delta1 = radians(dlatval-clatval);
float delta2 = radians(dlongval-clongval); //==================Heading Formula Calculation================//
float y = sin(delta2) * cos(teta2);
float x = cos(teta1)*sin(teta2) - sin(teta1)*cos(teta2)*cos(delta2);
float brng = atan2(y,x);
degris = degrees(brng);// radians to degrees
degris = ( ((int)degris + 360) % 360 );
dif_h=c_head - degris;
abs_dif_h=abs(dif_h);
}