이번 포스팅에서는 기기의 수평도를 확인하는 법에 대해 알아보도록 하겠습니다.
좌표계와 기울기에 대한 이해
안드로이드 시스템의 좌표계는 다음과 같이 구성됩니다.
기기가 세워진 상태로 정지하고 있을 때 가속도 센서로 각 축에 걸리는 가속도를 측정하면 x, z 축에서는 0, 그리고 y 축에는 9.8 m/s^2 값이 확인됩니다. y축의 -방향으로 9.8 m/s^2의 중력이 걸리고 있으므로 기기는 +방향으로 9.8 m/s^2 만큼 가속되는 것이기 때문입니다. 같은 이유로 기기를 책상에 눕혀놓으면 축이 바뀌면서 x, y 축에는 0, 그리고 z 축에는 +9.8 m/s^2의 가속도가 걸리게 됩니다.
그런데 다음과 같은 3D 좌표계에서 벡터 R과 Rx, Ry, Rz 사이의 각도는 수학적으로 다음과 같이 구할 수 있습니다.
$$ \begin{align} cos(A_{xr})=\frac{R_{x}}{R} \ cos(A_{yr})=\frac{R_{y}}{R} \ cos(A_{zr})=\frac{R_{z}}{R} \end{align} $$
Rx
, Ry
, Rz
벡터의 총 크기는 피타고라스 정리에 의해 다음과 같이 정의됩니다.
$$ \begin{align} R=\sqrt{R_{x}^2+R_{y}^2+R_{z}^2} \end{align} $$
기기가 벡터 R
처럼 기울었을 때 기기에 걸리는 가속도값은 Rx
, Ry
, Rz
입니다. 그러면 각 축에 대한 벡터R
의 기울기는 다음과 같이 계산할 수 있습니다.
$$ \begin{align} A_{xr}=arccos\left(\frac{R_{x}}{R}\right) \ A_{yr}=arccos\left(\frac{R_{y}}{R}\right) \ A_{zr}=arccos\left(\frac{R_{z}}{R}\right) \end{align} $$
수평계는 기기가 화면을 +z 방향으로 하고 누워있을 때의 x축과 y축에 대한 기울기를 구하는 것이니까 Axr
과 Ayr
을 구하면 됩니다.
그런데 가속도 센서는 노이즈에 민감하고, 또 기기가 사용자에 의해 움직이고 있을 때는 중력가속도에 외력이 더해지기 때문에 각도를 정확하게 측정할 수 없습니다. 그래서 여기서는 가속도 센서 대신 중력 센서를 사용할 겁니다. 중력센서는 가속도센서와 자이로스코프 보정을 통해 각 축의 중력강도만을 반환하기 때문에 외력의 영향을 무시할 수 있습니다.
수평계 구현
기기가 회전하면 좌표축이 바뀌게 되므로 우선은 기기가 회전하지 않도록 합니다. onCreate를 초기화하기 전에 setRequestedOrientation을 SCREEN_ORIENTATION_PORTRAIT로 설정해주면 됩니다.
|
|
다음은 센서를 인식시켜 줍니다. SensorManager 전역변수를 만들어주고 액티비티에서 SensorEventListener
를 상속받아 센서값의 변화를 통지받을 수 있게 합니다. onResume
에서는 registerListener로 센서를 등록합니다. 그리고 앱이 백그라운드로 전환되면 자원낭비를 막기 위해 unregisterListener로 사용을 해제하게 하면 됩니다.
|
|
센서값이 변화되면 onSensorChanged 콜백으로 값을 확인할 수 있습니다.
|
|
중력센서의 값은 SensorEvent의 value 속성으로 가져올 수 있습니다. 공식에 따라 r
값을 계산하고 Axr
과 Ayr
을 계산하면 됩니다. 계산값은 라디안으로 반환되기 때문에 (180/PI)를 곱해서 각도로 변환합니다. 그리고 안드로이드 시스템의 좌표계에서 기기가 누워있는 상태는 x, y축으로 90도 회전한 상태이기 때문에 이 값을 0으로 만들기 위해 90을 빼주면 됩니다.
이렇게 해서 센서를 이용해 기기의 수평도를 계산하는 방법에 대해 알아보았습니다.