Descripción general de la orientación del teléfono Android, incluida la brújula

107

He estado tratando de entender los sensores de orientación de Android durante un tiempo. Creí entenderlo. Entonces me di cuenta de que no. Ahora creo (espero) tener un mejor presentimiento de nuevo, pero todavía no estoy al 100%. Intentaré explicar mi comprensión irregular y espero que la gente pueda corregirme si me equivoco en algunas partes o si lleno los espacios en blanco.

Me imagino que estoy parado a 0 grados de longitud (primer meridiano) y 0 grados de latitud (ecuador). Esta ubicación está en el mar frente a la costa de África, pero tengan paciencia conmigo. Sostengo mi teléfono frente a mi cara para que la parte inferior del teléfono apunte a mis pies; Estoy de cara al norte (mirando hacia Greenwich), por lo que el lado derecho del teléfono apunta al este, hacia África. En esta orientación (con referencia al diagrama de abajo) tengo el eje X apuntando hacia el este, el eje Z apunta hacia el sur y el eje Y apunta hacia el cielo.

Ahora, los sensores del teléfono le permiten determinar la orientación (no la ubicación) del dispositivo en esta situación. Esta parte siempre me ha confundido, probablemente porque quería entender cómo funcionaba algo antes de aceptar que simplemente funcionaba. Parece que el teléfono calcula su orientación utilizando una combinación de dos técnicas diferentes.

Antes de llegar a eso, imagina estar de nuevo parado en ese pedazo de tierra imaginario a 0 grados de latitud y longitud en la dirección mencionada anteriormente. Imagínese también que tiene los ojos vendados y sus zapatos están fijados a una rotonda de juegos. Si alguien te empuja por la espalda, caerás hacia adelante (hacia el norte) y extenderás ambas manos para frenar la caída. De manera similar, si alguien te empuja en el hombro izquierdo, caerás sobre tu mano derecha. Su oído interno tiene "sensores gravitacionales" (clip de youtube) que le permiten detectar si está cayendo hacia adelante / atrás, o hacia la izquierda / derecha o cayendo (¡o hacia arriba!). Por lo tanto, los humanos pueden detectar la alineación y la rotación alrededor de los mismos ejes X y Z que el teléfono.

Ahora imagina que alguien ahora te gira 90 grados en la rotonda para que ahora mires hacia el este. Se le está rotando alrededor del eje Y. Este eje es diferente porque no podemos detectarlo biológicamente. Sabemos que estamos en cierto ángulo pero no sabemos la dirección en relación con el polo norte magnético del planeta. En su lugar, necesitamos usar una herramienta externa ... una brújula magnética. Esto nos permite determinar en qué dirección estamos mirando. Lo mismo ocurre con nuestro teléfono.

Ahora el teléfono también tiene un acelerómetro de 3 ejes. Tengo NOTengo idea de cómo funcionan realmente, pero la forma en que lo visualizo es imaginar la gravedad como una 'lluvia' constante y uniforme que cae del cielo e imaginar los ejes en la figura de arriba como tubos que pueden detectar la cantidad de lluvia que fluye a través. Cuando el teléfono se mantiene en posición vertical, toda la lluvia fluirá a través del 'tubo' en Y. Si el teléfono se gira gradualmente para que la pantalla mire hacia el cielo, la cantidad de lluvia que fluye a través de Y disminuirá a cero, mientras que el volumen a través de Z aumentará de manera constante hasta que fluya la cantidad máxima de lluvia. De manera similar, si ahora inclinamos el teléfono hacia un lado, el tubo X eventualmente recogerá la cantidad máxima de lluvia. Por lo tanto, dependiendo de la orientación del teléfono midiendo la cantidad de lluvia que fluye a través de los 3 tubos, puede calcular la orientación.

El teléfono también tiene una brújula electrónica que se comporta como una brújula normal: su "aguja virtual" apunta al norte magnético. Android fusiona la información de estos dos sensores para que, siempre que se genere una SensorEventde, TYPE_ORIENTATIONla values[3]matriz tenga
valores [0]: Azimut - (la brújula que se dirige al este del norte magnético)
valores [1]: Paso, rotación alrededor del eje x (es el teléfono inclinado hacia adelante o hacia atrás)
valores [2]: Rollo, rotación alrededor del eje y (el teléfono está inclinado sobre su lado izquierdo o derecho)

