1

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);

    }

}
gilonm
  • 1,829
  • 1
  • 12
  • 22
  • Maybe my answer for question post by Urban would help. You need to change your mGravity = event.values; to mGravity = event.values.clone; and similarly or mGeoMagnetic. – Hoan Nguyen Apr 02 '14 at 16:23
  • I will check that, thanks. Could you explain why? thanks for your help! – gilonm Apr 03 '14 at 05:12
  • 1
    The assignment is a reference, a pointer in C language. So mGravity point to the address of event.value. This address may be anything the next time onSensorChanged is called. – Hoan Nguyen Apr 03 '14 at 07:42
  • @gilonm did you find a solution? I'm still struggling with [my question](http://stackoverflow.com/questions/22794011/azimuth-values-changing-when-changing-pitch), so I put a bounty on it. – Urban Apr 03 '14 at 18:39
  • @Urban unfortunately not yet, more so - I have noticed that my compass app based on code above behaves completely different on other phone. Tested on Samsung Galaxy 3 and 4, and Nexus 7. Very strange and frustrating - I have a feeling I am missing something... – gilonm Apr 04 '14 at 02:11
  • hey @gilonm check out my question. I was able to find a solution myself and have added it as an answer there. Hope that helps. – Urban Apr 08 '14 at 21:17
  • Thanks @Urban!! Look very promising, I will give it a try later on today. Thanks so much and I will of course let you know! Cheers! – gilonm Apr 09 '14 at 05:18

0 Answers0