Capteurs pour le Web

Utilisez l'API Generic Sensor pour accéder aux capteurs de l'appareil, tels que les accéléromètres, les gyroscopes et les magnétomètres.

Alex Shalamov
Alex Shalamov
Mikhail Pozdnyakov
Mikhail Pozdnyakov

Aujourd'hui, les données des capteurs sont utilisées dans de nombreuses applications spécifiques à une plate-forme pour permettre des cas d'utilisation tels que les jeux immersifs, le suivi de la forme physique et la réalité augmentée ou virtuelle. Ne serait-il pas intéressant de combler le fossé entre les applications spécifiques à une plate-forme et les applications Web ? Saisissez l'API Generic Sensor pour le Web.

Qu'est-ce que l'API Generic Sensor ?

L'API Generic Sensor est un ensemble d'interfaces qui exposent les capteurs à la plate-forme Web. L'API se compose de l'interface de base Sensor et d'un ensemble de classes de capteurs concrètes construites par-dessus. L'utilisation d'une interface de base simplifie le processus d'implémentation et de spécification pour les classes de capteurs concrètes. Par exemple, examinez la classe Gyroscope. Il est minuscule ! La fonctionnalité principale est spécifiée par l'interface de base, et Gyroscope se contente de l'étendre avec trois attributs représentant la vitesse angulaire.

Certaines classes de capteurs interagissent avec des capteurs matériels réels, comme les classes d'accéléromètre ou de gyroscope. Il s'agit de capteurs de bas niveau. D'autres capteurs, appelés capteurs de fusion, fusionnent les données de plusieurs capteurs de bas niveau pour exposer des informations qu'un script devrait autrement calculer. Par exemple, le capteur AbsoluteOrientation fournit une matrice de rotation quatre par quatre prête à l'emploi, basée sur les données obtenues à partir de l'accéléromètre, du gyroscope et du magnétomètre.

Vous pensez peut-être que la plate-forme Web fournit déjà des données de capteurs, et vous avez tout à fait raison. Par exemple, les événements DeviceMotion et DeviceOrientation exposent les données du détecteur de mouvement. Alors pourquoi avons-nous besoin d'une nouvelle API ?

