움직임 감지 센서

Android 플랫폼은 움직임을 모니터링할 수 있는 여러 센서를 제공합니다. 기기의 역할을 합니다

센서 가능한 아키텍처는 센서 유형에 따라 다릅니다.

  • 중력, 선형 가속, 회전 벡터, 중요한 움직임, 걸음 보행 탐지기 센서는 하드웨어 기반 또는 소프트웨어 기반입니다.
  • 가속도계와 자이로스코프 센서는 언제나 하드웨어 기반입니다.

대부분의 Android 구동 기기에는 가속도계가 있으며, 현재 대부분이 자이로스코프를 사용합니다. 소프트웨어 기반 센서의 가용성은 왜냐하면 이러한 모델은 종종 하나 이상의 하드웨어 센서에 의존하여 데이터를 수집하는 데 사용됩니다 기기에 따라 이러한 소프트웨어 기반 센서는 가속도계와 자기계 또는 자이로스코프로부터 데이터를 받습니다.

움직임 감지 센서는 기기의 움직임(예: 기울이기, 흔들기, 회전, 스윙. 움직임은 보통 사용자의 직접 입력을 반영한 것입니다 (예: 사용자가 게임 속에서 자동차를 조종하는 사용자나 사용자가 공을 조종하는 게임)를 보여주지만 이는 기기가 있는 물리적 환경 (예: 운전 중에 사용자와 함께 이동) 자동차)을 입력합니다. 첫 번째 경우 기기의 기준계를 기준으로 움직임을 모니터링합니다. 애플리케이션 기준 두 번째 경우는 잔여물 수에 따라 쉽게 이해할 수 있습니다 움직임 감지 센서는 그 자체로는 일반적으로 모니터링에 사용되지 않습니다. 지자기장 센서와 같은 다른 센서와 함께 사용하여 세계 기준계를 기준으로 기기의 위치를 결정합니다 (자세한 내용은 위치 센서 참조). 있습니다.

모든 움직임 감지 센서는 SensorEvent마다 센서 값의 다차원 배열을 반환합니다. 예를 들어 단일 센서 이벤트 중에 가속도계는 자이로스코프는 회전 속도를 반환함 3개의 좌표축에 대한 데이터입니다. 이 데이터 값은 float 배열에 반환됩니다. (values) 및 다른 SensorEvent 매개변수입니다. 표 1은 Android 플랫폼에서 사용 가능한 동작 센서를 요약한 것입니다.

표 1. Android 플랫폼에서 지원되는 움직임 감지 센서

