728x170
해당 글에서는 디바이스에 탑재되어 있는 자이로 센서를 이용하는 expo-sensors 라이브러리를 활용하여 자이로스코프(Gyroscope)와 디바이스 모션(DeviceMotion)을 이해하고 값을 추출하는 방법을 이해하기 위한 글입니다.
1) 라이브러리 사용 목적
💡 사용자가 디바이스를 어떠한 각도에서 카메라로 측정을 하고 있는지에 대한 값을 추출하고 이를 계산하여 각도 값을 도출하여 최적의 디바이스의 카메라 각도를 파악하기 위해서 이를 추출 및 계산하여 데이터를 적재하는 것을 목적으로 하고 있습니다
2) 자이로 센서(Gyrosensor)와 자이로스코프(Gyroscope) 정의
💡 ‘자이로(Gyro)’라는 단어는 라틴어로 ‘회전하는 것’이라는 의미로 회전하는 물체의 회전각 센서를 통해 디바이스의 위치를 감지하는 것을 ‘자이로 센서(Gyrosensor)’라고 합니다. 이 자이로 센서를 기반으로 디바이스의 회전 위치 값의 범위를 의미하는 것이 ‘자이로 스코프(Gyroscope)'라고 합니다.
3) expo-sensors의 Gyroscope 메서드
1. Gyroscope 메서드 설명
💡 자이로 센서를 기반으로 expo-sensors의 Gyroscope 메서드는 액세스를 제공하여 3D 공간의 회전 변화에 응답하여 줍니다. 해당 메서드는 변화에 따라 값을 도출해 냅니다. 디바이스가 X, Y, Z 축이 모두 0인 상태에서 디바이스의 움직임에 따라서 각각의 값을 도출해 줍니다.
2. 적용 소스코드
💡 해당 소스 구성은 화면이 렌더링 되었을 때, Gyroscope 값을 불러오는 함수를 호출합니다.
이 함수에서 Gyroscope를 호출하여서, 디바이스의 감지 속도 시간을 ‘밀리세컨드’ 기준으로 얼마 시간 동안 움직임에 대한 감지 할지에 대한 지정을 합니다. 지정을 통해서 리스너를 수행하여서 디바이스의 변화된 위치 값을 도출해 줍니다.
useEffect(() => {
fn_gyroscope();
},[]);
/**
* [함수] expo-sensors를 기반으로 Gyroscope 값을 도출합니다.
*/
const fn_gyroscope = (): void => {
// 감지 속도 지정 (밀리세컨드 기준)
Gyroscope.setUpdateInterval(1000);
// 디바이스의 변화된 위치에 대해서 감지를 한다.
Gyroscope.addListener((gyroscopeData) => {
const { x, y, z } = gyroscopeData;
const round_x = Math.floor(x);
const round_y = Math.floor(y);
const round_z = Math.floor(z);
console.log(`디바이스 변화값 x: [${round_x}] y: [${round_y}] z: [${round_z}]`);
// 좌표값을 정수로 변경하여 변화가 발생하였을 경우 이를 체크함
if (round_x !== 0 || round_y !== 0 || round_z !== 0) {
console.log("[+] Device Position Change ");
}
});
};
[참고] 자이로 스코프 라이브러리 관련 공식 사이트
Gyroscope - Expo Documentation
Expo is an open-source platform for making universal native apps for Android, iOS, and the web with JavaScript and React.
docs.expo.dev
💡 해당 메서드를 사용해서는 디바이스가 위치한 위치 값을 알 수 없었고,
디바이스의 변화량 자체만 체크하기에 목적과 상이하다고 판단하였습니다.
4) expo-sensors의 DeviceMotion 메서드
1. DeviceMotion 메서드 설명
💡 DeviceMotion을 메서드도 자이로 센서를 기반으로 디바이스의 기준 값을 3개의 축으로 제공해 줍니다. 이는 X는 왼쪽에서 오른쪽으로, Y는 아래에서 위로, Z는 화면을 통해 뒤에서 앞으로 수직으로 이어지는 값을 반환해 줍니다.
[참고] Alpha, Beta, Gamma에 따른 방향 설명
[출처] https://levelup.gitconnected.com/tower-a-react-native-device-motion-example-app-8a8e81d333c3
[참고] 디바이스 모션 관련 공식 사이트
DeviceMotion - Expo Documentation
Expo is an open-source platform for making universal native apps for Android, iOS, and the web with JavaScript and React.
docs.expo.dev
2. DeviceMotion의 인수
- listener (function) - DeviceMotion 업데이트를 사용할 수 있을 때 호출되는 콜백입니다. 호출 시 리스너에는 다음 필드를 포함하는 객체인 단일 인수가 제공됩니다.
- interval (number) - 기본 플랫폼에서 데이터를 가져오는 간격입니다. 밀리 초로 표시됩니다.
- acceleration (object) - x, y, z 키가 있는 개체로 세 축의 장치 가속. m/s 2로 표시됩니다.
- accelerationIncludingGravity (object) - x, y, z 키가 있는 개체로 세 축에 대한 중력의 영향을 받는 장치 가속. m/s 2로 표시됩니다.
- rotation (object) - 알파, 베타, 감마 키가 있는 객체로서의 공간에서의 장치 방향. 여기서 알파는 Z 축 주위 회전, 베타는 X축 회전, 감마는 Y축 회전입니다.
- rotationRate (object) - 초당 각도(deg/s)로 표시되는 공간에서의 장치 회전 속도입니다.
- alpha (number): X축 회전
- beta (number): Y축 회전
- gamma (number): Z 축 회전
- orientation (number) - 화면 회전을 기준으로 한 장치 방향입니다. 값은 0(세로), 90(오른쪽 가로), 180(거꾸로), -90(왼쪽 가로)에 있습니다.
3. 각각에 대한 값 설명
💡 DeviceMotion 메서드를 통해서 도출되는 Alpha, beta, Gamma 값을 통해서 각각 이동된 값을 실시간으로 도출해 줍니다.
[참고] 해당 메서드를 이용한 소스코드 작성
useEffect(() => {
fn_deviceMotion();
},());
const fn_deviceMotion = () => {
DeviceMotion.setUpdateInterval(1000);
DeviceMotion.addListener((_resultValue: DeviceMotionMeasurement) => {
// 장치의 좌표계 최소 -3.14 최대 3.14
const { alpha, beta, gamma } = _resultValue.rotation;
// 수평 기준의 디바이스 위치 값
const round_alpha = Math.round(alpha * 100) / 100;
const round_beta = Math.round(beta * 100) / 100;
const round_gamma = Math.round(gamma * 100) / 100;
}
}
[참고] 설명 기준(기본값) 값의 범위
값 | 설명 | 기준(기본값) | 값의 범위 |
Alpha | 디바이스의 좌우 움직임에 대한 값 | 디바이스의 위치가 북쪽(0) | -3.14 ~ 3.14 |
Beta | 디바이스의 상하 움직임에 대한 값 | 디바이스의 위치가 평지(0) | -1.57 ~ 1.57 |
Gamma | 디바이스의 회전 움직임에 대한 값 | 디바이스의 위치가 정면(0) | -3.14 ~ 3.14 |
4. 계산식을 적용한 각각의 각도 계산
💡 DeviceMotion 메서드를 통해서 도출되는 Alpha, beta, Gamma 값을 통해서 각각 이동된 값을 실시간으로 도출된 값을 통해서 각도를 계산합니다.
[참고] 해당 메서드를 이용한 소스코드 작성
[참고] 해당 메서드를 이용한 소스코드 작성
useEffect(() => {
fn_deviceMotion();
},[]);
const fn_deviceMotion = () => {
DeviceMotion.setUpdateInterval(1000);
DeviceMotion.addListener((_resultValue: DeviceMotionMeasurement) => {
// 장치의 좌표계 최소 -3.14 최대 3.14
const { alpha, beta, gamma } = _resultValue.rotation;
// 수평 기준의 디바이스 위치 값
const round_alpha = Math.round(alpha * 100) / 100;
const round_beta = Math.round(beta * 100) / 100;
const round_gamma = Math.round(gamma * 100) / 100;
// 위치 값에 따른 계산식 : (값) / 3.14 x 180
const x_angle = Math.round(round_alpha / 3.14 * 180);
const y_angle = Math.round(round_beta / 3.14 * 180);
const z_angle = Math.round(round_gamma / 3.14 * 180);
}
}
💡 위에 메서드에서 전달받은 내용을 기반으로 (값) / 3.14 x 180이라는 계산식을 통해서 결과를 도출하였음.
범위 | 기준(기본값) | 90도 | 180도 or 0도 | -90도 | |
Alpha | -180도 ~ 180도 | 디바이스의 위치가 북쪽(0도) | 디바이스의 위치가 서쪽(90도) | 디바이스의 위치가 남쪽(180도 or -180도) | 디바이스의 위치가 동쪽(-90도) |
Beta | -90도 ~ 90도 | 디바이스의 위치가 평지(0도) | 디바이스를 세운 경우(90도) | 디바이스를 눕힌 경우(0도) | 디바이스를 아래로 세운 경우(-90도) |
Gamma | -180도 ~ 180도 | 디바이스의 위치가 정면(0도) | 디바이스가 오른쪽을 바라본 경우(90도) | 디바이스를 눕힌 경우(180도) | 디바이스가 왼쪽을 바라본 경우(-90도) |
useEffect(() => {
fn_deviceMotion();
},[]);
/**
* [함수] expo-sensors의 DeviceMotion를 통하여 디바이스의 x,y,z 축을 구하는 함수
*/
const fn_deviceMotion = () => {
DeviceMotion.setUpdateInterval(1000);
DeviceMotion.addListener((_resultValue: DeviceMotionMeasurement) => {
// 장치의 좌표계 최소 -3.14 최대 3.14
const { alpha, beta, gamma } = _resultValue.rotation;
// console.log(`디바이스 포지션 지정 : round_alpha [${alpha}] / round_beta [${beta}] / round_gamma [${gamma}] `);
// 수평 기준의 디바이스 위치 값
const round_alpha = Math.floor(alpha * 100) / 100;
const round_beta = Math.floor(beta * 100) / 100;
const round_gamma = Math.floor(gamma * 100) / 100;
console.log(`디바이스 좌표값 x: [${round_alpha}] y: [${round_beta}] z: [${round_gamma}]`);
/**
* 위치 값에 따른 계산식 : (값) / 3.14 x 180
*/
const x_angle = Math.floor(round_alpha / 3.14 * 180);
const y_angle = Math.floor(round_beta / 3.14 * 180);
const z_angle = Math.floor(round_gamma / 3.14 * 180);
console.log(`x축 [${x_angle}도] y축 [${y_angle}도] z축[${z_angle}도]`);
});
}
[참고] 최종 적용 소스코드
[참고 소스코드] 최종 적용 소스코드
1. fn_insertTable() 함수 내에서는 디바이스의 각도를 추출받아서 x, y, z축의 값을 데이터베이스로 적재를 합니다.
2. fn_resultDeviceMotion() 함수 내에서는 DeviceMotion을 통해서 x, y, z축의 값을 반환해 줍니다.
** 해당 소스코드에서 부분에서 주의할 점이 있습니다.
DeviceMotion.getListenerCount()를 통해서 누적되는 리스너를 확인해 보았을 때, 매번 1개씩 누적이 되고 있습니다.
이에 따라서 관리를 위해 누적된 리스너를 _subscription.remove() 메서드를 통해서 제거를 해주어야 합니다.
import { DeviceMotion, DeviceMotionMeasurement } from 'expo-sensors';
const DeviceMotionComponent = () => {
/**
* [구조체] 디바이스의 축 각도
*/
type DeviceAxisAngleType = {
x_axis_angle: number;
y_axis_angle: number;
z_axis_angle: number;
}
/**
* [함수] 테이블 내에 디바이스의 x,y,z축의 각도 INSERT
*/
const fn_insertTable = () => {
const _insertObj = {
device_angle_x: 0,
device_angle_y: 0,
device_angle_z: 0,
}
const _subscription = DeviceMotion.addListener((_resultValue: DeviceMotionMeasurement) => {
DeviceMotion.setUpdateInterval(1000); // 감지 시간 지정(1초)
const _deviceMotionObj: DeviceAxisAngleType = fn_resultDeviceMotion(_resultValue); // [함수] 자이로 센서 기반의 디바이스 모션 관리 호출
// 자이로 센서로부터 받은 값이 있다면 INSERT
if (_deviceMotionObj) {
const { x_axis_angle, y_axis_angle, z_axis_angle } = _deviceMotionObj;
_insertObj.device_angle_x = x_axis_angle; // 디바이스 X축 값
_insertObj.device_angle_y = y_axis_angle; // 디바이스 Y축 값
_insertObj.device_angle_z = z_axis_angle; // 디바이스 Z축 값
fn_insertHeadPose(_insertObj); // Table Insert
if (DeviceMotion.getListenerCount() >= 1 && _subscription !== null) _subscription.remove(); // 루프를 수행하면서 쌓인 리스너 취소
}
});
}
/**
* [함수] 자이로 센서 기반의 디바이스 모션 관리
* @param { DeviceMotionMeasurement }_esultValue
* @returns {DeviceAngleType}
*/
const fn_resultDeviceMotion = (_resultValue: DeviceMotionMeasurement): DeviceAxisAngleType => {
const _resultObj: DeviceAxisAngleType = {
x_axis_angle: 0,
y_axis_angle: 0,
z_axis_angle: 0
}
if (_resultValue.rotation) {
// 장치의 좌표계 최소 -3.14 최대 3.14
const { alpha, beta, gamma } = _resultValue.rotation;
// 수평 기준의 디바이스 위치 값
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;
// 위치 값에 따른 계산식 : (값) / 3.14 x 180
_resultObj.x_axis_angle = Math.round(round_alpha / 3.14 * 180);
_resultObj.y_axis_angle = Math.round(round_beta / 3.14 * 180);
_resultObj.z_axis_angle = Math.round(round_gamma / 3.14 * 180)
}
return _resultObj;
}
}
export default DeviceMotionComponent();
5) [참고] 메서드 활용 사례
[출처] https://www.youtube.com/watch?v=t9n9ZCWmbBM
[출처] Device Motion 관련 공식 사이트 예제
Device Motion Example - Snack
Try this project on your phone! Use Expo's online editor to make changes and save your own copy.
snack.expo.dev
6) 오늘의 결론
해당 메서드의 정보를 기반으로 다양하게 활용이 되고 있고, 활용할 범위가 많을 것 같습니다.
이해하고 추후에 기능을 추가하게 된다면 활용하시면 좋을 것 같습니다.
오늘도 감사합니다😀
그리드형
'React & React Native > 라이브러리 활용' 카테고리의 다른 글
[RN] React Native 페이지 이동 관리 이해하고 설정하기: react-native-navigation (4) | 2023.06.09 |
---|---|
[RN] react-native-cli에서 expo-cli 모듈 사용하기 (0) | 2022.05.15 |
[RN] React Native Tensorflow.js 메모리 관리 이해하기 (0) | 2022.04.10 |
[RN] React Native 앱 상태 관리 이해 및 구성 방법: AppState (0) | 2022.03.27 |
[RN] React Native Tensorflow의 blazeface 모델을 이용한 얼굴 감지 (6) | 2022.03.09 |