위치 센서

Android 플랫폼은 위치를 파악할 수 있는 두 개의 센서를 제공합니다. 지자기장 센서와 가속도계입니다. Android 또한 코끼리의 얼굴이 주변에서 얼마나 가까이 있는지를 객체 (근접 센서라고 함)와 관련이 있습니다. 이 지자기장 센서와 근접 센서는 하드웨어 기반입니다. 대부분 핸드셋 및 태블릿 제조업체에는 지자기장 센서가 포함되어 있습니다. 마찬가지로 핸드셋 제조업체는 보통 기기가 충전 또는 충전 중일 때 핸드셋을 사용자 얼굴 가까이에 갖다 대고 있음 (예: 전화 통화 시) 호출). 기기의 방향을 결정하려면 장치의 가속도계와 지자기장 센서에 의해 결정됩니다.

참고: 방향 센서는 Android 2.2에서 지원 중단되었습니다. (API 수준 8)에서 지원되며 방향 센서 유형은 Android 4.4W에서 지원 중단됨 (API 수준 20)

위치 센서는 방에 기기의 물리적 위치를 결정하는 데 쉽게 이해할 수 있습니다 예를 들어, 지자기장을 사용하여 가속도계와 함께 사용하여 기기의 위치 파악 북극에 대해 엄청나게 커집니다. 또한 이러한 센서를 사용하여 애플리케이션의 기준계에서 기기의 방향을 결정할 수 있습니다. 위치 센서는 일반적으로 기기의 움직임이나 모션을 모니터링하는 데 사용되지 않으며 흔들기, 기울이기, 밀기 등 (자세한 내용은 움직임 감지 센서 참고)

지자기장 센서와 가속도계가 다차원 배열을 반환합니다. 각 SensorEvent의 센서 값입니다. 예를 들어 지자기장 센서는 다음에 대한 지자기장 강도 값을 3개의 좌표축 각각에 저장됩니다. 마찬가지로 가속도계 센서는 센서 이벤트를 수신합니다. 사용되는 좌표계에 대한 자세한 내용은 센서별, 페이지 참조 센서 좌표계. 근접 센서에서 단일 값 제공 해야 합니다. 표 1에는 Android 플랫폼에서 지원됩니다.

표 1. Android 플랫폼에서 지원되는 위치 센서

센서 센서 이벤트 데이터 설명 측정 단위
TYPE_GAME_ROTATION_VECTOR SensorEvent.values[0] x축의 회전 벡터 구성요소(x * sin(θ/2)). 단위 없음
SensorEvent.values[1] y축의 회전 벡터 구성요소(y * sin(θ/2)).
SensorEvent.values[2] z축의 회전 벡터 구성요소(z * sin(θ/2)).
TYPE_GEOMAGNETIC_ROTATION_VECTOR SensorEvent.values[0] x축의 회전 벡터 구성요소(x * sin(θ/2)). 단위 없음
SensorEvent.values[1] y축의 회전 벡터 구성요소(y * sin(θ/2)).
SensorEvent.values[2] z축의 회전 벡터 구성요소(z * sin(θ/2)).
TYPE_MAGNETIC_FIELD SensorEvent.values[0] x축의 지자기장 강도. μT
SensorEvent.values[1] y축의 지자기장 강도.
SensorEvent.values[2] z축의 지자기장 강도.
TYPE_MAGNETIC_FIELD_UNCALIBRATED SensorEvent.values[0] x축의 지자기장 강도(강철 보정 없음). μT
SensorEvent.values[1] y축의 지자기장 강도(강철 보정 없음).
SensorEvent.values[2] z축의 지자기장 강도(강철 보정 없음).
SensorEvent.values[3] x축의 철 편향 추정치.
SensorEvent.values[4] y축의 철 편향 추정치.
SensorEvent.values[5] z축의 철 편향 추정치.
TYPE_ORIENTATION1 SensorEvent.values[0] 방위각(z축을 중심으로 한 각도).
SensorEvent.values[1] 경사(x축을 중심으로 한 각도).
SensorEvent.values[2] 롤(y축을 중심으로 한 각도).
TYPE_PROXIMITY SensorEvent.values[0] 물체로부터의 거리2 cm

