vaguely

和歌山に戻りました。ふらふらと色々なものに手を出す毎日。

AndroidでSensor

思いつきで(いつものことですが)Androidでgyroセンサーを使ってみたメモ。

後述の理由により取得したそのまま値を使って何かする、というのは難しそうなので、とりあえず値を取るところだけ。

実装内容

  1. インターフェース[SensorEventListener]をセンサー使用クラスで実装する
  2. SensorManagerを使って、使用するセンサーのリスナーを登録する
  3. メソッド[onAccuracyChanged]の追加(今回は何も変更しませんが、ないとエラーになるので)
  4. メソッド[onSensorChanged]を追加して、センサーの値が更新された時にその値を取得する

MainActivity.java

package masanori.co.jp.and_gyroctrl;

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity implements SensorEventListener
{
    private SensorManager _snmSensorManager;
    private TextView _txvGyroValue;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        _txvGyroValue = (TextView)findViewById(R.id.gyro_value);
        _snmSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
    }
    protected void onResume()
    {
        super.onResume();
        // ジャイロセンサーをリスナーに登録.
        _snmSensorManager.registerListener(
            this
            , _snmSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
            , SensorManager.SENSOR_DELAY_NORMAL);

    }

    protected void onPause()
    {
        super.onPause();
        // リスナーの登録解除.
        _snmSensorManager.unregisterListener(this);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy)
    {
        // 今回は特に変更なし.
    }
    @Override
    public void onSensorChanged(SensorEvent event)
    {
      // センサーで取得できる値が変更された場合は全てこのメソッドが呼ばれるため、Gyroの値かを確認する.
      if(event.sensor.getType() == Sensor.TYPE_GYROSCOPE)
      {
        _txvGyroValue.setText("X = " + event.values[0] + " Y = " + event.values[1] + " Z = " + event.values[2]);
      }
    }

}
  • その他加速度センサーなどの値も、リスナー登録時に指定する[Sensor.TYPE_GYROSCOPE]の部分を変更すれば同じように取得できます。
    (Developerサイト参照)
  • 複数のセンサーを同時に扱いたい場合は、registerListenerをそれぞれのタイプ登録して、onSensorChangedの[event.sensor.getType()]で分岐させます。
  • センサーの値を更新する頻度は、registerListenerの第三引数で行っています。

問題点

このように、結構簡単に値が取得できるのは便利です。

が、実機で動かしてみるとデバイスを机の上などに置いて動かしていない場合でも値が変化し続けてしまうため、例えばデバイスの向きに合わせて画像や3Dオブジェクトを動かそうとすると上手く制御できません。

実はiOSでも同様で、取得した値を加工してやる必要がありそうです。

簡単に思いつくところでは小数点第三位ぐらいで四捨五入してやるとか、閾値を設けてそれ以下の変化は無視するなどでしょうか。
ただその場合でも、あまりやりすぎるとカクカクしたり動きがワンテンポ遅くなったりと不自然になってしまうため、調整が大変そうです。

世の中にあるアプリなどは、どのように解決しているのでしょうね。
もう少し調べてみます。

【参考】