2012-04-19 19 views
27

estoy haciendo una aplicación de mapas, incluyendo la flecha ubicación que le muestra el camino que está enfrentando, así:¿Cómo conseguir la orientación del teléfono Android que coincida con la orientación humana?

Map with a blue arrow

puedo obtener la orientación directamente de SensorManager.getOrientation(), utilizando el primer valor devuelto: azimut. Cuando se sostiene el teléfono para que la pantalla apunte sobre el horizonte y en vertical, la flecha funciona bien. Sin embargo:

  • Cuando se sostiene el teléfono de manera que la pantalla apunte debajo del horizonte, la flecha apunta 180 grados con respecto a la dirección que está mirando el usuario.
  • Cuando se sostiene el teléfono para que la pantalla quede alineada con el horizonte, la flecha no tiene ni idea de qué dirección apunta. Azimuth no devuelve resultados significativos en absoluto.
  • Cuando el teléfono se inclina hacia la izquierda o hacia la derecha (o se mantiene en modo horizontal), la flecha se inclina hacia la izquierda o hacia la derecha.

La imagen cuidadosamente construida y científica a continuación muestra lo que quiero decir (donde el azul es el frente del usuario, el rojo es la dirección de la flecha, la pantalla está enfrentando al usuario y Google Maps hace exactamente lo que quiero):

Graph of what happens vs what I want

(Tenga en cuenta que, con Google Maps, no lo hace con éxito los últimos dos acciones en la lista si auto-rotación está apagado. Pero ni siquiera estoy en esa etapa, sin embargo. Uno cosa a la vez.)

Parece como si fuera simplemente usando la dirección de puntería del eje Y como se muestra aquí: http://developer.android.com/reference/android/hardware/SensorEvent.html, cuando quiero que use la dirección opuesta al eje Z, la mayoría de las veces, y la Y cuando el teléfono está plano. Sin embargo, dados los valores que devuelve getOrientation(), tendría que escribir casos complejos para corregir algunos de los problemas, y el caso de uso del teléfono que se enfrenta al horizonte no tiene solución. Estoy seguro de que hay una manera más fácil.

Aquí está mi código (cuando lastAcceleration y lastMagneticField ambos llegaron desde el sensor interno):

float[] rotationMatrix = new float[9]; 
if(SensorManager.getRotationMatrix(rotationMatrix, null, lastAcceleration, lastMagneticField)){ 
    float[] orientMatrix = new float[3]; 
    SensorManager.getOrientation(rotationMatrix, orientMatrix); 

    orientation = orientMat[0]*180/(float)Math.PI; 
} 

¿Qué estoy haciendo mal? ¿Hay alguna forma más fácil de hacer esto?

Editar: Solo para aclarar, supongo que el usuario está sosteniendo el dispositivo en frente de ellos, y la pantalla apunta hacia ellos. Más allá de eso, obviamente no puedo decir si solo uno de ellos rota. Además, estoy usando el movimiento del usuario cuando se están moviendo, pero esto es para cuando están estacionarios.

+16

+1 para la imagen científica –

+0

¿Ha resuelto su problema? ¿Cómo obtuviste lastAcceleration, lastMagneticField? –

+0

No. Nunca resuelto Tal vez nunca fue solucionable, y parece que Google Maps no fue tan inteligente como pensé en ese momento. Hace tiempo que lo descarté de mi lista de tareas que necesitaba hacer, ya que ya no trabajo para la misma empresa, y mucho menos para el mismo proyecto. Android de todos modos funciona de manera totalmente diferente en estos días, de todos modos. – AlbeyAmakiir

Respuesta

0

Esto se ve bastante complicado. Estoy desarrollando un PNS para Android y estoy enfrentando un problema de alguna manera similar para el que todavía necesito la luz: How to get the rotation between accelerometer's axis and motion vector?

Lo que pasa es que me resulta absolutamente imposible encontrar en qué dirección se encuentra el usuario (no el dispositivo) si no se está moviendo. Es decir, el humano no tiene sensor en su cuerpo, entonces, ¿qué pasa si el dispositivo se mantiene en la misma posición pero el usuario gira 90 °? No veo ninguna forma de encontrar esto.

Lo que puedo sugerir (y que realmente se ajusta a mi problema) es que podrías (no sé lo que realmente haces en tu código) usar el movimiento del usuario para determinar su rumbo. Dejame explicar. Digamos que tiene una primera posición A. El usuario va a B.Luego puedes construir el vector AB y obtener el título del usuario cuando se detenga en B. Tendrás que limitar tu código a la dirección que está enfrentando cuando llegue al destino.

