2012-06-17 8 views
12

Wie kann ich einen Richtungsvektor erhalten, der die Richtung darstellt, in der die Rückseite des Geräts relativ zu den Erdkoordinaten zeigt?Richtungsvektor in Android erhalten

Zum Beispiel sollte es auf einem Tisch (Bildschirmseite nach oben) sollte [0,0, -1] und wenn es senkrecht nach Norden gehalten wird sollte es [1,0,0], etc.

lesen

Ich weiß, wie man es aus Überschrift, Tonhöhe und Rolle berechnen kann, solange diese relativ zu den Erdkoordinaten sind. Um hier klar zu sein, suche ich nicht nach der Winkelgeschwindigkeit, sondern nach dem tatsächlichen aktuellen Winkel relativ zur tangentialen Ebene der Erde. Wenn das Gerät also senkrecht und nach Norden ausgerichtet ist, sollte der Winkel "Alpha" 0 oder 360, der Winkel "Beta" sollte 90 und "Gamma" sollte 0 sein. Ich kann nicht herausfinden, wie diese Werte erhalten werden entweder.

Ich habe den API den ganzen Tag gelesen und ich kann immer noch nicht finden, wie man eines dieser Dinge bekommt.

public void onSensorChanged(SensorEvent event) { 
    // ?  
} 

Vielen Dank für alle Einsichten.

Antwort

9

SensorManager.getRotationMatrix() tut, was unten beschrieben ist, geschrieben, bevor ich das herausgefunden habe. Ich werde die zusätzliche Erklärung hinterlassen, denn wenn du den Unterschied zwischen magnetischem und echtem Norden korrigieren willst, wirst du es immer noch brauchen.

Der grobe Algorithmus ist, die Rotationsmatrix zu erhalten, multiplizieren Sie Vektor [0,0,-1] damit, und passen Sie dies dann an Ihr Koordinatensystem an. Warum? Android docs gibt die Koordinatensysteme für die Einrichtung und die Welt

deviceworld

Hinweis [0,0,-1] in Android Gerät Koord Punkte senkrecht nach rückwärts von dem Bildschirm entfernt. Wenn Sie die Rotationsmatrix R mit diesem Vektor multiplizieren, erhalten Sie [0,0,-1] in Weltkoordinaten, wenn das Gerät auf dem Tisch liegt, wie Sie es wünschen. Wenn es nach Norden ausgerichtet ist, erhalten Sie [0,-1,0], was bedeutet, dass Sie ein Koordinatensystem gewählt haben, in dem x und y in Bezug auf das Android-System ausgetauscht werden, aber das ist nur eine Änderung der Konventionen.

Hinweis R * [0,0,-1]^T ist nur die dritte Spalte von R negiert. Von diesem bekomme ich den Pseudocode:

getRotationMatrix(R); 
Let v = first three elements of third column of R. 
swap v[0] and v[1] 

Dies sollte bekommen, was Sie wollen.

Weitere Informationen darüber, was getRotationMatrix() tut, folgt.


Sie benötigen beiden accerometer Daten die Richtung „down“ und Magnetometer-Daten, die Richtung zu bestimmen, zu etablieren „nördlich.“ Sie müssen annehmen, dass die Beschleunigungsmesser nur die Schwerkraft messen (das Gerät ist stationär oder bewegt sich mit einer gleichmäßigen Geschwindigkeit). Dann müssen Sie den Magnetometervektor auf die Ebene senkrecht zum Gravitationsvektor projizieren (weil das Magnetfeld im Allgemeinen nicht tangential zur Erdoberfläche ist). Dies gibt Ihnen zwei Achsen. Die dritte ist orthogonal, so kann durch Kreuzprodukt berechnet werden. Dies gibt Ihnen die Erdkoordinatenvektoren im Gerätesystem. Es sieht so aus, als ob Sie das Gegenteil wollen: Gerätekoordinaten in Erdkoordinaten. Dazu konstruiere einfach die Matrix von Richtungskosinus und invertiere.

Ich füge hinzu, dass die obige Diskussion annimmt, dass der Magnetometervektor nach Norden zeigt. Ich denke (aus der Highschool-Wissenschaft!)) Es ist eigentlich in Richtung magnetischer Süden, aber habe kein Gerät zur Hand, also kann ich es nicht versuchen. Natürlich ist der magnetische Norden/Süden von Null bis 180 Grad verschieden, je nachdem, wo du dich auf der Erde befindest. Sie können GPS-Koordinaten abrufen und einen tatsächlichen Offset berechnen.

Wenn Sie nicht vertraut mit der Mathematik sind notwendig, um diese zu tun, kann ich erklären weiter, aber es wird später sein.

+0