Así que creo (es decir, no sé) que la razón por la que Android da el acimut (rumbo de la brújula) en lugar de la lectura del tercer acelerómetro es que el rumbo de la brújula es más útil. No estoy seguro de por qué desaprobaron este tipo de sensor, ya que ahora parece que necesita registrar un oyente con el sistema para SensorEvents de tipo TYPE_MAGNETIC_FIELD. La value[]matriz del evento debe pasarse al SensorManger.getRotationMatrix(..)método para obtener una matriz de rotación (ver más abajo) que luego se pasa al SensorManager.getOrientation(..)método. ¿Alguien sabe por qué el equipo de Android está obsoleto Sensor.TYPE_ORIENTATION? ¿Es una cuestión de eficiencia? Eso es lo que está implícito en uno de los comentarios a una pregunta similar , pero aún necesita registrar un tipo diferente de oyente en eldesarrollo / samples / Compass / src / com / example / android / compass / CompassActivity.java ejemplo.

Ahora me gustaría hablar sobre la matriz de rotación. (Aquí es donde no estoy seguro) Así que arriba tenemos las tres cifras de la documentación de Android, las llamaremos A, B y C.

A = Figura del método SensorManger.getRotationMatrix (..) y representa el sistema de coordenadas del mundo

B = Sistema de coordenadas utilizado por la API SensorEvent.

C = Figura del método SensorManager.getOrientation (..)

Así que tengo entendido que A representa el "sistema de coordenadas del mundo" que supongo que se refiere a la forma en que las ubicaciones en el planeta se dan como un par (latitud, longitud) con una (altitud) opcional. X es el "easting" co-ordenada, Y es el "northing" co-ordenadas. Z apunta al cielo y representa la altitud.

El sistema de coordenadas de los teléfonos que se muestra en la figura B es fijo. Su eje Y siempre apunta hacia arriba. El teléfono calcula constantemente la matriz de rotación y permite el mapeo entre los dos. Entonces, ¿tengo razón al pensar que la matriz de rotación transforma el sistema de coordenadas de B en C? Entonces, cuando llama al SensorManager.getOrientation(..)método, usa la values[]matriz con valores que corresponden a la figura C.Cuando el teléfono apunta al cielo, la matriz de rotación es la matriz de identidad (la matriz matemática equivalente a 1), lo que significa que no es necesario un mapeo ya que el dispositivo está alineado con el sistema de coordenadas del mundo.

Okay. Creo que mejor me detengo ahora. Como dije antes, espero que la gente me diga en qué me equivoqué o ayudé a la gente (¡o confundí a la gente aún más!)

Tim
fuente
25
Me gusta mucho esta pregunta. No puedo contestar pero me gusta.
Octavian A. Damiean
4
Tim, ¿alguna vez obtuviste una respuesta? Me he estado rascando la cabeza al mismo tiempo. Esta es una de las API más pobremente documentadas que he visto.
Pierre-Luc Paour
Realmente no tengo miedo. Tuve que seguir adelante. Algún día volveré a este tema.
Tim
1
Aquí tengo la misma pregunta, ¿casi? Y la solución Response también. Hice público mi código en Github.
Lo mismo que me pregunto, he implementado una brújula en un dispositivo Android y funciona correctamente si recibí ayuda de Internet, funciona bien, pero lo que es confuso es ... Supongamos que mi dispositivo está colocado en la superficie del suelo hacia mí y está apuntando al norte ahora tomo mi móvil y lo coloco verticalmente sobre mi cabeza sin y mi cara todavía está hacia mí. En primer lugar, la aguja debería cambiar de dirección y por qué. Creo que no debería, ya que no he cambiado de dirección, pero está cambiando en mi aplicación y en todas las demás aplicaciones que he descargado. ¿Alguien puede explicar por qué?
Syed Raza Mehdi

Respuestas:

26

Es posible que desee ver el giro de una pantalla que merece otro . Explica por qué necesita la matriz de rotación.

En pocas palabras, los sensores del teléfono siempre usan el mismo sistema de coordenadas, incluso cuando se gira el dispositivo.

