Sensori per il Web

Utilizza l'API Generic Sensor per accedere ai sensori sul dispositivo come accelerometri, giroscopi e magnetometri.

Alex Shalamov
Alex Shalamov
Mikhail Pozdnyakov
Mikhail Pozdnyakov

Oggi i dati dei sensori vengono utilizzati in molte applicazioni specifiche della piattaforma per consentire casi d'uso come giochi immersivi, monitoraggio del fitness e realtà aumentata o virtuale. Non sarebbe bello colmare il divario tra applicazioni specifiche della piattaforma e web? Inserisci l'API Generic Sensor per il web.

Che cos'è l'API Generic Sensor?

L'API Generic Sensor è un insieme di interfacce che espongono i dispositivi dei sensori alla piattaforma web. L'API è composta dall'interfaccia di base Sensor e da un insieme di classi di sensori concreti integrate. Un'interfaccia di base semplifica il processo di implementazione e specifica per le classi di sensori per calcestruzzo. Ad esempio, dai un'occhiata alla classe Gyroscope. È minuscolo! La funzionalità di base è specificata dall'interfaccia di base e Gyroscope si limita a estenderla con tre attributi che rappresentano la velocità angolare.

Alcune classi di sensori si interfacciano con sensori hardware reali come, ad esempio, le classi dell'accelerometro o del giroscopio. Sono noti come sensori di basso livello. Altri sensori, denominati sensori di fusione, uniscono i dati di diversi sensori di basso livello per esporre informazioni che altrimenti dovrebbero essere calcolate da uno script. Ad esempio, il sensore AbsoluteOrientation fornisce una matrice di rotazione 4 x 4 pronta all'uso basata sui dati ottenuti dall'accelerometro, dal giroscopio e dal magnetometro.

Potresti pensare che la piattaforma web fornisca già dati dei sensori e hai perfettamente ragione. Ad esempio, gli eventi DeviceMotion e DeviceOrientation espongono i dati dei sensori di movimento. Perché abbiamo bisogno di una nuova API?

Rispetto alle interfacce esistenti, l'API Generic Sensor offre numerosi vantaggi:

  • L'API Sensor generica è un framework di sensori che può essere facilmente esteso con nuove classi di sensori e ciascuna di queste classi manterrà l'interfaccia generica. Il codice client scritto per un tipo di sensore può essere riutilizzato per un altro tipo con pochissime modifiche.
  • Puoi configurare il sensore. Ad esempio, puoi impostare la frequenza di campionamento adatta alle tue esigenze di applicazione.
  • Puoi rilevare se un sensore è disponibile sulla piattaforma.
  • Le letture dei sensori hanno timestamp ad alta precisione, che consentono una migliore sincronizzazione con altre attività nell'applicazione.
  • I modelli dei dati dei sensori e i sistemi di coordinate sono chiaramente definiti, consentendo ai fornitori dei browser di implementare soluzioni interoperabili.
  • Le interfacce generiche basate su sensori non sono associate al DOM (ovvero non sono né navigatorwindow oggetti) e questo apre la strada a opportunità future per l'utilizzo dell'API all'interno di service worker o per l'implementazione in runtime JavaScript headless, ad esempio i dispositivi incorporati.
  • Gli aspetti relativi a sicurezza e privacy sono la priorità assoluta per l'API Generic Sensor e offrono una sicurezza di gran lunga migliore rispetto alle API dei sensori meno recenti. Esiste un'integrazione con l'API Permissions.
  • La sincronizzazione automatica con le coordinate dello schermo è disponibile per Accelerometer, Gyroscope, LinearAccelerationSensor, AbsoluteOrientationSensor, RelativeOrientationSensor e Magnetometer.

API generiche disponibili per i sensori

Quando scrivi, ci sono diversi sensori che puoi provare a usare.

Sensori di movimento:

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

