Учебник getRotationMatrix и getOrientation

Я пытаюсь получить фактическую ориентацию своего устройства, используя getOrientation. Получение показаний акселерометра и магнитного поля через TYPE_ACCELEROMETER и TYPE_MAGNETIC_FIELD прямолинейно, так как получает ориентацию через TYPE_ORIENTATION. Но получить ориентацию в соответствии с мировой системой координат, используя getOrientation. Здесь и здесь есть несколько хороших учебников, но мне еще предстоит собрать все вместе. С этой целью я разрабатывал приложение, которое просто выплевывает акселерометр, магнитное поле, необработанные данные ориентации и данные ориентации из getOrientation. Я прикрепил код, но он постоянно терпит неудачу на моем телефоне. Какие-либо предложения?

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

Следующие со мной работали:

 float[] r = new float[**16**]; 

Использовать null для I

 float[] mOrientation = new float[4]; 

Да 4 не 3 . Однако вы используете только 3.

 SensorManager.getRotationMatrix(rotationMatrix, null, accelVals, magVals); 

Этот код работал для меня.

Это, вероятно, не относится к вашему коду, но с точки зрения использования getRotationMatrix () в целом, это может решить проблемы других.

Я не уверен, что это проблема с getRotationMatrix() на моей стороне, но я проверил исходный код getRotationMatrix() и, в отличие от того, что в документации говорится о параметрах R[] и I[] , они НЕ МОГУТ быть нулевыми , После объявления моего R и I это нравится:

float[] r = new float[9];

float[] i = new float[9];

Метод работает правильно.

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

… странная ошибка документации.

В ответ на ваше приложение, требующее силы закрытия, это звучит для меня так же, как вы слишком много делаете в области пользовательского интерфейса. Вы получаете данные от трех разных датчиков с задержкой SENSOR_DELAY_NORMAL . В то время как это должно быть около 5 показаний в секунду, я видел, что это может быть более 20 показаний в секунду (так как задержка датчика является только предполагаемой задержкой). Таким образом, вы МОЖЕТЕ получать более 60 отсчетов в секунду для всех 3 датчиков. Для каждого чтения вы обновляете 12 TextView , поэтому вы можете делать больше 720 обновлений пользовательского интерфейса в секунду. Это также привело к сбою моего телефона. Попробуйте установить минимальное время между обновлениями пользовательского интерфейса:

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

Вы можете хранить данные с быстрыми интервалами для использования, если вам это нужно, но замедлять обновления пользовательского интерфейса.

Прием событий не соответствует потоку выполнения линейной программы. Во избежание проблем рекомендуется рекомендовать код, связанный с получением событий датчиков во взаимном блоке исключения.

Я имею в виду:

 public void onSensorChanged(SensorEvent event) { synchronized (this) { ... } } 

Надеюсь это поможет.