웹용 센서

Generic Sensor API를 사용하여 가속도계, 자이로스코프, 자기계와 같은 기기 내 센서에 액세스합니다.

Alex Shalamov
Alex Shalamov
Mikhail Pozdnyakov
Mikhail Pozdnyakov

오늘날 센서 데이터는 몰입형 게임, 피트니스 추적, 증강/가상 현실과 같은 사용 사례를 지원하기 위해 많은 플랫폼별 애플리케이션에서 사용됩니다. 플랫폼별 애플리케이션과 웹 애플리케이션 간의 격차를 줄이는 것이 바람직하지 않을까요? 웹용 Generic Sensor API를 입력합니다.

Generic Sensor API란 무엇인가요?

Generic Sensor API는 센서 기기를 웹 플랫폼에 노출하는 인터페이스 집합입니다. API는 기본 Sensor 인터페이스와 그 위에 빌드된 구체적인 센서 클래스 집합으로 구성됩니다. 기본 인터페이스가 있으면 구체적인 센서 클래스의 구현 및 사양 프로세스가 간소화됩니다. 예를 들어 Gyroscope 클래스를 살펴보세요. 엄청나게 작죠! 핵심 기능은 기본 인터페이스에 의해 지정되며 Gyroscope는 각 속도를 나타내는 속성 3개로 기본 인터페이스를 확장합니다.

일부 센서 클래스는 가속도계 또는 자이로스코프 클래스와 같은 실제 하드웨어 센서에 인터페이스합니다. 이러한 센서를 하위 수준 센서라고 합니다. 퓨전 센서라고 하는 다른 센서는 여러 하위 수준 센서의 데이터를 병합하여 스크립트에서 계산해야 하는 정보를 노출합니다. 예를 들어 AbsoluteOrientation 센서는 가속도계, 자이로스코프, 자기계에서 얻은 데이터를 기반으로 즉시 사용할 수 있는 4:4 회전 행렬을 제공합니다.

여러분은 웹 플랫폼이 이미 센서 데이터를 제공한다고 생각할 수도 있겠지만, 맞습니다. 예를 들어 DeviceMotionDeviceOrientation 이벤트는 움직임 감지 센서 데이터를 노출합니다. 새 API가 필요한 이유는 무엇일까요?

기존 인터페이스와 비교할 때 Generic Sensor API가 제공하는 많은 이점이 있습니다.

  • Generic Sensor API는 새로운 센서 클래스로 쉽게 확장할 수 있는 센서 프레임워크이며 이러한 각 클래스는 일반 인터페이스를 유지합니다. 한 센서 유형을 위해 작성된 클라이언트 코드는 거의 수정하지 않고 다른 유형에 재사용할 수 있습니다.
  • 센서를 구성할 수 있습니다. 예를 들어 애플리케이션 요구사항에 맞게 샘플링 빈도를 설정할 수 있습니다.
  • 플랫폼에서 센서를 사용할 수 있는지 감지할 수 있습니다.
  • 센서 판독값에는 정밀도가 높은 타임스탬프가 있어 애플리케이션의 다른 활동과의 동기화가 개선됩니다.
  • 센서 데이터 모델 및 좌표계가 명확하게 정의되어 있어 브라우저 공급업체가 상호 운용 가능한 솔루션을 구현할 수 있습니다.
  • 일반 센서 기반 인터페이스는 DOM에 바인딩되지 않으며 (navigatorwindow 객체도 아니기 때문에) 향후 서비스 워커 내에서 API를 사용하거나 내장형 기기와 같은 헤드리스 JavaScript 런타임에서 API를 구현할 수 있는 기회를 열어줍니다.
  • 보안 및 개인 정보 보호 측면은 Generic Sensor API의 최우선 사항이며 이전 센서 API에 비해 훨씬 더 나은 보안을 제공합니다. Permissions API와 통합되어 있습니다.
  • Accelerometer, Gyroscope, LinearAccelerationSensor, AbsoluteOrientationSensor, RelativeOrientationSensor, Magnetometer에 대해 화면 좌표와 자동 동기화를 사용할 수 있습니다.

사용 가능한 일반 센서 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를 지원하지 않는 브라우저의 경우 polyfill을 사용할 수 있습니다. polyfill을 사용하면 관련 센서의 구현만 로드할 수 있습니다.

// 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)에서 센서를 호스팅하는 기기의 가속을 측정합니다. 이 센서는 관성 센서입니다.즉, 기기가 선형 자유 낙하 상태이면 총 측정된 가속도가 0m/s2이고, 기기가 테이블에 평평하게 놓여 있을 때 위쪽 방향 (Z 축)의 가속도는 지구의 중력과 같습니다. 즉, 기기가 위로 밀린 힘이 +9.8m입니다. 기기를 오른쪽으로 밀면 X축의 가속은 양수가 되고 기기가 오른쪽에서 왼쪽으로 가속하면 음수가 됩니다.

가속도계는 걸음 수 계산, 움직임 감지, 간단한 기기 방향 등에 사용할 수 있습니다. 가속도계 측정값은 다른 소스의 데이터와 결합되어 방향 센서와 같은 퓨전 센서를 만드는 경우가 많습니다.

LinearAccelerationSensor는 중력 기여를 제외하고 센서를 호스팅하는 기기에 적용되는 가속을 측정합니다. 기기가 휴식 상태일 때는(예: 테이블에 평평하게 놓여 있을 때) 센서는 3축에서 proxima 0m/s2 가속을 측정합니다.

중력 센서

