Présentation de l'orientation du téléphone Android avec boussole

107

J'essaie de comprendre les capteurs d'orientation Android depuis un moment. Je pensais l'avoir compris. Puis j'ai réalisé que non. Maintenant, je pense (j'espère) que j'ai à nouveau un meilleur sentiment mais je ne suis toujours pas à 100%. J'essaierai d'expliquer ma compréhension inégale de celui-ci et j'espère que les gens pourront me corriger si je me trompe dans certaines parties ou remplir des blancs.

J'imagine que je me tiens à 0 degrés de longitude (méridien principal) et à 0 degrés de latitude (équateur). Cet endroit est en fait dans la mer au large des côtes de l'Afrique, mais soyez indulgents avec moi. Je tiens mon téléphone devant mon visage de sorte que le bas du téléphone pointe vers mes pieds; Je suis face au nord (regardant vers Greenwich), donc le côté droit du téléphone pointe vers l'est vers l'Afrique. Dans cette orientation (en référence au diagramme ci-dessous), j'ai l'axe X pointant vers l'est, l'axe Z pointe vers le sud et l'axe Y vers le ciel.

Désormais, les capteurs du téléphone vous permettent 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 fonctionnait. Il semble que le téléphone détermine son orientation en utilisant une combinaison de deux techniques différentes.

Avant d'en arriver là, imaginez être de retour sur ce terrain imaginaire à 0 degré de latitude et de longitude dans la direction mentionnée ci-dessus. Imaginez aussi que vous avez les yeux bandés et que vos chaussures sont fixées à un rond-point de l'aire de jeux. Si quelqu'un vous pousse dans le dos, vous tomberez en avant (vers le nord) et étirez les deux mains pour interrompre votre chute. De même, si quelqu'un vous pousse l'épaule gauche, vous tomberez sur votre main droite. Votre oreille interne dispose de "capteurs gravitationnels" (clip youtube) qui vous permettent de détecter si vous tombez en avant / arrière, ou si vous tombez à gauche / droite ou si vous tombez (ou vers le haut !!). Par conséquent, les humains peuvent 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 pour que vous soyez maintenant face à l'Est. Vous faites 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 montant, 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 ... une boussole magnétique. Cela nous permet de déterminer dans quelle direction nous sommes confrontés. La même chose est vraie avec notre téléphone.

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

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 de ces deux capteurs de sorte que chaque fois qu'un SensorEventde TYPE_ORIENTATIONest généré, le values[3]tableau a des
valeurs [0]: Azimut - (le cap de la boussole à l'est du nord magnétique)
valeurs [1]: Pitch, rotation autour de l'axe x (est le téléphone penché en avant ou en arrière)
valeurs [2]: Roulement, rotation autour de l'axe y (le téléphone se penche-t-il 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 au compas) plutôt que la lecture du troisième accéléromètre est que le relèvement au compas est simplement plus utile. Je ne sais pas pourquoi ils ont désapprouvé ce type de capteur car il semble maintenant que vous deviez enregistrer un auditeur auprès du système pour les SensorEvents de type TYPE_MAGNETIC_FIELD. Le value[]tableau de l'événement doit être passé dans la SensorManger.getRotationMatrix(..)méthode pour obtenir une matrice de rotation (voir ci-dessous) qui est ensuite passée dans la SensorManager.getOrientation(..)méthode. Quelqu'un sait-il pourquoi l'équipe Android est obsolète Sensor.TYPE_ORIENTATION? Est-ce une question d'efficacité? C'est ce qu'implique l'un des commentaires d'une question similaire, mais vous devez tout de même enregistrer un type d'auditeur différent dans ledevelopment / samples / Compass / src / com / example / android / compass / CompassActivity.java exemple.

Je voudrais maintenant parler de la matrice de rotation. (C'est là que je suis le plus incertain) Donc, ci-dessus, nous avons les trois chiffres de la documentation Android, nous les appellerons A, B et C.

A = SensorManger.getRotationMatrix (..) figure de la méthode 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 (..)

Donc, je crois comprendre que A représente le "système de coordonnées du monde" qui, je suppose, se réfère à la façon dont les emplacements sur la planète sont donnés sous forme de couple (latitude, longitude) avec une (altitude) facultative. X est la coordonnée «est» , Y est la coordonnée «nord» . Z pointe vers le ciel et représente l'altitude.

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

D'accord. 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 gâché ou aidé les gens (ou encore plus confondu les gens!)

Tim
la source
25
J'aime vraiment cette question. Je ne peux pas y répondre mais j'aime ça.
Octavian A. Damiean le
4
Tim, as-tu déjà obtenu une réponse? Je me suis gratté la tête en même temps. C'est l'une des API les moins documentées que j'ai jamais vues.
Pierre-Luc Paour
Pas vraiment j'ai peur. Je devais passer à autre chose. Un jour, je reviendrai sur cette question.
Tim
1
Ici, j'ai la même question, presque? Et la réponse, solution aussi. Rendu public mon code sur Github.
la même chose que je me demande, j'ai implémenté une boussole sur un appareil Android et fonctionne correctement si j'ai pris de l'aide d'Internet, cela fonctionne bien, mais la chose qui prête à confusion est ... Supposons que mon appareil soit placé sur le visage au sol vers moi et son pointage vers le nord maintenant je prends mon portable et le mets verticalement au-dessus de ma tête sans et le visage est toujours vers moi. Tout d'abord, l'aiguille doit changer de direction et pourquoi. Je pense que cela ne devrait pas car je n'ai pas changé de direction, mais cela change dans mon application et toutes les autres applications que j'ai téléchargées. Quelqu'un peut-il expliquer pourquoi?
Syed Raza Mehdi

Réponses:

26

Vous voudrez peut-être consulter l'article Un virage d'écran mérite un autre . Cela explique pourquoi vous avez besoin de la matrice de rotation.

En un mot, 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 le dispositif 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 le système de coordonnées d'écran. La matrice de rotation dans ce cas est utilisée pour transformer A en C (B reste toujours fixe).

Voici un extrait de code pour vous montrer comment il peut être utilisé.

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
la source
4
mentionnez simplement que l'azimut, le tangage et le roulis ne sont PAS les mêmes que ceux sortant de l'OrientationSensor obsolète. orientation[0] = orientation[0] >= 0 ? orientation[0]: orientation[0] + 360;normalisera l'azimut et if (orientation[1] <= -90) { orientation[1] += (-2*(90+orientation[1])); } else if(orientation[1] >= 90){ orientation[1] += (2*(90 - orientation[1])); }normalisera la hauteur
Rafael T
@RafaelT et normaliser le rouleau? Ou cela n'a-t-il aucun sens?
Matthias
@RafaelT: Votre normalisation de l'azimut semble avoir un effet: les valeurs vont de [-180,180] à [0, 360]. Mais les valeurs de hauteur que j'obtiens sont déjà en [-90,90], donc la normalisation que vous proposez n'a aucun effet.
Matthias
Qu'est-ce que cela signifie si après vérification (gravité! = Null && geomag! = Null), la valeur de geomag est toujours 0, peu importe comment je déplace la tablette? Peut-être une tablette sans capteur geomag?
Avancé le
3

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

Le pas est le même, un pas de 90 degrés vers le haut place toute la composante de gravité dans le registre y.

Le lacet / cap / azimut n'a aucun effet sur la gravité, il est TOUJOURS perpendiculaire à la gravité, par conséquent, peu importe la manière dont vous faites face à la gravité, il sera immesurable.

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

Craig
la source
0

J'avais ce problème alors j'ai cartographié ce qui se passe dans différentes directions. Si l'appareil est monté en mode paysage, par exemple dans un montage 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, alors avance de 0 à 269. 270 devient -90

Toujours en paysage mais avec l'appareil couché sur le dos, mon capteur donne 0-360. et en mode portrait, il tourne de 0 à 360 à la fois couché sur le dos et debout en portrait.

J'espère que ça aide quelqu'un

bob sans espoir
la source