React & React Native/라이브러리 활용

[RN] expo-sensor의 DeviceMotion 이해하고 활용하기

adjh54 2023. 12. 20. 22:54
반응형
해당 글에서는 expo-sensor를 이용하여서 실제 디바이스가 움직이는 모션을 이용하는 방법에 대해 알아봅니다.


 

💡 [참고] 이전에 작성한 글을 기반으로 좀 더 보기 편하게 재구성하였습니다.
 

[RN] 자이로센서를 활용한 자이로스코프, 디바이스 모션 이해하기: expo-sensors

해당 글에서는 디바이스에 탑재되어 있는 자이로 센서를 이용하는 expo-sensors 라이브러리를 활용하여 자이로스코프(Gyroscope)와 디바이스 모션(DeviceMotion)을 이해하고 값을 추출하는 방법을 이해하

adjh54.tistory.com

 

 

1) expo-sensors


💡 expo-sensors

- Expo SDK에서 제공하는 센서 관련 기능을 사용하기 위한 라이브러리입니다. 이 라이브러리를 사용하면 Expo 앱에서 다양한 센서를 활용할 수 있습니다.
- 이러한 센서를 통해, 움직임, 방향, 압력, 자기장, 주변광, 걸음 수를 측정할 수 있는 장치 센서에 액세스 할 수 있는 다양한 API를 제공합니다.

 

 

2) expo-sensors 종류


💡 expo-sensors 종류

- expo-sensors를 이용하여서 사용이 가능한 센서들에 대해 확인해봅니다
센서 타입 이름 지원 플랫폼 설명
Accelerometer 가속도계 ALL platform 장치의 가속도 측정을 통해 움직임을 감지하는 센서
Barometer 기압계 Andriod, iOS 대기압을 측정하여 고도를 추정하는 센서
DeviceMotion 디바이스 모션 ALL platform 장치의 모션 및 방향을 측정하는 센서
Gyroscope 자이로스코프 ALL platform 장치의 회전 속도를 측정하는 센서
LightSensor 조도 센서 Android 주변의 조도를 측정하는 센서
Magnetometer 자력계 Andriod, iOS 자기장을 측정하여 방위각을 계산하는 센서
Pedometer 보행 센서 Andriod, iOS 걸음 수를 측정하는 센서
 

Sensors

A library that provides access to a device's accelerometer, barometer, motion, gyroscope, magnetometer, and pedometer.

docs.expo.dev

 

 

 

3) DeviceMotion 주요 메서드


메서드 설명
addListener() 이벤트 리스너를 추가하여 디바이스 모션 이벤트를 수신합니다.
getListenerCount() 현재 등록된 이벤트 리스너의 수를 반환합니다.
getPermissionsAsync() 디바이스 모션에 대한 액세스 권한 상태를 비동기적으로 반환합니다.
hasListeners() 현재 이벤트에 대한 리스너가 있는지 여부를 확인합니다.
isAvailableAsync() 디바이스 모션 기능이 사용 가능한지 여부를 비동기적으로 반환합니다.
removeAllListeners() 모든 이벤트 리스너를 제거합니다.
removeSubscription() 특정 이벤트 리스너를 제거합니다.
requestPermissionsAsync() 디바이스 모션에 대한 액세스 권한을 요청합니다.
setUpdateInterval() 디바이스 모션 이벤트를 업데이트하는 간격을 설정합니다.
 

DeviceMotion

A library that provides access to a device's motion and orientation sensors.

docs.expo.dev

 

 

 

[ 더 알아보기 ]

💡 DeviceMotion을 사용하기 위해서는 권한허용이 필요한가?


- 안드로이드의 경우는 해당 권한이 필요하지 않지만 iOS에서는 권한이 필요하다고 합니다.

 

DeviceMotion

A library that provides access to a device's motion and orientation sensors.

docs.expo.dev

 

 

NSMotionUsageDescription | Apple Developer Documentation

A message that tells the user why the app is requesting access to the device’s motion data.

developer.apple.com

 

 

4) DeviceMotion x, y, z 축 이해하기


💡 DeviceMotion

- expo-sensors를 이용하여 ‘디바이스 장치의 동작 및 방향 센서’에 대한 정보를 제공받을 수 있습니다.
- 이러한 정보는 세 개의 축(x, y, z)으로 제공을 합니다.

 

1. DeviceMotion x축의 방향


💡 DeviceMotion x축의 방향

- 디바이스 모션에서 x축의 방향은 ‘왼쪽에서 오른쪽으로 이동하는 방향’을 가리킵니다.

 

https://levelup.gitconnected.com/tower-a-react-native-device-motion-example-app-8a8e81d333c3

 

 

2. DeviceMotion y축의 방향


 

💡 DeviceMotion x축의 방향