센서 센서 이벤트 데이터 설명 측정 단위
TYPE_ACCELEROMETER SensorEvent.values[0] x축의 가속력(중력 포함). m/s2
SensorEvent.values[1] y축의 가속력(중력 포함).
SensorEvent.values[2] z축의 가속력(중력 포함).
TYPE_ACCELEROMETER_UNCALIBRATED SensorEvent.values[0] 편향 보상 없이 X축을 따라 측정한 가속. m/s2
SensorEvent.values[1] 편향 보상 없이 Y축을 따라 측정한 가속.
SensorEvent.values[2] 편향 보상 없이 Z축을 따라 측정한 가속.
SensorEvent.values[3] 추정된 편향 보상을 적용하여 X축을 따라 측정한 가속.
SensorEvent.values[4] 추정된 편향 보상을 적용하여 Y축을 따라 측정한 가속.
SensorEvent.values[5] 추정된 편향 보상을 적용하여 Z축을 따라 측정한 가속.
TYPE_GRAVITY SensorEvent.values[0] x축의 중력. m/s2
SensorEvent.values[1] y축의 중력.
SensorEvent.values[2] z축의 중력.
TYPE_GYROSCOPE SensorEvent.values[0] x축을 중심으로 한 회전 속도. rad/s
SensorEvent.values[1] y축을 중심으로 한 회전 속도.
SensorEvent.values[2] z축을 중심으로 한 회전 속도.
TYPE_GYROSCOPE_UNCALIBRATED SensorEvent.values[0] x축을 중심으로 한 회전 속도(드리프트 보상 없음). rad/s
SensorEvent.values[1] y축을 중심으로 한 회전 속도(드리프트 보상 없음).
SensorEvent.values[2] z축을 중심으로 한 회전 속도(드리프트 보상 없음).
SensorEvent.values[3] x축을 중심으로 추정한 드리프트.
SensorEvent.values[4] y축을 중심으로 추정한 드리프트.
SensorEvent.values[5] z축을 중심으로 추정한 드리프트.
TYPE_LINEAR_ACCELERATION SensorEvent.values[0] x축의 가속력(중력 제외). m/s2
SensorEvent.values[1] y축의 가속력(중력 제외).
SensorEvent.values[2] z축의 가속력(중력 제외).
TYPE_ROTATION_VECTOR SensorEvent.values[0] x축의 회전 벡터 구성요소(x * sin(θ/2)). 단위 없음
SensorEvent.values[1] y축의 회전 벡터 구성요소(y * sin(θ/2)).
SensorEvent.values[2] z축의 회전 벡터 구성요소(z * sin(θ/2)).
SensorEvent.values[3] 회전 벡터의 스칼라 구성요소 ((cos(Workspace/2))입니다.1
TYPE_SIGNIFICANT_MOTION 해당 사항 없음 해당 사항 없음 해당 사항 없음
TYPE_STEP_COUNTER SensorEvent.values[0] 마지막 재부팅 이후 센서가 있는 동안 사용자가 걸은 걸음 수 이(가) 활성화되었습니다. 단계
TYPE_STEP_DETECTOR 해당 사항 없음 해당 사항 없음 해당 사항 없음

1 스칼라 구성요소는 선택적 값입니다.

회전 벡터 센서와 중력 센서는 움직임에 가장 자주 사용되는 센서입니다. 탐지 및 모니터링입니다 회전 벡터 센서는 특히 용도가 다양하며, 동작 감지, 각도 변화 모니터링, 상대적 방향 변화를 모니터링할 수 있습니다. 예를 들어, 회전 벡터 센서는 게임, 증강 현실 애플리케이션, 2차원 또는 3차원 나침반을 개발하고 있습니다. 카메라 손떨림 보정 앱을 사용하는 것이 좋습니다 대부분의 경우 이러한 센서를 사용하는 것이 가속도계와 지자기장 센서 또는 방향 센서 등이 있습니다.

Android 오픈소스 프로젝트 센서

Android 오픈소스 프로젝트(AOSP)에서는 3개의 소프트웨어 기반 움직임 감지 센서(중력 센서)를 제공합니다. 선형 가속 센서 및 회전 벡터 센서 등이 있습니다. 다음에서 업데이트된 센서: Android 4.0 이상에서는 (다른 센서 외에도) 기기의 자이로스코프를 사용하여 확인할 수 있습니다 이러한 센서를 사용해 보려면 getVendor() 메서드와 getVersion() 메서드를 사용하여 식별할 수 있습니다. 공급업체는 Google LLC이고 버전 번호는 3입니다. 공급업체별로 이러한 센서를 식별하고 Android 시스템에서는 이 세 개의 센서를 보조 센서로 간주하므로 버전 번호가 필요합니다. 있습니다. 예를 들어 기기 제조업체가 자체 중력 센서를 제공하는 경우 AOSP는 보조 중력 센서로 표시됩니다. 이 세 가지 센서는 모두 자이로스코프: 기기에 자이로스코프가 없는 경우 이러한 센서는 표시되지 않으며 사용할 수 있습니다

중력 센서 사용

중력 센서는 중력 센서의 3차원 벡터를 인코더-디코더에 의해 생성됩니다. 일반적으로 이 센서는 기기의 상대적 방향을 나타냅니다. 다음 코드는 기본 중력 센서의 인스턴스를 가져옵니다.

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY)

자바

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);

단위는 가속에 사용된 것과 동일합니다. (m/s2), 좌표계는 가속도 센서가 있어야 합니다.

참고: 기기가 대기 상태일 때는 중력 센서의 출력이 가속도계와 동일해야 합니다.

선형 가속도계 사용

선형 가속 센서는 3차원 벡터와 각 기기 축을 따른 가속(중력을 제외)을 나타냅니다. 이때 이 값을 사용하여 동작 감지를 실행합니다. 이 값은 데드 레커닝(Dead reckoning)을 사용하는 관성 항법 시스템입니다. 다음 코드는 기본 선형 가속 센서의 인스턴스를 가져오는 방법은 다음과 같습니다.

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION)

자바

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);

