Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getRotationMatrix and getOrientation tutorial

I have been struggling with getting the actual orientation of my device using getOrientation. Getting the accelerometer and magnetic field readings via TYPE_ACCELEROMETER and TYPE_MAGNETIC_FIELD is straightforward as is getting the orientation via TYPE_ORIENTATION. But getting the orientation according to the world coordinate-system using getOrientation. There are a number of good tutorials out there here and here but I have yet to put it all together. To that end I was developing an app that simply spit out the Accelerometer, Magnetic Field, raw Orientation data, and Orientation data from getOrientation. I have attached the code but it constantly fails on my phone. ANy suggestions?

package com.sensorall;


import com.sensorall.R;
import android.hardware.*;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;



public class OrientationAccelerometer extends Activity {

    SensorManager sensorManager;
    float[] mGravs = new float[3];
    float[] mGeoMags = new float[3];
    float[] mRotationM = new float[16];
    float[] mInclinationM = new float[16];
    float[] mOrientation = new float[3];
    float[] mOldOreintation = new float[3];
    String[] mAccelerometer =  new String[3];
    String[] mMagnetic =  new String[3];    
    String[] mRotation =  new String[16];
    String[] mInclination =  new String[16];
    String[] mOrientationString =  new String[3];
    String[] mOldOreintationString =  new String[3];


    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.orientationaccelerometer);
        sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);

    } /* End onCreate activity */

    private SensorEventListener sensorEventListener = new SensorEventListener() {

        public void onAccuracyChanged(Sensor sensor, int accuracy) {

        }


        /* Get the Sensors */
        public void onSensorChanged(SensorEvent event) {

              switch (event.sensor.getType()) {
                     case Sensor.TYPE_ACCELEROMETER:
                              System.arraycopy(event.values, 0, mGravs, 0, 3);
                              break;
                     case Sensor.TYPE_MAGNETIC_FIELD:
                              System.arraycopy(event.values, 0, mGeoMags, 0, 3);
                              break;
                     case Sensor.TYPE_ORIENTATION:
                            System.arraycopy(event.values, 0, mOldOreintation, 0, 3);
                      break;

                     default:
                              return;
            }

                // If mGravs and mGeoMags have values then find rotation matrix
                if (mGravs != null && mGeoMags != null) {

                    // checks that the rotation matrix is found
                    boolean success = SensorManager.getRotationMatrix(mRotationM, mInclinationM, mGravs, mGeoMags);
                    if (success) {
                        /* getOrientation Values */   
                        SensorManager.getOrientation(mRotationM, mOrientation);

                          for(int i=0; i<2; i++){
                              mAccelerometer[i] = Float.toString(mGravs[i]);
                              mMagnetic[i] = Float.toString(mGeoMags[i]);
                              mOrientationString[i] = Float.toString(mOrientation[i]);
                              mOldOreintationString[i] = Float.toString(mOldOreintation[i]);
                          }

                          /* Make everything text to show on device */
                          TextView xaxisAccelerometerText = (TextView)findViewById(R.id.xaxisAccelerometer);
                          xaxisAccelerometerText.setText(mAccelerometer[0]);      
                          TextView yaxisAccelerometerText = (TextView)findViewById(R.id.yaxisAccelerometer);
                          yaxisAccelerometerText.setText(mAccelerometer[1]);
                          TextView zaxisAccelerometerText = (TextView)findViewById(R.id.zaxisAccelerometer);
                          zaxisAccelerometerText.setText(mAccelerometer[2]);    
                          TextView xaxisMagneticText = (TextView)findViewById(R.id.xaxisMagnetic);
                          xaxisMagneticText.setText(mMagnetic[0]);    
                          TextView yaxisMagneticText = (TextView)findViewById(R.id.yaxisMagnetic);
                          yaxisMagneticText.setText(mMagnetic[1]);
                          TextView zaxisMagneticText = (TextView)findViewById(R.id.zaxisMagnetic);
                          zaxisMagneticText.setText(mMagnetic[2]);
                          TextView xaxisOrientationText = (TextView)findViewById(R.id.xaxisOrientation);
                          xaxisOrientationText.setText(mOrientationString[0]);    
                          TextView yaxisOrientationText = (TextView)findViewById(R.id.yaxisOrientation);
                          yaxisOrientationText.setText(mOrientationString[1]);
                          TextView zaxisOrientationText = (TextView)findViewById(R.id.zaxisOrientation);
                          zaxisOrientationText.setText(mOrientationString[2]);
                          TextView xaxisOldOrientationText = (TextView)findViewById(R.id.xaxisOldOrientation);
                          xaxisOldOrientationText.setText(mOldOreintationString[0]);      
                          TextView yaxisOldOrientationText = (TextView)findViewById(R.id.yaxisOldOrientation);
                          yaxisOldOrientationText.setText(mOldOreintationString[1]);
                          TextView zaxisOldOrientationText = (TextView)findViewById(R.id.zaxisOldOrientation);
                          zaxisOldOrientationText.setText(mOldOreintationString[2]);

                    }else{

                         /* Make everything text to show on device even if getRotationMatrix fails*/
                          String matrixFailed = "Rotation Matrix Failed";
                          TextView xaxisAccelerometerText = (TextView)findViewById(R.id.xaxisAccelerometer);
                          xaxisAccelerometerText.setText(mAccelerometer[0]);      
                          TextView yaxisAccelerometerText = (TextView)findViewById(R.id.yaxisAccelerometer);
                          yaxisAccelerometerText.setText(mAccelerometer[1]);
                          TextView zaxisAccelerometerText = (TextView)findViewById(R.id.zaxisAccelerometer);
                          zaxisAccelerometerText.setText(mAccelerometer[2]);    
                          TextView xaxisMagneticText = (TextView)findViewById(R.id.xaxisMagnetic);
                          xaxisMagneticText.setText(mMagnetic[0]);    
                          TextView yaxisMagneticText = (TextView)findViewById(R.id.yaxisMagnetic);
                          yaxisMagneticText.setText(mMagnetic[1]);
                          TextView zaxisMagneticText = (TextView)findViewById(R.id.zaxisMagnetic);
                          zaxisMagneticText.setText(mMagnetic[2]);
                          TextView xaxisOrientationText = (TextView)findViewById(R.id.xaxisOrientation);
                          xaxisOrientationText.setText(matrixFailed);     
                          TextView yaxisOrientationText = (TextView)findViewById(R.id.yaxisOrientation);
                          yaxisOrientationText.setText(matrixFailed);
                          TextView zaxisOrientationText = (TextView)findViewById(R.id.zaxisOrientation);
                          zaxisOrientationText.setText(matrixFailed);
                          TextView xaxisOldOrientationText = (TextView)findViewById(R.id.xaxisOldOrientation);
                          xaxisOldOrientationText.setText(mOldOreintationString[0]);      
                          TextView yaxisOldOrientationText = (TextView)findViewById(R.id.yaxisOldOrientation);
                          yaxisOldOrientationText.setText(mOldOreintationString[1]);
                          TextView zaxisOldOrientationText = (TextView)findViewById(R.id.zaxisOldOrientation);
                          zaxisOldOrientationText.setText(mOldOreintationString[2]);





                    }
                }


        }
    };


    @Override
     protected void onResume() {
        super.onResume();
        sensorManager.registerListener(sensorEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
        sensorManager.registerListener(sensorEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_NORMAL);
        sensorManager.registerListener(sensorEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL);
     }


    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(sensorEventListener);
    }    

}
like image 480
John Kossik Avatar asked Aug 12 '11 21:08

