The Android Developer Challenge is back! Submit your idea before December 2.

モーション センサー

Android プラットフォームには、端末の動きをモニターするためのさまざまなセンサーが搭載されています。

センサーの有効なアーキテクチャは、センサーのタイプに応じて異なります。

  • 重力センサー、線形加速度センサー、回転ベクトル センサー、移動検出センサー、歩数計センサー、歩行検出センサーは、ハードウェアベースまたはソフトウェアベースです。
  • 加速度計センサーとジャイロスコープ センサーは常にハードウェアベースです。

ほとんどの Android 搭載端末には加速度計が搭載されており、また多くの端末にはジャイロスコープが搭載されるようになってきています。ソフトウェアベースのセンサーはデータの取得に 1 つ以上のハードウェア センサーを使用することが多いので、ソフトウェアベースのセンサーが利用可能であるかどうかは、状況に応じてかなり異なります。端末に応じて、ソフトウェアベース センサーはデータを加速度計と磁力計から取得したり、ジャイロスコープから取得することができます。

モーション センサーは、端末の動き(傾き、シェイク、回転、揺れなど)をモニターするのに役立ちます。通常、このような動きは直接的なユーザー入力(ユーザーがゲームで車を運転することや、ボールをコントロールすることなど)を反映していますが、端末の周りの物理的な状況を反映することもあります(ユーザーが車を運転しているために移動している場合など)。前者の場合は端末の座標系またはアプリの座標系を基準に動きをモニターしており、後者の場合は世界の座標系を基準に動きをモニターしています。通常、モーション センサー自体は端末の位置のモニターには使用されませんが、他のセンサー(地磁気センサーなど)と組み合わせて、世界の座標系における端末の現在位置を判別するために使用することができます(詳細については位置センサーをご覧ください)。

すべてのモーション センターは、SensorEvent ごとにセンサー値の多次元配列を返します。たとえば、1 つのセンサー イベントでは加速度計から 3 つの座標軸の加速力データが返され、ジャイロスコープから 3 つの座標軸の回転速度データが返されます。これらのデータ値は、他の SensorEvent パラメータとともに、float 配列(values)に入れて返されます。表 1 に、Android プラットフォームで使用可能なモーション センサーの要約を示します。

表 1. Android プラットフォームでサポートされているモーション センサー。

