I need the device's azimuth and roll values for an augmented reality app I'm working on. I'm getting the rotation matrix - from getRotationMatrix - using the accelerometer and the magnetic field. Since this is an AR app, I need to render objects that wouldn't change their positions in the real world (when seen through the camera) when the device is moved.
The problem is, when physically rolling the device (in attempts to observe the variations in the pitch values), I can observe changes in the azimuth orientation values, even though that should remain stable. Moreover, the azimuth strays off only when the pitch is changing, and returns back to its original value when the rolling is stopped. So to clarify, as I start the roll, the azimuth starts changing as well, and when the roll stops, the azimuth slowly returns back to the correct value. I can't figure out why the azimuth is behaving so.
Here is the code that gets the sensor data and calculates the rotation matrix.
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
switch (sensorEvent.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
accel = lowPass(sensorEvent.values.clone(), accel);
break;
case Sensor.TYPE_MAGNETIC_FIELD:
magnet = lowPass(sensorEvent.values.clone(), magnet);
break;
}
if (accel == null || magnet == null)
return;
if (!SensorManager.getRotationMatrix(rotationMatrix, null, accel, magnet))
return;
SensorManager.remapCoordinateSystem(rotationMatrix, SensorManager.AXIS_Z,
SensorManager.AXIS_MINUS_X, outRotationMatrix); // Remapping because the device is held in landscape.
SensorManager.getOrientation(outRotationMatrix, orientationValues);
currentOrientation = (float) (Math.toDegrees(orientationValues[0]) + this.getDeclination()); //Azimuth; (Degrees);
eyeLevelInclination = (float) Math.toDegrees(orientationValues[1]); //Pitch; (Degrees); down is 90 , up is -90.
deviceOrientation = (float) Math.toDegrees(orientationValues[2]);
sendSensorBroadcast();
}
So in the code above, currentOrientation (responsible for horizontally stabilizing the rendered AR objects) changes during device roll, when only eyeLevelInclination should be changing (responsible for vertically stabilizing the rendered AR object).
I'm also using a low pass filter to stabilize the sensor data. Although I dont believe this is responsible for the azimuth variations, I'm putting its code here regardless-
static final float ALPHA = 0.15f;
/**
* @see Adapted from http://blog.thomnichols.org/2011/08/smoothing-sensor-data-with-a-low-pass-filter
*/
protected float[] lowPass( float[] input, float[] output ) {
if ( output == null ) return input;
for ( int i=0; i<input.length; i++ ) {
output[i] = output[i] + ALPHA * (input[i] - output[i]);
}
return output;
}
Apologies if the question isn't very clear. It's a bit hard to explain the problem.
Edit: I've tried using raw values, instead of going through a low pass filter and the azimuth still changes. I notice that the rendered object goes along a diagonal when changing the pitch, when it should only be going vertically up or down. It moves diagonally as the azimuth and the pitch both are changing when I physically change the device's pitch, causing the diagonal movement. Maybe there's something wrong with my axis?