Wie bekomme ich den Azimut eines Telefons mit Kompasslesungen und Gyroskop-Lesungen?

Ich möchte die aktuelle Ausrichtung des Telefons nach folgender Methode erhalten:

  1. Holen Sie sich die Anfangsorientierung (Azimut) zuerst über die getRotationMatrix() und getOrientation() .
  2. Füge die Integration der Gyroskop-Lesung über die Zeit, um die aktuelle Orientierung zu bekommen.

Telefon Ausrichtung:

  • Wie erstelle ich eine Datenbank in Android?
  • Android-Bildansicht ändern Tönung zu simulieren Schaltfläche klicken
  • Set windowTranslucentStatus = true bei androiden Lutscher oder höher
  • Android logcat logs chatty Modul Zeile Ablauf Nachricht
  • Fügen Sie benutzerdefinierte Daten / Attribute zu Button in Android
  • Rx Java mergeDelayError funktioniert nicht wie erwartet
  • Die xy-Ebene des Telefons ist parallel zur Grundebene fixiert. Dh in einer "texting-while-walking" -Orientierung.

    " getOrientation() " Rückkehr:

    Android API erlaubt mir, die Orientierung, dh Azimut, Pitch, Roll, von getOrientation() leicht zu bekommen.

    Bitte beachten Sie , dass diese Methode immer ihren Wert innerhalb des Bereichs zurückgibt: [0, -PI] und [o, PI] .

    Mein Problem:

    Da die Integration von Gyroskop-Lesung, die mit dR bezeichnet wird, ziemlich groß sein kann, so kann die [0, -PI] , wenn ich CurrentOrientation += dR [0, -PI] und [o, PI] überschreiten.

    Welche Manipulationen sind nötig, damit ich IMMER die aktuelle Orientierung innerhalb der [0, -PI] und [o, PI] Bereiche erreichen kann?

    Ich habe in Python das folgende ausprobiert, aber ich bezweifle sehr, dass es richtig ist.

     rotation = scipy.integrate.trapz(gyroSeries, timeSeries) # integration if (headingDirection - rotation) < -np.pi: headingDirection += 2 * np.pi elif (headingDirection - rotation) > np.pi: headingDirection -= 2 * np.pi # Complementary Filter headingDirection = ALPHA * (headingDirection - rotation) + (1 - ALPHA) * np.mean(azimuth[np.array(stepNo.tolist()) == i]) if headingDirection < -np.pi: headingDirection += 2 * np.pi elif headingDirection > np.pi: headingDirection -= 2 * np.pi 

    Bemerkungen

    Das ist nicht so einfach, denn es handelt sich um die folgenden Störer:

    1. Die Ausrichtung des Ausrichtungssensors geht von 0 nach -PI und dann DIRECTLY JUMPS auf +PI und kehrt allmählich über +PI/2 wieder auf 0 zurück.
    2. Die Integration des Gyroskop-Lesens führt auch zu einigen Schwierigkeiten. Sollte ich dR zur Orientierung hinzufügen oder dR subtrahieren.

    Verweisen Sie bitte zuerst auf die Android-Dokumentationen, bevor Sie eine bestätigte Antwort erhalten.

    Geschätzte Antworten helfen nicht.

  • Wie kann ich ein DialogFragment über ein anderes heben?
  • Android 5 (HTC) EACCES (Berechtigung verweigert)
  • Wie fülle ich einen Pfad in Android mit einem linearen Gradienten?
  • Wie beendet man Android NDK (native Aktivität) Anwendung programmatisch?
  • Warum Warnung: Kann keine optionale Bibliothek finden: org.apache.http.legacy tritt auf?
  • Bestätigung und Rückgängigmachen in RecyclerView
  • 4 Solutions collect form web for “Wie bekomme ich den Azimut eines Telefons mit Kompasslesungen und Gyroskop-Lesungen?”

    Der Orientierungssensor leitet seine Messwerte tatsächlich aus dem realen Magnetometer und dem Beschleunigungsmesser ab.

    Ich vermute, vielleicht ist das die Quelle der Verwirrung. Wo ist das in der Dokumentation angegeben? Noch wichtiger ist, dass die Dokumentation irgendwo explizit anzeigt, dass die Gyro-Lesungen ignoriert werden? Soweit ich weiß, ist die in diesem Video beschriebene Methode implementiert:

    Sensor Fusion auf Android Devices: Eine Revolution in der Bewegungsverarbeitung

    Diese Methode verwendet die Gyros und integriert ihre Lesungen. Das macht den Rest der Frage so ziemlich. Trotzdem werde ich versuchen, es zu beantworten.


    Der Orientierungssensor integriert bereits die Gyro-Messwerte für Sie , so erhalten Sie die Orientierung. Ich verstehe nicht, warum du es selbst machst.

    Du machst die Integration der Gyro-Lesungen nicht richtig , es ist komplizierter als CurrentOrientation += dR (was falsch ist). Wenn du die Gyro-Lesungen integrieren musst (ich sehe nicht warum der SensorManager schon für dich da ist). Bitte lesen Sie die Richtung Cosinus Matrix IMU: Theorie, wie man es richtig macht (Gleichung 17).

    Versuche nicht, mit Euler-Winkeln zu integrieren (aka Azimut, Pitch, Roll), nichts Gutes kommt heraus.

    Bitte verwenden Sie entweder Quaternionen oder Rotationsmatrizen in Ihren Berechnungen anstelle von Euler-Winkeln. Wenn du mit Rotationsmatrizen arbeitest, kannst du sie immer in Euler-Winkel umwandeln, siehe

    Berechnen von Euler-Winkeln aus einer Rotationsmatrix von Gregory G. Slabaugh

    (Das gleiche gilt für Quaternionen.) Es gibt (im Nicht-Degenrat-Fall) zwei Möglichkeiten, eine Rotation darzustellen, das heißt, du bekommst zwei Euler-Winkel. Wählen Sie diejenige aus, die in dem gewünschten Bereich ist. (Im Falle einer Kardansperre gibt es unendlich viele Euler-Winkel, siehe PDF oben). Verstehen Sie einfach, dass Sie nicht beginnen, Euler Winkel wieder in Ihren Berechnungen nach der Rotationsmatrix zu Euler Winkel Umwandlung zu verwenden.

    Es ist unklar, was du mit dem komplementären Filter machst. Sie können eine ziemlich verdammt gute Sensor Fusion auf der Grundlage der Direction Cosinus Matrix IMU implementieren : Theory Manuskript, die im Grunde ein Tutorial ist. Es ist nicht trivial, es zu tun, aber ich glaube nicht, dass Sie ein besseres, verständlicheres Tutorium finden werden als dieses Manuskript.

    Eine Sache, die ich selbst entdecken musste, als ich die Sensorfusion auf der Grundlage dieses Manuskripts implementierte, war, dass die sogenannte integrale Aufwicklung auftreten kann. Ich habe mich darum gekümmert, indem ich die TotalCorrection (Seite 27) beschränke. Du wirst verstehen, wovon ich rede, wenn du diese Sensor-Fusion implementierst.



    UPDATE: Hier beantworte ich deine Fragen, die du nach der Annahme der Antwort in Kommentaren geschrieben hast.

    Ich denke, der Kompass gibt mir meine aktuelle Orientierung mit Schwerkraft und Magnetfeld, richtig? Ist Gyroskop im Kompass verwendet?

    Ja, wenn das Telefon mehr oder weniger stationär für mindestens eine halbe Sekunde ist, können Sie eine gute Orientierungsschätzung erhalten, indem Sie die Schwerkraft und den Kompass nur verwenden. Hier ist, wie es zu tun: Kann mir jemand sagen, ob Gravitationssensor als Neigungssensor zur Verbesserung der Richtungsgenauigkeit ist?

    Nein, die Gyroskope werden nicht im Kompass verwendet.

    Könnten Sie bitte bitte erklären, warum die von mir durchgeführte Integration falsch ist? Ich verstehe, dass, wenn mein Telefon Pitch zeigt, Euler Winkel fehlschlägt. Aber irgendwelche anderen Dinge falsch mit meiner Integration?

    Es gibt zwei unabhängige Dinge: (i) die Integration sollte anders durchgeführt werden, (ii) Euler-Winkel sind Schwierigkeiten wegen der Kardansperre. Ich wiederhole, diese beiden sind nicht verwandt.

    Wie für die Integration: Hier ist ein einfaches Beispiel, wie Sie tatsächlich sehen können, was mit Ihrer Integration falsch ist. Sei x und y die Achsen der horizontalen Ebene im Raum. Holen Sie sich ein Telefon in Ihren Händen. Drehen Sie das Telefon um die x-Achse (des Raumes) um 45 Grad, dann um die y-Achse (des Raumes) um 45 Grad. Dann wiederholen Sie diese Schritte von Anfang an, drehen Sie sich nun um die y-Achse und dann um die x-Achse. Das Telefon endet in einer völlig anderen Orientierung. Wenn du die Integration nach CurrentOrientation += dR machst, wirst du keinen Unterschied sehen! Bitte lesen Sie die oben verknüpfte Direction Cosinus Matrix IMU: Theory Manuskript, wenn Sie die Integration richtig machen wollen.

    Wie für die Euler-Winkel: sie schrauben die Stabilität der Anwendung und es ist genug für mich, sie nicht für beliebige Rotationen in 3D zu verwenden.

    Ich verstehe immer noch nicht, warum du versuchst, es selbst zu tun, warum du nicht die von der Plattform bereitgestellte Orientierungsschätzung nutzen willst. Die Chancen sind, das kannst du nicht besser machen.

    Ich denke, du solltest den abgeschriebenen "Orientierungssensor" vermeiden und sensorfusion Methoden wie getRotationVector, getRotationMatrix verwenden, die bereits Fusionsalgorithmen speziell von Invensense implementieren, die bereits Gyroskop-Daten verwenden.

    Wenn Sie einen einfachen Sensor Fusion Algorithmus namens Balance Filter (siehe http://www.filedump.net/dumped/filter1285099462.pdf ) verwendet werden kann. Ansatz ist wie in

    http://postimg.org/image/9cu9dwn8z/

    Dies integriert das Gyroskop, um Winkel zu bekommen, dann Hochpassfilter das Ergebnis, um Drift zu entfernen, und fügt es zu den geglätteten Beschleunigungsmesser und Kompass Ergebnisse. Die integrierten, hochpassgelegten Gyro-Daten und die Beschleunigungs- / Kompass-Daten werden so addiert, dass die beiden Teile zu einem hinzufügen, so dass die Ausgabe eine genaue Schätzung in Einheiten ist, die sinnvoll sind. Für den Ausgleichsfilter kann die Zeitkonstante angepasst werden, um die Antwort abzustimmen. Je kürzer die Zeitkonstante, desto besser ist die Reaktion, aber je mehr Beschleunigungsgeräusche durchlaufen werden können.

    Um zu sehen, wie das funktioniert, stellen Sie sich vor, Sie haben den neuesten Gyro-Datenpunkt (in rad / s), der im Gyroskop gespeichert ist, die neueste Winkelmessung aus dem Beschleunigungsmesser wird in angle_acc gespeichert und dtis die Zeit von den letzten Gyro-Daten bis jetzt. Dann würde Ihr neuer Winkel berechnet werden

    Winkel = b * (Winkel + Kreisel * dt) + (1 – b) * (angle_acc);

    Sie können mit b = 0.98 zum Beispiel versuchen. Sie werden wahrscheinlich auch eine schnelle Gyroskop-Messzeit dt verwenden, damit der Gyro nicht mehr als ein paar Grad driftet, bevor die nächste Messung durchgeführt wird. Der Ausgleichsfilter ist nützlich und einfach zu implementieren, ist aber nicht der ideale Sensor-Fusionsansatz. Der Ansatz von Invensense beinhaltet einige kluge Algorithmen und wahrscheinlich irgendeine Form von Kalman-Filter.

    Quelle: Professionelle Android Sensor Programmierung, Adam Stroud.

    Wenn der Azimutwert aufgrund von magnetischen Störungen ungenau ist, gibt es nichts, was du tun kannst, um es so weit wie möglich zu eliminieren. Um ein stabiles Lesen des Azimuts zu erhalten, müssen Sie die Beschleunigungsmesserwerte filtern, wenn TYPE_GRAVITY nicht verfügbar ist. Wenn TYPE_GRAVITY nicht verfügbar ist, dann bin ich mir ziemlich sicher, dass das Gerät keinen Gyro hat, also der einzige Filter, den du verwenden kannst, ist Tiefpassfilter. Der folgende Code ist eine Implementierung eines stabilen Kompasses mit TYPE_GRAVITY und TYPE_MAGNETIC_FIELD.

     public class Compass implements SensorEventListener { public static final float TWENTY_FIVE_DEGREE_IN_RADIAN = 0.436332313f; public static final float ONE_FIFTY_FIVE_DEGREE_IN_RADIAN = 2.7052603f; private SensorManager mSensorManager; private float[] mGravity; private float[] mMagnetic; // If the device is flat mOrientation[0] = azimuth, mOrientation[1] = pitch // and mOrientation[2] = roll, otherwise mOrientation[0] is equal to Float.NAN private float[] mOrientation = new float[3]; private LinkedList<Float> mCompassHist = new LinkedList<Float>(); private float[] mCompassHistSum = new float[]{0.0f, 0.0f}; private int mHistoryMaxLength; public Compass(Context context) { mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); // Adjust the history length to fit your need, the faster the sensor rate // the larger value is needed for stable result. mHistoryMaxLength = 20; } public void registerListener(int sensorRate) { Sensor magneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); if (magneticSensor != null) { mSensorManager.registerListener(this, magneticSensor, sensorRate); } Sensor gravitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY); if (gravitySensor != null) { mSensorManager.registerListener(this, gravitySensor, sensorRate); } } public void unregisterListener() { mSensorManager.unregisterListener(this); } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_GRAVITY) { mGravity = event.values.clone(); } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { mMagnetic = event.values.clone(); } if (!(mGravity == null || mMagnetic == null)) { mOrientation = getOrientation(); } } private void getOrientation() { float[] rotMatrix = new float[9]; if (SensorManager.getRotationMatrix(rotMatrix, null, mGravity, mMagnetic)) { float inclination = (float) Math.acos(rotMatrix[8]); // device is flat if (inclination < TWENTY_FIVE_DEGREE_IN_RADIAN || inclination > ONE_FIFTY_FIVE_DEGREE_IN_RADIAN) { float[] orientation = sensorManager.getOrientation(rotMatrix, mOrientation); mCompassHist.add(orientation[0]); mOrientation[0] = averageAngle(); } else { mOrientation[0] = Float.NAN; clearCompassHist(); } } } private void clearCompassHist() { mCompassHistSum[0] = 0; mCompassHistSum[1] = 0; mCompassHist.clear(); } public float averageAngle() { int totalTerms = mCompassHist.size(); if (totalTerms > mHistoryMaxLength) { float firstTerm = mCompassHist.removeFirst(); mCompassHistSum[0] -= Math.sin(firstTerm); mCompassHistSum[1] -= Math.cos(firstTerm); totalTerms -= 1; } float lastTerm = mCompassHist.getLast(); mCompassHistSum[0] += Math.sin(lastTerm); mCompassHistSum[1] += Math.cos(lastTerm); float angle = (float) Math.atan2(mCompassHistSum[0] / totalTerms, mCompassHistSum[1] / totalTerms); return angle; } } 

    In deiner Aktivität instanziiere ein Kompassobjekt in onCreate, registerListener in onResume und unregisterListener in onPause

     private Compass mCompass; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCompass = new Compass(this); } @Override protected void onPause() { super.onPause(); mCompass.unregisterListener(); } @Override protected void onResume() { super.onResume(); mCompass.registerListener(SensorManager.SENSOR_DELAY_NORMAL); } 

    Es ist besser, die Implementierung der Orientierungserkennung von Android zu übernehmen. Nun, ja Werte, die du bekommst, sind von -PI zu PI, und du kannst sie in Grad umwandeln (0-360). Ich habe eine Allzweckklasse geschaffen, um dies zu tun ( hier zu finden), einige relevante Teile:

    Speichern von zu verarbeitenden Daten:

     @Override public void onSensorChanged(SensorEvent sensorEvent) { switch (sensorEvent.sensor.getType()) { case Sensor.TYPE_ACCELEROMETER: mAccValues[0] = sensorEvent.values[0]; mAccValues[1] = sensorEvent.values[1]; mAccValues[2] = sensorEvent.values[2]; break; case Sensor.TYPE_MAGNETIC_FIELD: mMagValues[0] = sensorEvent.values[0]; mMagValues[1] = sensorEvent.values[1]; mMagValues[2] = sensorEvent.values[2]; break; } } 

    Berechnen von Roll, Pech und Gier (Azimut). mI und mI sind Arrys, um Rotations- und Neigungsmatrizen zu halten, mO ist ein temporäres Array. Das Array mResults hat die Werte in Grad, am Ende:

      private void updateData() { SensorManager.getRotationMatrix(mR, mI, mAccValues, mMagValues); /** * arg 2: what world(according to app) axis , device's x axis aligns with * arg 3: what world(according to app) axis , device's y axis aligns with * world x = app's x = app's east * world y = app's y = app's north * device x = device's left side = device's east * device y = device's top side = device's north */ switch (mDispRotation) { case Surface.ROTATION_90: SensorManager.remapCoordinateSystem(mR, SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_X, mR2); break; case Surface.ROTATION_270: SensorManager.remapCoordinateSystem(mR, SensorManager.AXIS_MINUS_Y, SensorManager.AXIS_X, mR2); break; case Surface.ROTATION_180: SensorManager.remapCoordinateSystem(mR, SensorManager.AXIS_MINUS_X, SensorManager.AXIS_MINUS_Y, mR2); break; case Surface.ROTATION_0: default: mR2 = mR; } SensorManager.getOrientation(mR2, mO); //--upside down when abs roll > 90-- if (Math.abs(mO[2]) > PI_BY_TWO) { //--fix, azimuth always to true north, even when device upside down, realistic -- mO[0] = -mO[0]; //--fix, roll never upside down, even when device upside down, unrealistic -- //mO[2] = mO[2] > 0 ? PI - mO[2] : - (PI - Math.abs(mO[2])); //--fix, pitch comes from opposite , when device goes upside down, realistic -- mO[1] = -mO[1]; } CircleUtils.convertRadToDegrees(mO, mOut); CircleUtils.normalize(mOut); //--write-- mResults[0] = mOut[0]; mResults[1] = mOut[1]; mResults[2] = mOut[2]; } 
    Das Android ist ein Google Android Fan-Website, Alles ├╝ber Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.