Différentes valeurs entre capteurs type accéléromètre / type champ magnétique et ORIENTATION du TYPE

il y a 2 façons d'obtenir les 3 valeurs de rotation (Azimut, tangage, roulis).

on enregistre un auditeur D'une orientation de type TYPE_ORIENTATION. C'est le moyen le plus simple et j'obtiens une plage correcte de valeurs de chaque rotation comme le dit la documentation.: Azimut: [0, 359] pitch: [-180 à 180] rouleau: [-90, 90]

l'autre, le plus précis et complexe à comprendre la première fois que vous le voyez. Android le recommande, si je veux l'utiliser, mais j'ai des valeurs différentes.

azimut: [-180, 180]. -180 / 180 is S, 0 I N, 90 E et -90 W.

pitch: [-90, 90]. 90 est 90, -90 est -90, 0 est 0 mais -180 / 180 (couché avec l'écran vers le bas) est 0.

roll: [-180, 180].

je devrais avoir les mêmes valeurs mais avec des décimales, Non?

j'ai le code suivant:

aValues = new float[3];
mValues = new float[3];

sensorListener = new SensorEventListener (){
    public void onSensorChanged (SensorEvent event){
        switch (event.sensor.getType ()){
            case Sensor.TYPE_ACCELEROMETER:
                aValues = event.values.clone ();
                break;
            case Sensor.TYPE_MAGNETIC_FIELD:
                mValues = event.values.clone ();
                break;
        }

        float[] R = new float[16];
        float[] orientationValues = new float[3];

        SensorManager.getRotationMatrix (R, null, aValues, mValues);
        SensorManager.getOrientation (R, orientationValues);

        orientationValues[0] = (float)Math.toDegrees (orientationValues[0]);
        orientationValues[1] = (float)Math.toDegrees (orientationValues[1]);
        orientationValues[2] = (float)Math.toDegrees (orientationValues[2]);

        azimuthText.setText ("azimuth: " + orientationValues[0]);
        pitchText.setText ("pitch: " + orientationValues[1]);
        rollText.setText ("roll: " + orientationValues[2]);
    }

    public void onAccuracyChanged (Sensor sensor, int accuracy){}
};

Aidez-moi. C'est très frustrant.

Dois-je traiter avec ces valeurs, ou je fais quelque chose de mal?

Merci.

14
demandé sur Gabriel Llamas 2010-11-13 22:55:05

3 réponses

je sais que je joue à thread nécromancer ici, mais j'ai beaucoup travaillé sur ce truc dernièrement, donc j'ai pensé que je pourrais jeter dans mes 2 cents.

l'appareil ne contient pas de compas ou d'inclinomètres, de sorte qu'il ne mesure pas l'azimut, le pas ou le roulis directement. (Nous appelons ces angles D'Euler, BTW). Il utilise plutôt des accéléromètres et des magnétomètres, qui produisent tous deux des vecteurs XYZ à 3 espaces. Ils sont utilisés pour calculer l'Azimut, etc. valeur.

Vecteurs sont dans l'espace de coordonnées de l'appareil:

Device coordinates

les coordonnées mondiales ont Y faisant face au nord, X faisant face à l'est, et Z faisant face au haut:

World coordinates

ainsi, l'orientation "neutre" d'un appareil repose à plat sur le dos sur une table, le dessus de l'appareil étant orienté vers le nord.

l'accéléromètre produit un vecteur dans le sens" haut". Le magnétomètre produit un vecteur dans la direction" nord". (Notez que dans l'hémisphère nord, cela tend à pointer vers le bas en raison de dip magnétique .)

le vecteur accéléromètre et le vecteur magnétomètre peuvent être combinés mathématiquement par SensorManager.getRotationMatrix () qui renvoie une matrice 3x3 qui va cartographier les vecteurs dans les coordonnées des périphériques aux coordonnées du monde ou vice-versa. Pour un dispositif en position neutre, cette fonction retournerait la matrice d'identité.

Cette matrice ne varie pas avec l'orientation de l'écran. Cela signifie que votre application doit être au courant de l'orientation et de compenser en conséquence.

SensorManager.getOrientation () prend la matrice de transformation et calcule les valeurs d'azimut, de tangage et de roulis. Celles-ci sont prises par rapport à un dispositif en position neutre.

Je ne sais pas quelle est la différence entre appeler cette fonction et juste utiliser TYPE_ORIENTATION capteur, sauf que la fonction vous permet de manipuler la matrice.

si le dispositif est incliné vers le haut à 90° ou près de lui, alors l'utilisation d'angles D'Euler tombe en morceaux. C'est un cas dégénéré mathématiquement. Dans ce domaine, Comment l'appareil est censé savoir si vous changez l'Azimut ou le rouleau?

la fonction SensorManager.remapCoordinateSystem () peut être utilisé pour manipuler la matrice de transformation pour compenser ce que vous pouvez savoir sur le orientation du dispositif. Cependant, mon expérience montre que cela ne couvre pas tous les cas, même pas certains de la commune. Par exemple, si vous voulez faire un remap pour un appareil tenu droit (par exemple pour prendre une photo), vous voulez multiplier la matrice de transformation par cette matrice:

1 0 0
0 0 1
0 1 0

avant d'appeler getOrientation (), et ce n'est pas une des modifications d'orientation que remapCoordinateSystem () supporte [quelqu'un s'il Vous Plaît me corriger si j'ai manqué quelque chose ici].