1이 센서는 Android 2.2 (API)에서 지원 중단되었습니다. 이 센서 유형은 Android 4.4W (API 수준 20)에서 지원 중단되었습니다. 센서 프레임워크는 기기 획득을 위한 대체 방법 제공 이는 Compute Engine VM에서 기기 방향

2 일부 근접 센서는 바이너리 값만 제공합니다. 가깝고 먼 것을 나타냅니다.

게임 회전 벡터 센서 사용

게임 회전 벡터 센서는 회전 지자기장을 사용하지 않는다는 점만 다릅니다. 따라서 Y축은 북쪽을 가리키지만 대신 다른 참조를 가리키게 됩니다. 그러한 참조는 기준표에 따라 Z 축을 중심으로 자이로스코프가 드리프트하는 것과 같은 자릿수의 확률을 가질 수 있습니다.

게임 회전 벡터 센서가 자기장을 사용하지 않기 때문에 상대적 회전은 더 정확하고 자기장 변화의 영향을 받지 않습니다. 다음과 같은 경우 게임에서 이 센서 사용 북쪽이 어디에 있는지 신경 쓰지 않아도 되며, 정상적인 회전 벡터가 자기장에 의존하기 때문이죠.

다음 코드는 기본 게임 회전 벡터의 인스턴스를 가져오는 방법을 보여줍니다. 센서:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR)

자바

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

지자기 회전 벡터 센서 사용

지자기 회전 벡터 센서는 회전 벡터 센서를 사용하여 자이로스코프를 사용하지 않습니다. 이 센서의 정확도가 일반 회전 벡터보다 낮습니다. 전력 소비가 감소합니다. 회전 데이터를 수집하려는 경우에만 이 센서 사용 백그라운드에서 정보를 검색할 수 있습니다. 사용할 때 가장 유용한 센서 살펴보겠습니다

다음 코드는 기본 지자기 회전 인스턴스를 가져오는 방법을 보여줍니다. 벡터 센서:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR)

자바

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

기기 방향 계산

장치의 방향을 계산하여 장치의 위치를 가장 근접한 전자기 거리 (특히 자석간)를 북극). 다음 코드는 기기의 데이터 세트에 대한 방향:

Kotlin

private lateinit var sensorManager: SensorManager
...
// Rotation matrix based on current readings from accelerometer and magnetometer.
val rotationMatrix = FloatArray(9)
SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerReading, magnetometerReading)

// Express the updated rotation matrix as three orientation angles.
val orientationAngles = FloatArray(3)
SensorManager.getOrientation(rotationMatrix, orientationAngles)

자바

private SensorManager sensorManager;
...
// Rotation matrix based on current readings from accelerometer and magnetometer.
final float[] rotationMatrix = new float[9];
SensorManager.getRotationMatrix(rotationMatrix, null,
    accelerometerReading, magnetometerReading);

// Express the updated rotation matrix as three orientation angles.
final float[] orientationAngles = new float[3];
SensorManager.getOrientation(rotationMatrix, orientationAngles);