개념적으로 이 센서는 다음에 따라 가속 데이터를 제공합니다. 관계:

linear acceleration = acceleration - acceleration due to gravity

일반적으로 이 센서는 다른 센서의 영향을 받지 않고 가속 데이터를 얻고자 할 때 사용합니다. 일어날 수 있습니다. 예를 들어 이 센서를 사용하여 자동차가 얼마나 빨리 움직이는지 알아낼 수 있습니다. 선형 가속 센서에는 항상 오프셋이 있으므로 제거해야 합니다. 이 작업을 수행하는 가장 간단한 방법은 애플리케이션에 보정 단계를 빌드합니다. 보정 중에 사용자에게 세 축 모두의 오프셋을 읽을 수 있습니다. 그런 다음 가속도 센서의 직접 판독값으로부터 오프셋을 사용하여 가속합니다.

센서 좌표 system은 가속 센서에서 사용하는 것과 동일하며 측정 단위도 마찬가지입니다. (m/s2).

회전 벡터 센서 사용

회전 벡터는 기기의 방향을 축 (x, y 또는 z)을 중심으로 기기가 회전하는 각도 당일입니다. 다음 기본 회전 벡터 센서의 인스턴스를 가져오는 방법을 보여주는 코드입니다.

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)

자바

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);

회전 벡터의 세 가지 요소는 다음과 같이 나타냅니다.

x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)

여기서 회전 벡터의 크기는 sin(예측/2)와 같고 회전 벡터는 회전 축의 방향과 같습니다.

그림 1. 회전 벡터 센서에서 사용하는 좌표계입니다.

회전 벡터의 세 요소는 단위의 마지막 세 가지 구성요소와 같음 4차수수 (cos(특)/2), x*sin(ANR/2), Y*sin(Workspace/2), z*sin(Workspace/2)), 회전 벡터의 요소는 있습니다. x, y, z 축은 가속 센서와 동일한 방식으로 정의됩니다. 참조 좌표계는 직접적인 정규직교를 기준으로 정의됩니다 (그림 1 참조). 이 좌표계 특징은 다음과 같습니다.

  • X는 벡터 Y x Z의 곱으로 정의됩니다. 인코더-디코더는 지면이 기기의 현재 위치에서 대략 동쪽을 가리킵니다.
  • Y는 기기가 현재 위치하는 지면에 대해 접선 방향이며 지자기 북극.
  • Z는 하늘을 향해 있고 기준 평면에 직각입니다.

회전 벡터 센서 사용 방법을 보여주는 샘플 애플리케이션은 을(를) 참조하세요. rotVectorDemo.java에 대한 응답 메시지입니다.

중요한 동작 센서 사용

중요한 움직임 감지 센서는 중요한 움직임이 감지될 때마다 이벤트를 트리거하고 자체적으로 사용 중지됩니다 중요한 움직임이란 음의 변화를 유발할 수 있는 사용자의 위치 예를 들어 걷기, 자전거 타기, 움직이는 자동차에 앉아 있습니다. 다음 코드는 기본적인 중요한 움직임 감지 센서의 인스턴스를 가져오는 방법 및 이벤트를 등록하는 방법 리스너:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val mSensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION)
val triggerEventListener = object : TriggerEventListener() {
    override fun onTrigger(event: TriggerEvent?) {
        // Do work
    }
}
mSensor?.also { sensor ->
    sensorManager.requestTriggerSensor(triggerEventListener, sensor)
}

자바

private SensorManager sensorManager;
private Sensor sensor;
private TriggerEventListener triggerEventListener;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);

triggerEventListener = new TriggerEventListener() {
    @Override
    public void onTrigger(TriggerEvent event) {
        // Do work
    }
};

sensorManager.requestTriggerSensor(triggerEventListener, mSensor);

자세한 내용은 TriggerEventListener를 참조하세요.

보행 계수기 센서 사용

보행 계수기 센서는 마지막 재부팅 이후 사용자가 걸은 걸음 수를 제공합니다. 될 수 있습니다. 걸음수 측정기는 지연 시간 (최대 10초)이 더 길지만 보행 탐지기 센서보다 훨씬 정확합니다.

참고: ACTIVITY_RECOGNITION 이 센서를 사용할 수 있도록 권한을 부여해야 합니다. Android 10 (API 수준 29) 이상