センサー センサーイベント データ 説明 測定単位
TYPE_ACCELEROMETER SensorEvent.values[0] x 軸方向の加速力(重量を含む)。 m/s2
SensorEvent.values[1] y 軸方向の加速力(重量を含む)。
SensorEvent.values[2] z 軸方向の加速力(重量を含む)。
TYPE_ACCELEROMETER_UNCALIBRATED SensorEvent.values[0] X 軸方向の測定加速度(バイアス補償なし)。 m/s2
SensorEvent.values[1] Y 軸方向の測定加速度(バイアス補償なし)。
SensorEvent.values[2] Z 軸方向の測定加速度(バイアス補償なし)。
SensorEvent.values[3] X 軸方向の測定加速度(推定バイアス補償あり)。
SensorEvent.values[4] Y 軸方向の測定加速度(推定バイアス補償あり)。
SensorEvent.values[5] Z 軸方向の測定加速度(推定バイアス補償あり)。
TYPE_GRAVITY SensorEvent.values[0] x 軸方向の重力。 m/s2
SensorEvent.values[1] y 軸方向の重力。
SensorEvent.values[2] z 軸方向の重力。
TYPE_GYROSCOPE SensorEvent.values[0] x 軸周りの回転速度。 rad/s
SensorEvent.values[1] y 軸周りの回転速度。
SensorEvent.values[2] z 軸周りの回転速度。
TYPE_GYROSCOPE_UNCALIBRATED SensorEvent.values[0] x 軸周りの回転速度(ドリフト補償なし)。 rad/s
SensorEvent.values[1] y 軸周りの回転速度(ドリフト補償なし)。
SensorEvent.values[2] z 軸周りの回転速度(ドリフト補償なし)。
SensorEvent.values[3] x 軸周りの推定ドリフト。
SensorEvent.values[4] y 軸周りの推定ドリフト。
SensorEvent.values[5] z 軸周りの推定ドリフト。
TYPE_LINEAR_ACCELERATION SensorEvent.values[0] x 軸方向の加速力(重量を除く)。 m/s2
SensorEvent.values[1] y 軸方向の加速力(重量を除く)。
SensorEvent.values[2] z 軸方向の加速力(重量を除く)。
TYPE_ROTATION_VECTOR SensorEvent.values[0] x 軸に関する回転ベクトル成分(x * sin(θ/2))。 単位なし
SensorEvent.values[1] y 軸に関する回転ベクトル成分(y * sin(θ/2))。
SensorEvent.values[2] z 軸に関する回転ベクトル成分(z * sin(θ/2))。
SensorEvent.values[3] 回転ベクトルのスカラー成分((cos(θ/2))。1
TYPE_SIGNIFICANT_MOTION なし なし なし
TYPE_STEP_COUNTER SensorEvent.values[0] 最終再起動時以降、センサーがアクティベートされている間に、ユーザーが歩いた歩数。 ステップ
TYPE_STEP_DETECTOR なし なし なし

1 スカラー成分は省略可能な値です。

回転ベクトル センサーと重力センサーは、動作の検出とモニターに最もよく使用されるセンサーです。回転ベクトル センサーは特に多目的に利用でき、モーションが関連するさまざまなタスク(操作の検出、傾きの変化のモニター、相対方位の変化のモニターなど)に使用できます。たとえば回転ベクトル センサーは、ゲーム、拡張現実(AR)アプリ、2D または 3D コンパス、カメラ スタビライザー アプリなどを開発している場合に適しています。ほとんどの場合、加速度計と地磁気センサーまたはオリエンテーション センサーを使用するよりも、これらのセンサーを使用する方が適切です。

Android オープンソース プロジェクト センサー

Android オープンソース プロジェクト(AOSP)は、3 つのソフトウェアベースのモーション センサー(重力センサー、線形加速度センサー、回転ベクトル センサー)を提供しています。これらのセンサーは Andorid 4.0 で更新され、現在では(その他のセンサーに加えて)端末のジャイロスコープを使用しており、安定性とパフォーマンスが向上しています。これらのセンサーを使ってみる場合は、getVendor() メソッドと getVersion() メソッド(ベンダーは Google LLC、バージョン番号は 3)を使用してこれらのセンサーを識別できます。Android システムではこの 3 つのセンサーはセカンダリ センサーとして見なされるため、ベンダーとバージョン番号を使用してこれらのセンサーを識別する必要があります。たとえば、端末の製造元が独自の重力センサーを提供している場合、AOSP 重力センサーはセカンダリ重力センサーとして表示されます。3 つのセンサーはすべてジャイロスコープを使用します。端末にジャイロスコープが搭載されていない場合、これらのセンサーは表示されず、使用できません。

重力センサーを使用する

重力センサーは、重力の方向と大きさを示す 3 次元ベクトルを提供します。一般にこのセンサーは、空間での端末の相対的な方向を判別するために使用されます。以下のコードは、デフォルトの重力センサーのインスタンスを取得する方法を示します。

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);

単位は加速度センサーで使用されている単位と同じであり(m/s2)、座標系は加速度センサーで使用されている座標系と同じです。

注:端末が動いていない場合、重力センサーの出力は加速度計の出力と同一になります。

線形加速度計を使用する

線形加速度センサーは、端末の各軸の方向の加速度(重力なし)を表す 3 次元ベクトルを提供します。この値を使用して、操作検出を実行できます。この値は、推測航法を使用する慣性航法装置への入力としても使用できます。以下のコードは、デフォルトの線形加速度センサーのインスタンスを取得する方法を示します。

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);

