位置センサー

Android プラットフォームには、位置を測定するためのセンサーが 2 つあります。 地磁気センサーと加速度計ですAndroid プラットフォームには、顔と顔の位置を デバイスと物体(近接センサー)とが接する位置。「 地磁場センサーと近接センサーはハードウェアベースです。ほとんど 地磁気センサーは、スマートフォンとタブレットのメーカーによって製造されています。同様に メーカーは通常、近接センサーを搭載しており、 ユーザーの顔に手を近づけているとき(電話時など) 。デバイスの向きを判断するには、 デバイスの加速度計と地磁気センサーが含まれます

注: 方向センサーは Android 2.2 でサポートが終了しました。 (API レベル 8)をサポートし、方向センサーのタイプは Android 4.4W でサポートが終了しました。 (API レベル 20)。

位置センサーは、デバイスの物理的な位置の特定に役立ちます。 世界基準の枠組みになりますたとえば、地磁気を使用して センサーと加速度計を組み合わせて、デバイスの位置を特定します 磁気北極を基準としますこれらのセンサーを使用して 方向は、アプリの参照フレーム内でのデバイスの向きを決定します。 通常、位置センサーはデバイスの動きや動きの監視には使用されず、 (詳しくは、モーション センサーをご覧ください)。

地磁気センサーと加速度計が多次元の配列を返す 各 SensorEvent に対するセンサー値の数。たとえば 地磁気センサーは、地磁気の強さの値を 3 つの座標軸のそれぞれについて、1 つのセンサー イベントで表します。同様に 加速度計センサーは、 トリガーされます。使用される座標系について詳しくは、 については、をご覧ください。 センサー座標系。近接センサーは、各センサーで センサーイベントごとに生成されます表 1 は、Google Pixel に組み込まれている サポートしています。

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

センサー センサー イベント データ 説明 測定単位
TYPE_GAME_ROTATION_VECTOR SensorEvent.values[0] x 軸に沿った回転ベクトル成分(x × sin(サー/2))。 単位なし
SensorEvent.values[1] y 軸に沿った回転ベクトルの成分(y * sin(q/2))。
SensorEvent.values[2] z 軸に沿った回転ベクトル成分(z × sin(z/2))。
TYPE_GEOMAGNETIC_ROTATION_VECTOR SensorEvent.values[0] x 軸に沿った回転ベクトル成分(x × sin(サー/2))。 単位なし
SensorEvent.values[1] y 軸に沿った回転ベクトルの成分(y * sin(q/2))。
SensorEvent.values[2] z 軸に沿った回転ベクトル成分(z × sin(z/2))。
TYPE_MAGNETIC_FIELD SensorEvent.values[0] x 軸に沿った地磁場の強さ。 μT
SensorEvent.values[1] y 軸に沿った地磁場の強さ。
SensorEvent.values[2] z 軸に沿った地磁場の強さ。
TYPE_MAGNETIC_FIELD_UNCALIBRATED SensorEvent.values[0] x 軸に沿った地磁場の強さ(強鉄によるキャリブレーションなし)。 μT
SensorEvent.values[1] y 軸に沿った地磁場の強さ(強鉄によるキャリブレーションなし)。
SensorEvent.values[2] z 軸に沿った地磁場の強さ(硬い鉄によるキャリブレーションなし)。
SensorEvent.values[3] x 軸に沿った鉄バイアスの推定。
SensorEvent.values[4] y 軸に沿った鉄バイアスの推定。
SensorEvent.values[5] z 軸に沿った鉄バイアスの推定。
TYPE_ORIENTATION1 SensorEvent.values[0] 方位角(Z 軸を中心とした角度)。
SensorEvent.values[1] ピッチ(X 軸を中心とする角度)。
SensorEvent.values[2] Roll(Y 軸を中心とする角度)
TYPE_PROXIMITY SensorEvent.values[0] 対象物からの距離2 cm

1このセンサーは Android 2.2(API)でサポートが終了しました レベル 8 など)、このセンサータイプは Android 4.4W(API レベル 20)でサポートが終了しました。 センサー フレームワークがデバイスを取得するための代替メソッドを提供する 詳しくは、Compute Engine デバイスの向きに応じて異なります

2 一部の近接センサーはバイナリ値しか提供しません。 近距離と遠距離を表します

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

ゲームの回転ベクトル センサーは、 ローテーション ベクトル センサーを使用します。ただし、地磁場は使用しません。そのため Y 軸は 北を指していますが、代わりに他の基準を指します。このリファレンスは Z 軸を中心にジャイロスコープがドリフトするのと同程度の大きさです。