- 디바이스 모션에서 y축의 방향은 ‘아래에서 위로 이동하는 방향’을 가리킵니다.

https://levelup.gitconnected.com/tower-a-react-native-device-motion-example-app-8a8e81d333c3

 

 

3. DeviceMotion의 z축의 방향


 💡 DeviceMotion의 z축의 방향

- 디바이스 모션에서 z축의 방향은 ‘화면을 뒤에서 앞으로 수직 통과하는 방향’을 가리킵니다.

https://levelup.gitconnected.com/tower-a-react-native-device-motion-example-app-8a8e81d333c3

 

 

4. x, y, z 축의 정리


💡 x, y, z 축의 정리

- 디바이스 모션을 이용하여 x, y, z 축에 대한 값을 반환받습니다.

- 해당 x, y, z 축의 기본값과 값이 가지는 범위에 대해서 확인해 봅니다.

 

값  설명 기준(기본값) 값의 범위
Alpha(x축) 디바이스의 좌우 움직임에 대한 값 디바이스의 위치가 북쪽(0) -3.14 ~ 3.14
Beta(y축) 디바이스의 상하 움직임에 대한 값 디바이스의 위치가 평지(0) -1.57 ~ 1.57
Gamma(z축) 디바이스의 회전 움직임에 대한 값 디바이스의 위치가 정면(0) -3.14 ~ 3.14

 

 

 

5. x, y, z 축을 각도로 변환


💡 x, y, z 축을 각도로 변환

- 디바이스 모션으로 추출한 값을 직관적으로 이해하기 어렵기에 이를 위해 각각의 값을 각도로 계산을 하였습니다.

- 해당 계산법은 DeviceMotion 메서드를 통해서 도출되는 Alpha, beta, Gamma 값을 통해서 각각 이동된 값을 실시간으로 도출된 값을 통해서 각도를 계산합니다.
- 이러한 값을 기반으로 ‘(값) / 3.14 x 180’이라는 계산식을 통해서 각도로 변환을 하였습니다.

 

 

5) DeviceMotion 활용하기


 

1. DeviceMotion 추가


 

# 패키지 매니저로 npm을 사용하는 경우 
$ npm i expo-sensors

# 패키지 매니저로 yarn을 사용하는 경우 
$ yarn add expo-sensors

# expo cli를 사용하는 경우 
$ npx expo install expo-sensors

 

 

expo-sensors

Provides access to a hardware device's accelerometer, gyroscope, magnetometer, and pedometer.. Latest version: 12.5.0, last published: 4 months ago. Start using expo-sensors in your project by running `npm i expo-sensors`. There are 32 other projects in th

www.npmjs.com

 

 

 

2. DeviceMotion 리스너 구성


💡 DeviceMotion 리스너 구성

- 디바이스 모션을 수행하기 위한 함수를 구성하였습니다.

- 해당 함수에서는 디바이스 모션 정보를 가져올 시간을 정하고, 리스너를 등록하여 지정한 시간마다 alpha(x), beta(y), gamma(z)의 값을 가져오는 형태로 구성을 하였습니다.
import { DeviceMotion, DeviceMotionMeasurement } from "expo-sensors";

/**
 * 디바이스 모션 수행을 관리합니다.
 */
const handleDeviceMotion = () => {

    // [STEP1] 리스너로 디바이스 모션을 통해 가져 올 시간을 지정합니다.(ms 기준)
    DeviceMotion.setUpdateInterval(1000);

    // [STEP2] 디바이스 모션 리스너를 등록합니다.
    DeviceMotion.addListener((decMotionResult: DeviceMotionMeasurement) => {
        const { alpha, beta, gamma } = decMotionResult.rotation;
        console.log("alpha :: [", alpha, "]  beta :: [", beta, "]   gamma :: [", gamma, "] ")
    })

}

 

💡 [참고] DeviceMotionMeasurement의 속성값
속성  반환 값 설명
acceleration x, y, z 기기의 가속도를 표현하는 값입니다. (m/s^2)
accelerationIncludingGravity x, y, z 중력을 포함한 가속도를 표현하는 값입니다. (m/s^2)
interval number 기본 플랫폼에서 데이터를 가져오는 초 입니다
orientation DeviceMotionOrientation 화면 회전에 따른 장치 방향입니다. 값은 0, 90, 180, -90 중의 값을 가집니다.
rotation alpha, beta, gamma 알파, 베타, 감마 키가 있는 객체로서 공간에서의 장치 방향입니다. 여기서 알파는 Z축 중심 회전, 베타는 X축 회전, 감마는 Y축 회전을 나타냅니다.
rotationRate alpha, beta, gamma 초당 각도(deg/s)로 표시되는 공간 내 장치의 회전 속도입니다.

 

💡 결과 화면

- 아래와 같이 디바이스를 움직일 때마다 값이 출력되는 것을 확인할 수 있습니다.

 

 

 