이미 사용자가 AccelerometerLinearAccelerometer 판독값을 수동으로 검사하여 중력 센서의 판독값에 근접한 판독값을 수동으로 도출할 수 있지만 이는 번거로울 수 있으며 이러한 센서에서 제공하는 값의 정확성에 따라 달라질 수 있습니다. Android와 같은 플랫폼은 운영체제의 일부로 중력 판독값을 제공할 수 있습니다. 중력 판독은 계산 측면에서 더 저렴하고, 사용자의 하드웨어에 따라 더 정확한 값을 제공하며, API 에르고노믹스 측면에서 사용하기가 더 쉽습니다. GravitySensor는 중력으로 인한 기기의 X, Y, Z축을 따라 가속 효과를 반환합니다.

자이로스코프

자이로스코프 센서 측정

Gyroscope 센서는 기기의 로컬 X, Y, Z축을 중심으로 하는 각속도를 초당 라디안 단위로 측정합니다. 대부분의 소비자 기기에는 관성 코리올리의 힘을 기반으로 회전 속도를 측정하는 관성 센서인 기계적 (MEMS) 자이로스코프가 있습니다. MEMS 자이로스코프는 센서의 내부 기계 시스템을 변형하는 센서의 중력 민감도로 인해 드리프트가 발생하기 쉽습니다. 자이로스코프는 따라서 수십 kHz는 다른 센서에 비해 더 많은 전력을 소비할 수 있습니다.

방향 센서

절대 방향 센서 측정

AbsoluteOrientationSensor는 지구 좌표계를 기준으로 기기의 회전을 측정하는 퓨전 센서이고 RelativeOrientationSensor는 고정된 참조 좌표계를 기준으로 동작 센서를 호스팅하는 기기의 회전을 나타내는 데이터를 제공합니다.

모든 최신 3D JavaScript 프레임워크는 회전을 나타내기 위해 쿼터니언회전 행렬을 지원합니다. 하지만 WebGL을 직접 사용하면 OrientationSensor에 편리하게 quaternion 속성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();

바빌론

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

방향 센서는 몰입형 게임, 증강 현실, 가상 현실과 같은 다양한 사용 사례를 지원합니다.

움직임 감지 센서, 고급 사용 사례, 요구사항에 관한 자세한 내용은 움직임 감지 센서 설명 문서를 참고하세요.

화면 좌표와 동기화

기본적으로 공간 센서 판독값은 기기에 바인딩된 로컬 좌표계에서 확인되고 화면 방향을 고려하지 않습니다.

기기 좌표계
기기 좌표계

그러나 게임이나 증강 현실 및 가상 현실과 같은 많은 사용 사례에서는 센서 판독값이 화면 방향에 바인딩된 좌표계에서 확인되어야 합니다.

화면 좌표계
화면 좌표계

이전에는 센서 판독값을 화면 좌표로 재매핑해야 했습니다. 이 접근 방식은 비효율적이며 웹 애플리케이션 코드의 복잡성을 상당히 증가시킵니다. 웹 애플리케이션은 화면 방향 변경을 관찰하고 센서 판독값의 좌표 변환을 실행해야 하며, 이는 오일러 각 또는 사원수의 경우 간단한 일이 아닙니다.

Generic Sensor API가 훨씬 간단하고 신뢰할 수 있는 솔루션을 제공합니다. 로컬 좌표계는 정의된 모든 공간 센서 클래스(Accelerometer, Gyroscope, LinearAccelerationSensor, AbsoluteOrientationSensor, RelativeOrientationSensor, Magnetometer)에서 구성할 수 있습니다. 사용자는 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 모델의 회전 사원수(쿼터니언)를 수정합니다. modelquaternion 속성이 있는 3.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 모델의 방향 업데이트

펀치미터

다음 코드 스니펫은 펀치미터 데모에서 추출한 것으로, 기기가 처음에 가만히 배치되어 있다고 가정하고 선형 가속 센서를 사용하여 기기의 최대 속도를 계산하는 방법을 보여줍니다.

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에 가속도계 데이터 액세스 권한을 부여하는 방법을 보여줍니다. 즉, 이제 여기서 Accelerometer 또는 LinearAccelerationSensor 객체를 만들 수 있습니다.

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

센서 판독값 전송이 정지될 수 있습니다.

센서 측정값은 보이는 웹페이지(즉, 사용자가 실제로 상호작용할 때)에서만 액세스할 수 있습니다. 또한 사용자 포커스가 교차 출처 서브프레임으로 변경되면 센서 데이터가 상위 프레임에 제공되지 않습니다. 이렇게 하면 상위 프레임이 사용자 입력을 추론하는 것을 방지할 수 있습니다.

다음 단계

주변광 센서 또는 근접 센서와 같이 이미 지정된 센서 클래스 세트가 조만간 구현될 예정입니다. 하지만 일반 센서 프레임워크의 뛰어난 확장성 덕분에 다양한 센서 유형을 나타내는 더 많은 새로운 클래스가 나타날 것으로 예상할 수 있습니다.

향후 작업을 위한 또 다른 중요한 영역은 Generic Sensor API 자체를 개선하는 것입니다. 일반 센서 사양은 현재 Candidate Recommendation입니다. 즉, 개발자에게 필요한 새로운 기능을 수정하고 도입할 시간이 아직 남아 있습니다.

도움을 줄 수 있습니다.

센서 사양이 후보 추천 성숙도 수준에 도달했으므로 웹 및 브라우저 개발자의 의견을 높이 평가합니다. 추가하면 좋은 기능이나 현재 API에 수정하고 싶은 기능이 있으면 알려주시기 바랍니다.

Chrome 구현에 관한 사양 문제bugs를 언제든지 제출해 주세요.

자료

감사의 말

이 문서는 Joe MedleyKayce Basques가 검토했습니다. Wikimedia Commons를 통해 Misko의 히어로 이미지