概念的には、このセンサーは次の関係に従って加速度データを提供します。

linear acceleration = acceleration - acceleration due to gravity

一般にこのセンサーを使用するのは、重力の影響がない状態での加速度データを取得する必要がある場合です。たとえば、このセンサーを使用して自動車の走行速度を確認できます。線形加速度センサーでは常にオフセットがあるので、オフセットを取り除く必要があります。最も簡単な方法は、アプリにキャリブレーション ステップを組み込む方法です。キャリブレーション中に、ユーザーに対して端末をテーブルに置くように指示し、3 つのすべての軸のオフセットを読み取ることができます。次に加速度センサーの直接測定値からこのオフセットを差し引いて、実際の線形加速度を算出します。

このセンサーの座標系は、加速度センサーが使用する座標系と同じであり、測定単位も加速度センサーと同じです(m/s2)。

回転ベクトル センサーを使用する

回転ベクトルは、端末の向きを角度と軸の組み合わせで表します。端末は、軸(x、y、z)の周りを角度 θ でこの方向に回転しています。以下のコードは、デフォルトの回転ベクトル センサーのインスタンスを取得する方法を示します。

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);

回転ベクトルの 3 つの要素は次のように表されます。

x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)

回転ベクトルの大きさが sin(θ/2) に等しい場合、回転ベクトルの方向は回転軸の方向と等しくなります。

図 1. 回転ベクトル センサーにより使用される座標系。

回転ベクトルの 3 つの要素は、単位四元数 (cos(θ/2), x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)) の最後の 3 つの成分と等しくなります。回転ベクトルの要素には単位がありません。x、y、z の各軸は、加速度センサーの場合と同様に定義されます。基準座標系は、正規直交基底として定義されます(図 1 を参照)。この座標系の特徴は次のとおりです。

  • X はベクトル積 Y x Z として定義されます。これは、端末の現在位置で地面に接しており、ほぼ東を指しています。
  • Y は端末の現在位置で地面に接しており、北磁極を指しています。
  • Z は天を指し、地表面に対して垂直です。

回転ベクトル センサーの使い方を示すサンプルアプリについては、 RotationVectorDemo.javaをご覧ください。

移動検出センサーを使用する

移動検出センサーは、移動(significant motion)が検出されるたびにトリガーされ、その後センサー自体を無効にします。移動とは、ユーザーの位置が変化する動きです(歩行、自転車走行、走行中の車に乗っている場合など)。次のコードは、デフォルトの移動検出センサーのインスタンスを取得する方法と、イベント リスナーの登録方法を示します。

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val mSensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION)
val triggerEventListener = object : TriggerEventListener() {
    override fun onTrigger(event: TriggerEvent?) {
        // Do work
    }
}
mSensor?.also { sensor ->
    sensorManager.requestTriggerSensor(triggerEventListener, sensor)
}

Java

private SensorManager sensorManager;
private Sensor sensor;
private TriggerEventListener triggerEventListener;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);

triggerEventListener = new TriggerEventListener() {
    @Override
    public void onTrigger(TriggerEvent event) {
        // Do work
    }
};

sensorManager.requestTriggerSensor(triggerEventListener, mSensor);

詳細については、TriggerEventListener をご覧ください。

歩数計センサーを使用する

歩数計センサーは、最終再起動以降、センサーがアクティベートされている間にユーザーが歩いた歩数を提供します。歩数計カウンターは、歩行検出カウンターよりも遅延が長い(最大 10 秒)ですが、精度が高くなります。

注:Android 10 (API level 29) 以上が稼働している端末でアプリがこのセンサーを使用できるようにするには、ACTIVITY_RECOGNITION パーミッションを宣言する必要があります。

以下のコードは、デフォルトの歩数計センサーのインスタンスを取得する方法を示します。

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);