Sé que esto no es tan bueno como lo que Google Maps obtiene, pero ¿sabes lo que Google usa para esto? Quiero decir, ¿solo usan los sensores acelero y mag.field?

+0

Supongo que el usuario está sosteniendo el dispositivo frente a ellos, con la pantalla apuntando hacia ellos. Más allá de eso, obviamente no puedo hacer más. Además, estoy tomando la iniciativa del usuario. Es solo que, cuando se detengan, el acelerómetro y el campo magnético deberían tomar el control. – AlbeyAmakiir

6

¿Ha llamado a remapCoordinateSystem? De lo contrario, solo obtendrá el valor correcto cuando el teléfono se mantenga vertical. Para el caso Cuando se sostiene el teléfono para que la pantalla quede alineada con el horizonte, no hay forma de que pueda mirar al usuario. Porque para obtener el revestimiento debe proyectar el valor z de la lectura del sensor en el plano xy en la coordenada mundial y es cero cuando el dispositivo se mantiene horizontalmente.

Para ser más precisos, si quiere que el teléfono mire hacia delante, entonces el teléfono debe estar inclinado al menos unos 25 grados desde la horizontal y debe llamar a remapCoordinateSystem. El siguiente código le dará lo que desea para las últimas 2 imágenes de arriba.
Código

float[] rotationMatrix = new float[9]; 

if(SensorManager.getRotationMatrix(rotationMatrix, null, lastAcceleration, lastMagneticField)){ 
    float[] orientMatrix = new float[3]; 
    float remapMatrix = new float[9]; 
    SensorManager.remapCoordinateSystem(rotationMatrix, SensorManager.AXIS_X, SensorManager.AXIS_Z, remapMatrix); 
    SensorManager.getOrientation(remapMatrix, orientMatrix); 

    orientation = orientMat[0]*180/(float)Math.PI; 
} 

El getOrientation le da los valores correctos, suponiendo que el teléfono está en posición plana. Por lo tanto, si el teléfono se mantiene verticalmente, entonces debe reasignar las coordenadas para obtener la posición plana. Geométricamente, proyecta el eje del teléfono -z hacia el plano xy del mundo y luego calcula el ángulo entre este vector de proyección y el eje y del mundo.

+0

No estoy seguro de seguir. O tal vez no. No es imposible obtener la orientación cuando la pantalla es horizontal, porque eso es lo que hace Google y lo que tengo ahora. Quisiera conseguir el revestimiento cuando el teléfono está vertical. Y no. No he llamado 'remapCoordinateSystem'. Los documentos no son del todo claros sobre cómo usarlo. – AlbeyAmakiir

+0

Puede obtener la dirección de la brújula, pero no la dirección del teléfono si se sostiene el teléfono para que la pantalla quede alineada con el horizonte. Es decir, el teléfono está apuntando al suelo, por lo que no tiene sentido hablar de Norte, Sur, etc. Puedes obtener la "dirección de la brújula", pero esta dirección depende de la orientación del teléfono. Es decir, si el teléfono está plano en modo retrato frente a usted y la brújula muestra 0 grados, cuando gira hacia el paisaje, la brújula mostrará 90 o 270 grados dependiendo de la dirección en que gire. –

0

Parece que el camino adecuado para conseguir el cojinete cuando el usuario está sosteniendo el teléfono en posición vertical es utilizar algo como esto:

// after calling getRotationMatrix pass the rotationMatix below: 
SensorManager.remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR); 

Si desea manejar en ambos sentidos (verticales y planas) que se probablemente necesite detectar eso y luego solo realizar esta reasignación cuando esté vertical.

Consulte la documentación de la API here.

0

Debe tomar el tono y determinar si el usuario está cerca de sostener el teléfono verticalmente hacia arriba.

escogí que después de un pitch de 45 grados hacia arriba o hacia abajo desde el plano en la mesa, el sistema de coordenadas debe ser reasignado.

if (Math.round(Math.toDegrees(-orientation[1])) < 45 && Math.round(Math.toDegrees(-orientation[1])) > -45) { 
//do something while the phone is horizontal 
}else{ 
//R below is the original rotation matrix 
float remapOut[] = new float[9]; 
SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X, SensorManager.AXIS_Z, remapOut); 
//get the orientation with remapOut 
float remapOrientation[] = new float[3]; 
SensorManager.getOrientation(remapOut, remapOrientation); 

Ha funcionado bastante bien. Avíseme si alguien puede sugerir una mejora al respecto. Gracias.

Cuestiones relacionadas