Sensori ambientali:

  • AmbientLightSensor (dietro il flag #enable-generic-sensor-extra-classes in Chromium)
  • Magnetometer (dietro il flag #enable-generic-sensor-extra-classes in Chromium)

Rilevamento delle funzionalità

Il rilevamento delle funzionalità delle API hardware è complicato, poiché devi rilevare sia se il browser supporta l'interfaccia in questione, e se il dispositivo dispone del sensore corrispondente. Verificare se il browser supporta un'interfaccia è semplice. Sostituisci Accelerometer con una delle altre interfacce menzionate sopra.

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

Per ottenere un risultato significativo del rilevamento di una funzionalità, devi provare a connetterti anche al sensore. Questo esempio illustra come fare.

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

Per i browser che non supportano l'API Generic Sensor, è disponibile un polyfill. Il polyfill ti consente di caricare solo le implementazioni dei sensori pertinenti.

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

Cosa sono tutti questi sensori? Come posso usarle?

L'area dedicata ai sensori potrebbe richiedere una breve introduzione. Se hai familiarità con i sensori, puoi passare direttamente alla sezione pratica della programmazione. Altrimenti, vediamo in dettaglio ciascun sensore supportato.

Accelerometro e sensore di accelerazione lineare

Misure del sensore dell'accelerometro

Il sensore Accelerometer misura l'accelerazione di un dispositivo che lo ospita su tre assi (X, Y e Z). Questo sensore è un sensore inerziale, il che significa che quando il dispositivo si trova in caduta libera lineare, l'accelerazione totale misurata è pari a 0 m/s2 e, quando un dispositivo appoggiato su un tavolo, l'accelerazione in direzione verso l'alto (asse Z) sarà uguale alla gravità della Terra, ossia g ≈ +9,8 m/s2 Se spingi il dispositivo verso destra, l'accelerazione sull'asse X sarà positiva o negativa se il dispositivo viene accelerato da destra verso sinistra.

L'accelerometro può essere usato, ad esempio, per il conteggio dei passi, il rilevamento del movimento o per un semplice orientamento del dispositivo. Molto spesso, le misurazioni dell'accelerometro vengono combinate con dati di altre fonti per creare sensori di fusione, come i sensori di orientamento.

LinearAccelerationSensor misura l'accelerazione applicata al dispositivo che ospita il sensore, escludendo il contributo della gravità. Quando un dispositivo è fermo, ad esempio in posizione orizzontale sul tavolo, il sensore misura l'accelerazione di ≈ 0 m/s2 su tre assi.

Sensore di gravità

Gli utenti possono già calcolare manualmente le letture vicine a quelle di un sensore di gravità controllando manualmente le letture di Accelerometer e LinearAccelerometer, ma questa operazione può risultare difficile e dipendere dalla precisione dei valori forniti da questi sensori. Le piattaforme come Android possono fornire letture della gravità come parte del sistema operativo, che dovrebbe essere più economico in termini di calcolo, fornire valori più accurati a seconda dell'hardware dell'utente ed essere più facili da usare in termini di ergonomia dell'API. GravitySensor restituisce l'effetto dell'accelerazione lungo gli assi X, Y e Z del dispositivo a causa della gravità.

Giroscopio

Misurazioni del sensore del giroscopio

Il sensore Gyroscope misura la velocità angolare in radianti al secondo attorno agli assi X, Y e Z locali del dispositivo. La maggior parte dei dispositivi di consumo dispone di giroscopi meccanici (MEMS), sensori inerziali che misurano la velocità di rotazione sulla base della forza di Coriolis inerziale. I giroscopi MEMS sono soggetti alla deriva causata dalla sensibilità gravitazionale del sensore, che deforma il sistema meccanico interno del sensore. I giroscopi oscillano a frequenze relative elevate, ad esempio 10 secondi di kHz e, di conseguenza, potrebbero consumare più energia rispetto ad altri sensori.

Sensori di orientamento

Misure del sensore con orientamento assoluto

AbsoluteOrientationSensor è un sensore di fusione che misura la rotazione di un dispositivo in relazione al sistema di coordinate terrestri, mentre RelativeOrientationSensor fornisce dati che rappresentano la rotazione di un dispositivo che ospita sensori di movimento in relazione a un sistema di coordinate di riferimento fisso.

Tutti i moderni framework JavaScript 3D supportano le quaternioni e le matrici di rotazione per rappresentare la rotazione; tuttavia, se utilizzi direttamente WebGL, OrientationSensor ha sia una proprietà quaternion sia un populateMatrix()metodo. Ecco alcuni snippet:

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

I sensori di orientamento consentono vari casi d'uso, tra cui giochi immersivi, realtà aumentata e virtuale.

Per ulteriori informazioni sui sensori di movimento, sui casi d'uso avanzati e sui requisiti, consulta il documento esplicativo sui sensori di movimento.

Sincronizzazione con le coordinate dello schermo

Per impostazione predefinita, le letture dei sensori spaziali vengono risolte in un sistema di coordinate locali che è associato al dispositivo e non prende in considerazione l'orientamento dello schermo.

Sistema di coordinate dei dispositivi
Sistema di coordinate dei dispositivi

Tuttavia, molti casi d'uso come i giochi o la realtà aumentata e virtuale richiedono che le letture del sensore vengano risolte in un sistema di coordinate che è invece vincolato all'orientamento dello schermo.

Sistema di coordinate sullo schermo
Sistema di coordinate dello schermo

In precedenza, era necessario implementare in JavaScript la rimappatura delle letture dei sensori alle coordinate dello schermo. Questo approccio è inefficiente e aumenta anche notevolmente la complessità del codice dell'applicazione web; l'applicazione web deve osservare i cambiamenti dell'orientamento dello schermo ed eseguire trasformazioni delle coordinate per le letture dei sensori, il che non è una cosa banale per gli angoli o i quaterni di Eulero.

L'API Generic Sensor offre una soluzione molto più semplice e affidabile. Il sistema di coordinate locali è configurabile per tutte le classi di sensori spaziali definite: Accelerometer, Gyroscope, LinearAccelerationSensor, AbsoluteOrientationSensor, RelativeOrientationSensor e Magnetometer. Passando l'opzione referenceFrame al costruttore dell'oggetto sensore, l'utente definisce se le letture restituite verranno risolte nelle coordinate dispositivo o schermo.

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

Codifica!

L'API Generic Sensor è molto semplice e intuitiva. L'interfaccia del sensore include metodi start() e stop() per controllare lo stato dei sensori e diversi gestori di eventi per la ricezione di notifiche relative all'attivazione dei sensori, agli errori e alle nuove letture disponibili. Le classi dei sensori del calcestruzzo di solito aggiungono attributi di lettura specifici alla classe base.

Ambiente di sviluppo

Durante lo sviluppo potrai utilizzare i sensori fino al giorno localhost. Se stai sviluppando dispositivi mobili, configura il port forwarding per il tuo server locale e sarà tutto pronto.

Quando il codice è pronto, eseguine il deployment su un server che supporta HTTPS. Le pagine GitHub vengono pubblicate tramite HTTPS ed è il luogo ideale per condividere le demo.

Rotazione modello 3D

In questo semplice esempio, utilizziamo i dati di un sensore di orientamento assoluto per modificare il quaternione di rotazione di un modello 3D. model è un'istanza di classe tre.js Object3D con una proprietà quaternion. Il seguente snippet di codice della demo relativa al telefono con orientamento mostra come è possibile utilizzare il sensore di orientamento assoluto per ruotare un modello 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'orientamento del dispositivo verrà mostrato nella rotazione 3D model all'interno della scena WebGL.

Il sensore aggiorna l'orientamento del modello 3D
Il sensore aggiorna l'orientamento di un modello 3D

Pugnometro

Il seguente snippet di codice viene estratto dalla demo del punchmeter, che illustra come è possibile utilizzare il sensore di accelerazione lineare per calcolare la velocità massima di un dispositivo supponendo che inizialmente sia rimasto 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 velocità attuale viene calcolata come un'approssimazione all'integrale della funzione di accelerazione.

Applicazione web demo per la misurazione della velocità
Misurazione della velocità di perforazione

Debug e override dei sensori con Chrome DevTools

In alcuni casi non è necessario un dispositivo fisico per giocare con l'API Generic Sensor. Chrome DevTools offre un ottimo supporto per la simulazione dell'orientamento del dispositivo.

Chrome DevTools utilizzato per eseguire l&#39;override dei dati relativi all&#39;orientamento personalizzato di un telefono virtuale
Simulazione dell'orientamento del dispositivo con Chrome DevTools

Privacy e sicurezza

Le letture dei sensori sono dati sensibili che possono essere soggetti a vari attacchi da parte di pagine web dannose. Le implementazioni delle API generiche dei sensori applicano alcune limitazioni per ridurre i possibili rischi per la sicurezza e la privacy. Queste limitazioni devono essere prese in considerazione dagli sviluppatori che intendono utilizzare l'API, perciò eccole brevemente.

Solo HTTPS

Poiché l'API Generic Sensor è una funzionalità molto utile, il browser la consente solo in contesti sicuri. In pratica, significa che per utilizzare l'API Generic Sensor devi accedere alla tua pagina tramite HTTPS. Durante lo sviluppo puoi farlo tramite http://localhost, ma per la produzione dovrai utilizzare HTTPS sul tuo server. Per conoscere le best practice e le linee guida, consulta la raccolta Protezione e sicurezza.

Integrazione dei criteri relativi alle autorizzazioni

L'integrazione dei criteri di autorizzazione nell'API Generic Sensor controlla l'accesso ai dati dei sensori per un frame.

Per impostazione predefinita, gli oggetti Sensor possono essere creati solo all'interno di un frame principale o di sottoframe della stessa origine, impedendo così agli iframe multiorigine di leggere i dati dei sensori non soggetti a sanzioni. Questo comportamento predefinito può essere modificato attivando o disattivando esplicitamente le funzionalità controllate dai criteri corrispondenti.

Lo snippet seguente mostra come concedere l'accesso ai dati dell'accelerometro a un iframe multiorigine, il che significa che ora è possibile creare oggetti Accelerometer o LinearAccelerationSensor in questo iframe.

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

L'invio delle letture del sensore può essere sospeso

Le letture del sensore sono accessibili solo da una pagina web visibile, ad esempio quando l'utente interagisce con il sensore. Inoltre, i dati dei sensori non verrebbero forniti al frame principale se l'elemento attivo dell'utente passa a un frame secondario multiorigine. In questo modo il frame principale non deduce l'input dell'utente.

Passaggi successivi

È prevista l'implementazione di una serie di classi di sensori già specificate nel prossimo futuro, ad esempio il sensore della luce ambientale o il sensore di prossimità. Tuttavia, grazie alla grande estensibilità del framework di sensori generici, possiamo prevedere la comparsa di ancora più nuove classi che rappresentano vari tipi di sensori.

Un'altra area importante per il lavoro futuro è il miglioramento dell'API Generic Sensor. Attualmente, la specifica Generic Sensor è un suggerimento per i candidati, il che significa che c'è ancora tempo per apportare correzioni e apportare nuove funzionalità di cui gli sviluppatori hanno bisogno.

Puoi aiutarmi!

Le specifiche dei sensori hanno raggiunto il livello di maturità dei consigli dei candidati, pertanto il feedback degli sviluppatori di browser e web è molto apprezzato. Facci sapere quali funzionalità vorresti aggiungere o se vuoi modificare qualcosa nell'API attuale.

Non esitare a segnalare problemi specifici e bugs per l'implementazione di Chrome.

Risorse

Ringraziamenti

Questo articolo è stato recensito da Joe Medley e Kayce Basques. Immagine hero di Misko tramite Wikimedia Commons.