SIN@SAPPOROWORKSの覚書

C#を中心に、夜な夜な試行錯誤したコードの記録です。

Xamarin.Android 方位の取得2(磁気センサー/加速度センサー)

【 Xamarin 記事一覧 】

1 方位の取得方法

Androidで方位を取得する方法は、次の2つがあります。
(1) TYPE_ORIENTATION(傾きセンサー)による方法
(2) TYPE_MAGNETIC_FIELD(磁気センサー)とTYPE_ACCELEROMETER(加速度センサー)による方法

今回は、(2)の磁気センサーと加速度センサーを使用してみます。
なお、API Level8 で「方位角」及び「傾き」を求める場合は、TYPE_ORIENTATIONは非推奨になっているようです。

2 磁気センサー(TYPE_MAGNETIC_FIELD)及び加速度センサー(TYPE_ACCELEROMETER)

センサー自体の使用方法は、傾きセンサーの時と同じですが、「方位角」と「傾き」は、SensorManagerのメソッドで計算しています。
http://developer.android.com/reference/android/hardware/SensorManager.html

// 加速度センサーと磁気センサーの値から回転行列を求める
public static bool GetRotationMatrix(float[] R, float[] I, float[] gravity, float[] geomagnetic)
// 端末の画面設定に合わせる変換行列を求める(以下は, 縦表示で画面を上にした場合)
public static bool RemapCoordinateSystem(float[] inR, Android.Hardware.Axis X, Android.Hardware.Axis Y, float[] outR)
// 方位角及び傾きを求める
public static float[] GetOrientation(float[] R, float[] values)

サンプルは、傾きセンサーの値も合わせて表示して違いを比べて見ましたが、ほとんど同じでした。
※回転角の符号が逆転しているのに注意が必要です。

[Activity(Label = "AndroidApplication1", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity, ISensorEventListener{

    private SensorManager _senseManager;
    private TextView _textView;

    protected override void OnCreate(Bundle bundle){
        base.OnCreate(bundle);
        SetContentView(Resource.Layout.Main);

        _senseManager = (SensorManager) GetSystemService(SensorService);
        _textView = FindViewById<TextView>(Resource.Id.textView);
    }

    protected override void OnResume(){
        base.OnResume();
        //リスナー登録
        _senseManager.RegisterListener(this, _senseManager.GetDefaultSensor(SensorType.MagneticField),SensorDelay.Ui);
        _senseManager.RegisterListener(this, _senseManager.GetDefaultSensor(SensorType.Accelerometer),SensorDelay.Ui);
        _senseManager.RegisterListener(this, _senseManager.GetDefaultSensor(SensorType.Orientation), SensorDelay.Ui);
    }

    protected override void OnPause(){
        base.OnPause();
        //リスナー解除            
        _senseManager.UnregisterListener(this);
    }

    //ISensorEventListenerで必須
    public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy){ }

    float [] _aVal;
    float [] _mVal;
    float[] _oVal;
    public void OnSensorChanged(SensorEvent e) {
        //センサー値の取得
        switch (e.Sensor.Type){
            case SensorType.Accelerometer: //加速度センサー
                _aVal = new float[3];
                _aVal = e.Values.ToArray();
                break;
            case SensorType.MagneticField: //磁気センサー
                _mVal = new float[3];
                _mVal = e.Values.ToArray();
                break;
            case SensorType.Orientation: //傾きセンサー
                _oVal = new float[3];
                _oVal = e.Values.ToArray();
                break;
        }
 
        var sb = new System.Text.StringBuilder();
  
        if (_oVal != null) {
            sb.Append(String.Format("傾きセンサー\n"));
            sb.Append(String.Format("方位角:{0:F1}\n", _oVal[0]));
            sb.Append(String.Format("傾斜角:{0:F1}\n", _oVal[1]));
            sb.Append(String.Format("回転角:{0:F1}\n", _oVal[2]));
            sb.Append(String.Format("\n"));
        }

        if (_aVal != null && _mVal != null) {
            var R1 = new float[16];
            var R2= new float[16];
            var I = new float[16];
            var val = new float[3];

            // 加速度センサーと磁気センサーの値から回転行列を求める
            SensorManager.GetRotationMatrix(R1, I, _aVal, _mVal);
            // 端末の画面設定に合わせる変換行列を求める(以下は, 縦表示で画面を上にした場合)
            SensorManager.RemapCoordinateSystem(R1, Axis.X, Axis.Y, R2);
            // 方位角及び傾きを求める
            SensorManager.GetOrientation(R2, val);
            //ラジアンを角度に変換
            for (var i = 0; i < 3; i++) {
                val[i] = (float)(val[i] * 180 / Math.PI);
            }

            sb.Append(String.Format("磁気センサー + 加速度センサー\n"));
            sb.Append(String.Format("方位角:{0:F1}\n", (val[0] < 0) ? val[0] + 360 : val[0]));
            sb.Append(String.Format("傾斜角:{0:F1}\n", val[1]));
            sb.Append(String.Format("回転角:{0:F1}\n", val[2]));
        }
        //表示
        _textView.Text = sb.ToString();
    }
}

【 Xamarin 記事一覧 】