Konvertieren Magnetfeld in X -, Y -, Z-Werte aus dem Gerät in die Globale Referenz-frame
Wenn Sie TYPE_MAGNETOMETER sensor, bekommen Sie X -, Y -, Z-Werte der magnetischen Feldstärke in Bezug auf die Geräte-Ausrichtung. Was ich möchte ist, konvertieren Sie diese Werte in die Globale Referenz-frame, Präzisierung: der Benutzer nimmt das Gerät, Messen Sie diese Werte, als drehen Sie das Gerät für einige Grad um jede Achse und erhält ~die gleichen Werte.
Bitte, finden Sie ähnliche Fragen unten:
Erste Magnetfeld-Werte in globalen Koordinaten
Wie kann ich das Magnetfeld-Vektor, unabhängig von der Drehung des Geräts?
In dieser Antwort-beispiellösung beschrieben wird (es ist für lineare Beschleunigung, aber ich denke, es spielt keine Rolle): https://stackoverflow.com/a/11614404/2152255
Ich benutzte es, und ich habe 3 Werte, X ist immer sehr klein (denke nicht, dass es richtig ist), Y und Z sind OK, aber Sie noch ein wenig verändert, wenn ich das Gerät drehen. Wie könnte es korrigiert werden? Und konnte es gelöst werden? Ich verwende einfache Kalman-filter, um die Ungefähre Messwerte, da w/o es ich sich ruhig unterschiedliche Werte, auch wenn das Gerät keine beweglichen/rotierenden überhaupt. Bitte, finden Sie meine folgenden code:
import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.opengl.Matrix;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import com.test.statistics.filter.kalman.KalmanState;
import com.example.R;
/**
* Activity for gathering magnetic field statistics.
*/
public class MagneticFieldStatisticsGatheringActivity extends Activity implements SensorEventListener {
public static final int KALMAN_STATE_MAX_SIZE = 80;
public static final double MEASUREMENT_NOISE = 5;
/** Sensor manager. */
private SensorManager mSensorManager;
/** Magnetometer spec. */
private TextView vendor;
private TextView resolution;
private TextView maximumRange;
/** Magnetic field coordinates measurements. */
private TextView magneticXTextView;
private TextView magneticYTextView;
private TextView magneticZTextView;
/** Sensors. */
private Sensor mAccelerometer;
private Sensor mGeomagnetic;
private float[] accelerometerValues;
private float[] geomagneticValues;
/** Flags. */
private boolean specDefined = false;
private boolean kalmanFiletring = false;
/** Rates. */
private float nanoTtoGRate = 0.00001f;
private final int gToCountRate = 1000000;
/** Kalman vars. */
private KalmanState previousKalmanStateX;
private KalmanState previousKalmanStateY;
private KalmanState previousKalmanStateZ;
private int previousKalmanStateCounter = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main2);
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mGeomagnetic = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
vendor = (TextView) findViewById(R.id.vendor);
resolution = (TextView) findViewById(R.id.resolution);
maximumRange = (TextView) findViewById(R.id.maximumRange);
magneticXTextView = (TextView) findViewById(R.id.magneticX);
magneticYTextView = (TextView) findViewById(R.id.magneticY);
magneticZTextView = (TextView) findViewById(R.id.magneticZ);
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_FASTEST);
mSensorManager.registerListener(this, mGeomagnetic, SensorManager.SENSOR_DELAY_FASTEST);
}
/**
* Refresh statistics.
*
* @param view - refresh button view.
*/
public void onClickRefreshMagneticButton(View view) {
resetKalmanFilter();
}
/**
* Switch Kalman filtering on/off
*
* @param view - Klaman filetring switcher (checkbox)
*/
public void onClickKalmanFilteringCheckBox(View view) {
CheckBox kalmanFiltering = (CheckBox) view;
this.kalmanFiletring = kalmanFiltering.isChecked();
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
if (sensorEvent.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
return;
}
synchronized (this) {
switch(sensorEvent.sensor.getType()){
case Sensor.TYPE_ACCELEROMETER:
accelerometerValues = sensorEvent.values.clone();
break;
case Sensor.TYPE_MAGNETIC_FIELD:
if (!specDefined) {
vendor.setText("Vendor: " + sensorEvent.sensor.getVendor() + " " + sensorEvent.sensor.getName());
float resolutionValue = sensorEvent.sensor.getResolution() * nanoTtoGRate;
resolution.setText("Resolution: " + resolutionValue);
float maximumRangeValue = sensorEvent.sensor.getMaximumRange() * nanoTtoGRate;
maximumRange.setText("Maximum range: " + maximumRangeValue);
}
geomagneticValues = sensorEvent.values.clone();
break;
}
if (accelerometerValues != null && geomagneticValues != null) {
float[] Rs = new float[16];
float[] I = new float[16];
if (SensorManager.getRotationMatrix(Rs, I, accelerometerValues, geomagneticValues)) {
float[] RsInv = new float[16];
Matrix.invertM(RsInv, 0, Rs, 0);
float resultVec[] = new float[4];
float[] geomagneticValuesAdjusted = new float[4];
geomagneticValuesAdjusted[0] = geomagneticValues[0];
geomagneticValuesAdjusted[1] = geomagneticValues[1];
geomagneticValuesAdjusted[2] = geomagneticValues[2];
geomagneticValuesAdjusted[3] = 0;
Matrix.multiplyMV(resultVec, 0, RsInv, 0, geomagneticValuesAdjusted, 0);
for (int i = 0; i < resultVec.length; i++) {
resultVec[i] = resultVec[i] * nanoTtoGRate * gToCountRate;
}
if (kalmanFiletring) {
KalmanState currentKalmanStateX = new KalmanState(MEASUREMENT_NOISE, accelerometerValues[0], (double)resultVec[0], previousKalmanStateX);
previousKalmanStateX = currentKalmanStateX;
KalmanState currentKalmanStateY = new KalmanState(MEASUREMENT_NOISE, accelerometerValues[1], (double)resultVec[1], previousKalmanStateY);
previousKalmanStateY = currentKalmanStateY;
KalmanState currentKalmanStateZ = new KalmanState(MEASUREMENT_NOISE, accelerometerValues[2], (double)resultVec[2], previousKalmanStateZ);
previousKalmanStateZ = currentKalmanStateZ;
if (previousKalmanStateCounter == KALMAN_STATE_MAX_SIZE) {
magneticXTextView.setText("x: " + previousKalmanStateX.getX_estimate());
magneticYTextView.setText("y: " + previousKalmanStateY.getX_estimate());
magneticZTextView.setText("z: " + previousKalmanStateZ.getX_estimate());
resetKalmanFilter();
} else {
previousKalmanStateCounter++;
}
} else {
magneticXTextView.setText("x: " + resultVec[0]);
magneticYTextView.setText("y: " + resultVec[1]);
magneticZTextView.setText("z: " + resultVec[2]);
}
}
}
}
}
private void resetKalmanFilter() {
previousKalmanStateX = null;
previousKalmanStateY = null;
previousKalmanStateZ = null;
previousKalmanStateCounter = 0;
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
}
Danke an alle, die dies Lesen post und die post einige Gedanken über das problem im Voraus.
InformationsquelleAutor Yahor | 2013-03-09
Du musst angemeldet sein, um einen Kommentar abzugeben.
In meinem Kommentar für die markierten Antworten auf dem link, den Sie oben, ich bezog mich auf meine einfache Antwort auf berechnen Sie die Beschleunigung in Bezug auf die wahre Nordrichtung
Lassen Sie mich die Antwort auch hier wieder mit mehr Klarheit. Die Antwort ist das Produkt der rotation matrix und die Magnetfeld Werte. Wenn Sie Lesen Sie weiter auf der "X-ist immer sehr klein" ist der richtige Wert.
Dem Beschleunigungsmesser und Magnetfeld-sensoren Messen die Beschleunigung von dem Gerät und dem Magnetfeld der Erde an den Standort des Geräts bzw. Sie sind Vektoren in der 3 dimensionale Raum, lassen Sie Sie nennen eine und m bzw.
Wenn Sie still stehen und das Gerät drehen, theoretisch m nicht ändern, vorausgesetzt, es gibt keine magnetischen Interferenzen von umgebenden Objekten (eigentlich m sollte sich wenig verändern, wenn Sie sich bewegen, da das Magnetfeld der Erde sollte sich wenig verändern in kurzer Entfernung). Aber
a
ändert, obwohl es sollte nicht drastisch sein in den meisten situation.Nun ein Vektor v im 3-dimensionalen Raum dargestellt werden kann durch ein 3-Tupel (v_1, v_2, v_3) in Bezug auf einige der basis (e_1, e_2, e_3), ich.e v = v_1 e_1 + v_2 e_2 + v_3 e_3. (v_1, v_2, v_3) heißen die Koordinaten von v mit Bezug auf die basis (e_1, e_2, e_3).
In Android-Geräten, die basis ist (x, y, z), wo, für die meisten Handy, x ist entlang der kürzeren Seite und nach rechts, y ist entlang der längeren Seite und nach oben und z senkrecht zum Bildschirm und zeigen.
Nun ist diese Grundlage ändert, wie die position des Geräts ändert. Man kann sich denken, dass diese Basen als Funktion der Zeit (x(t), y(t), z(t)), in der Mathematik ein Begriff, es ist ein bewegliches Koordinatensystem.
Also auch wenn m nicht ändern, aber die Veranstaltung.Werte zurück, indem Sie die sensoren sind unterschiedlich, weil die basis unterschiedlich ist (ich sprechen über die Fluktuation höher). Wie ist die Veranstaltung.Werte sind nutzlos, denn Sie gibt uns die Koordinaten, aber wir wissen nicht, was die basis ist, ich.e in Bezug auf einige der basis, die wir kennen.
Ist jetzt die Frage: ist es möglich, finden Sie die Koordinaten von eine und m mit Bezug auf die Feste Welt-basis (w_1, w_2, w_3), wo w_1 Punkte in Richtung Osten, w_2 Punkte in Richtung magnetischen Norden und w_3 Punkte gegen den Himmel?
Die Antwort ist ja, sofern 2 wichtige Annahmen sind zufrieden.
Mit diesen 2 Annahmen es ist einfach zu berechnen (nur ein paar Kreuz-Produkte), die änderung der basis-matrix R von der basis (x, y, z) zu der basis (w_1, w_2, w_3), die in Android heißt die Rotation matrix. Dann die Koordinaten eines Vektors v mit Bezug auf die basis (w_1, w_2, w_3) erhalten wird durch multiplizieren R mit den Koordinaten der v mit Bezug auf die (x, y, z). Also die Koordinaten von m mit Bezug auf das Welt-Koordinaten-system ist nur das Produkt des rotation matrix und die Veranstaltung.Werte zurück durch die TYPE_MAGNETIC_FIELD sensor und ähnlich für eine.
In android die rotation matrix erhält man durch den Aufruf getRotationMatrix (float[] R, float [], float[] Schwerkraft, float[] geomagnetischen) und wir normalerweise übergeben Sie die zurückgegebenen accelerometer-Werte für die Schwerkraft, die parameter und die Magnetfeld-Werte für die geomagnetische.
Den 2 wichtige Annahmen sind:
1- Die Schwerkraft parameter stellt einen Vektor liegen in w_3, mehr ist es insbesondere das minus der Vektor beeinflusst durch die Schwerkraft allein.
Also, wenn Sie pass in die accelerometer-Werte ohne Filterung, die rotation matrix wird leicht ausschalten. Das ist, warum Sie benötigen, filtern Sie den Beschleunigungsmesser, so dass die filter-Werte sind etwa nur die minus-Schwerkraft-Vektor. Da die Gravitationsbeschleunigung ist der dominierende Faktor bei der Beschleunigungsmesser Vektor, normalerweise low pass filter ist ausreichend.
2- Die geomagnetischen parameter stellt einen Vektor liegt in der Ebene aufgespannt von der w_2 und die w_3 Vektoren. Das ist es liegt in der Nord-Himmel-Ebene. So ist im Begriff der (w_1, w_2, w_3) basis, die erste Koordinate soll 0 sein. Also, die "X ist immer sehr klein", wie Sie erklärten, dass es über den richtigen Wert, es sollte im Idealfall 0 sein. Nun die Magnetfeld-Werte schwanken ziemlich. Dies ist eine Art von erwartet, gerade wie einen regelmäßigen Kompassnadel wird nicht still stehen, wenn Sie halten es in Ihrer hand, und Ihre hand zuckt ein wenig. Auch kann es zu Störungen kommen aus Objekten, die Sie umgeben und in diesem Fall das magnetische Feld Werte sind unberechenbar. Ich mal testen, meine Kompass-app, die sitzen in der Nähe von "Stein" Tisch und mein Kompass war um mehr als 90 Grad, nur mit einem echten Kompass, fand ich heraus, dass es ist nichts falsch mit meiner app und der "Stein" - Tabelle erzeugt ein echt starkes Magnetfeld.
Mit der Schwerkraft als eine dominante Sie können filter accelerometer-Werte, aber ohne jedes andere wissen, wie Sie fitler magnetische Werte? Wie wissen Sie, ob es ist oder nicht Störungen werden von den umliegenden Objekten?
Können Sie viel mehr tun, wie die Kenntnisse über Ihr Gerät die räumliche position usw. mit dem Verständnis von rotation matrix.
Sie können überprüfen, ob das Gerät TYPE_GRAVITY und verwenden Sie es anstelle von TYPE_ACCELEROMETER, die sparen Sie sich die Bearbeitung der Kalman-filter.
Ja, ich wollte es versuchen, aber leider hat mein Gerät hat keine TYPE_GRAVITY zur Verfügung. Ich Plane auch versuchen ein anderes Gerät mit ein bisschen später.
Je nachdem, was Sie tun, Kalman-filter vielleicht zu viel des guten. Für Kompass-oder augmented-reality-Anwendungen, low-pass-filter sollten reichen. Ich weiß nicht, was Kalman-filter ist, aber ich habe gehört, dass es cpu-intensiv.
Ich habe noch eine Frage, TYPE_ACCELEROMETER wie ich es verstehe, ist tatsächlich etwas wie TYPE_LINEAR_ACCELERATION + TYPE_GRAVITY, ist es nicht? Ist es ok, pass auf getRotationMatrix Werte von TYPE_GRAVITY? Wird es genauer sein, wenn das Gerät in Bewegung ist (ich habe gelesen, dass wenn das Gerät zu beschleunigen, getRotationMatrix Ausgabe ist nicht korrekt).
InformationsquelleAutor Hoan Nguyen
Gemäß der obigen Erklärung, tun dies
InformationsquelleAutor vineetv2821993