Capteurs pour le Web

Utilisez l'API Generic Sensor pour accéder aux capteurs intégrés à 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 l'activité physique et la réalité augmentée ou virtuelle. N'est-il pas intéressant de combler l'écart entre les applications Web et celles spécifiques à une plate-forme ? Entrez dans 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 des appareils de capteurs à la plate-forme Web. L'API se compose de l'interface Sensor de base et d'un ensemble de classes de capteurs concrets construites sur cette base. Une interface de base simplifie le processus d'implémentation et de spécification des classes de capteurs concrètes. Par exemple, examinez la classe Gyroscope. C'est super petit ! La fonctionnalité de base est spécifiée par l'interface de base, et Gyroscope l'étend simplement avec trois attributs représentant la vitesse angulaire.

Certaines classes de capteurs s'interfacent avec des capteurs matériels réels, tels que 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 x 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 des capteurs de mouvement. 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 capteur qui peut être facilement étendu avec de nouvelles classes de capteurs. Chacune de ces classes conserve l'interface générique. Le code client écrit pour un type de capteur peut être réutilisé pour un autre 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 les autres activités de votre application.
  • Les modèles de données des capteurs et les systèmes de coordonnées sont clairement définis, ce qui permet aux fournisseurs de navigateurs de mettre en œuvre des solutions interopérables.
  • Les interfaces basées sur un 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 offre de nouvelles possibilités d'utiliser l'API au sein des service workers ou de l'implémenter dans des environnements d'exécution JavaScript sans interface graphique, tels que des appareils intégrés.
  • Les aspects de la sécurité et de la confidentialité sont la priorité absolue de l'API Generic Sensor, et ils offrent une sécurité bien supérieure par rapport aux anciennes API de capteurs. Il existe une intégration avec l'API Permissions.
  • 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'ambiance :

  • AmbientLightSensor (derrière l'indicateur #enable-generic-sensor-extra-classes dans Chromium)
  • Magnetometer (derrière l'indicateur #enable-generic-sensor-extra-classes dans Chromium)

Détection de caractéristiques

La détection des fonctionnalités des API matérielles est délicate, car vous devez déterminer 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és réellement pertinent, vous devez également essayer de vous connecter au capteur. Cet exemple 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

Pour les navigateurs qui ne sont pas compatibles avec l'API Generic Sensor, un polyfill est disponible. Le polyfill vous permet de ne charger que les implémentations des capteurs pertinents.

// 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 });

À quoi correspondent tous ces capteurs ? Comment les utiliser ?

Les capteurs sont un domaine qui nécessite peut-être une brève introduction. Si vous connaissez bien les capteurs, vous pouvez passer directement à la section dédiée au codage pratique. Sinon, examinons chaque capteur compatible plus 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 il 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 est positive, ou négative si l'appareil est accéléré de droite à gauche.

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

LinearAccelerationSensor mesure l'accélération appliquée à l'appareil hébergeant le capteur, en excluant la contribution de la gravité. Lorsqu'un appareil est au repos, par exemple lorsqu'il est posé à 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ériver manuellement des mesures proches de celles d'un capteur de gravité en inspectant manuellement les mesures 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 mesures de gravité dans le cadre du système d'exploitation, ce qui 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 de 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 qui mesurent la vitesse de rotation en fonction de la force Coriolis inertielle. Les gyroscopes MEMS sont sujets à la dérive causée par la sensibilité gravitationnelle du capteur, qui déforme son système mécanique interne. Les gyroscopes oscillent à des fréquences relativement élevées 10 kHz, et peut donc consommer plus d'énergie que les 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 directement WebGL, OrientationSensor possède facilement une propriété quaternion et 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 Présentation des capteurs de mouvement.

Synchronisation avec les coordonnées de l'écran

Par défaut, les mesures des capteurs spatiaux sont résolues dans un système de coordonnées local lié à l'appareil et qui ne tient 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 des 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 relevés de capteurs avec les coordonnées de l'écran devait être implémenté en JavaScript. Cette approche est inefficace et augmente également de manière assez importante 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 des capteurs, ce qui n'est pas une tâche simple pour les angles d'Euler ni pour 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 de l'objet du capteur, l'utilisateur définit si les lectures renvoyées seront résolues en coordonnées appareil ou écran.

// 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' });

Commençons à coder !

L'API Generic Sensor est très simple et facile à utiliser. L'interface Sensor dispose des méthodes start() et stop() pour contrôler l'état du capteur et 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 concrètes 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 à partir !

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 Object3D three.js possédant une propriété quaternion. L'extrait de code suivant de la démonstration de l'orientation du télé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 sera reflétée par la rotation model 3D dans la scène WebGL.

Mise à jour de l'orientation du modèle 3D par le capteur
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 illustre 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éboguer et remplacer les capteurs avec les outils pour les développeurs Chrome

Dans certains cas, vous n'avez pas besoin d'un appareil physique pour utiliser l'API Generic Sensor. Les outils pour les développeurs Chrome sont très adaptés à la simulation de l'orientation de l'appareil.

Chrome DevTools permettait de 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 mesures des capteurs sont des données sensibles qui peuvent être soumises à diverses attaques de la part de pages Web malveillantes. Les implémentations des API de capteurs génériques appliquent quelques restrictions pour atténuer les risques potentiels de sécurité et de confidentialité. Ces limites doivent être prises en compte par les développeurs qui souhaitent utiliser l'API. Voyons-les brièvement.

HTTPS uniquement

Étant donné que l'API Generic Sensor est une fonctionnalité puissante, le navigateur ne l'autorise que dans les 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 disposer du protocole HTTPS sur votre serveur. Consultez la collection Sécurité pour connaître les bonnes pratiques et les consignes.

Intégration des règles d'autorisation

L'intégration de la stratégie d'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 inter-origines de lire les données des capteurs de manière non autorisée. 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 inter-origine, ce qui signifie que des objets Accelerometer ou LinearAccelerationSensor peuvent y être créés.

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

La diffusion des relevés des capteurs peut être suspendue

Les mesures des capteurs ne sont accessibles que par une page Web visible, c'est-à-dire lorsque l'utilisateur interagit avec elle. De plus, les données des capteurs ne seraient pas fournies au frame parent si le focus de l'utilisateur change pour un sous-frame inter-origine. Cela empêche le frame parent d'inférer l'entrée utilisateur.

Étape suivante

Un ensemble de classes de capteurs déjà spécifiées doit être implémenté dans un avenir proche, comme le capteur de luminosité ambiante ou le capteur de proximité. Toutefois, grâce à la grande extensibilité du framework de capteurs génériques, nous pouvons anticiper l'apparition de nouvelles classes représentant différents types de capteurs.

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

Tu peux m'aider !

Les spécifications du capteur ont atteint le niveau de maturité recommandations de candidats. Par conséquent, les commentaires des développeurs de sites Web et de navigateurs sont très appréciés. Indiquez-nous les fonctionnalités que vous aimeriez ajouter ou les modifications que vous souhaitez apporter à l'API actuelle.

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

Ressources

Remerciements

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