다음 코드는 기본 단계의 인스턴스를 가져오는 방법을 보여줍니다. 카운터 센서:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)

자바

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);

앱을 실행하는 기기에서 배터리를 보존하려면 현재 값을 가져올 JobScheduler 클래스 보행 계수기 센서를 특정 간격으로 측정합니다. 다양한 유형의 앱이 다른 센서 읽기 간격이 필요한 경우 이 간격을 가능한 한 오래 걸릴 수 있습니다.

보행 탐지기 센서 사용

보행 탐지기 센서는 사용자가 걸음을 걸을 때마다 이벤트를 트리거합니다. 지연 시간은 2초 미만일 것으로 예상됩니다

참고: ACTIVITY_RECOGNITION 이 센서를 사용할 수 있도록 권한을 부여해야 합니다. Android 10 (API 수준 29) 이상

다음 코드는 기본 단계의 인스턴스를 가져오는 방법을 보여줍니다. 감지기 센서:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR)

자바

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);

원시 데이터 작업

다음 센서는 앱에 선형 및 선형 알고리즘에 대한 원시 데이터를 기기에 적용되는 회전력 이 이러한 센서를 효과적으로 사용하려면 환경에서 요소를 필터링해야 하고, 일종의 장치입니다. 추세에 스무딩 알고리즘을 적용해야 할 수도 있습니다. 노이즈를 줄이기 위해 사용됩니다

가속도계 사용

가속 센서는 가속도를 포함하여 일어날 수 있습니다. 다음의 코드는 기본 가속 센서의 인스턴스를 가져오는 방법을 나타냅니다.

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)

자바

private SensorManager sensorManager;
private Sensor sensor;
  ...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

참고: 앱이 Android 12 (API 수준 31) 또는 이 센서는 rate-limited.

개념적으로 가속 센서는 적용되는 가속을 결정합니다. 센서에 가해지는 힘을 측정하여 기기에 적용하는 시간 (Ad) 자체 (Fs) 사이의 값을 갖습니다.

A_D=-(1/mass)∑F_S

그러나 중력은 항상 측정된 가속도에 영향을 미칩니다. 다음 관계입니다.

A_D=-g-(1/mass)∑F_S

따라서 기기가 테이블 위에 놓여 있고 빨라지지 않으면 가속도계가 g = 9.81m/s2의 크기를 판독했습니다. 마찬가지로 기기가 자유 낙하하므로 9.81m/s2의 속도로 지면으로 빠르게 가속하고 가속도계가 g = 0m/s2의 크기를 판독합니다. 따라서 실제 가속도에 영향을 미치지 않으므로 가속도계 데이터입니다. 하이 패스 필터를 적용하면 중력을 삭제할 수 있습니다. 반대로 로우 패스는 필터를 사용하여 중력을 분리할 수 있습니다. 다음 예는 다음과 같습니다.

Kotlin

override fun onSensorChanged(event: SensorEvent) {
    // In this example, alpha is calculated as t / (t + dT),
    // where t is the low-pass filter's time-constant and
    // dT is the event delivery rate.

    val alpha: Float = 0.8f

    // Isolate the force of gravity with the low-pass filter.
    gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0]
    gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1]
    gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2]

    // Remove the gravity contribution with the high-pass filter.
    linear_acceleration[0] = event.values[0] - gravity[0]
    linear_acceleration[1] = event.values[1] - gravity[1]
    linear_acceleration[2] = event.values[2] - gravity[2]
}

자바

public void onSensorChanged(SensorEvent event){
    // In this example, alpha is calculated as t / (t + dT),
    // where t is the low-pass filter's time-constant and
    // dT is the event delivery rate.

    final float alpha = 0.8;

    // Isolate the force of gravity with the low-pass filter.
    gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
    gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
    gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];

    // Remove the gravity contribution with the high-pass filter.
    linear_acceleration[0] = event.values[0] - gravity[0];
    linear_acceleration[1] = event.values[1] - gravity[1];
    linear_acceleration[2] = event.values[2] - gravity[2];
}

참고: 다양한 기법을 사용하여 센서 데이터를 필터링할 수 있습니다. 위의 코드 샘플은 단순 필터 상수(알파)를 사용하여 로우 패스 필터를 생성합니다. 이 필터 상수(t)는 시간 상수(t)에서 파생되며 필터가 센서 이벤트에 추가되고 센서의 이벤트 전달 속도 (dt)가 추가됩니다. 코드 샘플 에서는 데모를 위해 알파 값 0.8을 사용합니다. 이 필터링 방법을 사용할 경우 다른 알파 값을 선택할 수 있습니다.

