Gyroscopeを使った回転量の計算|Android開発

AndroidのセンサGyroscopeを使用して回転量を取る方法です。

解説

Gyroscopeからは各軸を中心とした角速度(rad/sec)が通知されます。
角速度は前回通知~今回通知までの値なので、通知時間を掛けてやると前回通知から今回通知までに移動した角度(rad)が算出されます。

角速度(rad/sec) × 時間(sec) = 角度(rad)

軸は下の図のようになっています。

axis_device

使用例

下記サンプルでは、start時を0(360)とし、通知毎に移動角度を加算していくことで、時計回りなら3600へ、反時計回りなら0360へと値が変化します。
※移動量なので、続けるとマイナス値(負数)にもなるし、360を超えます。

public class GyroscopeTest implements SensorEventListener {

    private static final float NS2S = 1.0f / 1000000000.0f;
    private float mLastTimestamp;

    private float mRadianLandscape;
    private float mRadianPortrait;

    protected int mCurrentDegreeLandscape;
    protected int mCurrentDegreePortrait;
    protected int mDirection;
    protected boolean isLandscape;

    public static final Object SynchronizedObject = new Object();

    public void start(int rotation, int direction) {
        isLandscape = (rotation == 0 || rotation == 180);
        synchronized (SynchronizedObject) {
            mLastTimestamp = 0;
            mRadianLandscape = 0;
            mRadianPortrait = 0;
            mDirection = direction;
        }
    }

    protected int currentDegree() {
        return isLandscape ? mCurrentDegreeLandscape : mCurrentDegreePortrait;
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() != Sensor.TYPE_GYROSCOPE) {
            return;
        }

        synchronized (SynchronizedObject) {
            if (mLastTimestamp != 0) {
                final float dT = (event.timestamp - mLastTimestamp) * NS2S;
                float axisX = event.values[0];
                float axisY = event.values[1];
                float axisZ = event.values[2];

                mRadianLandscape += (axisX * dT);
                mRadianPortrait += (axisY * dT);
            }

            mLastTimestamp = event.timestamp;
            int degreeLandscape = radianToDegree(mRadianLandscape);
            int degreePortrait = radianToDegree(mRadianPortrait);

            if (degreeLandscape < 0) {
                degreeLandscape += 360;
            }
            if (degreePortrait < 0) {
                degreePortrait += 360;
            }

            mCurrentDegreeLandscape = degreeLandscape;
            mCurrentDegreePortrait = degreePortrait;
            //Log.v("GyroscopeTest", String.format("Gyroscope: %d %d", mCurrentDegreeLandscape, mCurrentDegreePortrait));
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // NOP
    }

    protected static int radianToDegree(float radian) {
        return (int) Math.floor(Math.toDegrees(radian));
    }
}
このエントリーをはてなブックマークに追加
にほんブログ村 IT技術ブログへ

コメント

メールアドレスが公開されることはありません。 が付いている欄は必須項目です