I am implementing a compass, getting readings from SensorManager.getRotationMatrix
(see code below).
I have an imageView
that rotates using RotateAnimation
.
The compass and animation works fine except for one issue:
Through the SensorManager.getOrientation
I get an array of three values - Azimuth, Pitch and Roll. I only use the array[0]
which holds the Azimuth Value
If I hold the phone flat and turn it around on the Z axis (azimuth) - it works perfectly. But, the minute I tilt the phone on the X or Y axis (Pitch or Roll) - the compass goes off the correct measurement. In other words - when tilting Pitch or Roll - it seriously effects the readings from the Azimuth.
So, to sum up my question - How would I block interference from the Pitch/Roll readings (although I do NOT address them in the code at all) - Or, am I doing something wrong?
Thanks in advance!
Here is most of my code:
public class MainActivity extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
private Sensor accelerometer;
private Sensor magnetometer;
private float[] mGravity;
private float[] mGeomagnetic;
float avgRead[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
private TextView tvCurrAzim;
private ImageView ivCompass;
private float currentDegree = 0f;
private float azimuth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
tvCurrAzim = (TextView) findViewById(R.id.tvaz);
ivCompass = (ImageView) findViewById(R.id.imageView1);
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accelerometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
// Compass Sensor Methods:
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity,
mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
//Creating a running smooth average of readings
avgRead[0] = avgRead[1];
avgRead[1] = avgRead[2];
avgRead[2] = avgRead[3];
avgRead[3] = avgRead[4];
avgRead[4] = avgRead[5];
avgRead[5] = avgRead[6];
avgRead[6] = avgRead[7];
avgRead[7] = avgRead[8];
avgRead[8] = orientation[0]; // orientation contains: azimuth, pitch and roll
azimuth = (avgRead[0] + avgRead[1] + avgRead[2] + avgRead[3]
+ avgRead[4] + avgRead[5] + avgRead[6] + avgRead[7] + avgRead[8]) / 9;
azimuth = Math.round(azimuth * 360 / (2 * 3.14159f));
if (azimuth < 0 && azimuth > -180)
azimuth += 360;
}
}
tvCurrAzim.setText(Float.toString(azimuth));
// get the angle around the z-axis rotated
// create a rotation animation (reverse turn degree degrees)
if (-azimuth - currentDegree > 180)
azimuth = azimuth - 360;
RotateAnimation ra = new RotateAnimation(currentDegree, -azimuth,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
// how long the animation will take place
ra.setDuration(50);
// set the animation after the end of the reservation status
ra.setFillAfter(true);
// Start the animation
ivCompass.startAnimation(ra);
currentDegree = -azimuth;
}
@Override
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
@Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, accelerometer,
SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this, magnetometer,
SensorManager.SENSOR_DELAY_UI);
}
}