3. DeviceMotion 계산식 적용


💡 DeviceMotion 계산식 적용

- 각각 축에 따라 각도 형태로 반환하도록 구성하였습니다.

- 이전의 값을 기반으로 ‘(값) / 3.14 x 180’이라는 계산식을 통해서 각도로 변환을 하였습니다.

 

import { DeviceMotion, DeviceMotionMeasurement } from "expo-sensors";

/**
 * 디바이스 모션 수행을 관리합니다.
 */
const handleDeviceMotion = () => {

    // [STEP1] 리스너로 디바이스 모션을 통해 가져 올 시간을 지정합니다.(ms 기준)
    DeviceMotion.setUpdateInterval(1000);

    // [STEP2] 디바이스 모션 리스너를 등록합니다.
    DeviceMotion.addListener((decMotionResult: DeviceMotionMeasurement) => {
        const { alpha, beta, gamma } = decMotionResult.rotation;

        // [STEP3] 수평 기준의 디바이스 위치 값 계산식
        const round_alpha: number = Math.round(alpha * 100) / 100;
        const round_beta: number = Math.round(beta * 100) / 100;
        const round_gamma: number = Math.round(gamma * 100) / 100;

        // [STEP4] 위치 값에 따른 계산식 : (값) / 3.14 x 180
        const x_axis_angle = Math.round(round_alpha / 3.14 * 180);
        const y_axis_angle = Math.round(round_beta / 3.14 * 180);
        const z_axis_angle = Math.round(round_gamma / 3.14 * 180);

        const deviceMotionObj = {
            x: x_axis_angle,
            y: y_axis_angle,
            z: z_axis_angle,
        }
        console.log("DeviceMotion :: ", deviceMotionObj)
    })
}

 

💡결과화면

- 아래와 같은 결과값을 출력합니다.

 

 

 

4. DeviceMotion Cleanup + 최종 소스코드


💡 DeviceMotion Cleanup

1. 최초 화면이 렌더링 되면 DeviceMotion이 수행된 리스너가 있는지 확인을 하고 존재하면 리스너를 모두 제거합니다.
2. Devicemotion 리스너를 생성하는 함수를 호출합니다.
3. 해당 페이지에서 clean-up 시점에 리스너를 종료시킵니다.
import { DeviceMotion, DeviceMotionMeasurement } from "expo-sensors";
import { useEffect } from "react";

const DeviceMotionTestScreen = () => {

    useEffect(() => {

        // 1. 최초 화면이 렌더링 되면 DeviceMotion이 수행된 리스너가 있는지 확인을 하고 존재하면 리스너를 모두 제거합니다.
        if (DeviceMotion.getListenerCount() >= 1) {
            DeviceMotion.removeAllListeners();     // 루프를 수행하면서 쌓인 리스너 취소 
        }

        // 2. Devicemotion 리스너를 생성하는 함수를 호출합니다.
        handleDeviceMotion();

        return () => {
            // 3. 해당 페이지에서 clean-up 시점에 리스너를 종료시킵니다.
            console.log("clean-up")
            DeviceMotion.removeAllListeners();     // 루프를 수행하면서 쌓인 리스너 취소 
        };
    }, []);

    /**
    * 디바이스 모션 수행을 관리합니다.
    */
    const handleDeviceMotion = () => {

        // [STEP1] 리스너로 디바이스 모션을 통해 가져 올 시간을 지정합니다.(ms 기준)
        DeviceMotion.setUpdateInterval(1000);

        // [STEP2] 디바이스 모션 리스너를 등록합니다.
        DeviceMotion.addListener((decMotionResult: DeviceMotionMeasurement) => {
            const { alpha, beta, gamma } = decMotionResult.rotation;

            // [STEP3] 수평 기준의 디바이스 위치 값 계산식
            const round_alpha: number = Math.round(alpha * 100) / 100;
            const round_beta: number = Math.round(beta * 100) / 100;
            const round_gamma: number = Math.round(gamma * 100) / 100;

            // [STEP4] 위치 값에 따른 계산식 : (값) / 3.14 x 180
            const x_axis_angle = Math.round(round_alpha / 3.14 * 180);
            const y_axis_angle = Math.round(round_beta / 3.14 * 180);
            const z_axis_angle = Math.round(round_gamma / 3.14 * 180);

            const deviceMotionObj = {
                x: x_axis_angle,
                y: y_axis_angle,
                z: z_axis_angle,
            }
            console.log("DeviceMotion :: ", deviceMotionObj)
        })

    }
}
export default DeviceMotionTestScreen;

 

💡 결과화면

- 페이지를 이동하는 경우 clean-up을 하면서 DeviceMotion 리스너를 종료합니다.

 

 

 

 

 

오늘도 감사합니다. 😀

 

 

반응형