ゲーム回転ベクトル センサーは磁場を使用しないため、相対回転は より正確で、磁場の変化の影響を受けません。次の場合にこのセンサーをゲームで使用する 北がどの位置にあるかは考慮されず、正回転ベクトルはニーズに合わない なぜなら 磁場に依存しているからです

次のコードは、デフォルトのゲーム回転ベクトルのインスタンスを取得する方法を示しています。 sensor:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR)

Java

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

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

地磁気回転ベクトル センサーは、 回転ベクトルセンサーですが、 ジャイロスコープは使用していませんこのセンサーの精度は正回転ベクトルよりも低くなっています 消費電力が削減されます。このセンサーは、回転を収集する場合にのみ使用してください バックグラウンドで情報をやり取りできます。このセンサーは、 一括処理と併用できます

次のコードは、デフォルトの地磁気回転のインスタンスを取得する方法を示しています。 ベクトル センサー:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR)

Java

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

デバイスの向きを計算する

デバイスの向きを計算することで、デバイスの向きを 地球の基準フレーム(具体的には、 北極)。次のコードは、デバイスの IP アドレスを 向き:

Kotlin

private lateinit var sensorManager: SensorManager
...
// Rotation matrix based on current readings from accelerometer and magnetometer.
val rotationMatrix = FloatArray(9)
SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerReading, magnetometerReading)

// Express the updated rotation matrix as three orientation angles.
val orientationAngles = FloatArray(3)
SensorManager.getOrientation(rotationMatrix, orientationAngles)

Java

private SensorManager sensorManager;
...
// Rotation matrix based on current readings from accelerometer and magnetometer.
final float[] rotationMatrix = new float[9];
SensorManager.getRotationMatrix(rotationMatrix, null,
    accelerometerReading, magnetometerReading);

// Express the updated rotation matrix as three orientation angles.
final float[] orientationAngles = new float[3];
SensorManager.getOrientation(rotationMatrix, orientationAngles);

向きの角度は、デバイスの地磁気を使用して フィールド センサーとデバイスの加速度計の組み合わせ。これら 2 つの ハードウェア センサーを使用すると、システムは次の 3 つの 方位角:

  • 方位角(-z 軸を中心とした回転度)。これは、 デバイスの現在のコンパス方向と磁北がなす角度。 デバイスの上端が磁北を向いている場合、方位角は 0 になります。 度上端が南を向いている場合、方位角は 180 度です。同様に 上端が東を向いている場合は方位角が 90 度、上端が東を向いている場合は方位角は 90 度です。 西を向き、方位角は 270 度です。
  • ピッチ(x 軸を中心とする回転数)。これが デバイスの画面に平行な平面と平行な平面がなす角度 着陸します。デバイスを地面と平行にして、 デバイスの上端を地面に向けて傾けます。 傾斜角が正になります。反対方向に傾斜 - デバイスの上端が地面から離されると、 ピッチ角が負になるように調整します値の範囲は -90 度から 90 度。
  • [Roll(y 軸を中心とする回転数)]これが デバイスの画面に垂直な平面と 地面に対して垂直です。デバイスを地面と平行に持つ場合 下端を一番手前に向け、デバイスの左端を傾けます 地面に向かうにつれ、ロール角は正になります。反対に傾斜 (デバイスの右端を地面に向けて移動させる) ロール角度が負になります。値の範囲は -180 度です 180 度に設定します。

注: センサーのロールの定義は、 実装の大多数を占めています

これらの角度は、 航空機で使用されるもの(ヨー、ピッチ、ロール用)です。航空システムでは x 軸は面の長辺に沿って、尾から鼻までの長さです。

方向センサーは、未加工のセンサーデータを処理してデータを取得します。 加速度計と地磁気センサーからのものです大量の 方向性の正確性と精度が記述されており、 センサーが小さくなります。具体的には、このセンサーはロールが 0 です。そのため、Android で方向センサーのサポートは終了しました。 2.2(API レベル 8)をサポートし、方位センサーのタイプは Android で非推奨になりました 4.4W(API レベル 20)です。 方向センサーの元データを使用する代わりに、 getRotationMatrix() を使用する メソッドを getOrientation() メソッド を使用して向きの値を計算します。次のコードサンプルをご覧ください。構成要素として 使用したい場合は、 remapCoordinateSystem() メソッドを使用して、画面の向きの値をアプリケーションのフレーム ご覧ください。

Kotlin

class SensorActivity : Activity(), SensorEventListener {