시스템은 기기의 지자기 필드 센서를 장치의 가속도계와 함께 사용합니다. 이 두 가지를 시스템은 다음 세 가지 센서에 대한 데이터를 방향 각도:

  • 방위각(-z축을 중심으로 한 회전 각도). 이것은 기기의 현재 나침반 방향과 자북 사이의 각도입니다. 기기의 상단 가장자리가 자북을 향하는 경우 방위각은 0입니다. 도; 상단 가장자리가 남쪽을 향하면 방위각은 180도입니다. 마찬가지로 위쪽 가장자리가 동쪽을 향하면 방위각은 90도이고 상단 가장자리가 방위각은 270도입니다.
  • 피치 (x축을 중심으로 한 회전 각도). 이것은 기기 화면과 평행한 평면과 평행한 평면 사이의 각도 땅에 닿게 합니다. 기기를 바닥과 평행으로 잡으면 기기의 상단 가장자리를 지면 쪽으로 기울이세요. 피치각이 양수가 됩니다. 반대 방향으로 기울이기— 기기의 상단 가장자리를 지면에서 떨어뜨려 놓으면 안 됩니다. 피치 각도가 음수가 됩니다. 값 범위는 -90도~ 90도입니다.
  • 롤 (y축을 중심으로 한 회전 각도). 이것은 기기 화면과 직각인 평면과 평면 사이의 각도 지면과 직각을 이룹니다. 기기를 지면과 평행하게 들고 있는 경우 아래쪽 가장자리를 사용자 가까이에 두고 기기의 왼쪽 가장자리를 기울입니다. 지면을 향하면 롤 각도가 양수가 됩니다. 반대 방향으로 기울이기 기기의 오른쪽 가장자리를 지면을 향해 이동) 롤 각도가 음수가 됩니다. 값 범위는 -180도입니다. 180도까지 설정할 수 있습니다

참고: 센서의 롤 정의가 지오센서 생태계에서 구현되는 경우가 대부분입니다.

이러한 각도는 항공에서 사용되는 기술 (요, 피치, 롤)입니다. 항공 시스템에서 x 축은 꼬리부터 코까지 평면의 긴 면을 따릅니다.

방향 센서가 원시 센서 데이터를 처리하여 데이터를 얻음 가속도계와 지자기장 센서로부터 수집됩니다. Kubernetes가 방향의 정확성과 정밀도가 줄어들 수 있습니다. 특히 이 센서는 롤아웃이 안 되는 경우에만 각이 0입니다. 따라서 방향 센서가 Android에서 지원 중단되었습니다. 2.2 (API 수준 8)에서 지원되며 방향 센서 유형은 Android에서 지원 중단됨 4.4W (API 수준 20). 방향 센서의 원시 데이터를 사용하는 대신 getRotationMatrix() 사용 메서드를 getOrientation() 메서드 다음 코드 샘플과 같이 방향 값을 계산합니다. 일부 Cloud Shell에서 remapCoordinateSystem() 메서드를 사용하여 방향 값을 애플리케이션의 프레임으로 변환합니다. 참조

Kotlin

class SensorActivity : Activity(), SensorEventListener {

    private lateinit var sensorManager: SensorManager
    private val accelerometerReading = FloatArray(3)
    private val magnetometerReading = FloatArray(3)

    private val rotationMatrix = FloatArray(9)
    private val orientationAngles = FloatArray(3)

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        // Do something here if sensor accuracy changes.
        // You must implement this callback in your code.
    }

    override fun onResume() {
        super.onResume()

        // Get updates from the accelerometer and magnetometer at a constant rate.
        // To make batch operations more efficient and reduce power consumption,
        // provide support for delaying updates to the application.
        //
        // In this example, the sensor reporting delay is small enough such that
        // the application receives an update before the system checks the sensor
        // readings again.
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)?.also { accelerometer ->
            sensorManager.registerListener(
                    this,
                    accelerometer,
                    SensorManager.SENSOR_DELAY_NORMAL,
                    SensorManager.SENSOR_DELAY_UI
            )
        }
        sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)?.also { magneticField ->
            sensorManager.registerListener(
                    this,
                    magneticField,
                    SensorManager.SENSOR_DELAY_NORMAL,
                    SensorManager.SENSOR_DELAY_UI
            )
        }
    }

    override fun onPause() {
        super.onPause()

        // Don't receive any more updates from either sensor.
        sensorManager.unregisterListener(this)
    }

    // Get readings from accelerometer and magnetometer. To simplify calculations,
    // consider storing these readings as unit vectors.
    override fun onSensorChanged(event: SensorEvent) {
        if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
            System.arraycopy(event.values, 0, accelerometerReading, 0, accelerometerReading.size)
        } else if (event.sensor.type == Sensor.TYPE_MAGNETIC_FIELD) {
            System.arraycopy(event.values, 0, magnetometerReading, 0, magnetometerReading.size)
        }
    }

    // Compute the three orientation angles based on the most recent readings from
    // the device's accelerometer and magnetometer.
    fun updateOrientationAngles() {
        // Update rotation matrix, which is needed to update orientation angles.
        SensorManager.getRotationMatrix(
                rotationMatrix,
                null,
                accelerometerReading,
                magnetometerReading
        )

        // "rotationMatrix" now has up-to-date information.

        SensorManager.getOrientation(rotationMatrix, orientationAngles)

        // "orientationAngles" now has up-to-date information.
    }
}

