Panoramica dell'orientamento del telefono Android inclusa la bussola


107

È da un po 'che cerco di capire i sensori di orientamento di Android. Pensavo di averlo capito. Poi ho capito di no. Ora penso (spero) di provare di nuovo una sensazione migliore, ma non sono ancora al 100%. Cercherò di spiegare la mia comprensione frammentaria e spero che le persone saranno in grado di correggermi se sbaglio in alcune parti o riempire gli spazi vuoti.

Immagino di trovarmi a 0 gradi di longitudine (primo meridiano) e 0 gradi di latitudine (equatore). Questa posizione è in realtà nel mare al largo della costa africana, ma abbi pazienza. Tengo il telefono davanti al viso in modo che la parte inferiore del telefono punti ai miei piedi; Sono rivolto a nord (guardando verso Greenwich) quindi il lato destro del telefono punta a est verso l'Africa. In questo orientamento (con riferimento al diagramma sottostante) ho l'asse X che punta a est, l'asse Z punta a sud e l'asse Y punta al cielo.

Ora i sensori sul telefono ti consentono di calcolare l'orientamento (non la posizione) del dispositivo in questa situazione. Questa parte mi ha sempre confuso, probabilmente perché volevo capire come funzionava qualcosa prima di accettare che funzionasse. Sembra che il telefono elabori il suo orientamento utilizzando una combinazione di due diverse tecniche.

Prima di arrivare a questo, immagina di essere di nuovo in piedi su quel pezzo di terra immaginario a 0 gradi di latitudine e longitudine nella direzione sopra menzionata. Immagina anche di essere bendato e le tue scarpe sono fissate alla rotonda di un parco giochi. Se qualcuno ti spinge nella schiena, cadrai in avanti (verso nord) e allungherai entrambe le mani per interrompere la caduta. Allo stesso modo, se qualcuno ti spinge sulla spalla sinistra, cadrai sulla mano destra. Il tuo orecchio interno ha dei "sensori gravitazionali" (clip di YouTube) che ti permettono di rilevare se stai cadendo in avanti / indietro, o cadendo a sinistra / destra o cadendo in basso (o in alto !!). Pertanto gli esseri umani possono rilevare l'allineamento e la rotazione attorno agli stessi assi X e Z del telefono.

Ora immagina che qualcuno ti ruoti di 90 gradi sulla rotatoria in modo che tu sia ora rivolto a est. Stai ruotando attorno all'asse Y. Questo asse è diverso perché non possiamo rilevarlo biologicamente. Sappiamo di essere angolati di una certa quantità, ma non conosciamo la direzione in relazione al polo nord magnetico del pianeta. Invece dobbiamo usare uno strumento esterno ... una bussola magnetica. Questo ci permette di accertarci in quale direzione siamo rivolti. Lo stesso vale con il nostro telefono.

Ora il telefono ha anche un accelerometro a 3 assi. Ho NOHo idea di come funzionano effettivamente, ma il modo in cui la visualizzo è immaginare la gravità come una "pioggia" costante e uniforme che cade dal cielo e immaginare gli assi nella figura sopra come tubi che possono rilevare la quantità di pioggia che scorre attraverso. Quando il telefono è tenuto in posizione verticale, tutta la pioggia scorrerà attraverso il "tubo" a Y. Se il telefono viene ruotato gradualmente in modo che lo schermo sia rivolto verso il cielo, la quantità di pioggia che scorre attraverso Y diminuirà fino a zero mentre il volume attraverso Z aumenterà costantemente fino a quando non scorre la quantità massima di pioggia. Allo stesso modo, se ora incliniamo il telefono su un lato, il tubo X alla fine raccoglierà la massima quantità di pioggia. Pertanto a seconda dell'orientamento del telefono misurando la quantità di pioggia che scorre attraverso i 3 tubi è possibile calcolare l'orientamento.

Il telefono ha anche una bussola elettronica che si comporta come una normale bussola: il suo "ago virtuale" punta al nord magnetico. Android unisce le informazioni di questi due sensori in modo che ogni volta che viene generato un SensorEventdi TYPE_ORIENTATIONl' values[3]array ha
valori [0]: Azimuth - (la bussola che si trova a est del nord magnetico)
valori [1]: Pitch, rotazione attorno all'asse x (è il telefono sporgendosi in avanti o indietro)
valori [2]: Roll, rotazione attorno all'asse y (è il telefono sporgendosi sul lato sinistro o destro)

Quindi penso (cioè non lo so) il motivo per cui Android fornisce l'azimut (rilevamento della bussola) piuttosto che la lettura del terzo accelerometro è che il rilevamento della bussola è solo più utile. Non sono sicuro del motivo per cui hanno deprecato questo tipo di sensore poiché ora sembra che sia necessario registrare un ascoltatore con il sistema per SensorEvents di tipo TYPE_MAGNETIC_FIELD. L' value[]array dell'evento deve essere passato al SensorManger.getRotationMatrix(..)metodo per ottenere una matrice di rotazione (vedi sotto) che viene poi passata al SensorManager.getOrientation(..)metodo. Qualcuno sa perché il team Android è stato deprecato Sensor.TYPE_ORIENTATION? È una cosa di efficienza? Questo è ciò che è implicito in uno dei commenti a una domanda simile, ma è comunque necessario registrare un diverso tipo di ascoltatore nelsviluppo / samples / Compass / src / com / example / android / compass / CompassActivity.java example.

Vorrei ora parlare della matrice di rotazione. (Qui è dove non sono più sicuro) Quindi sopra abbiamo le tre cifre della documentazione di Android, le chiameremo A, B e C.

