Feature

[Android] SensorManager를 활용한 좌우 걸음 간격 측정하기

Marchbreeze 2025. 5. 17. 05:26

구현 영상

 

 

걸음을 측정하는 기능을 구현한 후, 2가지의 정보를 가져와서 서비스에 활용했습니다.

  1. 총 걸음 수
  2. 왼발과 오른발 간의 걸음 시간 차이 (균형적인 걸음걸이 측정을 위해)

이러한 걸음 측정을 Android Sensor Framework를 활용해서 구현했습니다.

 

 

1. Android Sensor

Android 센서 프레임워크를 사용하면 다양한 유형의 센서에 액세스할 수 있습니다. 이러한 센서 중 일부는 하드웨어 기반이고 일부는 소프트웨어 기반입니다. 기기에 사용하고자 하는 센서 유형이 없을 수도 있습니다.

  1. 움직임 감지 센서 : 가속도, 중력, 자이로스코프, 회전, 기울기
  2. 환경 센서 : 기온, 압력, 조도, 습도
  3. 위치 센서 : 기기의 물리적 위치, 방향, 자기계

센서 프레임워크는 android.hardware 패키지의 일부이며 다음과 같은 클래스 및 인터페이스를 포함합니다.

  1. SensorManager : 센서 서비스의 인스턴스를 만드는 클래스이며, 센서 접근, 나열, 리스너 등록 등의 방법을 제공합니다.
  2. Sensor : 특정 센서의 인스턴스를 만드는 클래스이며, 센서의 기능을 결정할 수 있는 방법을 제공합니다.
  3. SensorEvent : 정보를 제공하는 센서 이벤트 객체를 만들며, 데이터, 유형, 정확도, 타임스탬프 등의 정보가 포함됩니다.
  4. 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

https://velog.io/@lifeisbeautiful/Compose%EC%97%90%EC%84%9C-SensorManager%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-%EA%B1%B8%EC%9D%8C-%EC%88%98-%EC%B8%A1%EC%A0%95%ED%95%98%EA%B8%B0