가속도계는 표준 센서 좌표를 사용합니다. 시스템을 참조하세요. 실제로 이는 기기를 누워 있을 때 다음 조건이 적용됨을 의미합니다. 탁자 위에 평평하게 배치되어 있습니다.

  • 기기를 왼쪽으로 밀면 (즉, 오른쪽으로 이동) x 가속 값은 양성입니다.
  • 기기를 하단으로 밀면 (기기가 사용자로부터 멀어짐) y 가속 값은 긍정적입니다
  • 기기를 Am/s2의 가속으로 하늘로 밀면 z 가속 값은 A + 9.81과 같고, 이는 기기 (+A m/s2)에서 중력을 뺀 값 (-9.81m/s2)입니다.
  • 움직이지 않은 기기의 가속 값은 +9.81이며, 이는 기기 가속 (0m/s2에서 중력을 뺀 값, -9.81) m/s2).

일반적으로 가속도계는 기기 동작을 모니터링할 때 사용하기에 좋은 센서입니다. 거의 모든 Android 구동 핸드셋과 태블릿에는 가속도계가 있으며 약 10배 다른 움직임 감지 센서보다 전력량이 적습니다. 한 가지 단점은 중력을 제거하고 노이즈를 줄이기 위한 저역 통과 및 고역 통과 필터

자이로스코프 사용

자이로스코프는 기기의 x, y x축입니다. 다음 코드는 기본 자이로스코프의 인스턴스를 가져오는 방법을 나타냅니다.

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)

자바

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);

참고: 앱이 Android 12 (API 수준 31) 또는 이 센서는 rate-limited.

센서의 좌표계 가속도 센서에 사용되는 것과 동일합니다. 순환은 다음에서 양수입니다. 반시계 방향 즉, 관측값의 원점에 위치한 기기에서 x, y 또는 z축의 양수 위치에서 이를 보고 기기가 시계 반대 방향으로 회전하는 것처럼 보이는 경우 양수로 회전합니다. 이것은 양의 회전의 표준 수학적 정의와 같지 않으며 방향 센서에서 사용하는 롤입니다.

일반적으로 자이로스코프의 출력은 시간에 따라 통합되어 타임스텝에 따른 각도 변화를 보여줍니다. 예를 들면 다음과 같습니다.

Kotlin

// Create a constant to convert nanoseconds to seconds.
private val NS2S = 1.0f / 1000000000.0f
private val deltaRotationVector = FloatArray(4) { 0f }
private var timestamp: Float = 0f

override fun onSensorChanged(event: SensorEvent?) {
    // This timestep's delta rotation to be multiplied by the current rotation
    // after computing it from the gyro sample data.
    if (timestamp != 0f && event != null) {
        val dT = (event.timestamp - timestamp) * NS2S
        // Axis of the rotation sample, not normalized yet.
        var axisX: Float = event.values[0]
        var axisY: Float = event.values[1]
        var axisZ: Float = event.values[2]

        // Calculate the angular speed of the sample
        val omegaMagnitude: Float = sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ)

        // Normalize the rotation vector if it's big enough to get the axis
        // (that is, EPSILON should represent your maximum allowable margin of error)
        if (omegaMagnitude > EPSILON) {
            axisX /= omegaMagnitude
            axisY /= omegaMagnitude
            axisZ /= omegaMagnitude
        }

        // Integrate around this axis with the angular speed by the timestep
        // in order to get a delta rotation from this sample over the timestep
        // We will convert this axis-angle representation of the delta rotation
        // into a quaternion before turning it into the rotation matrix.
        val thetaOverTwo: Float = omegaMagnitude * dT / 2.0f
        val sinThetaOverTwo: Float = sin(thetaOverTwo)
        val cosThetaOverTwo: Float = cos(thetaOverTwo)
        deltaRotationVector[0] = sinThetaOverTwo * axisX
        deltaRotationVector[1] = sinThetaOverTwo * axisY
        deltaRotationVector[2] = sinThetaOverTwo * axisZ
        deltaRotationVector[3] = cosThetaOverTwo
    }
    timestamp = event?.timestamp?.toFloat() ?: 0f
    val deltaRotationMatrix = FloatArray(9) { 0f }
    SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
    // User code should concatenate the delta rotation we computed with the current rotation
    // in order to get the updated rotation.
    // rotationCurrent = rotationCurrent * deltaRotationMatrix;
}