アプリを実行している端末の電池の消費電力量を節約するには、JobScheduler クラスを使用して、特定の間隔で歩数計カウンターから現行値を取得します。アプリによって必要とするセンサー読み取り間隔は異なりますが、アプリがセンサーからリアルタイム データを必要とする場合を除き、この間隔を可能な限り長くしてください。

歩行検出カウンターを使用する

歩行検出センサーは、ユーザーが歩くときに 1 歩ごとにイベントをトリガーします。遅延は 2 秒未満であると想定されます。

注:Android 10 (API level 29) 以上が稼働している端末でアプリがこのセンサーを使用できるようにするには、ACTIVITY_RECOGNITION パーミッションを宣言する必要があります。

以下のコードは、デフォルトの歩行検出センサーのインスタンスを取得する方法を示します。

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);

生データを処理する

端末に加えられる直線力と回転力に関する生データをアプリに提供するセンサーを次に示します。これらのセンサーからの値を効率的に使用するには、環境からの要因(重力など)を取り除く必要があります。また、ノイズを削減するため値の傾向に平滑化アルゴリズムを適用する必要もあります。

加速度計を使用する

加速度センサーは、端末に加えられる加速度(重力を含む)を測定します。以下のコードは、デフォルトの加速度センサーのインスタンスを取得する方法を示します。

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)

Java

private SensorManager sensorManager;
private Sensor sensor;
  ...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

概念的に、加速度センサーは端末に加えられる加速度(Ad)を判別するため、次の関係を使用してセンサー自体に加えられる力(Fs)を測定します。

A_D=-(1/mass)∑F_S

ただし、次の関係に従って、重力は常に測定される加速度に影響しています。

A_D=-g-(1/mass)∑F_S

このため、端末がテーブルの上に置かれている場合(加速していない場合)、加速度計は g の大きさを 9.81 m/s2と示します。同様に、端末が地面へ向けて 9.81 m/s2で急速に加速しながら自由落下中である場合、端末の加速度計は g の大きさを 0 m/s2と示します。したがって、端末の実際の加速度を測定するには、加速度計データから重力の影響を取り除く必要があります。このためには、ハイパス フィルタを適用します。反対に、重力だけを取り出すにはローパス フィルタを使用します。次の例に、この方法を示します。

Kotlin

override fun onSensorChanged(event: SensorEvent) {
    // In this example, alpha is calculated as t / (t + dT),
    // where t is the low-pass filter's time-constant and
    // dT is the event delivery rate.

    val alpha: Float = 0.8f

    // Isolate the force of gravity with the low-pass filter.
    gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0]
    gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1]
    gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2]

    // Remove the gravity contribution with the high-pass filter.
    linear_acceleration[0] = event.values[0] - gravity[0]
    linear_acceleration[1] = event.values[1] - gravity[1]
    linear_acceleration[2] = event.values[2] - gravity[2]
}

Java

public void onSensorChanged(SensorEvent event){
    // In this example, alpha is calculated as t / (t + dT),
    // where t is the low-pass filter's time-constant and
    // dT is the event delivery rate.

    final float alpha = 0.8;

    // Isolate the force of gravity with the low-pass filter.
    gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
    gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
    gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];

    // Remove the gravity contribution with the high-pass filter.
    linear_acceleration[0] = event.values[0] - gravity[0];
    linear_acceleration[1] = event.values[1] - gravity[1];
    linear_acceleration[2] = event.values[2] - gravity[2];
}

注:センサーデータのフィルタリングにはさまざまな方法を利用できます。上記のサンプルコードでは、単純なフィルタ定数(alpha)を使用してローパス フィルタを作成しています。このフィルタ定数は、時間定数(t)(フィルタがセンサー イベントに追加する遅延をおおまかに表す値)と、センサーのイベント配信率(dt)から導出されます。サンプルコードでは、デモの目的で alpha 値として 0.8 が使用されています。このフィルタ方法を使用する際には、異なる alpha 値を選択する必要がある場合があります。