자바

public class SensorActivity extends Activity implements SensorEventListener {

    private SensorManager sensorManager;
    private final float[] accelerometerReading = new float[3];
    private final float[] magnetometerReading = new float[3];

    private final float[] rotationMatrix = new float[9];
    private final float[] orientationAngles = new float[3];

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something here if sensor accuracy changes.
        // You must implement this callback in your code.
    }

    @Override
    protected void onResume() {
        super.onResume();

        // Get updates from the accelerometer and magnetometer at a constant rate.
        // To make batch operations more efficient and reduce power consumption,
        // provide support for delaying updates to the application.
        //
        // In this example, the sensor reporting delay is small enough such that
        // the application receives an update before the system checks the sensor
        // readings again.
        Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (accelerometer != null) {
            sensorManager.registerListener(this, accelerometer,
                SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
        }
        Sensor magneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        if (magneticField != null) {
            sensorManager.registerListener(this, magneticField,
                SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        // Don't receive any more updates from either sensor.
        sensorManager.unregisterListener(this);
    }

    // Get readings from accelerometer and magnetometer. To simplify calculations,
    // consider storing these readings as unit vectors.
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
          System.arraycopy(event.values, 0, accelerometerReading,
              0, accelerometerReading.length);
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            System.arraycopy(event.values, 0, magnetometerReading,
                0, magnetometerReading.length);
        }
    }

    // Compute the three orientation angles based on the most recent readings from
    // the device's accelerometer and magnetometer.
    public void updateOrientationAngles() {
        // Update rotation matrix, which is needed to update orientation angles.
        SensorManager.getRotationMatrix(rotationMatrix, null,
            accelerometerReading, magnetometerReading);

        // "rotationMatrix" now has up-to-date information.

        SensorManager.getOrientation(rotationMatrix, orientationAngles);

        // "orientationAngles" now has up-to-date information.
    }
}

일반적으로는 보고서에서 데이터를 처리하거나 필터링할 필요가 센서의 각도를 변환하지 않는 기기의 원시 방향각 좌표계를 애플리케이션의 기준계에 추가합니다.

지자기장 센서 사용

지자기장 센서를 사용하면 지구 자기장의 변화를 모니터링할 수 있습니다. 이 다음의 코드는 기본 지자기장 센서의 인스턴스를 가져오는 방법을 나타냅니다.

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)

자바

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

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

이 센서는 3개의 좌표축 각각에 대해 원시 자장 강도 데이터 (μT)를 제공합니다. 일반적으로는 이 센서를 직접 사용할 필요가 없습니다. 대신 회전 벡터를 사용해 센서를 사용하여 원시 회전 움직임을 파악하거나 가속도계와 지자기장을 사용할 수 있습니다. 센서를 getRotationMatrix() 메서드와 함께 사용하여 회전 매트릭스와 경사 매트릭스를 획득합니다. 그런 다음 이 행렬을 getOrientation()와 함께 사용 방위각을 얻기 위한 getInclination() 메서드 지자기 경사 데이터입니다.

