Датчик вращения не реагирует, если телефон перемещается медленно
Я пытаюсь прочитать азимут, тангаж и крен из диспетчера сенсоров. По какой-то причине, если я перемещаю телефон очень медленно, значения азимута, высоты тона и рулона не обновляются, они обновляются только в том случае, если я перемещаю телефон достаточно сильно. Другими словами, если я перемещаю телефон очень медленно, я могу сделать полный поворот на 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..
Я скачал несколько приложений для тестирования компаса и сенсора, и все они могли уловить это легкое движение, так что я предполагаю, что есть проблема с моим кодом.
РЕДАКТИРОВАТЬ: я попробовал другой пример кода, но он дает мне точно такие же результаты:
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, он вернет истину только в том случае, если с помощью акселерометра обнаружена достаточная сила:
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
Как я могу получить SensorManager.getRotationMatrix для запуска независимо от значения акселерометра? или как я могу преобразовать эти значения RAW в градусы?
Любые намеки, пожалуйста? Спасибо!
1 ответ
Оказывается, изменив SENSOR_DELAY_GAME на SENSOR_DELAY_NORMAL и используя только обычный TYPE_GYROSCOPE, решил проблему, и она срабатывает даже при малейшем движении!