ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Android] Sensor를 이용하여 방위각 구해보기~~
    Android📱 2024. 6. 4. 23:06

    안드로이드 센서로 방위각 구하기

     

    Android 기기에는 여러 가지 센서들이 존재합니다.

    안드로이드의 센서

     

    센서 개요  |  Sensors and location  |  Android Developers

    대부분의 Android 지원 기기에는 움직임, 방향 및 다양한 환경 조건을 측정하는 센서가 내장되어 있습니다. 이러한 센서는 높은 정밀도와 정확도로 원시 데이터를 제공할 수 있으며, 3차원 기기 이

    developer.android.com

     

     

    어릴때 자주 하던 이런 게임이 플레이가 가능했던 이유겠죠?

     

    그리고 네이버 맵, 카카오 맵 등 지도 앱에서도 유저가 어느 방향으로 가고 있는지를 알 수 있는 이유이기도 할 거 같습니다.

    또 폰이 가로모드인지 세로 모드인지도 센서 덕분에 알 수가 있죠

     

     

    그 중에도 이번 글에서는 지자기 센서와 가속계 센서를 이용해서 폰의 머리가 향하고 있는 방위각을 찾아보려 합니다.

     

    가속계 센서는 모션을 감지할 때 사용하는 센서이고 마그네틱 센서는 나침반을 만들기 위한 센서라고 보시면 됩니다.

     

    센서 값 받아오기

     

    센서의 값을 받아는 방법은 간단합니다.

    안드로이드에서 이벤트 리스너를 제공해 주는데요.

     

    SensorEventListener를 registerListener로 SensorManager에 달아주면 변경 시 값을 콜백으로 넘겨줍니다.

    물론 사용 중인 화면의 생명주기가 끝날 때 unregisterListener를 잊으면 안 되고요.

     

    object : SensorEventListener {
    
    	override fun onSensorChanged(event: SensorEvent?) {
    		event?.let {
            	Log.println(Log.INFO, "onSensorChanged", "onSensorChanged: ${event.values[0]} ${event.values[1]} ${event.values[2]}")
            }
        }
    
    	override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
    
    }

     

    콜백은 event 안에 배열 형태로 x, y, z 축에 대한 정보가 제공되며 인덱스 순으로 x, y, z입니다.

     

    지자기 센서

     

    지자기 센서는 µT를 단위로 x, y, z 축의 자기장 강도를 리턴해줍니다.

     

    가속계 센서

     

    가속계 센서는 x, y, z 축에 적용되는 가속도력을 m/s 2 단위로 제공해 줍니다.

    가속계 센서는 직접 기기를 동작해 보면 감이 옵니다만

     

    위 사진과 같은 느낌으로 센서 값이 변경되는 걸 볼 수 있습니다.

     

    폰을 좌우로 움직이면 x (가로 모드일 때처럼)

    앞뒤로 움직이면 y (위 사진의 pitch처럼)

    좌우로 뒤집으면 z가 천천히 바뀌는 걸 볼 수 있습니다 (위 사진의 roll처럼)

     

    방위각 구하기

     

    위 2개의 센서를 이용해서 방위각을 구할 수 있습니다.

     

    sensorManager를 받아옵니다.
    val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

     

    그리고 각각 센서를 받아옵니다
    val sensorAccelerator = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)

     

    val sensorMagnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)

     

    그리고 리스너를 만들어줍니다

     

    리스너로 값을 받으면 자기장 센서인지, 가속계 센서인지 분기를 하고,

    들어온 값을 배열에 복사해서

    getRotationMatrix로 경사도와 매트릭스 값을 구하고

    getOrientation을 통해서 기기의 방향을 구합니다.

    받아온 방위각을 라디안 값에서 toDegrees를 이용하여 우리가 많이 쓰는 Degrees로 변경하여 줍니다.

    그러면 폰의 방위각을 얻어 올 수 있게 됩니다.

     

    object : SensorEventListener {
    	private val accValue = FloatArray(3)
        private val magValue = FloatArray(3)
    
        private var isGetAcc = false
        private var isGetMAg = false
    
        override fun onSensorChanged(event: SensorEvent?) {
    		event?.let {
    
    			when (event.sensor.type) {
                	Sensor.TYPE_ACCELEROMETER -> {
                    	System.arraycopy(event.values, 0, accValue, 0, event.values.size)
                        isGetAcc = true
                    }
                    Sensor.TYPE_MAGNETIC_FIELD -> {
    					System.arraycopy(event.values, 0, magValue, 0, event.values.size)
    					isGetMAg = true
    				}
    			}
    
    			if (isGetAcc && isGetMAg) {
    				val r = FloatArray(9)
    				val i = FloatArray(9)
    
    				val orientationValues = FloatArray(3)
    
    				SensorManager.getRotationMatrix(
    						r,
    						i,
    						accValue,
    						magValue
    				)
    
    				SensorManager.getOrientation(r, orientationValues)
    
    				val azimuth = Math.toDegrees(orientationValues[0].toDouble()) // 방위각
    				val pitch = Math.toDegrees(orientationValues[1].toDouble()) // pitch각
    				val roll = Math.toDegrees(orientationValues[2].toDouble()) // roll 각
    
    				angle.doubleValue = if (azimuth < 0) {
    										azimuth + 360
                                        } else {
                                            azimuth
                                        }
    				}
    
    		}
    	}
    
    	override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
    
    }

     

    그리고 생명주기에 맞춰서 리스너를 추가하고 제거해 주면

     

     

    짜잔 방위각을 얻어올 수 있습니다.

     

    여러 가지 실험을 해보았는데

    자기장센서를 쓰는 만큼 근처에 자석이 있거나 센서를 혼란스럽게 할 만한 요소가 있다면

    당연히 이상한 값을 받아오게 됩니다.

    아마 비슷한 원인인 거 같은데 위나 아래에 다른 기기를 겹쳐서 두어도 값이 이상해집니다

    그리고 갤럭시는 지자기 센서가 없는 기기가 존재하기 때문에 대비를 할 필요가 있어 보입니다.

     

    전체 코드

Designed by Tistory.