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);
}
}
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.
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.
For determining a device's orientation, you can use the readings from the device's accelerometer and the geomagnetic field sensor.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With