    private lateinit var sensorManager: SensorManager
    private val accelerometerReading = FloatArray(3)
    private val magnetometerReading = FloatArray(3)

    private val rotationMatrix = FloatArray(9)
    private val orientationAngles = FloatArray(3)

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        // Do something here if sensor accuracy changes.
        // You must implement this callback in your code.
    }

    override fun onResume() {
        super.onResume()

        // Get updates from the accelerometer and magnetometer at a constant rate.
        // To make batch operations more efficient and reduce power consumption,
        // provide support for delaying updates to the application.
        //
        // In this example, the sensor reporting delay is small enough such that
        // the application receives an update before the system checks the sensor
        // readings again.
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)?.also { accelerometer ->
            sensorManager.registerListener(
                    this,
                    accelerometer,
                    SensorManager.SENSOR_DELAY_NORMAL,
                    SensorManager.SENSOR_DELAY_UI
            )
        }
        sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)?.also { magneticField ->
            sensorManager.registerListener(
                    this,
                    magneticField,
                    SensorManager.SENSOR_DELAY_NORMAL,
                    SensorManager.SENSOR_DELAY_UI
            )
        }
    }

    override fun onPause() {
        super.onPause()

        // Don't receive any more updates from either sensor.
        sensorManager.unregisterListener(this)
    }

    // Get readings from accelerometer and magnetometer. To simplify calculations,
    // consider storing these readings as unit vectors.
    override fun onSensorChanged(event: SensorEvent) {
        if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
            System.arraycopy(event.values, 0, accelerometerReading, 0, accelerometerReading.size)
        } else if (event.sensor.type == Sensor.TYPE_MAGNETIC_FIELD) {
            System.arraycopy(event.values, 0, magnetometerReading, 0, magnetometerReading.size)
        }
    }

    // Compute the three orientation angles based on the most recent readings from
    // the device's accelerometer and magnetometer.
    fun updateOrientationAngles() {
        // Update rotation matrix, which is needed to update orientation angles.
        SensorManager.getRotationMatrix(
                rotationMatrix,
                null,
                accelerometerReading,
                magnetometerReading
        )

        // "rotationMatrix" now has up-to-date information.

        SensorManager.getOrientation(rotationMatrix, orientationAngles)

        // "orientationAngles" now has up-to-date information.
    }
}

Java

public class SensorActivity extends Activity implements SensorEventListener {

    private SensorManager sensorManager;
    private final float[] accelerometerReading = new float[3];
    private final float[] magnetometerReading = new float[3];

    private final float[] rotationMatrix = new float[9];
    private final float[] orientationAngles = new float[3];

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something here if sensor accuracy changes.
        // You must implement this callback in your code.
    }

    @Override
    protected void onResume() {
        super.onResume();

        // Get updates from the accelerometer and magnetometer at a constant rate.
        // To make batch operations more efficient and reduce power consumption,
        // provide support for delaying updates to the application.
        //
        // In this example, the sensor reporting delay is small enough such that
        // the application receives an update before the system checks the sensor
        // readings again.
        Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (accelerometer != null) {
            sensorManager.registerListener(this, accelerometer,
                SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
        }
        Sensor magneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        if (magneticField != null) {
            sensorManager.registerListener(this, magneticField,
                SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        // Don't receive any more updates from either sensor.
        sensorManager.unregisterListener(this);
    }

    // Get readings from accelerometer and magnetometer. To simplify calculations,
    // consider storing these readings as unit vectors.
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
          System.arraycopy(event.values, 0, accelerometerReading,
              0, accelerometerReading.length);
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            System.arraycopy(event.values, 0, magnetometerReading,
                0, magnetometerReading.length);
        }
    }

    // Compute the three orientation angles based on the most recent readings from
    // the device's accelerometer and magnetometer.
    public void updateOrientationAngles() {
        // Update rotation matrix, which is needed to update orientation angles.
        SensorManager.getRotationMatrix(rotationMatrix, null,
            accelerometerReading, magnetometerReading);

        // "rotationMatrix" now has up-to-date information.

        SensorManager.getOrientation(rotationMatrix, orientationAngles);

        // "orientationAngles" now has up-to-date information.
    }
}

通常、データの処理やフィルタリングを行う必要は センサーの向きの変換のほかに、デバイスの 座標系をアプリケーションの参照フレームに追加します。

地磁気センサーを使用する

地磁気センサーを使用すると、地球の磁場の変化を監視できます。「 次のコードは、デフォルトの地磁気センサーのインスタンスを取得する方法を示しています。

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)

