La plate-forme Android fournit deux capteurs qui vous permettent de déterminer la position d'un appareil: le capteur de champ géomagnétique et l'accéléromètre. La plate-forme Android fournit également un capteur qui vous permet de déterminer la proximité de la face d'un appareil par rapport à un objet (appelé capteur de proximité). Le capteur de champ géomagnétique et le capteur de proximité sont basés sur du matériel. La plupart des fabricants de téléphones et de tablettes incluent un capteur de champ géomagnétique. De même, les fabricants de téléphones incluent généralement un capteur de proximité pour déterminer si un téléphone est tenu près du visage d'un utilisateur (par exemple, lors d'un appel téléphonique). Pour déterminer l'orientation d'un appareil, vous pouvez utiliser les mesures de l'accéléromètre et du capteur de champ géomagnétique de l'appareil.
Remarque:Le capteur d'orientation a été abandonné dans Android 2.2 (niveau d'API 8) et le type de capteur d'orientation a été abandonné dans Android 4.4W (niveau d'API 20).
Les capteurs de position sont utiles pour déterminer la position physique d'un appareil dans le référentiel mondial. Par exemple, vous pouvez utiliser le capteur de champ géomagnétique en combinaison avec l'accéléromètre pour déterminer la position d'un appareil par rapport au pôle Nord magnétique. Vous pouvez également utiliser ces capteurs pour déterminer l'orientation d'un appareil dans le cadre de référence de votre application. Les capteurs de position ne sont généralement pas utilisés pour surveiller les mouvements de l'appareil, tels que les secousses, l'inclinaison ou la poussée (pour en savoir plus, consultez la section Capteurs de mouvement).
Le capteur de champ géomagnétique et l'accéléromètre renvoient des tableaux multidimensionnels de valeurs de capteur pour chaque SensorEvent
. Par exemple, le capteur de champ géomagnétique fournit des valeurs de champ géomagnétique pour chacun des trois axes de coordonnées lors d'un seul événement de capteur. De même, le capteur d'accéléromètre mesure l'accélération appliquée à l'appareil lors d'un événement de capteur. Pour en savoir plus sur les systèmes de coordonnées utilisés par les capteurs, consultez la section
Systèmes de coordonnées des capteurs. Le capteur de proximité fournit une seule valeur pour chaque événement de capteur. Le tableau 1 récapitule les capteurs de position compatibles avec la plate-forme Android.
Capteur | Données des événements de capteur | Description | Unités de mesure |
---|---|---|---|
TYPE_GAME_ROTATION_VECTOR |
SensorEvent.values[0] |
Composante du vecteur de rotation le long de l'axe X (x * sin(θ/2)). | Sans unité |
SensorEvent.values[1] |
Composante du vecteur de rotation le long de l'axe Y (y * sin(θ/2)). | ||
SensorEvent.values[2] |
Composante du vecteur de rotation le long de l'axe z (z * sin(θ/2)). | ||
TYPE_GEOMAGNETIC_ROTATION_VECTOR |
SensorEvent.values[0] |
Composante du vecteur de rotation le long de l'axe X (x * sin(θ/2)). | Sans unité |
SensorEvent.values[1] |
Composante du vecteur de rotation le long de l'axe Y (y * sin(θ/2)). | ||
SensorEvent.values[2] |
Composante du vecteur de rotation le long de l'axe z (z * sin(θ/2)). | ||
TYPE_MAGNETIC_FIELD |
SensorEvent.values[0] |
Intensité du champ géomagnétique sur l'axe X. | μT |
SensorEvent.values[1] |
Intensité du champ géomagnétique le long de l'axe Y. | ||
SensorEvent.values[2] |
Intensité du champ géomagnétique le long de l'axe Z. | ||
TYPE_MAGNETIC_FIELD_UNCALIBRATED |
SensorEvent.values[0] |
Intensité du champ géomagnétique (sans calibrage du fer dur) sur l'axe X. | μT |
SensorEvent.values[1] |
Intensité du champ magnétique terrestre (sans calibrage du fer dur) sur l'axe Y. | ||
SensorEvent.values[2] |
Intensité du champ magnétique géomagnétique (sans calibrage du fer dur) le long de l'axe Z. | ||
SensorEvent.values[3] |
Estimation du biais de fer sur l'axe X. | ||
SensorEvent.values[4] |
Estimation du biais de fer sur l'axe Y. | ||
SensorEvent.values[5] |
Estimation du biais de fer sur l'axe Z. | ||
TYPE_ORIENTATION 1 |
SensorEvent.values[0] |
Azimut (angle autour de l'axe Z) | Degrés |
SensorEvent.values[1] |
Inclinaison (angle autour de l'axe X) | ||
SensorEvent.values[2] |
Roll (angle autour de l'axe Y) | ||
TYPE_PROXIMITY |
SensorEvent.values[0] |
Distance de l'objet2 | cm |
1Ce capteur a été abandonné dans Android 2.2 (niveau d'API 8) et ce type de capteur a été abandonné dans Android 4.4W (niveau d'API 20). Le framework de capteurs fournit d'autres méthodes d'acquisition de l'orientation de l'appareil, qui sont décrites dans la section Calculer l'orientation de l'appareil.
2 Certains capteurs de proximité ne fournissent que des valeurs binaires représentant la proximité et la distance.
Utiliser le capteur de vecteur de rotation du jeu
Le capteur de vecteur de rotation du jeu est identique au capteur de vecteur de rotation, à l'exception qu'il n'utilise pas le champ géomagnétique. Par conséquent, l'axe Y ne pointe pas vers le nord, mais vers une autre référence. Cette référence peut dériver du même ordre de grandeur que la dérive du gyroscope autour de l'axe Z.
Étant donné que le capteur de vecteur de rotation du jeu n'utilise pas le champ magnétique, les rotations relatives sont plus précises et ne sont pas affectées par les changements du champ magnétique. Utilisez ce capteur dans un jeu si vous ne vous souciez pas de l'emplacement du nord et que le vecteur de rotation normal ne répond pas à vos besoins en raison de sa dépendance au champ magnétique.
Le code suivant montre comment obtenir une instance du capteur de vecteur de rotation de jeu par défaut:
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);
Utiliser le capteur du vecteur de rotation géomagnétique
Le capteur de vecteur de rotation géomagnétique est semblable au capteur de vecteur de rotation, mais il n'utilise pas le gyroscope. La précision de ce capteur est inférieure à celle du capteur de vecteur de rotation normal, mais la consommation d'énergie est réduite. N'utilisez ce capteur que si vous souhaitez collecter des informations de rotation en arrière-plan sans utiliser trop de batterie. Ce capteur est particulièrement utile lorsqu'il est utilisé avec le traitement par lot.
Le code suivant montre comment obtenir une instance du capteur de vecteur de rotation géomagnétique par défaut:
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);
Calculer l'orientation de l'appareil
En calculant l'orientation d'un appareil, vous pouvez surveiller sa position par rapport au référentiel terrestre (plus précisément, au pôle nord magnétique). Le code suivant montre comment calculer l'orientation d'un appareil:
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);
Le système calcule les angles d'orientation à l'aide du capteur de champ géomagnétique de l'appareil en combinaison avec l'accéléromètre de l'appareil. À l'aide de ces deux capteurs matériels, le système fournit des données pour les trois angles d'orientation suivants:
- Azimut (degrés de rotation autour de l'axe -Z). Il s'agit de l'angle entre la direction de la boussole actuelle de l'appareil et le nord magnétique. Si le bord supérieur de l'appareil est orienté vers le nord magnétique, l'azimut est de 0 degrés. Si le bord supérieur est orienté vers le sud, l'azimut est de 180 degrés. De même, si le bord supérieur est orienté vers l'est, l'azimut est de 90 degrés, et si le bord supérieur est orienté vers l'ouest, l'azimut est de 270 degrés.
- Inclinaison (degrés de rotation autour de l'axe X). Il s'agit de l'angle entre un plan parallèle à l'écran de l'appareil et un plan parallèle au sol. Si vous tenez l'appareil parallèlement au sol, le bord inférieur le plus proche de vous et inclinez le bord supérieur de l'appareil vers le sol, l'angle d'inclinaison devient positif. Si vous inclinez l'appareil dans le sens opposé (en éloignant le bord supérieur de l'appareil du sol), l'angle d'inclinaison devient négatif. La plage de valeurs est comprise entre -90 et 90 degrés.
- Inclinaison (degrés de rotation autour de l'axe Y). Il s'agit de l'angle entre un plan perpendiculaire à l'écran de l'appareil et un plan perpendiculaire au sol. Si vous tenez l'appareil parallèlement au sol, avec le bord inférieur le plus proche de vous et que vous inclinez le bord gauche de l'appareil vers le sol, l'angle de roulis devient positif. Si vous inclinez l'appareil dans la direction opposée (en déplaçant le bord droit vers le sol), l'angle de roulis devient négatif. La plage de valeurs est comprise entre -180 et 180 degrés.
Remarque:La définition du roulis du capteur a changé pour refléter la grande majorité des implémentations dans l'écosystème des géocapteurs.
Notez que ces angles reposent sur un système de coordonnées différent de celui utilisé dans l'aviation (pour le lacet, le tangage et le roulis). Dans le système aéronautique, l'axe X se trouve le long du côté long de l'avion, de la queue au nez.
Le capteur d'orientation génère ses données en traitant les données brutes du capteur de l'accéléromètre et du capteur de champ géomagnétique. En raison du traitement lourd impliqué, la précision et la justesse du capteur d'orientation sont diminuées. Plus précisément, ce capteur n'est fiable que lorsque l'angle de roulis est nul. Par conséquent, le capteur d'orientation a été abandonné dans Android 2.2 (niveau d'API 8) et le type de capteur d'orientation a été abandonné dans Android 4.4W (niveau d'API 20).
Au lieu d'utiliser les données brutes du capteur d'orientation, nous vous recommandons d'utiliser la méthode getRotationMatrix()
avec la méthode getOrientation()
pour calculer les valeurs d'orientation, comme indiqué dans l'exemple de code suivant. Dans le cadre de ce processus, vous pouvez utiliser la méthode remapCoordinateSystem()
pour traduire les valeurs d'orientation dans le frame de référence de votre application.
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. } }
En règle générale, vous n'avez pas besoin de traiter ni de filtrer les données des angles d'orientation bruts de l'appareil, sauf pour traduire le système de coordonnées du capteur dans le cadre de référence de votre application.
Utiliser le capteur de champ géomagnétique
Le capteur de champ géomagnétique vous permet de surveiller les changements du champ magnétique terrestre. Le code suivant montre comment obtenir une instance du capteur de champ géomagnétique par défaut:
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);
Remarque : Si votre application cible Android 12 (niveau d'API 31) ou version ultérieure, ce capteur est limité en débit.
Ce capteur fournit des données brutes sur l'intensité du champ (en μT) pour chacun des trois axes de coordonnées.
En règle générale, vous n'avez pas besoin d'utiliser ce capteur directement. À la place, vous pouvez utiliser le capteur de vecteur de rotation pour déterminer le mouvement de rotation brut ou utiliser l'accéléromètre et le capteur de champ géomagnétique en conjonction avec la méthode getRotationMatrix()
pour obtenir la matrice de rotation et la matrice d'inclinaison. Vous pouvez ensuite utiliser ces matrices avec les méthodes getOrientation()
et getInclination()
pour obtenir des données d'azimut et d'inclinaison géomagnétique.
Remarque : Lorsque vous testez votre application, vous pouvez améliorer la précision du capteur en agitant l'appareil en forme de huit.
Utiliser le magnétomètre non étalonné
Le magnétomètre non étalonné est semblable au capteur de champ géomagnétique, à l'exception qu'aucun étalonnage en fer dur n'est appliqué au champ magnétique. Le calibrage d'usine et la compensation de température sont toujours appliqués au champ magnétique. Le magnétomètre non étalonné est utile pour gérer les mauvaises estimations de fer dur. En général, geomagneticsensor_event.values[0]
est proche de uncalibrated_magnetometer_event.values[0] -
uncalibrated_magnetometer_event.values[3]
. C'est-à-dire,
calibrated_x ~= uncalibrated_x - bias_estimate_x
Remarque:Les capteurs non étalonnés fournissent des résultats plus bruts et peuvent inclure un biais, mais leurs mesures contiennent moins de sauts dus aux corrections appliquées lors de l'étalonnage. Certaines applications peuvent préférer ces résultats non étalonnés, car ils sont plus fluides et plus fiables. Par exemple, si une application tente de réaliser sa propre fusion de capteurs, l'introduction de calibrages peut en fait fausser les résultats.
En plus du champ magnétique, le magnétomètre non étalonné fournit également le biais magnétique estimé dans chaque axe. Le code suivant montre comment obtenir une instance du magnétomètre non étalonné par défaut:
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);
Utiliser le capteur de proximité
Le capteur de proximité vous permet de déterminer la distance d'un objet par rapport à un appareil. Le code suivant montre comment obtenir une instance du capteur de proximité par défaut:
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);
Le capteur de proximité est généralement utilisé pour déterminer la distance entre la tête d'une personne et la face d'un appareil de téléphonie (par exemple, lorsqu'un utilisateur passe ou reçoit un appel téléphonique). La plupart des capteurs de proximité renvoient la distance absolue, en cm, mais certains ne renvoient que des valeurs proches et éloignées.
Remarque:Sur certains modèles d'appareils, le capteur de proximité se trouve sous l'écran, ce qui peut entraîner l'affichage d'un point clignotant sur l'écran s'il est activé lorsque l'écran est allumé.
Le code suivant montre comment utiliser le capteur de proximité:
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); } }
Remarque:Certains capteurs de proximité renvoient des valeurs binaires qui représentent "proche" ou "loin". Dans ce cas, le capteur indique généralement sa valeur de portée maximale dans l'état "loin" et une valeur inférieure dans l'état "proche". En règle générale, la valeur "loin" est supérieure à 5 cm, mais elle peut varier d'un capteur à l'autre. Vous pouvez déterminer la portée maximale d'un capteur à l'aide de la méthode getMaximumRange()
.