2012年6月29日金曜日

Androidでセンサーを使って方位(方角)を取得する

昨日書いた文字列を描画するっていう前触れはどこにいったのか。。。
今日はセンサーを使ってみました。

使ったセンサーは地磁気センサーと加速度センサー。
方位センサーっていうのがもともとTYPE_ORIENTATIONというのであったみたいなんですが今は非推奨。
ですのでこの2つのセンサーを利用して方位を取得します。

まずセンサーを利用する準備。
public class CompassTestActivity extends Activity
    implements SensorEventListener {

    private SensorManager sensor;

    /** lifecycle */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        Window window = getWindow();
        window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        
        sensor = (SensorManager)getSystemService(SENSOR_SERVICE);
        
        setContentView(R.layout.main);
    }
    
    @Override
    public void onResume() {
     super.onResume();
     
     // センサーイベントの登録
        sensor.registerListener(this, sensor.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_UI);
        sensor.registerListener(this, sensor.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);
    }
    
    @Override
    public void onPause() {
        // センサーイベントを削除
        sensor.unregisterListener(this);
     
        super.onPause();
    }
}

sensor.registerListenerの引数は

  • イベントリスナーのオブジェクト
  • センサーの種類
  • データ取得の頻度
といったかんじになります。
頻度をSENSOR_DELAY_UIとしてますが他にもSENSOR_DELAY_NORMALとかSENSOR_DELAY_GAMEなどいくつかありますのでつくるアプリ合わせて設定をします。

センサーは(センサーに限った話しではないですが)アプリがバックグランドになったときも動き続けますのでonResumeでイベント登録し、onPauseでイベント削除します。


つぎにセンサーイベントの実装です。
    /** SensorEventListener */
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) { }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
            return;

        switch (event.sensor.getType()) {
            case Sensor.TYPE_MAGNETIC_FIELD: // 地磁気センサ
                magneticValues = event.values.clone();
                break;
            case Sensor.TYPE_ACCELEROMETER:  // 加速度センサ
                accelerometerValues = event.values.clone();
                break;
        }

        if (magneticValues != null && accelerometerValues != null) {
            float[] rotationMatrix = new float[MATRIX_SIZE];
            float[] inclinationMatrix = new float[MATRIX_SIZE];
            float[] remapedMatrix = new float[MATRIX_SIZE];

            float[] orientationValues = new float[DIMENSION];

            // 加速度センサと地磁気センサから回転行列を取得
            SensorManager.getRotationMatrix(rotationMatrix, inclinationMatrix, accelerometerValues, magneticValues);
            SensorManager.remapCoordinateSystem(rotationMatrix, SensorManager.AXIS_X, SensorManager.AXIS_Z, remapedMatrix);
            SensorManager.getOrientation(remapedMatrix, orientationValues);

            // 方位を取得する
            int orientDegrees = toOrientationDegrees(orientationValues[0]);
            String orientString = toOrientationString(orientationValues[0]);

            Log.d(TAG, "orientDegrees = " + orientDegrees + " , orientString = " + orientString);
        }
    }
 
    /**
     * 方位の角度に変換する
     * @param angrad
     * @return
     */
    private int toOrientationDegrees(float angrad) {
        return (int)Math.floor(angrad >= 0 ? Math.toDegrees(angrad) : 360 + Math.toDegrees(angrad));
    }

    /**
     * 方位の文字列に変換する
     * @param angrad
     * @return
     */
    private String toOrientationString(float angrad) {
        double[] orientation_range = {
            - (Math.PI * 3 / 4), // 南
            - (Math.PI * 1 / 4), // 西
            + (Math.PI * 1 / 4), // 北
            + (Math.PI * 3 / 4), // 東
        };

        String[] orientation_string = {
            "south",
            "west",
            "north",
            "east",
        };

        for (int i = 0; i < orientation_range.length; i++) {
            if (angrad < orientation_range[i]) {
                return orientation_string[i];
            }
        }

        return orientation_string[0];
    }

まだまだわからないことがありますがセンサーイベントには、onAccuracyChangedとonSensorChangedがあります。

  • onAccuracyChanged・・・精度?に変化があった場合
  • onSensorChanged・・・値に変化があった場合
ここでは値に変化があった場合に処理するようにしています。
中身はあんまり詳しく説明できないので参考にしたサイト
このセンサーとカメラ機能を使っていま向いてる方位(4方位しかないですが)を表示するだけのものを作ってみました。

ただ、Galaxy Nexusでは動きませんでした。。。なんでだ。。。
動作はAQUOS PHONE f SH-13Cで確認しました




0 件のコメント:

コメントを投稿