加速度計は標準センサー座標系を使用します。実際には、端末がテーブルにその自然な向きで平らに置かれている場合には、次の条件が適用されます。

  • 端末の左側を押すと(端末が右に動く)、x の加速度値が正の値になります。
  • 端末の下側を押すと(端末が遠ざかる)、y の加速度値が正の値になります。
  • 端末を加速度 A m/s2で上空に向かって押し上げると、z の加速度値は A + 9.81 と等しくなります。これは、端末の加速度(+A m/s2)から重力(-9.81 m/s2)をマイナスしたものです。
  • 静止している端末の加速度値は +9.81 であり、これは端末の加速度(0 m/s2 から重力 -9.81 m/s2)をマイナスしたものです。

通常、加速度計は端末の動きをモニターするときに使用すると便利なセンサーです。ほとんどすべての Android 搭載携帯電話とタブレットには加速度計が搭載されています。加速度計の消費電力は、他のモーション センサーの約 1/10 です。短所として、重力を排除しノイズを削減するために、ローパス フィルタとハイパス フィルタを実装しなければならないことがあります。

Android SDK には、加速度センサーの使い方を示すサンプルアプリ(Accelerometer Play)があります。

ジャイロスコープを使用する

ジャイロスコープは、端末の x、y、z 軸周りの回転速度を rad/s で測定します。以下のコードは、デフォルトのジャイロスコープのインスタンスを取得する方法を示します。

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);

このセンサーの座標系は、加速度センサーで使用されている座標系と同じです。反時計回り方向の回転は正回転です。つまり、x、y、または x 軸で正の位置から、原点に位置する端末を観察している観察者は、端末が反時計回り方向に回転する場合は正回転を報告します。これは正回転の標準的な数学的定義であり、オリエンテーション センサーで使用される回転の定義とは異なります。

通常、ジャイロスコープの出力は時間の経過とともに積分され、タイムステップでの角度の変化を示す回転が計算されます。次に例を示します。

Kotlin

// Create a constant to convert nanoseconds to seconds.
private val NS2S = 1.0f / 1000000000.0f
private val deltaRotationVector = FloatArray(4) { 0f }
private var timestamp: Float = 0f

override fun onSensorChanged(event: SensorEvent?) {
    // This timestep's delta rotation to be multiplied by the current rotation
    // after computing it from the gyro sample data.
    if (timestamp != 0f && event != null) {
        val dT = (event.timestamp - timestamp) * NS2S
        // Axis of the rotation sample, not normalized yet.
        var axisX: Float = event.values[0]
        var axisY: Float = event.values[1]
        var axisZ: Float = event.values[2]

        // Calculate the angular speed of the sample
        val omegaMagnitude: Float = sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ)

        // Normalize the rotation vector if it's big enough to get the axis
        // (that is, EPSILON should represent your maximum allowable margin of error)
        if (omegaMagnitude > EPSILON) {
            axisX /= omegaMagnitude
            axisY /= omegaMagnitude
            axisZ /= omegaMagnitude
        }

        // Integrate around this axis with the angular speed by the timestep
        // in order to get a delta rotation from this sample over the timestep
        // We will convert this axis-angle representation of the delta rotation
        // into a quaternion before turning it into the rotation matrix.
        val thetaOverTwo: Float = omegaMagnitude * dT / 2.0f
        val sinThetaOverTwo: Float = sin(thetaOverTwo)
        val cosThetaOverTwo: Float = cos(thetaOverTwo)
        deltaRotationVector[0] = sinThetaOverTwo * axisX
        deltaRotationVector[1] = sinThetaOverTwo * axisY
        deltaRotationVector[2] = sinThetaOverTwo * axisZ
        deltaRotationVector[3] = cosThetaOverTwo
    }
    timestamp = event?.timestamp?.toFloat() ?: 0f
    val deltaRotationMatrix = FloatArray(9) { 0f }
    SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
    // User code should concatenate the delta rotation we computed with the current rotation
    // in order to get the updated rotation.
    // rotationCurrent = rotationCurrent * deltaRotationMatrix;
}

