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 répondre à des cas d'utilisation tels que les jeux immersifs, le suivi de l'activité physique et la réalité augmentée ou virtuelle. Ne serait-il pas cool de combler le fossé entre les applications Web et spécifiques à la plate-forme ? Découvrez 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 capteurs à la plate-forme Web. L'API se compose de l'interface Sensor de base et d'un ensemble de classes de capteurs concrètes basées sur une couche supérieure. 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 tout petit ! La fonctionnalité de base est spécifiée par l'interface de base, et Gyroscope ne fait que l'étendre avec trois attributs représentant la vitesse angulaire.

Certaines classes de capteurs interagissent avec des capteurs matériels réels, tels que les classes de l'accéléromètre ou du gyroscope. On les appelle capteurs de bas niveau. D'autres capteurs, appelés capteurs de fusion, fusionnent les données de plusieurs capteurs de bas niveau pour exposer les informations qu'un script aurait normalement besoin de 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 par l'accéléromètre, le gyroscope et le 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 ?

L'API Generic Sensor présente de nombreux avantages par rapport aux interfaces existantes:

  • L'API Generic Sensor est un framework de capteur 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 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 relevés de capteurs présentent des horodatages très précis, ce qui permet une meilleure synchronisation avec les 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 de mettre en œuvre des solutions interopérables.
  • Les interfaces génériques basées sur des capteurs ne sont pas liées au DOM (ce qui signifie qu'elles ne sont ni des objets navigator, ni window). Cela offre de futures possibilités d'utilisation de l'API dans les 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 sécurité et de confidentialité sont la priorité absolue de l'API Generic Sensor et offrent une sécurité nettement supérieure à celle des API de capteurs plus anciennes. Une intégration est disponible 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 génériques de capteurs disponibles

Au moment de la rédaction de ce document, vous pouvez faire des tests avec plusieurs capteurs.

Capteurs de mouvement:

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

Capteurs environnementaux:

  • 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 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 prend en charge l'interface en question et si l'appareil est équipé du capteur correspondant. Il est simple de vérifier si le navigateur accepte 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 que la détection des fonctionnalités soit vraiment pertinente, 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

Un polyfill est disponible pour les navigateurs qui ne sont pas compatibles avec l'API Generic Sensor. 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 });

En quoi consistent tous ces capteurs ? Comment puis-je les utiliser ?

Une brève présentation des capteurs peut être nécessaire. Si vous connaissez bien les capteurs, vous pouvez accéder directement à la section de codage pratique. Sinon, examinons en détail chaque capteur pris en charge.

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

Mesures de l'accéléromètre

Le capteur Accelerometer mesure l'accélération d'un appareil qui l'héberge 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, et lorsqu'un appareil est posé à plat sur une table, l'accélération vers le haut (axe Z) est égale à la gravité de la Terre, c'est-à-dire que la force mesurée par l'appareil est de +9,8 m/s. 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 comptabiliser, par exemple, les pas, la détection des mouvements ou une simple orientation de l'appareil. Très souvent, les mesures de l'accéléromètre sont combinées à des données provenant d'autres sources pour créer des capteurs de fusion, tels que des capteurs d'orientation.

Le LinearAccelerationSensor mesure l'accélération appliquée à l'appareil qui héberge le capteur, à l'exclusion de la contribution de la gravité. Lorsqu'un appareil est au repos (par exemple, s'il est à 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à obtenir manuellement des mesures proches de celles d'un capteur de gravité en inspectant manuellement les mesures Accelerometer et LinearAccelerometer, mais cela peut s'avérer 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 la gravité dans le 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 faciles à utiliser en termes d'ergonomie des API. Le GravitySensor renvoie l'effet de l'accélération de l'appareil en raison de la gravité sur l'axe X, Y et Z de l'appareil.

Gyroscope

Mesures du capteur du gyroscope

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

Capteurs d'orientation

Mesures du capteur d'orientation absolue

Le AbsoluteOrientationSensor est un capteur de fusion qui mesure la rotation d'un appareil par rapport au système de coordonnées terrestre, tandis que le 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 comporte à la fois 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();

BÉBÉLON

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, comme les jeux immersifs, la réalité augmentée et virtuelle.

Pour en savoir plus sur les capteurs de mouvement, les cas d'utilisation avancés et les exigences associées, consultez le document d'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 qui ne prend pas en compte l'orientation de l'écran.

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

Cependant, dans de nombreux cas d'utilisation tels que les jeux ou la réalité augmentée et virtuelle, les mesures des capteurs doivent être résolues dans un système de coordonnées qui est plutôt 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 capteur avec les coordonnées de l'é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 mesures des capteurs, ce qui n'est pas une opération banale pour les angles d'Euler ou les quaternions.

L'API Generic Sensor offre une solution beaucoup plus simple et fiable. Le système de coordonnées local peut être configuré 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 capteur, l'utilisateur détermine si les lectures renvoyées seront résolues en coordonnées device (appareil) ou screen (é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' });

Entrons dans le code !

L'API Generic Sensor est très simple et facile à utiliser. L'interface des capteurs comporte des méthodes start() et stop() pour contrôler l'état des capteurs, ainsi que plusieurs gestionnaires d'événements pour recevoir des notifications sur l'activation des capteurs, 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 des applications pour des appareils mobiles, configurez le transfert de port pour votre serveur local. Vous êtes prêt !

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 endroit idéal 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. L'instance de classe model est une Object3D three.js possédant une propriété quaternion. L'extrait de code suivant de la démonstration du téléphone d'orientation 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 dans la rotation model 3D dans la scène WebGL.

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

Compteur de poinçons

L'extrait de code suivant est extrait de la démonstration du poinçon, qui 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 immobile au départ.

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 poinçon
Mesure de la vitesse de perforation

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

Dans certains cas, vous n'avez pas besoin d'appareil physique pour jouer avec l'API Generic Sensor. Les outils pour les développeurs Chrome sont parfaitement compatibles avec la simulation de l'orientation de l'appareil.

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

Confidentialité et sécurité

Les relevés de capteurs sont des données sensibles qui peuvent faire l'objet de diverses attaques provenant de pages Web malveillantes. Les implémentations d'API Generic Sensor appliquent certaines limites pour atténuer les risques éventuels liés à la sécurité et à la confidentialité. Ces limites doivent être prises en compte par les développeurs qui ont l'intention d'utiliser l'API. Énumérons-les donc brièvement.

HTTPS uniquement

L'API Generic Sensor est une fonctionnalité puissante. Par conséquent, le navigateur ne l'autorise que sur 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 passer par http://localhost, mais pour la production, vous devrez disposer du protocole HTTPS sur votre serveur. Pour connaître les bonnes pratiques et les consignes, consultez la section Collecte sécurisée.

Intégration des règles d'autorisation

L'intégration des règles d'autorisation dans l'API Generic Sensor contrôle l'accès aux données des capteurs d'une trame.

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 évite que les iFrame multi-origines puissent lire les données de capteurs de façon 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 des règles correspondantes.

L'extrait ci-dessous montre comment accorder l'accès aux données de l'accéléromètre à un iFrame multi-origine, ce qui signifie qu'il est désormais possible de créer des objets Accelerometer ou LinearAccelerationSensor à cet endroit.

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

La diffusion des relevés des 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 des capteurs ne seront pas fournies à la trame parente si l'utilisateur sélectionne un sous-frame multi-origine. Cela empêche la trame parente de déduire les entrées utilisateur.

Étape suivante

Il existe un ensemble de classes de capteurs déjà spécifiées et qui seront mises en œuvre dans un avenir proche, comme le capteur de luminosité ambiante ou le capteur de proximité. Toutefois, grâce à l'extensibilité importante du framework de capteur générique, nous pouvons anticiper l'apparition d'encore plus de nouvelles classes représentant différents types de capteurs.

L'amélioration de l'API Generic Sensor elle-même constitue un autre aspect important. En effet, la spécification Generic Sensor est actuellement une recommandation de candidat, ce qui signifie qu'il est encore temps d'apporter des corrections et d'apporter de nouvelles fonctionnalités dont les développeurs ont besoin.

Vous pouvez nous aider !

Les spécifications du capteur ont atteint le niveau de maturité de la recommandation de candidat. Les commentaires des développeurs Web et navigateurs sont donc très appréciés. Indiquez-nous les fonctionnalités que vous souhaiteriez ajouter ou si vous souhaitez modifier quelque chose dans l'API actuelle.

N'hésitez pas à signaler les problèmes liés aux spécifications ainsi que les bugs liés à l'implémentation de Chrome.

Ressources

Remerciements

Cet article a été lu par Joe Medley et Kayce Basques. Image héros de Misko via Wikimedia Commons.