Sé que estoy reproduciendo thread nigromante aquí, pero he estado trabajando en esto mucho últimamente, así que pensé en agregar mi 2 ¢.
El dispositivo no contiene brújula ni inclinómetros, por lo que no mide el acimut, el cabeceo o el balanceo directamente. (Llamamos a esos ángulos de Euler, por cierto). En cambio, usa acelerómetros y magnetómetros, que producen vectores XYZ de 3 espacios. Estos se utilizan para calcular los valores de acimut, etc.
vectores están en el dispositivo de espacio de coordenadas:
coordenadas mundo han Y mirando al norte, X mirando hacia el este, y Z hacia arriba:
Por lo tanto, de un dispositivo " la orientación "neutral" está acostada boca arriba sobre una mesa, con la parte superior del dispositivo hacia el norte.
El acelerómetro produce un vector en la dirección "ARRIBA". El magnetómetro produce un vector en la dirección "norte". (Tenga en cuenta que en el hemisferio norte, esto tiende a apuntar hacia abajo debido a magnetic dip.)
El vector de acelerómetro y vector magnetómetro se pueden combinar matemáticamente a través de SensorManager.getRotationMatrix() que devuelve una matriz de 3x3 que mapear vectores en coordenadas del dispositivo a coordenadas mundiales o viceversa. Para un dispositivo en la posición neutral, esta función devolvería la matriz de identidad.
Esta matriz no varía con la orientación de la pantalla. Esto significa que su aplicación necesita conocer la orientación y compensar en consecuencia.
SensorManager.getOrientation() toma la matriz de transformación y calcula los valores azimuth, pitch y roll. Estos se toman en relación con un dispositivo en la posición neutral.
No tengo idea de cuál es la diferencia entre llamar a esta función y simplemente usar el sensor TYPE_ORIENTATION, excepto que la función le permite manipular primero la matriz.
Si el dispositivo está inclinado hacia arriba a 90 ° o cerca de él, el uso de ángulos de Euler se desmorona. Este es un caso degenerado matemáticamente. En este ámbito, ¿cómo se supone que el dispositivo debe saber si está cambiando el acimut o el balanceo?
La función SensorManager.remapCoordinateSystem() se puede utilizar para manipular la matriz de transformación para compensar lo que puede saber sobre la orientación del dispositivo. Sin embargo, mis experimentos han demostrado que esto no cubre todos los casos, ni siquiera algunos de los más comunes. Por ejemplo, si desea volver a asignar para un dispositivo en posición vertical (por ejemplo, para tomar una foto), sería necesario multiplicar la matriz de transformación de esta matriz:
1 0 0
0 0 1
0 1 0
antes de llamar getOrientation(), y esto no es uno de los remapeos de orientación que remapCoordinateSystem() admite [alguien por favor corrígeme si me he perdido algo aquí].
OK, así que esto ha sido una manera larga de decir que si estás usando la orientación, ya sea desde el sensor TYPE_ORIENTATION o desde getOrientation(), probablemente lo estás haciendo mal. La única vez que realmente quiere los ángulos de Euler es mostrar información de orientación de forma fácil de usar, anotar una fotografía, conducir la pantalla del instrumento de vuelo, o algo similar.
Si desea realizar cálculos relacionados con la orientación del dispositivo, es casi seguro que es mejor utilizar la matriz de transformación y trabajar con vectores XYZ.
Trabajando como consultor, cada vez que alguien viene a mí con un problema relacionado con ángulos de Euler, hacer copias de seguridad y pedirles que lo que están realmente tratando de hacer, y luego encontrar una manera de hacerlo con vectores lugar.
Al volver a su pregunta original, getOrientation() debería devolver tres valores en [-180 180] [-90 90] y [-180 180] (después de convertir de radianes). En la práctica, pensamos en acimut como números en [0 360], por lo que simplemente debe agregar 360 a los números negativos que reciba. Tu código se ve correcto como está escrito. Ayudaría si supiera exactamente qué resultados esperaba y qué obtendría en su lugar.
Editado para agregar: Un par de pensamientos más. Las versiones modernas de Android usan algo llamado "fusión de sensores", lo que básicamente significa que todas las entradas disponibles (acelerador, magnetómetro, giroscopio) se combinan en una caja negra matemática (normalmente un filtro de Kalman, pero depende del proveedor). Todos los diferentes sensores (aceleración, campo magnético, giroscopios, gravedad, aceleración lineal y orientación) se toman como salidas de esta caja negra.
Siempre que sea posible, debe usar TYPE_GRAVITY en lugar de TYPE_ACCELEROMETER como la entrada a getRotationMatrix().
He estado trabajando en esto yo misma por aproximadamente 2 semanas. Tu código se ve como debería (según la documentación que he podido encontrar), pero como has notado, no coincide con los resultados del sensor TYPE_ORIENTATION. Parecía una cosa simple comprobar los valores de orientación [0] para un valor negativo y agregarlo. Pero eso no acaba de hacer. No muestra la frecuencia de las actualizaciones de sus sensores. Descubrí que las actualizaciones más rápidas producen mejores resultados, aunque los resultados de TYPE_ORIENTATION parecen ser bastante estables. Si desea trabajar en conjunto, póngase en contacto con [email protected] –
Todos los sensores de velocidad son GAME, pero no creo que el problema esté relacionado con la velocidad. Es extraño porque todos los blogs y foros (¡y el libro que estoy leyendo!) Implementan los sensores de la misma manera. –
Bueno, todo el mundo dice cómo usar el acelerómetro y el campo magnético, pero nadie dice que los valores devueltos SON DIFERENTES de TYPE_ORIENTATION, incluso la documentación oficial. Buen trabajo, gente. Esperando una respuesta ... –