TYPE_MAGNETOMETERセンサーを使用すると、デバイスの向きに関連する磁場強度のX、Y、Z値が得られます。私が取得したいのは、これらの値をグローバル参照フレームに変換し、明確にすることです。ユーザーはデバイスを取得し、これらの値を測定します。次に、デバイスを任意の軸を中心にある程度回転させて、同じ値を取得します。以下の同様の質問を見つけてください。 グローバル座標での磁場値の 取得デバイスの回転に関係なく、磁場ベクトルを取得するにはどうすればよいですか。 この回答では、サンプルソリューションが説明されています(線形加速用ですが、問題ではないと思います):https ://stackoverflow.com/a/11614404/2152255 私はそれを使用し、3つの値を取得しました。Xは常に非常に小さく(正しいとは思わない)、YとZは問題ありませんが、デバイスを回転させると少し変化します。どのように調整できますか?そして、それはすべて解決できるでしょうか?単純なカルマンフィルターを使用して測定値を概算します。これを使用しないと、デバイスがまったく移動/回転していなくても、静かな異なる値が得られるためです。以下の私のコードを見つけてください:
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) {
}
}
この投稿を読んで、問題について事前にいくつかの考えを投稿してくれたすべての人に感謝します。