Comment dois-je calculer Azimut, pitch, orientation quand mon appareil Android n'est pas plat?
j'utilise les capteurs de gravité et de champ magnétique D'Android pour calculer l'orientation via SensorManager.getRotationMatrix et SensorManager.getOrientation. Cela me donne les numéros d'azimut, de pitch et d'orientation. Les résultats semblent sensés quand l'appareil est couché à plat sur une table.
cependant, j'ai désactivé les commutateurs entre le portrait et le paysage dans le manifeste, de sorte que getWindowManager().getDefaultDisplay ().getRotation () est toujours zéro. Lorsque je tourne le l'appareil est à 90 degrés, il est à la verticale, j'ai des problèmes. Parfois les chiffres semblent tout à fait faux, et j'ai réalisé que cela se rapporte à Gimbal lock . Cependant, d'autres applications ne semblent pas avoir ce problème. Par exemple, j'ai comparé mon application avec deux applications gratuites de test de capteurs ( Sensor Tester (Dicotomica) et Sensor Monitoring (R's Software) ). Mon application est d'accord avec ces applications quand l'appareil est plat, mais comme je faire pivoter le dispositif dans la position verticale il peut y avoir des différences significatives. Les deux applications semblent être d'accord l'une avec l'autre, alors comment peuvent-elles contourner ce problème?
2 réponses
je pense que la meilleure façon de définir vos angles d'orientation quand le dispositif n'est pas plat est d'utiliser un système de coordonnées angulaires plus approprié que les angles Euler standard que vous obtenez de SensorManager.getOrientation(...)
. Je suggère celui que je décris ici sur math.stackexchange.com . J'ai aussi mis un code qui l'implémente dans une réponse ici . En dehors d'une bonne définition de l'azimut, il a également une définition de l'angle de tangage qui est exactement l'angle donné par Math.acos(rotationMatrix[8])
qui est mentionné dans une autre réponse ici.
vous pouvez obtenir tous les détails à partir des deux liens que j'ai donnés dans le premier paragraphe. Cependant, en résumé, votre matrice de rotation R de SensorManager.getRotationMatrix(...) est
où (E x , E y , E z ), (N x , N y , N z ) et (G x , G y , G z ) sont des vecteurs pointant vers l'est, le Nord, et dans la direction de la gravité. Ensuite, l'angle d'azimut que vous voulez est donné par
Lorsque l'appareil n'est pas plat, vous devez appeler le remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);
avant d'appeler getOrientation
.
le azimuth
retourne par getOrientation
est obtenu en projetant orthogonalement l'Unité de périphérique Y axis
dans le monde East-North plane
et puis calculer l'angle entre le vecteur de projection résultant et l'axe du Nord.
maintenant, nous considérons normalement la direction comme la direction où la caméra arrière pointe. C'est l' la direction de -Z
où Z
est l'axe du dispositif pointant de l'écran. Quand l'appareil est plat nous ne pensons pas de direction et acceptons ce qui jamais donné. Mais quand il n'est pas plat, nous attendons, c'est la direction de -Z
. Mais getOrientation
calcule la direction du Y axis
, il faut donc changer le Y and Z axes
avant d'appeler getOrientation
. C'est exactement ce que remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR)
fait, il garde le X axis
intact et la carte Z to Y
.
alors comment savoir quand remap
ou pas. Vous pouvez le faire en cochant
float inclination = (float) Math.acos(rotationMatrix[8]);
if (result.inclination < TWENTY_FIVE_DEGREE_IN_RADIAN
|| result.inclination > ONE_FIFTY_FIVE_DEGREE_IN_RADIAN)
{
// device is flat just call getOrientation
}
else
{
// call remap
}
l'inclinaison ci-dessus est l'angle entre l'écran du dispositif et le plan mondial Est-Nord. Il montre combien l'appareil est inclinable.