Android プラットフォームには、デバイスの位置を特定できる 2 つのセンサー(地磁気センサーと加速度計)が用意されています。Android プラットフォームには、顔と顔の位置を デバイスと物体(近接センサー)とが接する場所。地磁気センサーと近接センサーはハードウェアベースです。ほとんど 地磁気センサーは、スマートフォンとタブレットのメーカーによって製造されています。同様に、ハンドセットのメーカーは通常、ハンドセットがユーザーの顔に近づいているかどうか(通話中など)を判断する近接センサーを搭載しています。デバイスの向きを特定するには、デバイスの加速度計と地磁気センサーの測定値を使用できます。
注: 向きセンサーは Android 2.2(API レベル 8)で非推奨になり、向きセンサータイプは Android 4.4W(API レベル 20)で非推奨になりました。
位置センサーは、デバイスの物理的な位置の特定に役立ちます。 世界基準の枠組みになりますたとえば、地磁気センサーと加速度計を組み合わせて使用することで、磁北に対するデバイスの位置を特定できます。また、これらのセンサーを使用して、アプリの参照フレーム内でデバイスの向きを特定することもできます。通常、位置センサーは、デバイスの動きやモーション(シェイク、傾斜、スラストなど)のモニタリングには使用されません(詳細については、モーション センサーをご覧ください)。
地磁気センサーと加速度計は、SensorEvent
ごとにセンサー値の多次元配列を返します。たとえば、地磁気センサーは、1 回のセンサイベント中に 3 つの座標軸のそれぞれについて地磁気の強度の値を提供します。同様に
加速度計センサーは、
トリガーされます。センサーで使用される座標系の詳細については、センサーの座標系をご覧ください。近接センサーは、センサーイベントごとに 1 つの値を返します。表 1 に、Android プラットフォームでサポートされている位置センサーの概要を示します。
表 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(θ/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_ORIENTATION 1 |
SensorEvent.values[0] |
方位角(Z 軸を中心とした角度)。 | 度 |
SensorEvent.values[1] |
ピッチ(X 軸を中心とする角度)。 | ||
SensorEvent.values[2] |
ロール(Y 軸周りの角度)。 | ||
TYPE_PROXIMITY |
SensorEvent.values[0] |
オブジェクトからの距離。2 | cm |
1このセンサーは Android 2.2(API)でサポートが終了しました レベル 8 など)、このセンサータイプは Android 4.4W(API レベル 20)でサポートが終了しました。 センサー フレームワークには、デバイスの向きを取得するための代替メソッドが用意されています。詳しくは、デバイスの向きを計算するをご覧ください。
2 一部の近接センサーはバイナリ値しか提供しません。 近距離と遠距離を表します
ゲームの回転ベクトル センサーを使用する
ゲームの回転ベクトル センサーは、 ローテーション ベクトル センサーを使用します。ただし、地磁場は使用しません。したがって、Y 軸は北を指すのではなく、その他の基準を指します。このリファレンスは Z 軸を中心にジャイロスコープがドリフトするのと同程度の大きさです。
ゲーム回転ベクトル センサーは磁場を使用しないため、相対回転は より正確で、磁場の変化の影響を受けません。北の向きが重要ではなく、通常の回転ベクトルが磁場に依存しているためニーズに合わない場合は、ゲームでこのセンサーを使用します。
次のコードは、デフォルトのゲーム回転ベクトル センサーのインスタンスを取得する方法を示しています。
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)
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR);
地磁気回転ベクトル センサーを使用する
地磁気回転ベクトル センサーは回転ベクトル センサーに似ていますが、ジャイロスコープは使用しません。このセンサーの精度は正回転ベクトルよりも低くなっています 消費電力が削減されます。このセンサーは、回転を収集する場合にのみ使用してください バックグラウンドで情報をやり取りできます。このセンサーは、 一括処理と併用できます
次のコードは、デフォルトの地磁気回転ベクトル センサーのインスタンスを取得する方法を示しています。
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)
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR);
デバイスの向きを計算する
デバイスの向きを計算することで、地球の参照フレーム(具体的には磁気北極)に対するデバイスの位置をモニタリングできます。次のコードは、デバイスの IP アドレスを計算する方法を示しています。 向き:
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)
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 度、上端が西を向いている場合、方位角は 270 度です。
- ピッチ(x 軸を中心とする回転数)。これが デバイスの画面に平行な平面と平行な平面がなす角度 着陸します。デバイスの下端を自分側に向けて地面と平行に持ち、デバイスの上端を地面に向けて傾けると、ピッチ角は正の値になります。反対方向に傾斜させる(デバイスの上端を地面から離す)と、ピッチ角度は負になります。値の範囲は -90 度から 90 度です。
- [Roll(y 軸を中心とする回転数)]これは、デバイスの画面に垂直な平面と地面に垂直な平面との間の角度です。デバイスを地面と平行に持つ場合 下端を一番手前に向け、デバイスの左端を傾けます 地面に向かうにつれ、ロール角は正になります。反対に傾斜 (デバイスの右端を地面に向けて移動させる) ロール角が負になります。値の範囲は -180 度です 180 度に設定します。
注: センサーのロール定義が変更され、ジオセンサー エコシステムのほとんどの実装が反映されています。
これらの角度は、 航空機で使用されるもの(ヨー、ピッチ、ロール)があります。航空システムでは、X 軸は飛行機の長辺(テールから機体の先頭まで)に沿って位置づけられます。
方向センサーは、未加工のセンサーデータを処理してデータを取得します。
加速度計と地磁気センサーからのものです大量の
方向性の正確性と精度が記述され、
センサーが小さくなります。具体的には、このセンサーはロールが
0 です。そのため、Android 2.2(API レベル 8)で向きセンサーが非推奨になり、Android 4.4W(API レベル 20)で向きセンサー タイプが非推奨になりました。方向センサーの元データを使用するのではなく、
getRotationMatrix()
を使用する
メソッドを
getOrientation()
メソッド
を使用して向きの値を計算します。次のコードサンプルをご覧ください。このプロセスの一環として、remapCoordinateSystem()
メソッドを使用して、向きの値をアプリの参照フレームに変換できます。
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. } }
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. } }
通常、センサーの座標系をアプリの参照フレームに変換する以外に、デバイスの未加工の向き角度のデータ処理やフィルタリングを行う必要はありません。
地磁気センサーを使用する
地磁気センサーを使用すると、地球の磁場の変化を監視できます。「 次のコードは、デフォルトの地磁気センサーのインスタンスを取得する方法を示しています。
private lateinit var sensorManager: SensorManager private var sensor: Sensor? = null ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
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
注: 未調整のセンサーはより多くの未加工の結果を提示し、バイアスが含まれることもありますが、調整によって適用される修正からの「ジャンプ」も少なくなります。一部のアプリケーションは、これらの未調整の結果を、よりスムーズで信頼性の高いものとして優先的に扱う場合があります。たとえば、アプリケーションが独自のセンサー フュージョンを実行しようとしている場合は、調整によって実際に結果に偏りが生じる可能性があります。
未調整の磁力計は磁場だけでなく 各軸の強鉄バイアスの推定値です。次のコードは、デフォルトの未調整のマグネットメーターのインスタンスを取得する方法を示しています。
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)
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED);
近接センサーを使用する
近接センサーを使用すると、デバイスから対象物までの距離を測定できます。次の デフォルトの近接センサーのインスタンスを取得するコードは次のようになります。
private lateinit var sensorManager: SensorManager private var sensor: Sensor? = null ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
近接センサーは通常、顔から人の頭までの距離を測定するために使用されます。 (たとえば、ユーザーが電話をかけたり着信したりしているときなど)に動作させることができます。ほとんど 近接センサーは絶対距離を cm 単位で返しますが、一部は近接センサーと 使用できます。
注: 一部のデバイスモデルでは、近接センサーは (画面がオンになっているときに有効にした場合、ドットが点滅することがあります)。 オンにします。
次のコードは、近接センサーの使用方法を示しています。
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) } }
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); } }
注: 一部の近接センサーは、値を表すバイナリ値を返します。
「近く」「遠」です。この場合、センサーは通常、遠く離れた状態の最大範囲値と、近くの状態の低い値を報告します。通常、遠方の値は 5 cm を超える値ですが、センサーによって異なります。センサーの最大範囲を特定するには、getMaximumRange()
メソッドを使用します。