참고: 앱을 테스트할 때 센서의 정확도를 낮추는 것입니다.

보정되지 않은 자기계 사용

미보정 자기계는 지자기장과 유사하지만 센서에 넣습니다. 단, 자기장에 강철 보정이 적용되지 않습니다. 공장 보정 온도 보상은 여전히 자기장에 적용됩니다. 미보정 자기계 잘못된 강철 추정치를 처리하는 데 유용합니다. 일반적으로 geomagneticsensor_event.values[0] uncalibrated_magnetometer_event.values[0] - uncalibrated_magnetometer_event.values[3]에 가까워집니다. 즉, 다음과 같습니다.

calibrated_x ~= uncalibrated_x - bias_estimate_x

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

자기장 외에도 미보정 자기계는 추정된 강철 바이어스입니다. 다음 코드는 기본 미보정 자기계:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED)

자바

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

근접 센서 사용

근접 센서를 통해 객체가 기기에서 얼마나 멀리 떨어져 있는지 확인할 수 있습니다. 다음 기본 근접 센서의 인스턴스를 가져오는 방법을 보여주는 코드입니다.

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)

자바

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

근접 센서는 일반적으로 사람의 머리가 얼굴에서 얼마나 멀리 떨어져 있는지 확인하는 데 사용됩니다. (예: 사용자가 전화를 걸거나 받을 때) 대부분 근접 센서는 절대 거리(cm)를 반환하지만 일부는 Far 값을 보여줍니다.

참고: 일부 기기 모델에서는 근접 센서의 이 기능이 사용 설정되어 있을 때 깜박이는 점이 화면에 나타날 수 있습니다. 을 탭합니다.

다음 코드는 근접 센서의 사용 방법을 나타냅니다.

Kotlin

class SensorActivity : Activity(), SensorEventListener {

    private lateinit var sensorManager: SensorManager
    private var proximity: Sensor? = null

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)

        // Get an instance of the sensor service, and use that to get an instance of
        // a particular sensor.
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        proximity = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        // Do something here if sensor accuracy changes.
    }

    override fun onSensorChanged(event: SensorEvent) {
        val distance = event.values[0]
        // Do something with this sensor data.
    }

    override fun onResume() {
        // Register a listener for the sensor.
        super.onResume()

        proximity?.also { proximity ->
            sensorManager.registerListener(this, proximity, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

    override fun onPause() {
        // Be sure to unregister the sensor when the activity pauses.
        super.onPause()
        sensorManager.unregisterListener(this)
    }
}

자바

public class SensorActivity extends Activity implements SensorEventListener {
    private SensorManager sensorManager;
    private Sensor proximity;

    @Override
    public final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Get an instance of the sensor service, and use that to get an instance of
        // a particular sensor.
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        proximity = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
    }

    @Override
    public final void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something here if sensor accuracy changes.
    }

    @Override
    public final void onSensorChanged(SensorEvent event) {
        float distance = event.values[0];
        // Do something with this sensor data.
    }

    @Override
    protected void onResume() {
        // Register a listener for the sensor.
        super.onResume();
        sensorManager.registerListener(this, proximity, SensorManager.SENSOR_DELAY_NORMAL);
      }

    @Override
    protected void onPause() {
        // Be sure to unregister the sensor when the activity pauses.
        super.onPause();
        sensorManager.unregisterListener(this);
    }
}

참고: 일부 근접 센서는 '주변' 또는 '먼'입니다. 이 경우 센서는 일반적으로 멀리 있는 상태에서 최대 범위 값을 보고합니다. 가까운 상태에 있는 값이 더 작은 것을 알 수 있습니다. 일반적으로 원거리 값은 5cm이지만 다를 수 있음 변합니다. getMaximumRange() 메서드를 사용하여 센서의 최대 범위를 확인할 수 있습니다.

참고 사항