Par rapport aux interfaces existantes, l'API Generic Sensor offre de nombreux avantages :

  • L'API Generic Sensor est un framework de capteurs qui peut être facilement étendu avec de nouvelles classes de capteurs. Chacune de ces classes conservera l'interface générique. Le code client écrit pour un type de capteur peut être réutilisé pour un autre type avec très peu de modifications.
  • Vous pouvez configurer le capteur. Par exemple, vous pouvez définir la fréquence d'échantillonnage adaptée aux besoins de votre application.
  • Vous pouvez détecter si un capteur est disponible sur la plate-forme.
  • Les lectures des capteurs sont associées à des codes temporels de haute précision, ce qui permet une meilleure synchronisation avec d'autres activités de votre application.
  • Les modèles de données de capteurs et les systèmes de coordonnées sont clairement définis, ce qui permet aux fournisseurs de navigateurs d'implémenter des solutions interopérables.
  • Les interfaces basées sur le capteur générique ne sont pas liées au DOM (ce qui signifie qu'elles ne sont ni des objets navigator ni des objets window). Cela ouvre de nouvelles possibilités d'utilisation de l'API dans les service workers ou de son implémentation dans des runtimes JavaScript sans interface graphique, tels que les appareils embarqués.
  • Les aspects liés à la sécurité et à la confidentialité sont la priorité absolue de l'API Generic Sensor, qui offre une sécurité bien meilleure que les anciennes API Sensor. L'API Permissions est intégrée.
  • La synchronisation automatique avec les coordonnées de l'écran est disponible pour Accelerometer, Gyroscope, LinearAccelerationSensor, AbsoluteOrientationSensor, RelativeOrientationSensor et Magnetometer.

API de capteur génériques disponibles

Au moment de la rédaction de cet article, vous pouvez tester plusieurs capteurs.

Capteurs de mouvement :

  • Accelerometer
  • Gyroscope
  • LinearAccelerationSensor
  • AbsoluteOrientationSensor
  • RelativeOrientationSensor
  • GravitySensor

Capteurs d'environnement :

  • AmbientLightSensor (Derrière le flag #enable-generic-sensor-extra-classes dans Chromium)
  • Magnetometer (Derrière le flag #enable-generic-sensor-extra-classes dans Chromium)

Détection de fonctionnalités

La détection des fonctionnalités des API matérielles est délicate, car vous devez détecter à la fois si le navigateur est compatible avec l'interface en question et si l'appareil dispose du capteur correspondant. Il est facile de vérifier si le navigateur est compatible avec une interface. (Remplacez Accelerometer par l'une des autres interfaces mentionnées ci-dessus.)

if ('Accelerometer' in window) {
  // The `Accelerometer` interface is supported by the browser.
  // Does the device have an accelerometer, though?
}

Pour obtenir un résultat de détection de fonctionnalité réellement significatif, vous devez également essayer de vous connecter au capteur. L'exemple suivant montre comment procéder.

let accelerometer = null;
try {
  accelerometer = new Accelerometer({ frequency: 10 });
  accelerometer.onerror = (event) => {
    // Handle runtime errors.
    if (event.error.name === 'NotAllowedError') {
      console.log('Permission to access sensor was denied.');
    } else if (event.error.name === 'NotReadableError') {
      console.log('Cannot connect to the sensor.');
    }
  };
  accelerometer.onreading = (e) => {
    console.log(e);
  };
  accelerometer.start();
} catch (error) {
  // Handle construction errors.
  if (error.name === 'SecurityError') {
    console.log('Sensor construction was blocked by the Permissions Policy.');
  } else if (error.name === 'ReferenceError') {
    console.log('Sensor is not supported by the User Agent.');
  } else {
    throw error;
  }
}

Polyfill

Un polyfill est disponible pour les navigateurs qui ne sont pas compatibles avec l'API Generic Sensor. Le polyfill vous permet de charger uniquement les implémentations des capteurs concernés.

// Import the objects you need.
import { Gyroscope, AbsoluteOrientationSensor } from './src/motion-sensors.js';

// And they're ready for use!
const gyroscope = new Gyroscope({ frequency: 15 });
const orientation = new AbsoluteOrientationSensor({ frequency: 60 });

Que sont tous ces capteurs ? Comment puis-je les utiliser ?

Les capteurs sont un domaine qui peut nécessiter une brève introduction. Si vous connaissez déjà les capteurs, vous pouvez passer directement à la section pratique sur le codage. Sinon, examinons chaque capteur compatible en détail.

Accéléromètre et capteur d'accélération linéaire

Mesures du capteur d'accéléromètre

Le capteur Accelerometer mesure l'accélération d'un appareil hébergeant le capteur sur trois axes (X, Y et Z). Ce capteur est un capteur inertiel, ce qui signifie que lorsque l'appareil est en chute libre linéaire, l'accélération totale mesurée est de 0 m/s2. Lorsqu'un appareil est posé à plat sur une table, l'accélération vers le haut (axe Z) est égale à la gravité terrestre, c'est-à-dire g ≈ +9,8 m/s2, car elle mesure la force de la table qui pousse l'appareil vers le haut. Si vous poussez l'appareil vers la droite, l'accélération sur l'axe X sera positive, ou négative si l'appareil est accéléré de la droite vers la gauche.

Les accéléromètres peuvent être utilisés pour des tâches telles que le comptage de pas, la détection de mouvement ou l'orientation simple de l'appareil. Les mesures de l'accéléromètre sont souvent combinées à des données provenant d'autres sources pour créer des capteurs de fusion, tels que les capteurs d'orientation.

LinearAccelerationSensor mesure l'accélération appliquée à l'appareil hébergeant le capteur, à l'exclusion de la contribution de la gravité. Lorsqu'un appareil est au repos, par exemple à plat sur une table, le capteur mesure une accélération d'environ 0 m/s2 sur trois axes.

Capteur de gravité

Les utilisateurs peuvent déjà déduire manuellement des valeurs proches de celles d'un capteur de gravité en inspectant manuellement les valeurs Accelerometer et LinearAccelerometer, mais cela peut être fastidieux et dépendre de la précision des valeurs fournies par ces capteurs. Des plates-formes telles qu'Android peuvent fournir des lectures de gravité dans le système d'exploitation. Cela devrait être moins coûteux en termes de calcul, fournir des valeurs plus précises en fonction du matériel de l'utilisateur et être plus facile à utiliser en termes d'ergonomie de l'API. GravitySensor renvoie l'effet de l'accélération le long des axes X, Y et Z de l'appareil en raison de la gravité.

Gyroscope

Mesures du capteur gyroscope

Le capteur Gyroscope mesure la vitesse angulaire en radians par seconde autour des axes X, Y et Z locaux de l'appareil. La plupart des appareils grand public sont équipés de gyroscopes mécaniques (MEMS), qui sont des capteurs inertiels mesurant la vitesse de rotation en fonction de la force de Coriolis inertielle. Les gyroscopes MEMS sont sujets à la dérive causée par la sensibilité du capteur à la gravité, qui déforme le système mécanique interne du capteur. Les gyroscopes oscillent à des fréquences relativement élevées, par exemple, dizaines de kHz et, par conséquent, peut consommer plus d'énergie que d'autres capteurs.

Capteurs d'orientation

Mesures du capteur d'orientation absolue

AbsoluteOrientationSensor est un capteur de fusion qui mesure la rotation d'un appareil par rapport au système de coordonnées de la Terre, tandis que RelativeOrientationSensor fournit des données représentant la rotation d'un appareil hébergeant des capteurs de mouvement par rapport à un système de coordonnées de référence fixe.

Tous les frameworks JavaScript 3D modernes sont compatibles avec les quaternions et les matrices de rotation pour représenter la rotation. Toutefois, si vous utilisez WebGL directement, OrientationSensor dispose à la fois d'une propriété quaternion et d'une méthode populateMatrix(). Voici quelques extraits :

three.js

let torusGeometry = new THREE.TorusGeometry(7, 1.6, 4, 3, 6.3);
let material = new THREE.MeshBasicMaterial({ color: 0x0071c5 });
let torus = new THREE.Mesh(torusGeometry, material);
scene.add(torus);

// Update mesh rotation using quaternion.
const sensorAbs = new AbsoluteOrientationSensor();
sensorAbs.onreading = () => torus.quaternion.fromArray(sensorAbs.quaternion);
sensorAbs.start();

// Update mesh rotation using rotation matrix.
const sensorRel = new RelativeOrientationSensor();
let rotationMatrix = new Float32Array(16);
sensor_rel.onreading = () => {
  sensorRel.populateMatrix(rotationMatrix);
  torus.matrix.fromArray(rotationMatrix);
};
sensorRel.start();

BABYLON

const mesh = new BABYLON.Mesh.CreateCylinder('mesh', 0.9, 0.3, 0.6, 9, 1, scene);
const sensorRel = new RelativeOrientationSensor({ frequency: 30 });
sensorRel.onreading = () => mesh.rotationQuaternion.FromArray(sensorRel.quaternion);
sensorRel.start();

WebGL

// Initialize sensor and update model matrix when new reading is available.
let modMatrix = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
const sensorAbs = new AbsoluteOrientationSensor({ frequency: 60 });
sensorAbs.onreading = () => sensorAbs.populateMatrix(modMatrix);
sensorAbs.start();

// Somewhere in rendering code, update vertex shader attribute for the model
gl.uniformMatrix4fv(modMatrixAttr, false, modMatrix);

Les capteurs d'orientation permettent différents cas d'utilisation, tels que les jeux immersifs, la réalité augmentée et la réalité virtuelle.

Pour en savoir plus sur les capteurs de mouvement, les cas d'utilisation avancés et les exigences, consultez le document Explication sur les capteurs de mouvement.

Synchronisation avec les coordonnées de l'écran

Par défaut, les lectures des capteurs spatiaux sont résolues dans un système de coordonnées local lié à l'appareil et ne tiennent pas compte de l'orientation de l'écran.

Système de coordonnées de l'appareil
Système de coordonnées de l'appareil

Toutefois, de nombreux cas d'utilisation, comme les jeux ou la réalité augmentée et virtuelle, nécessitent que les lectures de capteurs soient résolues dans un système de coordonnées lié à l'orientation de l'écran.

Système de coordonnées de l'écran
Système de coordonnées de l'écran

Auparavant, le remappage des lectures de capteurs en coordonnées d'écran devait être implémenté en JavaScript. Cette approche est inefficace et augmente considérablement la complexité du code de l'application Web. L'application Web doit surveiller les changements d'orientation de l'écran et effectuer des transformations de coordonnées pour les lectures de capteur, ce qui n'est pas une tâche simple pour les angles d'Euler ou les quaternions.

L'API Generic Sensor fournit une solution beaucoup plus simple et fiable. Le système de coordonnées local est configurable pour toutes les classes de capteurs spatiaux définies : Accelerometer, Gyroscope, LinearAccelerationSensor, AbsoluteOrientationSensor, RelativeOrientationSensor et Magnetometer. En transmettant l'option referenceFrame au constructeur d'objet du capteur, l'utilisateur définit si les lectures renvoyées seront résolues dans les coordonnées device ou screen.

// Sensor readings are resolved in the Device coordinate system by default.
// Alternatively, could be RelativeOrientationSensor({referenceFrame: "device"}).
const sensorRelDevice = new RelativeOrientationSensor();

// Sensor readings are resolved in the Screen coordinate system. No manual remapping is required!
const sensorRelScreen = new RelativeOrientationSensor({ referenceFrame: 'screen' });

Codons !

L'API Generic Sensor est très simple et facile à utiliser. L'interface Sensor comporte les méthodes start() et stop() pour contrôler l'état du capteur, ainsi que plusieurs gestionnaires d'événements pour recevoir des notifications sur l'activation du capteur, les erreurs et les nouvelles lectures disponibles. Les classes de capteurs concrets ajoutent généralement leurs attributs de lecture spécifiques à la classe de base.

Environnement de développement

Pendant le développement, vous pourrez utiliser les capteurs via localhost. Si vous développez pour des appareils mobiles, configurez le transfert de port pour votre serveur local, et vous êtes prêt à vous lancer !

Lorsque votre code est prêt, déployez-le sur un serveur compatible avec HTTPS. Les pages GitHub sont diffusées via HTTPS, ce qui en fait un excellent endroit pour partager vos démonstrations.

Rotation du modèle 3D

Dans cet exemple simple, nous utilisons les données d'un capteur d'orientation absolue pour modifier le quaternion de rotation d'un modèle 3D. model est une instance de classe three.js Object3D qui possède une propriété quaternion. L'extrait de code suivant de la démo orientation phone montre comment le capteur d'orientation absolue peut être utilisé pour faire pivoter un modèle 3D.

function initSensor() {
  sensor = new AbsoluteOrientationSensor({ frequency: 60 });
  sensor.onreading = () => model.quaternion.fromArray(sensor.quaternion);
  sensor.onerror = (event) => {
    if (event.error.name == 'NotReadableError') {
      console.log('Sensor is not available.');
    }
  };
  sensor.start();
}

L'orientation de l'appareil se reflète dans la rotation 3D model au sein de la scène WebGL.

Les capteurs mettent à jour l'orientation du modèle 3D
Le capteur met à jour l'orientation d'un modèle 3D

Punchmeter

L'extrait de code suivant est extrait de la démonstration du punchmètre. Il montre comment le capteur d'accélération linéaire peut être utilisé pour calculer la vitesse maximale d'un appareil en supposant qu'il est initialement immobile.

this.maxSpeed = 0;
this.vx = 0;
this.ax = 0;
this.t = 0;

/* … */

this.accel.onreading = () => {
  let dt = (this.accel.timestamp - this.t) * 0.001; // In seconds.
  this.vx += ((this.accel.x + this.ax) / 2) * dt;

  let speed = Math.abs(this.vx);

  if (this.maxSpeed < speed) {
    this.maxSpeed = speed;
  }

  this.t = this.accel.timestamp;
  this.ax = this.accel.x;
};

La vitesse actuelle est calculée comme une approximation de l'intégrale de la fonction d'accélération.

Application Web de démonstration pour la mesure de la vitesse de frappe
Mesure de la vitesse d'un coup de poing

Débogage et remplacement des capteurs avec les outils pour les développeurs Chrome

Dans certains cas, vous n'avez pas besoin d'un appareil physique pour jouer avec l'API Generic Sensor. Les outils pour les développeurs Chrome sont très utiles pour simuler l'orientation de l'appareil.

Outils pour les développeurs Chrome utilisés pour remplacer les données d&#39;orientation personnalisées d&#39;un téléphone virtuel
Simuler l'orientation de l'appareil avec les outils pour les développeurs Chrome

Confidentialité et sécurité

Les lectures de capteurs sont des données sensibles qui peuvent faire l'objet de diverses attaques de la part de pages Web malveillantes. Les implémentations des API Generic Sensor appliquent quelques limites pour atténuer les risques potentiels liés à la sécurité et à la confidentialité. Les développeurs qui souhaitent utiliser l'API doivent tenir compte de ces limites. Nous allons donc les énumérer brièvement.

HTTPS uniquement

L'API Generic Sensor étant une fonctionnalité puissante, le navigateur ne l'autorise que dans des contextes sécurisés. En pratique, cela signifie que pour utiliser l'API Generic Sensor, vous devez accéder à votre page via HTTPS. Pendant le développement, vous pouvez le faire via http://localhost, mais pour la production, vous devrez utiliser HTTPS sur votre serveur. Consultez la collection Sécurité et protection pour découvrir les bonnes pratiques et les consignes.

Intégration des règles sur les autorisations

L'intégration de la règle relative aux autorisations dans l'API Generic Sensor contrôle l'accès aux données des capteurs pour un frame.

Par défaut, les objets Sensor ne peuvent être créés que dans un frame principal ou des sous-frames de même origine, ce qui empêche les iframes d'origine croisée de lire les données des capteurs sans autorisation. Ce comportement par défaut peut être modifié en activant ou en désactivant explicitement les fonctionnalités contrôlées par les règles correspondantes.

L'extrait de code ci-dessous illustre l'octroi d'un accès aux données de l'accéléromètre à un iFrame d'origine croisée, ce qui signifie que des objets Accelerometer ou LinearAccelerationSensor peuvent désormais y être créés.

<iframe src="https://third-party.com" allow="accelerometer" />

La transmission des relevés de capteurs peut être suspendue

Les lectures des capteurs ne sont accessibles que par une page Web visible, c'est-à-dire lorsque l'utilisateur interagit réellement avec elle. De plus, les données du capteur ne seraient pas fournies au frame parent si l'utilisateur se concentrait sur un sous-frame d'origine croisée. Cela empêche le frame parent d'inférer les entrées utilisateur.

Étape suivante

Un ensemble de classes de capteurs déjà spécifiées doit être implémenté dans un avenir proche, comme Ambient Light Sensor ou Proximity Sensor. Toutefois, grâce à la grande extensibilité du framework Generic Sensor, nous pouvons anticiper l'apparition d'un nombre encore plus important de nouvelles classes représentant différents types de capteurs.

Un autre domaine important pour les futurs travaux consiste à améliorer l'API Generic Sensor elle-même. La spécification Generic Sensor est actuellement une recommandation candidate, ce qui signifie qu'il reste encore du temps pour apporter des corrections et ajouter de nouvelles fonctionnalités dont les développeurs ont besoin.

Vous pouvez nous aider !

Les spécifications des capteurs ont atteint le niveau de maturité Recommandation candidate. Les commentaires des développeurs Web et de navigateurs sont donc très appréciés. Faites-nous savoir quelles fonctionnalités seraient intéressantes à ajouter ou si vous souhaitez modifier quelque chose dans l'API actuelle.

N'hésitez pas à signaler les problèmes de spécification ainsi que les bugs pour l'implémentation Chrome.

Ressources

Remerciements

Cet article a été examiné par Joe Medley et Kayce Basques.