Sensoren für das Web

Über die Generic Sensor API erhalten Sie Zugriff auf geräteinterne Sensoren wie Beschleunigungsmesser, Gyroskope und Magnetometer.

Alex Shalamov
Alex Shalamov
Mikhail Pozdnyakov
Mikhail Pozdnyakov

Heute werden Sensordaten in vielen plattformspezifischen Anwendungen verwendet, um Anwendungsfälle wie immersives Gaming, Fitness-Tracking und Augmented oder Virtual Reality zu ermöglichen. Wäre es nicht toll, die Lücke zwischen plattformspezifischen Anwendungen und Webanwendungen zu schließen? Geben Sie die Generic Sensor API im Web ein.

Was ist die Generic Sensor API?

Die Generic Sensor API besteht aus einer Reihe von Schnittstellen, die Sensorgeräte für die Webplattform zur Verfügung stellen. Die API besteht aus der Basisschnittstelle Sensor und einer Reihe konkreter Sensorklassen, die darauf aufbauen. Eine Basisschnittstelle vereinfacht die Implementierung und Spezifikation für die konkreten Sensorklassen. Sehen Sie sich beispielsweise die Klasse Gyroscope an. Sie ist sehr klein! Die Hauptfunktion wird durch die Basisschnittstelle angegeben und Gyroscope erweitert sie lediglich um drei Attribute, die die Winkelgeschwindigkeit darstellen.

Einige Sensorklassen sind mit Hardwaresensoren verbunden, zum Beispiel mit den Beschleunigungsmesser- oder Gyroskopklassen. Diese werden als Low-Level-Sensoren bezeichnet. Andere Sensoren, die als Fusionssensoren bezeichnet werden, führen Daten aus mehreren Low-Level-Sensoren zusammen, um Informationen zur Verfügung zu stellen, die ein Skript andernfalls berechnen müsste. Der AbsoluteOrientation-Sensor bietet beispielsweise eine gebrauchsfertige 4 x 4-Drehungmatrix, die auf den Daten von Beschleunigungsmesser, Gyroskop und Magnetometer basiert.

Sie denken vielleicht, dass die Webplattform bereits Sensordaten bereitstellt. Sie haben absolut recht. Die Ereignisse DeviceMotion und DeviceOrientation stellen beispielsweise Bewegungssensordaten bereit. Warum brauchen wir eine neue API?

Im Vergleich zu den vorhandenen Benutzeroberflächen bietet die Generic Sensor API viele Vorteile:

  • Die Generic Sensor API ist ein Sensor-Framework, das einfach mit neuen Sensorklassen erweitert werden kann. Dabei behält jede dieser Klassen die generische Schnittstelle bei. Der für einen Sensortyp geschriebene Clientcode kann mit sehr wenigen Änderungen auch für einen anderen wiederverwendet werden.
  • Sie können den Sensor konfigurieren. Sie können z. B. die Stichprobenhäufigkeit festlegen, die für Ihre Anwendung geeignet ist.
  • Sie können feststellen, ob auf der Plattform ein Sensor verfügbar ist.
  • Die Sensormesswerte haben Zeitstempel mit hoher Genauigkeit, was eine bessere Synchronisierung mit anderen Aktivitäten in Ihrer Anwendung ermöglicht.
  • Die Sensordatenmodelle und Koordinatensysteme sind klar definiert, sodass Browseranbieter interoperable Lösungen implementieren können.
  • Die generischen Sensor-basierten Oberflächen sind nicht an das DOM gebunden (d. h. sie sind weder navigator- noch window-Objekte). Dies eröffnet zukünftige Möglichkeiten, die API in Service Workern zu verwenden oder in monitorlosen JavaScript-Laufzeiten wie eingebetteten Geräten zu implementieren.
  • Sicherheit und Datenschutz haben bei der Generic Sensor API höchste Priorität und bieten im Vergleich zu älteren Sensor APIs eine viel bessere Sicherheit. Die Berechtigungen-API ist eingebunden.
  • Die automatische Synchronisierung mit Bildschirmkoordinaten ist für Accelerometer, Gyroscope, LinearAccelerationSensor, AbsoluteOrientationSensor, RelativeOrientationSensor und Magnetometer verfügbar.

Verfügbare generische Sensor-APIs

Zum Zeitpunkt der Entstehung dieses Artikels gibt es mehrere Sensoren, mit denen Sie experimentieren können.

Bewegungssensoren:

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

