[Android] SensorManager를 활용한 좌우 걸음 간격 측정하기
구현 영상
걸음을 측정하는 기능을 구현한 후, 2가지의 정보를 가져와서 서비스에 활용했습니다.
- 총 걸음 수
- 왼발과 오른발 간의 걸음 시간 차이 (균형적인 걸음걸이 측정을 위해)
이러한 걸음 측정을 Android Sensor Framework를 활용해서 구현했습니다.
1. Android Sensor
Android 센서 프레임워크를 사용하면 다양한 유형의 센서에 액세스할 수 있습니다. 이러한 센서 중 일부는 하드웨어 기반이고 일부는 소프트웨어 기반입니다. 기기에 사용하고자 하는 센서 유형이 없을 수도 있습니다.
- 움직임 감지 센서 : 가속도, 중력, 자이로스코프, 회전, 기울기
- 환경 센서 : 기온, 압력, 조도, 습도
- 위치 센서 : 기기의 물리적 위치, 방향, 자기계
센서 프레임워크는 android.hardware 패키지의 일부이며 다음과 같은 클래스 및 인터페이스를 포함합니다.
- SensorManager : 센서 서비스의 인스턴스를 만드는 클래스이며, 센서 접근, 나열, 리스너 등록 등의 방법을 제공합니다.
- Sensor : 특정 센서의 인스턴스를 만드는 클래스이며, 센서의 기능을 결정할 수 있는 방법을 제공합니다.
- SensorEvent : 정보를 제공하는 센서 이벤트 객체를 만들며, 데이터, 유형, 정확도, 타임스탬프 등의 정보가 포함됩니다.
- SensorEventListener : 센서 값이 변경되거나 센서의 정확도가 변경될 때 알림을 수신하는 콜백 메서드를 만들 수 있습니다.
2. Step Detector 센서 연결
(1) 권한 설정
Manifest에서 신체 활동 정보에 대한 권한을 선언해야 합니다.
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
이후 이전에 작성했던 알림 권한과 동일한 방식으로, Android 10 이상에서 신체 활동 정보 권한을 받아오면 됩니다.
[Android] FCM(Firebase Cloud Messaging) 푸시알림 & 알림 권한 요청 구현 및 이후 액션 지정하기
구현 영상 앱 사용자가 특정 이벤트를 놓치지 않도록 Firebase Cloud Messaging(FCM)을 통해 푸시알림을 보내고, 알림을 눌렀을 때 원하는 화면으로 이동하도록 설정했습니다. 1. Firebase 연동(1) Firebase 콘
marchbreeze.tistory.com
(2) Screen에서 sensorManager 추가
val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
val stepDetectorSensor = sensorManager.getDefaultSensor(TYPE_STEP_DETECTOR)
DisposableEffect(sensorManager) {
val sensorListener = object : SensorEventListener {
override fun onSensorChanged(event: SensorEvent?) {
if (event?.sensor?.type == TYPE_STEP_DETECTOR) viewModel.addStepCount()
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
}
sensorManager.registerListener(sensorListener, stepDetectorSensor, SENSOR_DELAY_NORMAL)
onDispose { sensorManager.unregisterListener(sensorListener) }
}
- TYPE_STEP_DETECTOR : 걸음이 감지될 때마다 이벤트를 한 번씩만 발생시키는 센서입니다.
- event.values 에는 측정값(ex. values[0] == 1.0f)이 들어옵니다.
- SENSOR_DELAY_NORMAL : 센서 이벤트를 얼마나 자주 받을지 지정하는 상수입니다.
- 간격 - NORMAL (≈200ms 간격), UI (≈60ms), GAME (≈20ms), FASTEST (가능한 최대 빈도)
- Composition에 진입할 때 register를 진행하며, 화면이 사라질때 센서 리스너를 unregister를 진행하도록 구현했습니다.
3. 센서 측정값 변환
// viewModel
fun addStepCount() {
// 전체 걸음수 증가
_rhythmState.update { it.copy(stepCount = it.stepCount + 1) }
// 카운트마다 현재 시각 기록
val currentTime = System.currentTimeMillis()
// 1,2번쨰 걸음은 간격 측정을 건너뛰고 시간만 갱신
if (rhythmState.value.stepCount < 2) {
_beforeStepTime.value = currentTime
return
}
// 짝수, 홀수 걸음 기록
val isEven = rhythmState.value.stepCount % 2 == 0
// 이전 걸음과의 시간 간격 계산
val elapsedTime = currentTime - _beforeStepTime.value
// 짝수/홀수별 통계 업데이트
if (isEven) {
_evenStepCount.value++
_evenStepTime.value += elapsedTime
} else {
_oddStepCount.value++
_oddStepTime.value += elapsedTime
}
// 다음 간격 측정을 위해 기준 시각 갱신
_beforeStepTime.value = currentTime
}
- onSensorChanged가 실행될 때 마다 전체 카운트를 하나씩 늘리고, 각 짝수별/홀수별 걸음마다 이전 기록과의 시간 간격을 누적으로 계산했습니다.
다음과 같은 방식으로 센서를 활용하여, 총 걸음 수 & 왼발과 오른발 간의 걸음 시간 차이 데이터를 얻을 수 있었습니다.
참고 자료 :
https://developer.android.com/develop/sensors-and-location/sensors/sensors_overview?hl=ko
https://developer.android.com/develop/sensors-and-location/sensors/sensors_motion?hl=ko