モーション センサー

Android プラットフォームには、デバイスの動きをモニタリングできるセンサーがいくつか用意されています。

センサーの可能なアーキテクチャは、センサーの種類によって異なります。

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

ほとんどの Android 搭載デバイスには加速度計が搭載されており、現在では多くのデバイスにジャイロスコープが搭載されています。ソフトウェア ベースのセンサーは、多くの場合、1 つ以上のハードウェア センサーに依存してデータを取得するため、可用性はより変動します。デバイスによっては、これらのソフトウェア ベースのセンサーは、加速度計と磁力計、またはジャイロスコープからデータを取得できます。

モーション センサーは、傾き、揺れ、回転、スイングなど、デバイスの動きをモニタリングするのに役立ちます。通常、この動きはユーザーの直接入力(ゲームで車を運転する、ゲームでボールをコントロールするなど)を反映したものですが、デバイスが置かれている物理環境(車を運転しているときに一緒に移動するなど)を反映したものである場合もあります。最初のケースでは、デバイスの基準座標系またはアプリの基準座標系を基準として動きをモニタリングします。2 番目のケースでは、世界の基準座標系を基準として動きをモニタリングします。通常、モーション センサーは単独ではデバイスの位置のモニタリングに使用されませんが、地磁気センサーなどの他のセンサーと組み合わせて使用することで、世界の基準座標系に対するデバイスの位置を特定できます(詳細については、位置センサーをご覧ください)。

すべてのモーション センサーは、各 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 スカラー コンポーネントはオプションの値です。

回転ベクトル センサーと重力センサーは、モーションの検出とモニタリングに最もよく使用されるセンサーです。回転ベクトル センサーは特に汎用性が高く、ジェスチャーの検出、角度変化のモニタリング、相対的な向きの変化のモニタリングなど、幅広いモーション関連のタスクに使用できます。たとえば、回転ベクトル センサーは、ゲーム、拡張現実アプリ、2 次元または 3 次元のコンパス、カメラの手ぶれ補正アプリを開発する場合に最適です。ほとんどの場合、これらのセンサーを使用する方が、加速度計と地磁気センサーまたは向きセンサーを使用するよりも適しています。

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

Android オープンソース プロジェクト(AOSP)には、重力センサー、直線加速度センサー、回転ベクトル センサーという 3 つのソフトウェア ベースのモーション センサーが用意されています。これらのセンサーは Android 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 をご覧ください。

重大なモーション センサーを使用する

重大なモーション センサーは、重大な動きが検出されるたびにイベントをトリガーし、その後、自身を無効にします。大きなモーションとは、ユーザーの位置情報の変化につながる可能性のあるモーションです。たとえば、歩行、自転車、移動中の車内での着席などです。次のコードは、デフォルトの重大なモーション センサーのインスタンスを取得する方法と、イベント リスナーを登録する方法を示しています。

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 レベル 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 クラスを使用して、歩数計センサーから現在の値を特定の間隔で取得する必要があります。アプリの種類によって必要なセンサー読み取り間隔は異なりますが、アプリがセンサーからのリアルタイム データを必要としない限り、この間隔はできるだけ長くする必要があります。

歩行検出センサーを使用する

歩数検出センサーは、ユーザーが歩くたびにイベントをトリガーします。レイテンシは 2 秒未満になると予想されます。

注: Android 10(API レベル 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);

注: アプリが Android 12(API レベル 31)以降をターゲットとしている場合、このセンサーはレート制限されます。

概念的には、加速度センサーは、次の関係を使用してセンサー自体に適用される力(Fs)を測定することで、デバイスに適用される加速度(Ad)を決定します。

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];
}

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

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

  • デバイスの左側を押すと(右に移動すると)、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 搭載のハンドセットとタブレットには加速度計が搭載されており、他のモーション センサーよりも消費電力が約 10 分の 1 に抑えられています。欠点としては、重力を排除してノイズを低減するために、ローパス フィルタとハイパス フィルタを実装しなければならない場合があることです。

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

ジャイロスコープは、デバイスの 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);

注: アプリが Android 12(API レベル 31)以降をターゲットとしている場合、このセンサーはレート制限されます。

センサーの座標系は、加速度センサーで使用される座標系と同じです。回転は反時計回りの方向で正になります。つまり、x 軸、y 軸、z 軸の正の位置から原点に置かれたデバイスを見ている観測者は、デバイスが反時計回りに回転しているように見える場合、正の回転を報告します。これは、正の回転の標準的な数学的定義であり、方向センサーで使用されるロールの定義とは異なります。

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

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);

その他のコードサンプル

このページで説明した API の使用方法の他の例については、BatchStepSensor サンプルをご覧ください。

関連ドキュメント