酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

AndroidでSensorManagerを使って磁気センサー(コンパス)の方位を取得する

コンパスのように磁気センサーを使って磁北を指したい。

LocationServiceはユーザーの利用許諾が必要だったけれど、磁気センサーは特にユーザーに許可を得なくても利用できるようです。

sensorManager = (SensorManager) getActivity().getSystemService(Activity.SENSOR_SERVICE);
sensorManager.registerListener(this,
        sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
        SensorManager.SENSOR_DELAY_NORMAL);
sensorManager.registerListener(this,
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
        SensorManager.SENSOR_DELAY_NORMAL);

方角を得て、ImageViewを回転させます。

float[] accelerometerValues = new float[3];
float[] geomagneticMatrix = new float[3];
boolean sensorReady;

@Override
public void onSensorChanged(SensorEvent sensorEvent) {

    switch (sensorEvent.sensor.getType()) {
        case Sensor.TYPE_ACCELEROMETER:
            accelerometerValues = sensorEvent.values.clone();
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            geomagneticMatrix = sensorEvent.values.clone();
            sensorReady = true;
            break;
     default:
            return;
    }

    if (geomagneticMatrix == null || accelerometerValues == null || !sensorReady) {
        return;
    }
    sensorReady = false;

    float[] R = new float[16];
    float[] I = new float[16];

    SensorManager.getRotationMatrix(R, I, accelerometerValues, geomagneticMatrix);

    float[] actual_orientation = new float[3];
    SensorManager.getOrientation(R, actual_orientation);

    float orientDegree = (float) Math.toDegrees(actual_orientation[0]);

    pinImageView.setRotation(orientDegree);
}

@Override
public void onAccuracyChanged(Sensor sensor, int i) {

}

不定期だけど連続して発生するイベントを捌く必要があるので、最終的にはRxJavaに置き換えた方がいいかもしれないですね。

前回の位置測位もRxJavaでいい感じにできそう。今回も取り組みは実験的なものでありものを集めた感じだったけど、今後もよく使いそうなのでコピペで済むように俺俺ライブラリ化しておきたい。既にありそうだけど。

参考