ウェブ用センサー

Generic Sensor API を使用して、加速度計、ジャイロスコープ、磁力計などのデバイス上のセンサーにアクセスします。

現在、センサーデータは、没入型ゲーム、フィットネス トラッキング、拡張現実やバーチャル リアリティなどのユースケースを実現するために、多くのプラットフォーム固有のアプリケーションで使用されています。プラットフォーム固有のアプリケーションとウェブ アプリケーションのギャップを埋めることができたら、便利だと思いませんか?ウェブ向けの Generic Sensor API をご紹介します。

Generic Sensor API とは何ですか?

Generic Sensor API は、センサー デバイスをウェブ プラットフォームに公開するためのインターフェースのセットです。この API は、ベースの Sensor インターフェースと、それを利用する一連の具象センサークラスで構成されています。ベース インターフェースがあると、具体的なセンサークラスの実装と指定のプロセスが簡素化されます。たとえば、Gyroscope クラスをご覧ください。とても小さいです。コア機能はベース インターフェースで指定され、Gyroscope は角速度を表す 3 つの属性で拡張するだけです。

一部のセンサークラスは、加速度計クラスやジャイロスコープ クラスなど、実際のハードウェア センサーとインターフェースします。これらは低レベル センサーと呼ばれます。その他のセンサー(融合センサー)は、複数の低レベル センサーのデータを統合して、スクリプトで計算する必要のある情報を公開します。たとえば、AbsoluteOrientation センサーは、加速度計、ジャイロスコープ、地磁気センサーから取得したデータに基づいて、すぐに使用できる 4×4 の回転行列を提供します。

ウェブ プラットフォームですでにセンサーデータが提供されているとお考えかもしれませんが、そのとおりです。たとえば、DeviceMotion イベントと DeviceOrientation イベントはモーション センサー データを公開します。では、新しい API が必要な理由は何でしょうか。

既存のインターフェースと比較すると、Generic Sensor API には次のような多くの利点があります。

  • Generic Sensor API は、新しいセンサークラスで簡単に拡張できるセンサー フレームワークです。これらのクラスはそれぞれ汎用インターフェースを保持します。1 つのセンサータイプ用に作成されたクライアント コードは、ほとんど変更せずに別のセンサータイプで再利用できます。
  • センサーを構成できます。たとえば、アプリケーションのニーズに適したサンプリング頻度を設定できます。
  • プラットフォーム上でセンサーが利用できるかどうかを確認できます。
  • センサー測定値には高精度のタイムスタンプが付加されているため、アプリ内の他のアクティビティとの同期がより正確になります。
  • センサーデータモデルと座標系が明確に定義されているため、ブラウザ ベンダーは相互運用可能なソリューションを実装できます。
  • 汎用センサーベースのインターフェースは DOM にバインドされていません(つまり、navigator オブジェクトでも window オブジェクトでもありません)。これにより、サービス ワーカー内で API を使用したり、埋め込みデバイスなどのヘッドレス JavaScript ランタイムに実装したりできるようになります。
  • セキュリティとプライバシーは、汎用センサー API の最優先事項であり、以前のセンサー API と比較してセキュリティが大幅に強化されています。Permissions API との統合があります。
  • 画面座標との自動同期は、AccelerometerGyroscopeLinearAccelerationSensorAbsoluteOrientationSensorRelativeOrientationSensorMagnetometer で使用できます。

使用可能な汎用センサー API

執筆時点では、テストできるセンサーがいくつかあります。

モーション センサー:

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

