106 votes

Aperçu de l'orientation des téléphones Android, y compris la boussole

Ça fait un moment que j'essaie de comprendre les capteurs d'orientation d'Android. Je pensais l'avoir compris. Puis j'ai réalisé que ce n'était pas le cas. Aujourd'hui, je pense (j'espère) que j'ai à nouveau un meilleur feeling, mais je ne suis toujours pas à 100%. Je vais essayer d'expliquer ma compréhension inégale et j'espère que les gens seront en mesure de me corriger si je me trompe ou de combler les lacunes.

J'imagine que je me trouve à 0 degré de longitude (premier méridien) et à 0 degré de latitude (équateur). Cet endroit se trouve en réalité dans la mer, au large des côtes africaines, mais suivez-moi. Je tiens mon téléphone devant mon visage de façon à ce que le bas du téléphone pointe vers mes pieds ; je suis tourné vers le nord (en regardant vers Greenwich) et le côté droit du téléphone pointe donc vers l'est, vers l'Afrique. Dans cette orientation (par rapport au schéma ci-dessous), l'axe des X est orienté vers l'Est, l'axe des Z est orienté vers le Sud et l'axe des Y pointe vers le ciel.

Les capteurs du téléphone vous permettent maintenant de déterminer l'orientation (et non l'emplacement) de l'appareil dans cette situation. Cette partie m'a toujours dérouté, probablement parce que je voulais comprendre comment quelque chose fonctionnait avant d'accepter que cela fonctionne. Il semble que le téléphone calcule son orientation en utilisant une combinaison de deux techniques différentes.

Avant d'y venir, imaginez que vous vous retrouvez sur ce morceau de terre imaginaire situé à 0 degré de latitude et de longitude, dans la direction mentionnée ci-dessus. Imaginez également que vous avez les yeux bandés et que vos chaussures sont fixées à un rond-point de la cour de récréation. Si quelqu'un vous pousse dans le dos, vous tomberez en avant (vers le nord) et vous tendrez les deux mains pour amortir votre chute. De même, si quelqu'un vous pousse sur l'épaule gauche, vous tomberez sur votre main droite. Votre oreille interne possède des "capteurs gravitationnels". (clip youtube) qui vous permettent de détecter si vous tombez en avant/en arrière, ou à gauche/à droite ou en bas (ou en haut !). Les humains peuvent donc détecter l'alignement et la rotation autour des mêmes axes X et Z que le téléphone.

Imaginez maintenant que quelqu'un vous fasse pivoter de 90 degrés sur le rond-point de sorte que vous soyez maintenant tourné vers l'Est. Vous êtes en train de pivoter autour de l'axe Y. Cet axe est différent car nous ne pouvons pas le détecter biologiquement. Nous savons que nous sommes inclinés d'un certain angle, mais nous ne connaissons pas la direction par rapport au pôle Nord magnétique de la planète. Au lieu de cela, nous devons utiliser un outil externe... un compas magnétique. Celle-ci nous permet de déterminer dans quelle direction nous sommes orientés. Il en va de même avec notre téléphone.

Maintenant, le téléphone possède également un accéléromètre à 3 axes. J'ai NON Je n'ai aucune idée de la façon dont ils fonctionnent réellement, mais la façon dont je le visualise est d'imaginer la gravité comme une "pluie" constante et uniforme tombant du ciel et d'imaginer les axes dans la figure ci-dessus comme des tubes qui peuvent détecter la quantité de pluie qui s'écoule. Lorsque le téléphone est tenu à la verticale, toute la pluie s'écoule par le "tube" Y. Si le téléphone est progressivement tourné de façon à ce que son écran soit face au ciel, la quantité de pluie s'écoulant par le tube Y diminuera jusqu'à zéro tandis que le volume par le tube Z augmentera régulièrement jusqu'à ce que la quantité maximale de pluie s'écoule. De même, si nous inclinons maintenant le téléphone sur le côté, le tube X finira par recueillir la quantité maximale de pluie. Par conséquent, en fonction de l'orientation du téléphone, vous pouvez calculer l'orientation en mesurant la quantité de pluie qui s'écoule dans les trois tubes.