John Kossik


People also ask

What is the purpose of SensorManager?

SensorManager lets you access the device's sensors . Get an instance of this class by calling Context. getSystemService() with the argument SENSOR_SERVICE . Always make sure to disable sensors you don't need, especially when your activity is paused.

What is the difference between Sensor Manager and sensor class?

SensorManager: This is used to get access to various sensors present in the device to use it according to need. Sensor: This class is used to create an instance of a specific sensor. SensorEvent: This class is used to find the details of the sensor events.

Which sensor is used for orientation?

For determining a device's orientation, you can use the readings from the device's accelerometer and the geomagnetic field sensor.

What is a game rotation vector?

A game rotation vector sensor is similar to a rotation vector sensor but not using the geomagnetic field. Therefore the Y axis doesn't point north but instead to some other reference. That reference is allowed to drift by the same order of magnitude as the gyroscope drifts around the Z axis.


2 Answers

This probably doesn't apply to your code, but in terms of using getRotationMatrix() in general, it might solve others' problems.

I'm not sure if this was a versioning issue on my side, but I checked out the source code for the getRotationMatrix() method and, unlike what the documentation says about the R[] and I[] parameters, they CANNOT be null. After declaring my R and I like this:

float[] r = new float[9];

float[] i = new float[9];

The method operated correctly.

SensorManager.getRotationMatrix(r,i,gravity,geomagnetic) --> true

...strange documentation error.

like image 39
brainmurphy1 Avatar answered Oct 18 '22 22:10

brainmurphy1


In answer to your app requiring a force close, it sounds to me like you're doing too much on the UI thread too often. You are receiving data from 3 different sensors with a delay of SENSOR_DELAY_NORMAL. While that should be around 5 readings/sec, I've seen it can be more than 20 readings per second (since the sensor delay is only a suggested delay). So you COULD be receiving more than 60 readings per second for all 3 sensors. for each reading, you are updating 12 TextView's, so you could be doing more than 720 UI updates per second. This caused my phone to crash as well. Try setting a minimum time between UI updates:

long currentTime = System.currentTimeMillis();
if ((currentTime - lastUpdateTime) >= MIN_TIME_BETWEEN_UPDATES) {
    // Update UI
    lastUpdateTime = currentTime;
}

You can store the data at the fast intervals for use if you need it, but slow down the UI updates.

like image 59
James B Avatar answered Oct 18 '22 22:10

James B