How to make an accurate compass on android

eladrich picture eladrich · Oct 24, 2011 · Viewed 28.7k times · Source

my android application shows the direction of a particular place in the world and therefore in needs to get the compass degree.
This is the code I've been using to calculate the degrees:

public void getDirection() {        
    mySensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
    List<Sensor> mySensors = mySensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
    if(mySensors.size() > 0){
        mySensorManager.registerListener(mySensorEventListener, mySensors.get(0), SensorManager.SENSOR_DELAY_UI);           
    }
    else{
        TextView alert = (TextView)findViewById(R.id.instruct);
        alert.setText(getString(R.string.direction_not_found));
        myCompassView.setVisibility(myCompassView.INVISIBLE);

    }
}
private SensorEventListener mySensorEventListener = new SensorEventListener(){

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // TODO Auto-generated method stub
        compassBearing = (float)event.values[0];
        float bearing;
        bearing = compassBearing - templeBearing;
        if (bearing < 0)
            bearing = 360 + bearing;
        myCompassView.updateDirection(bearing);
        }
};

This method usually works but sometimes it just gets the wrong north, what do I have to do to get a more accurate location?

Answer

MobileCushion picture MobileCushion · Oct 24, 2011

I have a couple suggestions for you:

1) Your device may not be calibrated. In order to do it, move it around in a form of 8 (see this). If you don't if your device is calibrated or not make some tests by pointing the device at some known cardinal point direction and compare the values. Typically, if a device is not calibrated, you will see great variations in the azimuth value for small rotations. That is what I would be worried about.

Now, don't forget that the sensor gives you the bearing to Magnetic North, and not True North! This difference is known as declination of the magnetic field and its value changes from place to place and from time to time due to changes in Earth's magnetic field. This app can compute some of the values for you with relative accuracy. I wouldn't be too much worried about this as the declination is typically small, but you might be looking for good precision (where I live the declination is 3º, currently).

2) Stay away from metal objects or stuff that generate a strong magnetic field. For example, don't do tests if you have your phone near the computer or any physical keyboards! This is pure poison for testing compass-geolocation. Some apps can measure the intensity of the magnetic field (if the device supports it). When you get closer to metal stuff you will experience higher values and strong changes in directions. For fun, there are also some "metal detectors": this app recognises changes in the magnetic field and vibrates when you are close "metal object" or stuff that magnetically interfere with the device.

3) Remember to update the bearing when you tilt your device to landscape mode. (article is a must read!) This is because azimuth value is based on the rotation of the perpendicular axis to the plane of the phone. When you rotate the device to landscape, this value is changed by +/-90º! This is not resolved by disabling the application landscape mode! You will have to determine it programmatically by analysing rotations around the other two axis (pitch and roll). This is not trivial, but there are some examples somewhere in the net.

edit: If you are interested in some code, check out Mixare, it is an open source augmented reality framework under the GPL3 for Android. Take a look at their code regarding orientation, compass geolocation and bearing.

PS: I don't have any sort of connection with the creators of the mentioned applications.