Get Android device rotation angles with accelerometer and geomagnetic sensors

In first versions of Android, rotation angles could be got by using a sensor with Sensor.TYPE_ORIENTATION as type. But, since Android 2.2, this method is deprecated. However, a lot of applications and developers still use this way ! The following tutorial aims to show you how to get rotation angles (azimuth, pitch and roll) in the recommend way by using accelerometer and geomagnetic sensors.

rotation angles

First thing to do is to get a SensorManager instance like that :


SensorManager sManager = (SensorManager) getActivity().getSystemService(SENSOR_SERVICE);

Then, we need to register to SensorManager instance that we want to get notified when accelerometer or geomagnetic data change like that :


sManager.registerListener(mySensorEventListener, sManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_NORMAL);
sManager.registerListener(mySensorEventListener, sManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),SensorManager.SENSOR_DELAY_NORMAL);

Here, mySensorEventListener is an implementation of SensorEventListener interface :


private SensorEventListener mySensorEventListener = new SensorEventListener() {
   public void onAccuracyChanged(Sensor sensor, int accuracy) {
   }

   public void onSensorChanged(SensorEvent event) {
   }
};

In onSensorChanged method, we’re going to implement our algorithm to compute rotation angles thanks to accelerometer and geomagnetic sensors data. First, we must define the following properties in the parent class used :


// Gravity rotational data
private float gravity[];
// Magnetic rotational data
private float magnetic[]; //for magnetic rotational data
private float accels[] = new float[3];
private float mags[] = new float[3];
private float[] values = new float[3];

// azimuth, pitch and roll
private float azimuth;
private float pitch;
private float roll;

 

Now, you can implement algorithm in our SensorEventListener implementation :


private SensorEventListener mySensorEventListener = new SensorEventListener() {
   public void onAccuracyChanged(Sensor sensor, int accuracy) {
   }

   public void onSensorChanged(SensorEvent event) {
      switch (event.sensor.getType()) {
         case Sensor.TYPE_MAGNETIC_FIELD:
         mags = event.values.clone();
         break;
         case Sensor.TYPE_ACCELEROMETER:
         accels = event.values.clone();
         break;
      }

      if (mags != null && accels != null) {
         gravity = new float[9];
         magnetic = new float[9];
         SensorManager.getRotationMatrix(gravity, magnetic, accels, mags);
         float[] outGravity = new float[9];
         SensorManager.remapCoordinateSystem(gravity, SensorManager.AXIS_X,SensorManager.AXIS_Z, outGravity);
         SensorManager.getOrientation(outGravity, values);

         azimuth = values[0] * 57.2957795f;
         pitch =values[1] * 57.2957795f;
         roll = values[2] * 57.2957795f;
         mags = null;
         accels = null;
      }
   }
};

You can get azimuth, pitch and roll from appropriate properties once onSensorChanged has been called.

Leave a Reply