En las aplicaciones que no están bloqueadas en una sola orientación, el sistema de coordenadas de la pantalla cambia cuando gira el dispositivo. Por lo tanto, cuando el dispositivo se gira desde su modo de vista predeterminado, el sistema de coordenadas del sensor ya no es el mismo que el sistema de coordenadas de la pantalla. La matriz de rotación en este caso se usa para transformar A en C (B siempre permanece fijo).

Aquí hay un fragmento de código para mostrarle cómo se puede usar.

SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);

// Register this class as a listener for the accelerometer sensor
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                    SensorManager.SENSOR_DELAY_NORMAL);
// ...and the orientation sensor
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                    SensorManager.SENSOR_DELAY_NORMAL);

//...
// The following code inside a class implementing a SensorEventListener
// ...

float[] inR = new float[16];
float[] I = new float[16];
float[] gravity = new float[3];
float[] geomag = new float[3];
float[] orientVals = new float[3];

double azimuth = 0;
double pitch = 0;
double roll = 0;

public void onSensorChanged(SensorEvent sensorEvent) {
    // If the sensor data is unreliable return
    if (sensorEvent.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
        return;

    // Gets the value of the sensor that has been changed
    switch (sensorEvent.sensor.getType()) {  
        case Sensor.TYPE_ACCELEROMETER:
            gravity = sensorEvent.values.clone();
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            geomag = sensorEvent.values.clone();
            break;
    }

    // If gravity and geomag have values then find rotation matrix
    if (gravity != null && geomag != null) {

        // checks that the rotation matrix is found
        boolean success = SensorManager.getRotationMatrix(inR, I,
                                                          gravity, geomag);
        if (success) {
            SensorManager.getOrientation(inR, orientVals);
            azimuth = Math.toDegrees(orientVals[0]);
            pitch = Math.toDegrees(orientVals[1]);
            roll = Math.toDegrees(orientVals[2]);
        }
    }
}
Octavian A. Damiean
fuente
4
solo mencione que azimut, cabeceo y balanceo NO son lo mismo que salen del obsoleto OrientationSensor. orientation[0] = orientation[0] >= 0 ? orientation[0]: orientation[0] + 360;normalizará el acimut y if (orientation[1] <= -90) { orientation[1] += (-2*(90+orientation[1])); } else if(orientation[1] >= 90){ orientation[1] += (2*(90 - orientation[1])); }normalizará el tono
Rafael T
@RafaelT y normalizar rollo? ¿O eso no tiene sentido?
Matthias
@RafaelT: Su normalización de acimut parece tener efecto: los valores van de [-180,180] a [0, 360]. Pero los valores de tono que obtengo ya están en [-90,90] por lo que la normalización que propones no tiene ningún efecto.
Matthias
¿Qué significa si después de verificar (gravity! = Null && geomag! = Null), el valor de geomag es siempre 0, sin importar cómo mueva la tableta? ¿Podría ser una tableta sin sensor geomag?
Avanzado
3

El balanceo es una función de la gravedad, un balanceo de 90 grados pone toda la gravedad en el registro x.

El tono es el mismo, un tono hacia arriba de 90 grados pone todo el componente de la gravedad en el registro y.

La guiñada / rumbo / azimut no tiene ningún efecto sobre la gravedad, SIEMPRE está en ángulo recto con la gravedad, por lo tanto, no importa en qué dirección se mire, la gravedad será inconmensurable.

Es por eso que necesita una brújula para evaluar, ¿tal vez eso tenga sentido?

Craig
fuente
0

Estaba teniendo este problema, así que tracé un mapa de lo que sucede en diferentes direcciones. Si el dispositivo está montado de forma horizontal, por ejemplo, en un automóvil, los 'grados' de la brújula parecen ir de 0 a 275 (en el sentido de las agujas del reloj) por encima de 269 (entre el oeste y el norte), cuenta hacia atrás de -90 a 0, entonces avanza de 0 a 269. 270 se convierte en -90

Todavía en paisaje, pero con el dispositivo boca arriba, mi sensor da 0-360. y en el modo de retrato corre 0-360 tanto acostado de espaldas como de pie en retrato.

Espero que ayude a alguien

bob desesperado
fuente