Я пытаюсь прочитать азимут, тангаж и крен от диспетчера датчиков. По какой-то причине, если я перемещаю телефон очень медленно, значения азимута, шага и крена не обновляются, они обновляются, только если я перемещаю телефон достаточно сильно. Другими словами, если я перемещаю телефон очень медленно, я могу сделать полный поворот на 90 градусов без получения каких-либо новых значений.
Я вижу, что он «застревает» на этой строке, и если телефон перемещается слишком медленно, эта строка вернет false:
SensorManager.getRotationMatrix( R, I, mGravity, mGeomagnetic );
Похоже, что если на акселератор не действует значительная сила, то и вращение не будет обновляться.
Вот мой код:
mSensorManager = (SensorManager)activityContext.getSystemService(Context.SENSOR_SERVICE);;
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
А вот событие onSensorChanged:
@Override
public void onSensorChanged(SensorEvent event)
{
if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_ORIENTATION)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null)
{
// The code is triggering to this point fine
float R[] = new float[9];
float I[] = new float[9];
float forceX = Float.valueOf(((float)((float)mGravity[0] ) ) ) / (float)4.0;
float forceY = Float.valueOf(((float)((float)mGravity[1] ) ) ) / (float)4.0;
float forceZ = Float.valueOf(((float)((float)mGravity[2] ) ) ) / (float)4.0;
boolean success = SensorManager.getRotationMatrix( R, I, mGravity, mGeomagnetic );
if (success) // <-- this is only triggering if phone is moved fast enough
{
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
rotation_degrees_x = ((float)Math.toDegrees( orientation[0] ) + (float)180.0 ) / (float)360.0;
rotation_degrees_y = ((float)Math.toDegrees( orientation[1] ) + (float)180.0 ) / (float)360.0;
rotation_degrees_z = ((float)Math.toDegrees( orientation[2] ) + (float)180.0 ) / (float)360.0;
}
mGeomagnetic = null;
mGravity = null;
}
}
Я также вижу, что постоянно срабатывает следующее условие:
if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE)
Поэтому я добавил следующую строку в условие:
Log.d( "ROTATIONDEBUG", "TYPE_MAGNETIC_FIELD: " + mGeomagnetic[0] + "\t" + mGeomagnetic[1] + "\t" + mGeomagnetic[1] );
И получили некоторые значения, отражающие малейшие изменения поворота:
TYPE_MAGNETIC_FIELD: 23.5 20.7 20.7
TYPE_MAGNETIC_FIELD: 23.2 22.2 22.2
TYPE_MAGNETIC_FIELD: 23.0 24.9 24.9
TYPE_MAGNETIC_FIELD: 22.4 27.5 27.5
TYPE_MAGNETIC_FIELD: 21.5 29.2 29.2
TYPE_MAGNETIC_FIELD: 21.6 30.2 30.2
TYPE_MAGNETIC_FIELD: 21.1 32.1 32.10
TYPE_MAGNETIC_FIELD: 20.7 34.8 34.8
TYPE_MAGNETIC_FIELD: 20.7 34.7 34.7
TYPE_MAGNETIC_FIELD: 20.9 35.0 35.0
TYPE_MAGNETIC_FIELD: 20.6 36.0 36.0
Но не могу понять, почему они не работают вместе, а строка SensorManager.getRotationMatrix возвращает false..
Я скачал несколько приложений для тестирования компаса и датчиков, и все они могли уловить это движение света, так что я предполагаю, что это проблема с моим кодом.
EDIT: я попробовал другой пример кода, но он дает мне точно такие же результаты:
SensorEventListener sensorEventListener = new SensorEventListener() {
float[] mGravity;
float[] mGeomagnetic;
@Override
public void onSensorChanged(SensorEvent event) {
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 orientationData[] = new float[3];
SensorManager.getOrientation(R, orientationData);
azimuth = orientationData[0];
pitch = orientationData[1];
roll = orientationData[2];
}
}
}
};
Пока я вижу эту закономерность:
Если я прочитаю значения непосредственно из приведенного ниже условия, я смогу получить «подробные/чувствительные» изменения:
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
НО, если я попытаюсь использовать getRotationMatrix, он вернет true только в том случае, если с помощью акселерометра будет обнаружено достаточное усилие:
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
Как заставить SensorManager.getRotationMatrix срабатывать независимо от значения акселерометра? или как я могу преобразовать эти значения RAW в градусы?
Любые подсказки, пожалуйста? Спасибо!
"Because the game rotation vector sensor does not use the magnetic field, relative rotations are more accurate, and not impacted by magnetic field changes. Use this sensor in a game if you do not care about where north is, and the normal rotation vector does not fit your needs because of its reliance on the magnetic field."
- person Jon Goodwin   schedule 14.05.2018