A = figura del metodo SensorManger.getRotationMatrix (..) e rappresenta il sistema di coordinate del mondo

B = Sistema di coordinate utilizzato dall'API SensorEvent.

C = Figura del metodo SensorManager.getOrientation (..)

Quindi la mia comprensione è che A rappresenta il "sistema di coordinate del mondo" che presumo si riferisca al modo in cui le posizioni sul pianeta sono date come una coppia (latitudine, longitudine) con un opzionale (altitudine). X è la coordinata "est" , Y è la coordinata "nord" . Z indica il cielo e rappresenta l'altitudine.

Il sistema di coordinate dei telefoni è mostrato in figura B è fisso. Il suo asse Y indica sempre la parte superiore. La matrice di rotazione viene costantemente calcolata dal telefono e consente la mappatura tra i due. Quindi ho ragione nel pensare che la matrice di rotazione trasforma il sistema di coordinate di B in C? Quindi, quando chiami il SensorManager.getOrientation(..)metodo, usi l' values[]array con valori che corrispondono alla figura C.Quando il telefono è puntato verso il cielo la matrice di rotazione è matrice identità (l'equivalente matematico della matrice di 1), il che significa che non è necessaria alcuna mappatura poiché il dispositivo è allineato con il sistema di coordinate del mondo.

Ok. Penso che sia meglio smetterla ora. Come ho detto prima, spero che le persone mi diranno dove ho incasinato o aiutato le persone (o confuso ulteriormente le persone!)


25
Mi piace molto questa domanda. Non posso rispondere ma mi piace.
Ottaviano A. Damiean

4
Tim, hai mai ricevuto una risposta? Mi sono grattato la testa allo stesso modo. Questa è una delle API più scarsamente documentate che abbia mai visto.
Pierre-Luc Paour

Non ho davvero paura. Ho dovuto andare avanti. Un giorno tornerò su questo problema.
Tim

1
Qui ho quasi la stessa domanda? E la risposta, anche la soluzione . Ha reso pubblico il mio codice su Github.

la stessa cosa che mi chiedo, ho implementato una bussola su un dispositivo Android e funziona correttamente se ho ricevuto aiuto da Internet funziona bene ma la cosa che crea confusione è ... Supponiamo che il mio dispositivo sia posizionato sulla faccia a terra verso di me e punta a nord, ora prendo il mio cellulare e lo metto verticalmente sopra la mia testa senza e il viso è ancora verso di me. Per prima cosa l'ago dovrebbe cambiare direzione e perché. Penso che non dovrebbe perché non ho cambiato la mia direzione ma sta cambiando nella mia app e in tutte le altre app che ho scaricato. Qualcuno può spiegare perché?
Syed Raza Mehdi

Risposte:


26

Potresti voler controllare l'articolo One Screen Turn merita un altro . Spiega perché hai bisogno della matrice di rotazione.

In poche parole, i sensori del telefono utilizzano sempre lo stesso sistema di coordinate, anche quando il dispositivo viene ruotato.

Nelle applicazioni che non sono bloccate su un singolo orientamento, il sistema di coordinate dello schermo cambia quando si ruota il dispositivo. Pertanto, quando il dispositivo viene ruotato dalla modalità di visualizzazione predefinita, il sistema di coordinate del sensore non è più lo stesso del sistema di coordinate dello schermo. La matrice di rotazione in questo caso viene utilizzata per trasformare A in C (B rimane sempre fisso).

Ecco uno snippet di codice per mostrarti come può essere utilizzato.

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

4
basta menzionare che azimuth, beccheggio e rollio NON sono la stessa cosa che esce dal deprecato OrientationSensor. orientation[0] = orientation[0] >= 0 ? orientation[0]: orientation[0] + 360;normalizzerà l'azimut e if (orientation[1] <= -90) { orientation[1] += (-2*(90+orientation[1])); } else if(orientation[1] >= 90){ orientation[1] += (2*(90 - orientation[1])); }normalizzerà il passo
Rafael T

@RafaelT e per normalizzare roll? O non ha senso?
Matthias

@RafaelT: La tua normalizzazione dell'azimut sembra avere effetto: i valori vanno da [-180,180] a [0, 360]. Ma i valori di altezza che ottengo sono già [-90,90] quindi la normalizzazione che proponi non ha effetto.
Matthias

Cosa significa se dopo aver verificato (gravity! = Null && geomag! = Null), il valore di geomag è sempre 0, indipendentemente da come sposto il tablet? Potrebbe essere un tablet senza sensore geomag?
Avanzato

3

Il rollio è una funzione della gravità, un rollio di 90 gradi mette tutta la gravità nel registro x.

Il pitch è lo stesso, un pitch up di 90 gradi inserisce tutta la componente della gravità nel registro y.

L'imbardata / direzione / azimut non ha alcun effetto sulla gravità, è SEMPRE ad angolo retto rispetto alla gravità, quindi non importa da che parte stai affrontando la gravità sarà incommensurabile.

Questo è il motivo per cui hai bisogno di una bussola per valutare, forse ha senso?



0

Stavo riscontrando questo problema, quindi ho mappato cosa succede in direzioni diverse. Se il dispositivo è montato in orizzontale, ad esempio in un'auto montata, i 'gradi' dalla bussola sembrano andare da 0-275 (in senso orario) sopra 269 (tra ovest e nord) conta all'indietro da -90 a 0, quindi in avanti da 0 a 269. 270 diventa -90

Ancora in orizzontale ma con il dispositivo sdraiato sul retro il mio sensore dà 0-360. e in modalità ritratto corre da 0 a 360 sia sdraiato sulla schiena che in piedi in verticale.

Spero che aiuti qualcuno

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.