Направление компаса зависит от ориентации телефона
Моему приложению дополненной реальности нужен компас, ориентированный на изображение с камеры, и есть множество примеров получения направления от менеджера датчиков.
Однако я нахожу результирующее значение разным в зависимости от ориентации телефона - пейзаж, повернутый вправо, примерно на 10 градусов отличается от ландшафта, повернутого влево (разница между ROTATION_0 и ROTATION_180 меньше, но все же отличается). Этой разницы достаточно, чтобы разрушить любой эффект AR.
Это как-то связано с калибровкой? (Я не уверен, что делаю цифру 8 правильно - я пробовал различные способы, которые я нашел на YouTube).
Есть идеи, почему есть разница? Я что-то напутал на матрице вращения? У меня есть возможность ограничить приложение одной ориентацией, но меня все равно беспокоит, что показания компаса все еще не очень точны (хотя после фильтрации они довольно стабильны)
public void onSensorChanged(SensorEvent event) {
if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
return;
}
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[] rotationMatrixA = mRotationMatrixA;
if (SensorManager.getRotationMatrix(rotationMatrixA, null, mGravity, mGeomagnetic)) {
float[] rotationMatrixB = mRotationMatrixB;
Display display = getWindowManager().getDefaultDisplay();
int deviceRot = display.getRotation();
switch (deviceRot)
{
// portrait - normal
case Surface.ROTATION_0: SensorManager.remapCoordinateSystem(rotationMatrixA,
SensorManager.AXIS_X, SensorManager.AXIS_Z,
rotationMatrixB);
break;
// rotated left (landscape - keys to bottom)
case Surface.ROTATION_90: SensorManager.remapCoordinateSystem(rotationMatrixA,
SensorManager.AXIS_Z, SensorManager.AXIS_MINUS_X,
rotationMatrixB);
break;
// upside down
case Surface.ROTATION_180: SensorManager.remapCoordinateSystem(rotationMatrixA,
SensorManager.AXIS_X, SensorManager.AXIS_Z,
rotationMatrixB);
break;
// rotated right
case Surface.ROTATION_270: SensorManager.remapCoordinateSystem(rotationMatrixA,
SensorManager.AXIS_MINUS_Z, SensorManager.AXIS_X,
rotationMatrixB);
break;
default: break;
}
float[] dv = new float[3];
SensorManager.getOrientation(rotationMatrixB, dv);
// add to smoothing filter
fd.AddLatest((double)dv[0]);
}
mDraw.invalidate();
}
}
2 ответа
Попробуй это
public void onSensorChanged(SensorEvent event) {
if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
return;
}
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) mGravity = event.values.clone ();
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) mGeomagnetic = event.values.clone ();
if (mGravity != null && mGeomagnetic != null) {
float[] rotationMatrixA = mRotationMatrixA;
if (SensorManager.getRotationMatrix(rotationMatrixA, null, mGravity, mGeomagnetic)) {
float[] rotationMatrixB = mRotationMatrixB;
SensorManager.remapCoordinateSystem(rotationMatrixA,
SensorManager.AXIS_X, SensorManager.AXIS_Z,
rotationMatrixB);
float[] dv = new float[3];
SensorManager.getOrientation(rotationMatrixB, dv);
// add to smoothing filter
fd.AddLatest((double)dv[0]);
}
mDraw.invalidate();
}
}
Вы не нуждаетесь в операторе switch, кажется, есть много путаницы относительно getRotationMatrix, remapCoordinateSystem и getOrientation из вопросов stackru.
Я, вероятно, напишу подробное объяснение этого в ближайшем будущем.
Ответ Хоан на самом деле неверен, потому что он не учитывает поворот дисплея. Это правильный ответ.