OK, donc tout cela a été une façon de dire que si vous utilisez l'orientation, que ce soit à partir du capteur TYPE_ORIENTATION ou de getOrientation (), vous le faites probablement mal. La seule fois où vous réellement veulent les angles D'Euler est d'Afficher des informations d'orientation dans une forme facile à utiliser, annoter une photographie, pour conduire l'affichage des instruments de vol, ou quelque chose de similaire.

si vous voulez faire les calculs liés à l'orientation de l'appareil, vous êtes presque certainement mieux à l'aide de la matrice de transformation et de travailler avec les vecteurs XYZ.

travaillant comme consultant, chaque fois que quelqu'un vient à moi avec un problème impliquant des angles D'Euler, je recule et leur demande ce qu'ils sont vraiment essayer de faire, et puis trouver un moyen de le faire avec des vecteurs à la place.

en regardant en arrière à votre question originale, getOrientation () devrait retourner trois valeurs dans [-180 180] [-90 90] et [-180 180] (après la conversion de radians). En pratique, nous pensons azimuth comme des nombres dans [0 360], donc vous devriez simplement ajouter 360 à tous les nombres négatifs que vous recevez. Votre code semble correct tel qu'il est écrit. Cela m'aiderait si je savais exactement quels résultats vous attendez et ce que vous obtenez à la place.

édité pour ajouter: un couple d'autres pensées. Les versions modernes D'Android utilisent quelque chose appelé "fusion de capteur", qui signifie essentiellement que toutes les entrées disponibles-accéléromètre, magnétomètre, gyro-sont combinées ensemble dans une boîte noire mathématique (généralement un filtre de Kalman, mais dépend du vendeur). Tous les différents capteurs-accélération, champ magnétique, gyroscopes, gravité, accélération linéaire et orientation-sont pris comme sorties de cette boîte noire.

dans la mesure du possible, vous devez utiliser TYPE_GRAVITY plutôt que TYPE_ACCELEROMETER comme entrée pour geprotationmatrix().

21
répondu Edward Falk 2017-02-08 14:31:25

je tourne peut-être dans le noir, mais si je comprends bien votre question, vous vous demandez pourquoi vous obtenez [-179..179] au lieu de [0..360] ?

noter que -180 est le même que +180 et le même que 180 + N*360N est un nombre entier.

En d'autres termes, si vous voulez obtenir les mêmes nombres que avec capteur d'orientation, vous pouvez faire ceci:

// x = orientationValues[0];
// y = orientationValues[1];
// z = orientationValues[2];
x = (x + 360.0) % 360.0;
y = (y + 360.0) % 360.0;
z = (z + 360.0) % 360.0;

ce vous donnera les valeurs dans la gamme [0..360] comme vous le vouliez.

7
répondu johndodo 2012-05-14 11:48:43

il vous manque un calcul critique dans vos calculs.

Le remapCoordinateSystem appel afer vous faire un getRotationMatrix .

Ajouter à votre code et tout ira bien.

Vous pouvez lire plus à propos de it ici .

1
répondu TheCodeArtist 2012-11-21 05:20:34