環境センサー:

  • AmbientLightSensor(Chromium では #enable-generic-sensor-extra-classes フラグの後ろ)。
  • Magnetometer(Chromium では #enable-generic-sensor-extra-classes フラグの後ろ)。

機能検出

ハードウェア API の機能検出は、ブラウザが該当するインターフェースをサポートしているかどうかと、デバイスに対応するセンサーが搭載されているかどうかの両方を検出する必要があるため、難しい作業です。ブラウザがインターフェースをサポートしているかどうかを確認するのは簡単です。(Accelerometer は、上記で説明した他のインターフェースに置き換えます)。

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

実際に有意な特徴検出結果を得るには、センサーへの接続も試みる必要があります。この例は、その方法を示しています。

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

ポリフィル

Generic Sensor API をサポートしていないブラウザの場合は、ポリフィルを使用できます。ポリフィルを使用すると、関連するセンサーの実装のみを読み込むことができます。

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

これらすべてのセンサーは何ですか?どのように使用すればよいですか?

センサーは、簡単に説明する必要がある分野です。センサーに精通している場合は、実践的なコーディング セクションに直接進んでください。サポートされている各センサーについて詳しく見てみましょう。

加速度計と直線加速度センサー

加速度計センサーの測定

Accelerometer センサーは、3 つの軸(X、Y、Z)でセンサーをホストするデバイスの加速度を測定します。このセンサーは慣性センサーです。つまり、デバイスが直線的に自由落下している場合、測定される総加速度は 0 m/s2 になります。また、デバイスがテーブルの上に平らに置かれている場合、上方向(Z 軸)の加速度は地球の重力(g ≈ +9.8 m/s2)に等しくなります。これは、テーブルがデバイスを上方向に押す力を測定しているためです。デバイスを右に押すと、X 軸の加速度は正になります。デバイスが右から左に加速された場合は負になります。

加速度計は、歩数計、モーション センサー、デバイスの向きの検出などに使用できます。多くの場合、加速度計の測定値は他のソースのデータと組み合わせて、向きセンサーなどの融合センサーを作成します。

LinearAccelerationSensor は、センサーをホストするデバイスに適用される加速度を測定します(重力の影響は除きます)。デバイスが静止している場合(テーブルの上に平らに置かれている場合など)は、センサーは 3 つの軸で約 0 m/s2 の加速度を測定します。

重力センサー

ユーザーは、AccelerometerLinearAccelerometer の測定値を手動で検査することで、重力センサーの測定値に近い測定値を手動で導出できますが、これは手間がかかり、これらのセンサーから提供される値の精度に依存します。Android などのプラットフォームでは、オペレーティング システムの一部として重力測定値を提供できます。これは、計算の面で低コストで、ユーザーのハードウェアに応じてより正確な値を提供し、API の使い勝手の面でより簡単です。GravitySensor は、重力によるデバイスの X、Y、Z 軸の加速度の効果を返します。

ジャイロスコープ

ジャイロスコープ センサーの測定

Gyroscope センサーは、デバイスのローカル X、Y、Z 軸周りの角速度をラジアン / 秒単位で測定します。ほとんどのコンシューマ デバイスには、機械式(MEMS)ジャイロスコープが搭載されています。これは、慣性コリオリ力に基づいて回転速度を測定する慣性センサーです。MEMS ジャイロスコープは、センサーの重力感度によってセンサーの内部機械システムが変形し、ドリフトが発生しやすくなります。ジャイロスコープは、数十 kHz 帯では、他のセンサーよりも消費電力が大きくなる可能性があります。

方位センサー

絶対方向センサーの測定

AbsoluteOrientationSensor は、地球の座標系を基準としてデバイスの回転を測定する融合センサーです。RelativeOrientationSensor は、静止した参照座標系を基準として、モーション センサーを搭載したデバイスの回転を表すデータを提供します。

最新の 3D JavaScript フレームワークはすべて、回転を表す四元数回転行列をサポートしています。ただし、WebGL を直接使用する場合は、OrientationSensorquaternion プロパティpopulateMatrix() メソッドの両方を使用できます。以下にいくつかの例を示します。

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

向きセンサーは、没入型ゲーム、拡張現実、仮想現実などのさまざまなユースケースを可能にします。

モーション センサー、高度なユースケース、要件の詳細については、モーション センサーの説明のドキュメントをご覧ください。

画面座標との同期

デフォルトでは、空間センサーの読み取りは、デバイスにバインドされ、画面の向きを考慮しないローカル座標系で解決されます。

デバイスの座標系
デバイスの座標系

ただし、ゲームや拡張現実、仮想現実などの多くのユースケースでは、画面の向きにバインドされた座標系でセンサーの読み取りを解決する必要があります。

画面座標系
画面座標系

これまで、センサー測定値を画面座標に再マッピングするには、JavaScript で実装する必要がありました。この方法は非効率的であり、ウェブ アプリケーション コードの複雑さも著しく増大します。ウェブ アプリケーションは画面の向きの変化を監視し、センサー測定値の座標変換を実行する必要がありますが、オイラー角や四元数の場合に簡単なことではありません。

Generic Sensor API は、はるかにシンプルで信頼性の高いソリューションを提供します。ローカル座標系は、定義されたすべての空間センサークラス(AccelerometerGyroscopeLinearAccelerationSensorAbsoluteOrientationSensorRelativeOrientationSensorMagnetometer)で構成できます。referenceFrame オプションをセンサー オブジェクトのコンストラクタに渡すことで、返された測定値をデバイス座標または画面座標で解決するかどうかを定義します。

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

コーディングを始めましょう。

Generic Sensor API はとてもシンプルで、簡単に使用できます。センサー インターフェースには、センサーの状態を制御する start() メソッドと stop() メソッドがあります。また、センサーの有効化、エラー、新しく利用可能になった測定値に関する通知を受信するイベント ハンドラがいくつかあります。具体的なセンサークラスは通常、ベースクラスに特定の読み取り属性を追加します。

開発環境

開発中は、localhost を使用してセンサーを使用できます。モバイル デバイス用に開発している場合は、ローカルサーバーのポート転送を設定して、準備完了です。

コードの準備ができたら、HTTPS をサポートするサーバーにデプロイします。GitHub ページは HTTPS で提供されるため、デモを共有するのに最適です。

3D モデルの回転

この簡単な例では、絶対方向センサーのデータを使用して、3D モデルの回転クォータニオンを変更します。model は、quaternion プロパティを持つ three.js Object3D クラスのインスタンスです。スマートフォンの向きのデモの次のコード スニペットは、絶対方向センサーを使用して 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();
}

デバイスの向きは、WebGL シーン内の 3D model 回転に反映されます。

センサーが 3D モデルの向きを更新する
センサーが 3D モデルの向きを更新する

Punchmeter

次のコード スニペットは、パンチメーターのデモから抜粋したものです。最初に静止していると仮定し、直線加速度センサーを使用してデバイスの最大速度を計算する方法を示しています。

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

現在の速度は、加速度関数の積分の近似値として計算されます。

パンチ速度測定用のデモ ウェブ アプリケーション
パンチ速度の測定

Chrome DevTools によるデバッグとセンサーのオーバーライド

Generic Sensor API の使用に実機が不要な場合もあります。Chrome DevTools は、デバイスの向きのシミュレーションを強力にサポートしています。

仮想スマートフォンのカスタム 画面の向きデータをオーバーライドするために使用される Chrome DevTools
Chrome DevTools を使用してデバイスの向きをシミュレートする

プライバシーとセキュリティ

センサーの測定値は機密データであり、悪意のあるウェブページからのさまざまな攻撃の対象となる可能性があります。Generic Sensor API の実装では、セキュリティとプライバシーに関する潜在的なリスクを軽減するために、いくつかの制限が適用されます。これらの制限は、API を使用するデベロッパーが考慮する必要があります。以下に、その制限を簡単に示します。

HTTPS のみ

Generic Sensor API は高度な機能であるため、ブラウザでは安全なコンテキストでのみ許可されます。つまり、Generic Sensor API を使用するには、HTTPS 経由でページにアクセスする必要があります。開発中は http://localhost でアクセスできますが、本番環境ではサーバーで HTTPS を設定する必要があります。ベスト プラクティスとガイドラインについては、安全とセキュリティ コレクションをご覧ください。

権限に関するポリシーの統合

Generic Sensor API の権限ポリシーの統合は、フレームのセンサーデータへのアクセスを制御します。

デフォルトでは、Sensor オブジェクトはメインフレームまたは同じオリジンのサブフレーム内でのみ作成できるため、クロスオリジンの iframe がセンサーデータを許可なく読み取ることを防ぐことができます。このデフォルトの動作は、対応するポリシー制御機能を明示的に有効または無効にすることで変更できます。

以下のスニペットでは、クロスオリジンの iframe に加速度計データへのアクセス権を付与しています。つまり、この iframe で Accelerometer オブジェクトまたは LinearAccelerationSensor オブジェクトを作成できるようになりました。

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

センサー測定値の配信は停止できます

センサーの測定値にアクセスできるのは、表示されているウェブページ(ユーザーが実際に操作しているページ)に限られます。また、ユーザーのフォーカスがクロスオリジン サブフレームに移動した場合、センサーデータは親フレームに提供されません。これにより、親フレームがユーザー入力を推測しなくなります。

次のステップ

近い将来、周囲光センサー近接センサーなど、すでに指定されたセンサークラスのセットが実装される予定です。ただし、汎用センサー フレームワークの優れた拡張性により、さまざまなセンサータイプを表す新しいクラスがさらに登場することが予想されます。

今後の作業の重要な分野として、Generic Sensor API 自体の改善があります。Generic Sensor 仕様は現在候補推奨仕様です。つまり、デベロッパーが必要とする修正や新機能を追加する時間はまだあります。

ご協力いただけます。

センサーの仕様は候補の推奨事項の成熟度レベルに達しています。そのため、ウェブ デベロッパーとブラウザ デベロッパーからのフィードバックをお待ちしております。現在の API にどのような機能を追加すればよいか、あるいは変更したいものがあれば、お知らせください。

Chrome の実装に関する仕様に関する問題バグをお気軽に報告してください。

リソース

謝辞

この記事は、Joe MedleyKayce Basques によってレビューされました。