Hi, I wanna thank you very much for your explanation. The official documentation was very difficult to understand. And the example in the api sample (the compass) does use a depreciated methods (with sensorlistener).
I don't understand what does remapCoordinateSystem and his parameters, could you help? Thank you. On 16 juin, 06:28, "repDetect()" <n6mba50...@gmail.com> wrote: > Hi, > While trying to retrieve orientation data I found some pretty straight > forward code making use of SensorEventListener for > Sensor.TYPE_ORIENTATION and it works fine, but the > Sensor.TYPE_ORIENTATION constant has been deprecated recently - I > believe it was on 8 (API level) - which I understand to mean that > while I can still use it, I shouldn't. > The documentation [1] only says "use SensorManager.getOrientation() > instead." [2] but as a newbie, I had difficulties following that > "detailed" instruction. > > So the question is: > How to properly get device orientation data? > > In an attempt to make this discussion constructive, here is what I > managed to figure out, hopefully it will attract corrections relevant > to my limitations and not just general pointers to material I already > read (and misunderstood) and perhaps also benefit other newbies > struggling with this task. > So please fix any misconceptions or errors you find below. > > The most important thing to realize is that > SensorManager.getOrientation() doesn't get the orientation from the > sensors (as with SensorEvent for Sensor.TYPE_ORIENTATION), it merely > "Computes the device's orientation based on the rotation matrix" which > you must provide as the first parameter. > In a similar fashion SensorManager.getRotationMatrix() doesn't read > sensors data to produce the rotation matrix, it depends on you to > provide the data through the third and forth arguments (gravity, > geomagnetic), also note that the values of these arguments must be > within expected limits or the method will fail. This holds in > particular for the case where these are initialized to zeros, as this > will imply free fall for gravity and something even more disturbing > for geomagnetic. > Don't take my word on it look it up for yourself in the source [3], > for the Java end at list. > > Once that was digested it appears the only way to get sensor data is > through registering a sensor event listener (I thought it would be > really nice if I could query the sensors's readings at will and that > what I naively assumed was done by the get methods in SensorManager, > could anyone comment why this is not made available?), then that data > may be used to calculate the orientation as outlined below: > > 1) Retrieve sensor data from accelerometer and magnetic field sensor > as required by getRotationMatrix(): > This actually involves a number of steps in the Activity class: > 1.1) Obtain a sensor manager. > NOTE: Context.getSystemService needs a Context, typically called > within an Activity's context. > mSensMan = (SensorManager) getSystemService(SENSOR_SERVICE); > > 1.2) Register a sensor event listener for each of the above sensor > types. > mSensMan.registerListener(this, > mSensMan.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), > SensorManager.SENSOR_DELAY_UI); > mSensMan.registerListener(this, > mSensMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), > SensorManager.SENSOR_DELAY_UI); > > 1.3) In the listener's onSensorChanged method copy the data from the > SensorEvent.values. > NOTE: The data must be copied off the event.values as the system is > reusing that array in all SensorEvents, simply assigning won't work. > 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; > default: > return; > } > > } > > 2) Pass the copied sensor data as arrays to > SensorManager.getRotationMatrix() to receive the rotation matrix. > SensorManager.getRotationMatrix(mRotationM, null, mGravs, mGeoMags) > > Optionally transform the returned rotation matrix through > SensorManager.remapCoordinateSystem() or multiplying by a > transformation matrix. > > 3) Pass the rotation matrix to SensorManager.getOrientation() to > receive the orientation as yaw, pitch and roll expressed in radians. > SensorManager.getOrientation(mRotationM, mOrientation); > > Voila. > > Below the relevant code is wrapped with a complete Activity to allow > for testing and to get the whole picture, once again - corrections and > remarks are requested - the TODO: tags would also indicate areas where > knowledge is lacking. > > Please handle with care, this newbie is still a little wet and > slippery! > > [1]http://developer.android.com/reference/android/hardware/Sensor.html#T... > [2]http://developer.android.com/reference/android/hardware/SensorManager...[],%20float[]%29 > [3]http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;... > > <<------------------------------------------------------------------------------------------------------------------------ > > > > package my.odd.demo.orientation; > > import android.app.Activity; > import android.hardware.Sensor; > import android.hardware.SensorEvent; > import android.hardware.SensorEventListener; > import android.hardware.SensorManager; > import android.os.Bundle; > import android.view.ViewGroup.LayoutParams; > import android.widget.TextView; > > public class OrientationDemo extends Activity implements > SensorEventListener { > TextView mOrientationData; > private SensorManager mSensMan; > private float mAzimuth; > private float[] mGravs = new float[3]; > private float[] mGeoMags = new float[3]; > private float[] mOrientation = new float[3]; > private float[] mRotationM = new float[9]; // Use [16] > to co-operate with android.opengl.Matrix > private float[] mRemapedRotationM = new float[9]; > private boolean mFailed; > > /** Called when the activity is first created. */ > @Override > public void onCreate(Bundle savedInstanceState) { > super.onCreate(savedInstanceState); > > // I'd like to actually see something so let's have a view: > mOrientationData = new TextView(this); > setContentView(mOrientationData, new > LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); > > // Initiate the Sensor Manager and register this as Listener for > the required sensor types: > // TODO: Find how to get a SensorManager outside an Activity, to > implement as a utility class. > mSensMan = (SensorManager) getSystemService(SENSOR_SERVICE); > mSensMan.registerListener(this, > > mSensMan.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), // > Anonymous Sensors- no further use for them. > SensorManager.SENSOR_DELAY_UI); > mSensMan.registerListener(this, > mSensMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), > SensorManager.SENSOR_DELAY_UI); > } > > @Override > public void onAccuracyChanged(Sensor sensor, int accuracy) { > // Do nothing > } > > @Override > public void onSensorChanged(SensorEvent event) { > switch (event.sensor.getType()) { > case Sensor.TYPE_ACCELEROMETER: > /* > * NOTE: The data must be copied off the event.values > * as the system is reusing that array in all > SensorEvents. > * Simply assigning: > * mGravs = event.values won't work. > * > * I use a member array in an attempt to reduce > garbage production. > */ > System.arraycopy(event.values, 0, mGravs, 0, 3); > break; > case Sensor.TYPE_MAGNETIC_FIELD: > // Here let's try another way: > for (int i=0;i<3;i++) mGeoMags[i] = event.values[i]; > break; > default: > return; > } > > if (SensorManager.getRotationMatrix(mRotationM, null, mGravs, > mGeoMags)){ > // Rotate to the camera's line of view (Y axis along the > camera's > axis) > // TODO: Find how to use android.opengl.Matrix to rotate > to an > arbitrary coordinate system. > SensorManager.remapCoordinateSystem(mRotationM, > SensorManager.AXIS_X, > SensorManager.AXIS_Z, > mRemapedRotationM); > SensorManager.getOrientation(mRemapedRotationM, > mOrientation); > onSuccess(); > } > else onFailure(); > } > > void onSuccess(){ > if (mFailed) mFailed = false; > // Convert the azimuth to degrees in 0.5 degree resolution. > mAzimuth = (float) > Math.round((Math.toDegrees(mOrientation[0])) *2)/ > 2; > // Adjust the range: 0 < range <= 360 (from: -180 < range <= > 180). > mAzimuth = (mAzimuth+360)%360; // alternative: mAzimuth = > mAzimuth>=0 ? mAzimuth : mAzimuth+360; > mOrientationData.setText("Azimuth= " + mAzimuth); > } > > void onFailure() { > if (!mFailed) { > mFailed = true; > mOrientationData.setText("Failed to retrive rotation > Matrix"); > } > } > > } -- You received this message because you are subscribed to the Google Groups "Android Beginners" group. NEW! Try asking and tagging your question on Stack Overflow at http://stackoverflow.com/questions/tagged/android To unsubscribe from this group, send email to android-beginners+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/android-beginners?hl=en