Java

// Create a constant to convert nanoseconds to seconds.
private static final float NS2S = 1.0f / 1000000000.0f;
private final float[] deltaRotationVector = new float[4]();
private float timestamp;

public void onSensorChanged(SensorEvent event) {
    // This timestep's delta rotation to be multiplied by the current rotation
    // after computing it from the gyro sample data.
    if (timestamp != 0) {
      final float dT = (event.timestamp - timestamp) * NS2S;
      // Axis of the rotation sample, not normalized yet.
      float axisX = event.values[0];
      float axisY = event.values[1];
      float axisZ = event.values[2];

      // Calculate the angular speed of the sample
      float omegaMagnitude = sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);

      // Normalize the rotation vector if it's big enough to get the axis
      // (that is, EPSILON should represent your maximum allowable margin of error)
      if (omegaMagnitude > EPSILON) {
        axisX /= omegaMagnitude;
        axisY /= omegaMagnitude;
        axisZ /= omegaMagnitude;
      }

      // Integrate around this axis with the angular speed by the timestep
      // in order to get a delta rotation from this sample over the timestep
      // We will convert this axis-angle representation of the delta rotation
      // into a quaternion before turning it into the rotation matrix.
      float thetaOverTwo = omegaMagnitude * dT / 2.0f;
      float sinThetaOverTwo = sin(thetaOverTwo);
      float cosThetaOverTwo = cos(thetaOverTwo);
      deltaRotationVector[0] = sinThetaOverTwo * axisX;
      deltaRotationVector[1] = sinThetaOverTwo * axisY;
      deltaRotationVector[2] = sinThetaOverTwo * axisZ;
      deltaRotationVector[3] = cosThetaOverTwo;
    }
    timestamp = event.timestamp;
    float[] deltaRotationMatrix = new float[9];
    SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
    // User code should concatenate the delta rotation we computed with the current rotation
    // in order to get the updated rotation.
    // rotationCurrent = rotationCurrent * deltaRotationMatrix;
}

標準のジャイロスコープは、ノイズとドリフト(バイアス)をフィルタまたは補正していない生の回転データを提供します。実際には、ジャイロスコープのノイズとドリフトによってエラーが発生するので、このエラーを補正する必要があります。通常、ドリフト(バイアス)とノイズは、他のセンサー(重力センサーや加速度計など)をモニターすることで判別されます。

キャリブレーションなしのジャイロスコープを使用する

キャリブレーションなしのジャイロスコープは、ジャイロドリフト補正が回転速度に適用されていない点を除き、ジャイロスコープに似ています。それでも、工場出荷時キャリブレーションと温度補正は回転速度に適用されます。キャリブレーションなしのジャイロスコープは、方位データの後処理または融合に役立ちます。一般に、gyroscope_event.values[0]uncalibrated_gyroscope_event.values[0] - uncalibrated_gyroscope_event.values[3] に近い値になります。つまり、

calibrated_x ~= uncalibrated_x - bias_estimate_x

注:キャリブレーションなしのセンサーはさらに多くの生の結果を提供しますが、若干のバイアスがかかっている可能性があります。しかし、その測定値には、キャリブレーションによって適用された修正により飛躍した値がほとんど含まれていません。アプリケーションによっては、滑らかで信頼性が高いということから、これらのキャリブレーションなしの結果を使用する方が良いかもしれません。たとえば、アプリケーションが独自のセンサー融合を試みる場合、キャリブレーションを導入すると実際には結果が歪んでしまいます。

キャリブレーションなしのジャイロスコープは、回転速度の他に、各軸の周りの推定ドリフトを提供します。以下のコードは、デフォルトのキャリブレーションなしのジャイロスコープのインスタンスを取得する方法を示します:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED);

その他のコードサンプル

AccelerometerPlay サンプルAndroid BatchStepSensor サンプルでは、このページで説明した API の使い方をさらに詳しく示します。

関連ドキュメント