자바

// Create a constant to convert nanoseconds to seconds.
private static final float NS2S = 1.0f / 1000000000.0f;
private final float[] deltaRotationVector = new float[4]();
private float timestamp;

public void onSensorChanged(SensorEvent event) {
    // This timestep's delta rotation to be multiplied by the current rotation
    // after computing it from the gyro sample data.
    if (timestamp != 0) {
      final float dT = (event.timestamp - timestamp) * NS2S;
      // Axis of the rotation sample, not normalized yet.
      float axisX = event.values[0];
      float axisY = event.values[1];
      float axisZ = event.values[2];

      // Calculate the angular speed of the sample
      float omegaMagnitude = sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);

      // Normalize the rotation vector if it's big enough to get the axis
      // (that is, EPSILON should represent your maximum allowable margin of error)
      if (omegaMagnitude > EPSILON) {
        axisX /= omegaMagnitude;
        axisY /= omegaMagnitude;
        axisZ /= omegaMagnitude;
      }

      // Integrate around this axis with the angular speed by the timestep
      // in order to get a delta rotation from this sample over the timestep
      // We will convert this axis-angle representation of the delta rotation
      // into a quaternion before turning it into the rotation matrix.
      float thetaOverTwo = omegaMagnitude * dT / 2.0f;
      float sinThetaOverTwo = sin(thetaOverTwo);
      float cosThetaOverTwo = cos(thetaOverTwo);
      deltaRotationVector[0] = sinThetaOverTwo * axisX;
      deltaRotationVector[1] = sinThetaOverTwo * axisY;
      deltaRotationVector[2] = sinThetaOverTwo * axisZ;
      deltaRotationVector[3] = cosThetaOverTwo;
    }
    timestamp = event.timestamp;
    float[] deltaRotationMatrix = new float[9];
    SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
    // User code should concatenate the delta rotation we computed with the current rotation
    // in order to get the updated rotation.
    // rotationCurrent = rotationCurrent * deltaRotationMatrix;
}

표준 자이로스코프는 노이즈와 노이즈에 대한 필터링이나 수정 없이 원시 회전 데이터를 제공합니다. 드리프트 (편향) 실제로는 자이로스코프 노이즈와 드리프트로 인해 있습니다. 일반적으로 다음과 같은 다른 센서를 모니터링하여 드리프트 (편향)와 노이즈를 판단합니다. 중력 센서나 가속도계와 같은 형태가 됩니다.

무보정 자이로스코프 사용

미보정 자이로스코프는 자이로스코프와 비슷합니다. 자이로 드리프트 보상이 회전 속도에 적용되지 않는다는 점이 다릅니다. 공장 보정 온도 보상은 회전 속도에 계속 적용됩니다. 미보정 자이로스코프는 방향 데이터를 후처리 및 융합하는 데 유용합니다. 일반적으로 gyroscope_event.values[0]이(가) 가까이에 있습니다. uncalibrated_gyroscope_event.values[0] - uncalibrated_gyroscope_event.values[3]입니다. 즉, 다음과 같습니다.

calibrated_x ~= uncalibrated_x - bias_estimate_x

참고: 보정되지 않은 센서는 좀 더 원시적인 결과를 제공하며 일부 편향은 포함하지만 측정값의 오차는 0과 0을 뺀 값에서 있습니다. 일부 애플리케이션은 좀 더 매끄럽고 보정되지 않은 결과를 선호할 수 있습니다 제공합니다 예를 들어 애플리케이션이 자체 센서 융합을 수행하려는 경우 사용하면 결과가 왜곡될 수 있습니다.

무보정 자이로스코프는 회전 속도 외에도 각 축을 중심으로 드리프트가 발생합니다. 다음 코드는 기본 인스턴스의 인스턴스를 가져오는 방법을 무보정 자이로스코프:

Kotlin

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED)

자바

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED);

추가 코드 샘플

BatchStepSensor 샘플은 다음을 자세히 보여줍니다. 자세히 알아보겠습니다

참고 사항