Umgebungssensoren:

  • AmbientLightSensor (hinter der Markierung #enable-generic-sensor-extra-classes in Chromium.)
  • Magnetometer (hinter der Markierung #enable-generic-sensor-extra-classes in Chromium.)

Funktionserkennung

Die Funktionserkennung von Hardware-APIs ist schwierig, da Sie sowohl ermitteln müssen, ob der Browser die betreffende Schnittstelle unterstützt als auch, ob das Gerät über den entsprechenden Sensor verfügt. Es ist ganz einfach zu prüfen, ob der Browser eine Schnittstelle unterstützt. (Ersetzen Sie Accelerometer durch eine der anderen oben genannten Schnittstellen.)

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

Um ein aussagekräftiges Ergebnis bei der Funktionserkennung zu erhalten, müssen Sie auch versuchen, eine Verbindung zum Sensor herzustellen. Dieses Beispiel zeigt, wie das funktioniert.

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

Für Browser, die die Generic Sensor API nicht unterstützen, ist ein polyfill verfügbar. Mit Polyfill kannst du nur die Implementierungen der relevanten Sensoren laden.

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

Was sind das für all diese Sensoren? Wie kann ich sie verwenden?

Der Bereich „Sensoren“ sollte kurz vorgestellt werden. Wenn Sie mit Sensoren vertraut sind, können Sie direkt zum Abschnitt zum praktischen Coding springen. Schauen wir uns andernfalls jeden der unterstützten Sensoren im Detail an.

Beschleunigungsmesser und linearer Beschleunigungssensor

Messwerte des Beschleunigungsmesser-Sensors

Der Accelerometer-Sensor misst die Beschleunigung eines Geräts, das den Sensor auf drei Achsen (X, Y und Z) hostet. Dieser Sensor ist ein Inertialsensor. Das bedeutet, dass die gemessene Beschleunigung insgesamt 0 m/s2 beträgt, wenn sich das Gerät im linearen kostenlosen Fall befindet. Wenn ein Gerät flach auf dem Tisch liegt, entspricht die Beschleunigung nach oben (Z-Achse) der Schwerkraft der Erde, d. h. g + 2 m/S nach oben. Wenn Sie das Gerät nach rechts schieben, ist die Beschleunigung auf der X-Achse positiv oder negativ, wenn das Gerät von rechts nach links beschleunigt wird.

Beschleunigungsmesser können beispielsweise für die Schrittzählung, Bewegungssensoren oder die einfache Geräteausrichtung verwendet werden. Ziemlich oft werden die Messungen des Beschleunigungsmessers mit Daten aus anderen Quellen kombiniert, um Fusionssensoren zu erstellen, z. B. Ausrichtungssensoren.

Der LinearAccelerationSensor misst die Beschleunigung, die auf das Gerät angewendet wird, auf dem der Sensor gehostet wird, abzüglich des Beitrags der Schwerkraft. Wenn ein Gerät in Ruhe ist, z. B. flach auf dem Tisch liegt, würde der Sensor eine Beschleunigung von Achse auf drei Achsen messen.2

Schwerkraftsensor

Nutzer können Messwerte, die denen eines Schwerkraftsensors ähneln, bereits manuell ableiten, indem sie die Accelerometer- und LinearAccelerometer-Werte manuell überprüfen. Das kann jedoch mühsam sein und von der Genauigkeit der von diesen Sensoren bereitgestellten Werte abhängen. Plattformen wie Android können als Teil des Betriebssystems Gravitationsmessungen liefern, die in Bezug auf die Berechnung günstiger sein sollten, je nach Hardware des Nutzers genauere Werte liefern und im Hinblick auf die API-Ergonomie einfacher zu verwenden sein sollten. GravitySensor gibt den Einfluss der Beschleunigung entlang der Schwerkraft entlang der X-, Y- und Z-Achse des Geräts zurück.

Gyroskop

Messwerte des Gyroskopsensors

Der Gyroscope-Sensor misst die Winkelgeschwindigkeit in Radiant pro Sekunde um die lokale X-, Y- und Z-Achse des Geräts. Die meisten Verbrauchergeräte haben mechanische (MEMS) Gyroskope – Inertialsensoren, die die Rotationsrate basierend auf der inertialen Corioliskraft messen. MEMS-Gyroskope sind anfällig für Drift. Diese werden durch die Gravitationsempfindlichkeit des Sensors verursacht, die das interne mechanische System des Sensors verformt. Gyroskope schwingen bei relativ hohen Frequenzen, z.B. 10 kHz und verbrauchen daher möglicherweise mehr Energie als andere Sensoren.

Ausrichtungssensoren

Sensormessungen der absoluten Ausrichtung

Der AbsoluteOrientationSensor ist ein Fusionssensor, der die Drehung eines Geräts im Verhältnis zum Koordinatensystem der Erde misst. RelativeOrientationSensor stellt Daten bereit, die die Drehung eines Geräts mit Bewegungssensoren in Relation zu einem stationären Referenzkoordinatensystem darstellen.

Alle modernen 3D-JavaScript-Frameworks unterstützen Quaternions und Rotationsmatrizen zur Darstellung der Rotation. Wenn Sie WebGL direkt verwenden, verfügt OrientationSensor jedoch praktisch sowohl über eine quaternion-Eigenschaft als auch eine populateMatrix()-Methode. Hier sind einige Snippets:

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

Ausrichtungssensoren ermöglichen verschiedene Anwendungsfälle wie immersives Gaming, Augmented Reality und Virtual Reality.

Weitere Informationen zu Bewegungssensoren, erweiterten Anwendungsfällen und Anforderungen finden Sie in der Erläuterung zu Bewegungssensoren.

Synchronisierung mit Bildschirmkoordinaten

Standardmäßig werden die Messwerte der räumlichen Sensoren in einem lokalen Koordinatensystem aufgelöst, das an das Gerät gebunden ist und die Bildschirmausrichtung nicht berücksichtigt.

Gerätekoordinatensystem
Gerätekoordinatensystem

In vielen Anwendungsfällen wie Spielen oder Augmented und Virtual Reality müssen die Sensormesswerte jedoch in einem Koordinatensystem aufgelöst werden, das stattdessen an die Bildschirmausrichtung gebunden ist.

Bildschirmkoordinatensystem
Bildschirmkoordinatensystem

Zuvor musste die Neuzuordnung der Sensormesswerte zu den Bildschirmkoordinaten in JavaScript implementiert werden. Dieser Ansatz ist ineffizient und erhöht auch die Komplexität des Webanwendungscodes erheblich. Die Webanwendung muss Änderungen der Bildschirmausrichtung beobachten und Koordinatentransformationen für Sensormesswerte durchführen, was bei Eulerwinkeln oder Quaternien nicht einfach ist.

Die Generic Sensor API bietet eine wesentlich einfachere und zuverlässigere Lösung. Das lokale Koordinatensystem ist für alle definierten räumlichen Sensorklassen konfigurierbar: Accelerometer, Gyroscope, LinearAccelerationSensor, AbsoluteOrientationSensor, RelativeOrientationSensor und Magnetometer. Durch Übergeben der Option referenceFrame an den Sensorobjektkonstruktor definiert der Nutzer, ob die zurückgegebenen Werte in Gerätekoordinaten oder Bildschirmkoordinaten aufgelöst werden.

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

Dann lass uns programmieren!

Die Generic Sensor API ist sehr einfach zu verwenden. Die Sensorschnittstelle bietet die Methoden start() und stop() zur Steuerung des Sensorstatus und mehrere Event-Handler für den Empfang von Benachrichtigungen zur Sensoraktivierung, Fehlern und neu verfügbaren Messwerten. Die konkreten Sensorklassen fügen der Basisklasse in der Regel ihre spezifischen Leseattribute hinzu.

Entwicklungsumgebung

Während der Entwicklung können Sie über localhost Sensoren verwenden. Wenn Sie für Mobilgeräte entwickeln, richten Sie eine Portweiterleitung für Ihren lokalen Server ein. Fertig!

Wenn der Code fertig ist, stellen Sie ihn auf einem Server bereit, der HTTPS unterstützt. GitHub-Seiten werden über HTTPS bereitgestellt und eignen sich daher bestens, um Ihre Demos zu teilen.

3D-Modelldrehung

In diesem einfachen Beispiel verwenden wir die Daten eines absoluten Ausrichtungssensors, um die Rotationsquaternion eines 3D-Modells zu ändern. model ist eine drei.js-Klasseninstanz Object3D mit einem quaternion-Attribut. Das folgende Code-Snippet aus der Ausrichtungs-Smartphone-Demo zeigt, wie der Sensor für die absolute Ausrichtung zum Drehen eines 3D-Modells verwendet werden kann.

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

Die Ausrichtung des Geräts spiegelt sich in der 3D-model-Drehung innerhalb der WebGL-Szene wider.

Sensor aktualisiert die Ausrichtung des 3D-Modells
Sensor aktualisiert die Ausrichtung eines 3D-Modells

Punchmeter

Das folgende Code-Snippet wird aus der Punchmeter-Demo extrahiert. Es zeigt, wie mit dem linearen Beschleunigungssensor die maximale Geschwindigkeit eines Geräts berechnet werden kann, wenn davon ausgegangen wird, dass es anfangs still liegt.

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

Die aktuelle Geschwindigkeit wird als Annäherung zum Integral der Beschleunigungsfunktion berechnet.

Demo-Webanwendung zum Messen der Punch-Geschwindigkeit
Messung der Stoßgeschwindigkeit

Fehlerbehebung und Überschreiben des Sensors mit den Chrome-Entwicklertools

In einigen Fällen ist kein physisches Gerät erforderlich, um mit der Generic Sensor API zu spielen. Die Chrome-Entwicklertools bieten hervorragende Unterstützung für die Simulation der Geräteausrichtung.

Chrome-Entwicklertools zum Überschreiben der benutzerdefinierten Ausrichtungsdaten eines virtuellen Smartphones
Simulieren der Geräteausrichtung mit Chrome-Entwicklertools

Datenschutz und Sicherheit

Sensormesswerte sind sensible Daten, die verschiedenen Angriffen durch schädliche Webseiten ausgesetzt sein können. Für Implementierungen von Generic Sensor APIs gelten einige Einschränkungen, um mögliche Sicherheits- und Datenschutzrisiken zu minimieren. Entwickler, die die API verwenden möchten, müssen diese Einschränkungen berücksichtigen. Sie werden also kurz aufgeführt.

Nur HTTPS

Da die Generic Sensor API eine leistungsstarke Funktion ist, lässt der Browser sie nur in sicheren Kontexten zu. In der Praxis bedeutet das, dass du zur Verwendung der Generic Sensor API über HTTPS auf deine Seite zugreifen musst. Während der Entwicklung können Sie dies über http://localhost tun, aber für die Produktion müssen Sie HTTPS auf Ihrem Server haben. Best Practices und Richtlinien finden Sie in der Sammlung Sicher.

Integration von Berechtigungsrichtlinien

Über die Integration der Berechtigungsrichtlinie in der Generic Sensor API wird der Zugriff auf die Sensorendaten eines Frames gesteuert.

Standardmäßig können die Sensor-Objekte nur in einem Hauptframe oder Subframes desselben Ursprungs erstellt werden. Dadurch wird verhindert, dass ursprungsübergreifende iFrames Sensordaten nicht richtig lesen. Dieses Standardverhalten kann geändert werden, indem die entsprechenden richtliniengesteuerten Features explizit aktiviert oder deaktiviert werden.

Das folgende Snippet veranschaulicht, wie dem Beschleunigungsmesser Datenzugriff auf einen ursprungsübergreifenden iFrame gewährt wird, sodass dort jetzt Accelerometer- oder LinearAccelerationSensor-Objekte erstellt werden können.

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

Die Zustellung der Sensormesswerte kann ausgesetzt werden

Sensormesswerte sind nur über eine sichtbare Webseite zugänglich, d.h., wenn der Nutzer tatsächlich mit ihr interagiert. Außerdem werden dem übergeordneten Frame keine Sensordaten zur Verfügung gestellt, wenn der Nutzerfokus auf einen ursprungsübergreifenden Subframe wechselt. Dadurch wird verhindert, dass der übergeordnete Frame Nutzereingaben ableitet.

Nächste Schritte

Es gibt bereits eine Reihe bereits spezifizierter Sensorklassen, die in naher Zukunft implementiert werden sollen, z. B. Umgebungslichtsensor oder Näherungssensor. Dank der großen Erweiterbarkeit des Frameworks für generischen Sensor können wir jedoch davon ausgehen, dass noch mehr neue Klassen für verschiedene Sensortypen erscheinen.

Ein weiterer wichtiger Bereich für zukünftige Arbeiten ist die Verbesserung der Generic Sensor API selbst. Die generische Sensorspezifikation ist derzeit eine mögliche Empfehlung. Das bedeutet, dass noch Zeit für Fehlerbehebungen und die Einführung neuer Funktionen ist, die Entwickler benötigen.

Du kannst helfen!

Die Sensorspezifikationen haben den Reifegrad der Kandidatenempfehlung erreicht, daher ist das Feedback der Web- und Browserentwickler sehr zu schätzen. Teilen Sie uns mit, welche Features interessant wären oder ob Sie in der aktuellen API etwas ändern möchten.

Sie können gern Probleme mit den Spezifikationen sowie bugs im Zusammenhang mit der Chrome-Implementierung melden.

Ressourcen

Danksagungen

Dieser Artikel wurde von Joe Medley und Kayce Basques geprüft. Hero-Image von Misko über Wikimedia Commons.