Le téléphone dispose également d'une boussole électronique qui se comporte comme une boussole normale - son "aiguille virtuelle" pointe vers le nord magnétique. Android fusionne les informations provenant de ces deux capteurs de sorte que lorsqu'une SensorEvent de TYPE_ORIENTATION est généré le values[3] Le tableau a
valeurs[0] : Azimut - (le relèvement de la boussole à l'est du nord magnétique)
valeurs[1] : Pitch, rotation autour de l'axe x (le téléphone est-il penché en avant ou en arrière)
valeurs[2] : Roulis, rotation autour de l'axe des y (le téléphone est-il penché sur son côté gauche ou droit)

Je pense donc (c'est-à-dire que je ne sais pas) que la raison pour laquelle Android donne l'azimut (relèvement de la boussole) plutôt que la lecture du troisième accéléromètre est que le relèvement de la boussole est simplement plus utile. Je ne suis pas sûr de la raison pour laquelle ils ont déprécié ce type de capteur car maintenant il semble que vous devez enregistrer un écouteur avec le système pour SensorEvent de type TYPE_MAGNETIC_FIELD . L'événement value[] doit être passé dans SensorManger.getRotationMatrix(..) pour obtenir une matrice de rotation (voir ci-dessous) qui est ensuite transmise à la méthode SensorManager.getOrientation(..) méthode. Est-ce que quelqu'un sait pourquoi l'équipe Android a déprécié Sensor.TYPE_ORIENTATION ? Est-ce une question d'efficacité ? C'est ce que laisse entendre l'un des commentaires d'un article similaire. pregunta mais vous devez toujours enregistrer un autre type d'écouteur dans la section développement/exemples/Compass/src/com/exemple/Android/compass/CompassActivity.java exemple.

J'aimerais maintenant parler de la matrice de rotation. (C'est là que je suis le plus incertain). Nous avons donc ci-dessus les trois figures de la documentation Android, nous les appellerons A, B et C.

A = figure de la méthode SensorManger.getRotationMatrix(..) et représente le système de coordonnées du Monde

B = Système de coordonnées utilisé par l'API SensorEvent.

C= figure de la méthode SensorManager.getOrientation(..)

Si j'ai bien compris, A représente le "système de coordonnées du monde", ce qui, je suppose, fait référence à la manière dont les emplacements sur la planète sont donnés sous la forme d'un couple (latitude, longitude) avec une option (altitude). X représente le "easting" Y est la coordonnée "nord" coordonnée. Z pointe vers le ciel et représente l'altitude.

Le système de coordonnées des téléphones est représenté sur la figure B est fixe. Son axe Y pointe toujours vers le haut. La matrice de rotation est constamment calculée par le téléphone et permet le mappage entre les deux. Ai-je donc raison de penser que la matrice de rotation transforme le système de coordonnées de B en C ? Ainsi, lorsque vous appelez SensorManager.getOrientation(..) vous utilisez la méthode values[] avec des valeurs qui correspondent à la figure C. Lorsque le téléphone est pointé vers le ciel, la matrice de rotation est la matrice d'identité (l'équivalent mathématique de 1), ce qui signifie qu'aucun mappage n'est nécessaire puisque l'appareil est aligné sur le système de coordonnées du monde.

Ok. Je pense que je ferais mieux d'arrêter maintenant. Comme je l'ai déjà dit, j'espère que les gens me diront où j'ai fait des erreurs ou aidé les gens (ou encore plus confus !).

26voto

Levi Points 430

Vous pourriez vouloir vérifier le Un tour d'écran en mérite un autre article. Il explique pourquoi vous avez besoin de la matrice de rotation.

En bref, les capteurs du téléphone utilisent toujours le même système de coordonnées, même lorsque l'appareil est tourné.

Dans les applications qui ne sont pas verrouillées sur une seule orientation, le système de coordonnées de l'écran change lorsque vous faites pivoter l'appareil. Ainsi, lorsque l'appareil est tourné à partir de son mode d'affichage par défaut, le système de coordonnées du capteur n'est plus le même que celui de l'écran. Dans ce cas, la matrice de rotation est utilisée pour transformer A en C (B reste toujours fixe).

Voici un extrait de code pour vous montrer comment l'utiliser.

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]);
        }
    }
}

3voto

Craig Points 11

Le roulis est une fonction de la gravité, un roulis de 90 degrés met toute la gravité dans le registre x.

L'inclinaison est la même, une inclinaison de 90 degrés vers le haut met toute la composante de gravité dans le registre y.

Le lacet / le cap / l'azimut n'a aucun effet sur la gravité, il est TOUJOURS à angle droit par rapport à la gravité, donc quelle que soit votre orientation, la gravité sera imeasurable.

C'est pourquoi vous avez besoin d'une boussole pour évaluer, peut-être cela a-t-il un sens ?

2voto

gnclmorais Points 2288

La meilleure façon de mieux comprendre comment Android gère ces aspects est d'analyser cette page. Exemple d'accéléromètre et d'orientation pour Android . Il m'a beaucoup aidé à comprendre les capteurs d'Android et à les utiliser.

0voto

TheCodeArtist Points 6837

Jetez un coup d'oeil à ça : Stackoverflow.com : Q.5202147

Vous semblez avoir raison jusqu'aux 3 diagrammes A, B, C. Après cela, vous vous êtes embrouillé.

0voto

hopeless bob Points 15

J'ai rencontré ce problème et j'ai déterminé ce qui se passe dans différentes directions. Si l'appareil est monté en mode paysage, par exemple dans un support de voiture, les "degrés" de la boussole semblent aller de 0 à 275 (dans le sens des aiguilles d'une montre) ; au-dessus de 269 (entre l'ouest et le nord), il compte à rebours de -90 à 0, puis en avant de 0 à 269. 270 devient -90

Toujours en mode paysage mais avec l'appareil couché sur le dos mon capteur donne 0-360. et en mode portrait il donne 0-360 aussi bien couché sur le dos que debout en portrait.

J'espère que cela aidera quelqu'un

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X