Danke, das wirklich hilfreich ist. Ihr beide habt so gute Antworten gegeben, ich wünschte, es gäbe einen Weg, sie beide auszuwählen. Es sieht so aus, als ob ich den Gravitationsvektor mit nur Sensor.TYPE_GRAVITY bekommen kann - sie haben das für mich funktioniert. Ich wünschte, es wäre genauso einfach, einen "nördlichen" Vektor zu bekommen. – Joey

+0

Ich habe es mit Ihrer Erklärung bekommen. Es stellt sich heraus, dass ich die von einem Gravitationssensor und einem Magnetfeldsensor zurückgegebenen Werte direkt in getRotationMatrix() übergebe und alles funktioniert. Dann multiplizierte man diese Matrix einfach mit [0,0, -1] und erhielt das dv. – Joey

8

diese Seite lesen: http://developer.android.com/reference/android/hardware/Sensor.html

In API 8 und darüber gibt es „virtuelle“ Sensoren, die durch die Kombination der Eingänge aller verfügbaren Sensoren und entsprechenden Filtern erzeugt werden. Der „TYPE_ORIENTATION“ Sensor gibt Ihnen die allover Ausrichtung des Geräts, aber diese Schnittstelle aufgrund Ausfallzustände in bestimmten Orientierungen sind veraltet. Der neue Sensor ist TYPE_ROTATION_VECTOR (API 9 und höher), der Ihr Gerät als Quaternion ausrichtet. Dies ist wirklich der beste Sensor zu verwenden, aber die Mathematik dahinter ist ein wenig schwer.

dass Failing, was Sie tun, ist rufen SensorManager.getRotationMatrix(), die neueste Schwerkraft und Magnetometer-Daten übergeben. Dadurch wird eine Rotationsmatrix zurück, die verwendet werden könnte, um einen Vektor zu konvertieren von Gerät Koordinaten in Weltkoordinaten oder umgekehrt (nur die Matrix transponiert es zu invertieren).

Die GetOrientation() Funktion können Sie, Nicken und Rollen, aber diese haben die gleichen Fehler-Zustände als TYPE_ORIENTATION Sensor geben Überschrift.

Examples: 

    Device flat on a table, top facing north: 
    1 0 0 
    0 1 0 
    0 0 1 

    Tilted up 30 degrees (rotated about X axis) 
    1 0  0 
    0 0.86 -0.5 
    0 0.5 0.86 

    Device vertical (rotated about X axis), facing north: 
    1 0 0 
    0 0 -1 
    0 1 0 

    Device flat on a table, top facing west: 
    0 -1 0 
    1 0 0 
    0 0 1 

    Device rotated about its Y axis, onto its left side, top 
    facing north: 
    0 0 -1 
    0 1 0 
    1 0 0 

Hier ist ein Beispielcode Sie nützlich sein können: so viel

public void onSensorChanged(SensorEvent event) { 
    long now = event.timestamp;  // ns 

    switch(event.sensor.getType()) { 
     case Sensor.TYPE_ACCELEROMETER: 
     gData[0] = event.values[0]; 
     gData[1] = event.values[1]; 
     gData[2] = event.values[2]; 
     break; 
     case Sensor.TYPE_MAGNETIC_FIELD: 
     mData[0] = event.values[0]; 
     mData[1] = event.values[1]; 
     mData[2] = event.values[2]; 
     haveData = true; 
     break; 
    } 

    if(haveData) { 
     double dt = (now - last_time) * .000000001; 

     SensorManager.getRotationMatrix(R1, Imat, gData, mData); 
     getOrientation(R1, orientation); 
     pfdView.newOrientation(orientation[2], (float)dt); 


     Log.d(TAG, "yaw: " + (int)(orientation[0]*DEG)); 
     Log.d(TAG, "pitch: " + (int)(orientation[1]*DEG)); 
     Log.d(TAG, "roll: " + (int)(orientation[2]*DEG)); 

     acft.compass = orientation[0]; 

     last_time = now; 
    } 
} 
+0

Vielen Dank für Ihre Antwort - ich habe nur zwei Fragen, wenn ich TYPE_ROTATION_VECTOR verwenden, ist die quanternion ausgedrückt in Weltkoordinaten? Ist es bereits integriert, oder muss ich es integrieren, um den aktuellen Vektor zu erhalten? – Joey

+0

Weltkoordinaten des Gerätes, glaube ich. Wurde bereits in eine Quaternion-Einheit konvertiert, und manchmal wird der Term w weggelassen. Um ehrlich zu sein, ich habe es nie selbst benutzt. Der oben angezeigte Code stammt aus einer Flugnavigations-App, die ich für 1.5 geschrieben habe, bevor die neuen Sensortypen verfügbar waren. –