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. Android est également dotée d'un capteur permettant de déterminer la distance entre un appareil et un objet (également 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 les 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 l'accéléromètre et le 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 d'intensité du champ géomagnétique pour
chacun des trois axes de coordonnées
lors d'un événement de capteur unique. De même,
de l'accéléromètre mesure l'accélération appliquée à l'appareil
événement du capteur. Pour en savoir plus sur les systèmes de coordonnées utilisés
par capteurs, voir la section
Systèmes de coordonnées des capteurs Le capteur de proximité fournit une valeur unique
pour chaque événement de capteur. Le tableau 1 récapitule les capteurs de position
compatibles avec la plate-forme Android.
Tableau 1. Capteurs de position compatibles avec la plate-forme Android
Capteur | Données des événements des capteurs | Description | Unités de mesure |
---|---|---|---|
TYPE_GAME_ROTATION_VECTOR |
SensorEvent.values[0] |
Composante du vecteur de rotation le long de l'axe des x (x * sin(Percentage/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 le long de 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 étalonnage du fer dur) le long de 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 géomagnétique (sans étalonnage du fer dur) le long de l'axe Z. | ||
SensorEvent.values[3] |
Estimation du biais du fer le long de l'axe des x. | ||
SensorEvent.values[4] |
Estimation du biais du fer le long de l'axe des ordonnées. | ||
SensorEvent.values[5] |
Estimation du biais du fer le long de 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] |
Roulis (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 du capteur offre d'autres méthodes pour acquérir des données de calcul, qui sont abordés dans la section 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 varier même ordre de grandeur que le gyroscope dérive 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 Peu importe l'endroit où se trouve le nord, et le vecteur de rotation normal n'est pas adapté à 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 à vecteur de rotation géomagnétique
Le capteur à vecteur de rotation géomagnétique est similaire capteur à vecteur de rotation, mais il n'utilise pas le gyroscope. La précision de ce capteur est inférieure au vecteur de rotation normale capteur, mais la consommation d'énergie est réduite. N'utilisez ce capteur que si vous souhaitez collecter la rotation en arrière-plan sans consommer 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 vous montre comment calculer le score d'un appareil orientation:
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). C'est l'angle entre la direction actuelle de la boussole 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 de -90 degrés à 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 inclinez le bord gauche de l'appareil vers le sol, l'angle de roulis devient positif. Inclinaison inverse (en déplaçant le bord droit de l'appareil vers le sol) : l'angle de roulis devient négatif. La plage de valeurs est -180 degrés sur 180 degrés.
Remarque:La définition du mouvement du capteur a changé pour refléter pour 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 des abscisses se situe le long du côté le plus long de l'avion, de la queue au nez.
Le capteur d'orientation dérive 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. À cause du poids
le traitement impliqué, la précision et la précision de l'orientation
le capteur est diminué. Plus précisément, ce capteur n'est fiable que lorsque le mouvement
est égal à 0. 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,
utiliser l'getRotationMatrix()
en association avec
Méthode getOrientation()
pour calculer les valeurs d'orientation, comme illustré 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 général, il n'est pas nécessaire d'effectuer un traitement ni un filtrage des données les angles d'orientation bruts de l'appareil autres que la traduction le système de coordonnées au référentiel de votre application.
Utiliser le capteur de champ géomagnétique
Le capteur de champ géomagnétique vous permet de surveiller les variations du champ magnétique terrestre. La Le code suivant vous 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 plus haut, 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 vecteur de rotation
pour déterminer le mouvement de rotation brut, ou vous pouvez utiliser l'accéléromètre et le champ géomagnétique
capteur conjointement 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 calibré
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. Magnétomètre non calibré
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 calibrés fournissent des résultats plus bruts et peuvent incluent un certain biais, mais leurs mesures contiennent moins de sauts provenant des corrections appliquées un étalonnage. Certaines applications peuvent préférer que les résultats non calibrés soient plus fluides et plus fluides 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é permet de déterminer la distance entre un objet et 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 faire apparaître un point clignotant si l'option est activée alors que l'écran est activé.
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 plage maximale à l'état éloigné.
et une valeur inférieure dans l'état proche. Généralement, la valeur "loin" est une valeur > 5 cm, mais cela peut varier
entre les différents capteurs. Vous pouvez déterminer la portée maximale d'un capteur à l'aide de la méthode getMaximumRange()
.