Java

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

注: アプリが Android 12(API レベル 31)または このセンサーは レート制限される。

このセンサーは、3 つの座標軸のそれぞれについて、電界強度の元データ(μT)を提供します。 通常、このセンサーを直接使用する必要はありません。代わりに回転ベクトルを センサーを使って未加工の回転動きを特定することも、加速度計や地磁場を センサーを getRotationMatrix() メソッドと組み合わせて使用し、回転行列と傾斜行列を取得します。その後、 これらの行列を getOrientation() で使う 方位角を取得する getInclination() メソッド 地磁気傾斜データなどです

注: アプリをテストすることで、 8 の字にデバイスを振ることでセンサーの精度を高めます。

未調整の磁力計を使用する

未調整の磁力計は地球磁場に似ている センサーで測定します。ただし、磁場に硬い鉄による調整は適用されていません。工場での調整 温度補正は依然として磁場に適用されます。未調整の磁力計 は、不正な鉄鋼推定の処理に有用です。一般的に、geomagneticsensor_event.values[0] uncalibrated_magnetometer_event.values[0] - uncalibrated_magnetometer_event.values[3] に近くなります。つまり

calibrated_x ~= uncalibrated_x - bias_estimate_x

注: 未調整のセンサーでは、未加工の結果が多く得られるため、 バイアスはある程度含まれますが、測定値には、適用された修正からのジャンプが少なくなります。 調整します。アプリケーションによっては、未調整の結果がよりスムーズでわかりやすいものとして好まれる場合があります。 実現しますたとえば、アプリが独自のセンサー フュージョンを実行しようとしている場合、 調整を加えると 実際の結果がゆがむ可能性があります

未調整の磁力計は磁場だけでなく 各軸の強鉄バイアスの推定値です。次のコードは、 未調整のデフォルト磁力計:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED)

Java

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

近接センサーを使用する

近接センサーを使用すると、デバイスから対象物までの距離を測定できます。次の デフォルトの近接センサーのインスタンスを取得するコードは次のようになります。

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)

Java

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

近接センサーは通常、顔から人の頭までの距離を測定するために使用されます。 (たとえば、ユーザーが電話をかけたり受けたりしているときなど)。ほとんど 近接センサーは絶対距離を cm 単位で返しますが、一部は近接センサーと 使用できます。

注: 一部のデバイスモデルでは、近接センサーは (画面がオンになっているときに有効にした場合、ドットが点滅することがあります)。 オンにします。

次のコードは、近接センサーの使用方法を示しています。

Kotlin

class SensorActivity : Activity(), SensorEventListener {

    private lateinit var sensorManager: SensorManager
    private var proximity: Sensor? = null

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)

        // Get an instance of the sensor service, and use that to get an instance of
        // a particular sensor.
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        proximity = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        // Do something here if sensor accuracy changes.
    }

    override fun onSensorChanged(event: SensorEvent) {
        val distance = event.values[0]
        // Do something with this sensor data.
    }

    override fun onResume() {
        // Register a listener for the sensor.
        super.onResume()

        proximity?.also { proximity ->
            sensorManager.registerListener(this, proximity, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

    override fun onPause() {
        // Be sure to unregister the sensor when the activity pauses.
        super.onPause()
        sensorManager.unregisterListener(this)
    }
}

Java

public class SensorActivity extends Activity implements SensorEventListener {
    private SensorManager sensorManager;
    private Sensor proximity;

    @Override
    public final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Get an instance of the sensor service, and use that to get an instance of
        // a particular sensor.
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        proximity = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
    }

    @Override
    public final void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something here if sensor accuracy changes.
    }

    @Override
    public final void onSensorChanged(SensorEvent event) {
        float distance = event.values[0];
        // Do something with this sensor data.
    }

    @Override
    protected void onResume() {
        // Register a listener for the sensor.
        super.onResume();
        sensorManager.registerListener(this, proximity, SensorManager.SENSOR_DELAY_NORMAL);
      }

    @Override
    protected void onPause() {
        // Be sure to unregister the sensor when the activity pauses.
        super.onPause();
        sensorManager.unregisterListener(this);
    }
}

注: 一部の近接センサーは、値を表すバイナリ値を返します。 「近く」「遠」です。この場合、センサーは通常、遠く離れた状態で最大範囲の値をレポートします。 近似状態では小さい値になります。通常、far 値は >5 cm(変動の可能性あり) 比較できます。センサーの最大範囲を特定するには、getMaximumRange() メソッドを使用します。

関連ドキュメント