Датчики движения

Платформа Android предоставляет несколько датчиков, позволяющих отслеживать движение устройства.

Возможные архитектуры датчиков различаются в зависимости от типа датчика:

  • Датчики гравитации, линейного ускорения, вектора вращения, значительного движения, счетчика шагов и детектора шагов могут быть как аппаратными, так и программными.
  • Датчики акселерометра и гироскопа всегда имеют аппаратную основу.

Большинство устройств на базе Android оснащены акселерометром, а многие теперь также включают гироскоп. Доступность программных датчиков более вариативна, поскольку они часто используют один или несколько аппаратных датчиков для получения данных. В зависимости от устройства, эти программные датчики могут получать данные либо от акселерометра и магнитометра, либо от гироскопа.

Датчики движения полезны для мониторинга перемещения устройства, например, наклона, дрожания, вращения или качания. Движение обычно является отражением прямого ввода данных пользователем (например, пользователь управляет автомобилем в игре или мячом в игре), но оно также может быть отражением физической среды, в которой находится устройство (например, движение вместе с вами во время вождения автомобиля). В первом случае вы отслеживаете движение относительно системы координат устройства или системы координат вашего приложения; во втором случае вы отслеживаете движение относительно системы координат окружающего мира. Сами по себе датчики движения обычно не используются для мониторинга положения устройства, но их можно использовать с другими датчиками, такими как датчик геомагнитного поля, для определения положения устройства относительно системы координат окружающего мира (см. раздел «Датчики положения» для получения дополнительной информации).

Все датчики движения возвращают многомерные массивы значений датчиков для каждого SensorEvent . Например, во время одного события датчик акселерометр возвращает данные о силе ускорения по трем координатным осям, а гироскоп — данные о скорости вращения по трем координатным осям. Эти значения данных возвращаются в виде массива чисел float ( values ) вместе с другими параметрами SensorEvent . В таблице 1 приведена сводная информация о датчиках движения, доступных на платформе Android.

Таблица 1. Датчики движения, поддерживаемые платформой Android.

Датчик данные о событиях датчика Описание Единицы измерения
TYPE_ACCELEROMETER SensorEvent.values[0] Ускоряющая сила вдоль оси x (включая силу тяжести). м/с 2
SensorEvent.values[1] Ускоряющая сила вдоль оси Y (включая силу тяжести).
SensorEvent.values[2] Ускоряющая сила вдоль оси z (включая силу тяжести).
TYPE_ACCELEROMETER_UNCALIBRATED SensorEvent.values[0] Измеренное ускорение вдоль оси X без какой-либо компенсации смещения. м/с 2
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. м/с 2
SensorEvent.values[1] Сила тяжести вдоль оси Y.
SensorEvent.values[2] Сила тяжести вдоль оси z.
TYPE_GYROSCOPE SensorEvent.values[0] Скорость вращения вокруг оси x. рад/с
SensorEvent.values[1] Скорость вращения вокруг оси Y.
SensorEvent.values[2] Скорость вращения вокруг оси Z.
TYPE_GYROSCOPE_UNCALIBRATED SensorEvent.values[0] Скорость вращения (без компенсации дрейфа) вокруг оси x. рад/с
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 (без учета силы тяжести). м/с 2
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(θ/2)). 1
TYPE_SIGNIFICANT_MOTION Н/Д Н/Д Н/Д
TYPE_STEP_COUNTER SensorEvent.values[0] Количество шагов, пройденных пользователем с момента последней перезагрузки, когда датчик был активирован. Шаги
TYPE_STEP_DETECTOR Н/Д Н/Д Н/Д

1. Скалярная составляющая является необязательным значением.

Датчик вектора вращения и датчик гравитации являются наиболее часто используемыми датчиками для обнаружения и мониторинга движения. Датчик вектора вращения особенно универсален и может использоваться для широкого спектра задач, связанных с движением, таких как обнаружение жестов, мониторинг угловых изменений и мониторинг относительных изменений ориентации. Например, датчик вектора вращения идеально подходит для разработки игры, приложения дополненной реальности, двухмерного или трехмерного компаса или приложения для стабилизации камеры. В большинстве случаев использование этих датчиков является лучшим выбором, чем использование акселерометра, датчика геомагнитного поля или датчика ориентации.

Датчики проекта Android с открытым исходным кодом

Проект Android Open Source Project (AOSP) предоставляет три программных датчика движения: датчик гравитации, датчик линейного ускорения и датчик вектора вращения. Эти датчики были обновлены в Android 4.0 и теперь используют гироскоп устройства (в дополнение к другим датчикам) для повышения стабильности и производительности. Если вы хотите попробовать эти датчики, вы можете определить их, используя методы getVendor() и getVersion() (производитель — Google LLC; номер версии — 3). Идентификация этих датчиков по производителю и номеру версии необходима, поскольку система Android рассматривает эти три датчика как вторичные. Например, если производитель устройства предоставляет свой собственный датчик гравитации, то датчик гравитации AOSP отображается как вторичный датчик гравитации. Все три этих датчика используют гироскоп: если устройство не имеет гироскопа, эти датчики не отображаются и недоступны для использования.

Используйте датчик гравитации

Датчик гравитации предоставляет трехмерный вектор, указывающий направление и величину гравитации. Как правило, этот датчик используется для определения относительной ориентации устройства в пространстве. Следующий код показывает, как получить экземпляр стандартного датчика гравитации:

Котлин

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

Java

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

Единицы измерения совпадают с единицами измерения акселерометра (м/ с² ), и система координат также совпадает с системой координат акселерометра.

Примечание: Когда устройство находится в состоянии покоя, показания датчика гравитации должны быть идентичны показаниям акселерометра.

Используйте линейный акселерометр.

Датчик линейного ускорения предоставляет трехмерный вектор, представляющий ускорение вдоль каждой оси устройства, за исключением силы тяжести. Это значение можно использовать для распознавания жестов. Также это значение может служить входными данными для инерциальной навигационной системы, использующей метод инерциальной навигации. Следующий код показывает, как получить экземпляр стандартного датчика линейного ускорения:

Котлин

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

Java

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

Этот датчик обычно используется, когда необходимо получить данные об ускорении без учета влияния гравитации. Например, его можно использовать для измерения скорости автомобиля. Датчик линейного ускорения всегда имеет смещение, которое необходимо устранить. Простейший способ сделать это — включить этап калибровки в ваше приложение. Во время калибровки вы можете попросить пользователя установить устройство на стол, а затем считать смещения по всем трем осям. Затем вы можете вычесть это смещение из прямых показаний датчика ускорения, чтобы получить фактическое линейное ускорение.

Система координат датчика совпадает с системой координат, используемой акселерометром, как и единицы измерения (м/ с² ).

Используйте датчик вектора вращения.

Вектор вращения представляет ориентацию устройства как комбинацию угла и оси, на которую устройство повернулось на угол θ вокруг оси (x, y или z). Следующий код показывает, как получить экземпляр датчика вектора вращения по умолчанию:

Котлин

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

Java

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. Система координат, используемая датчиком вектора вращения.

Три элемента вектора вращения равны последним трем компонентам единичного кватерниона (cos(θ/2), x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)). Элементы вектора вращения безразмерны. Оси x, y и z определены так же, как и у акселерометра. Система координат задана как прямой ортонормированный базис (см. рисунок 1). Эта система координат обладает следующими характеристиками:

  • X определяется как векторное произведение Y x Z. Оно касательно земли в текущем местоположении устройства и направлено приблизительно на восток.
  • Точка Y касательна к земле в текущем местоположении устройства и направлена ​​в сторону геомагнитного Северного полюса.
  • Точка Z направлена ​​вверх и перпендикулярна плоскости земли.

Пример приложения, демонстрирующего использование датчика вектора вращения, можно найти в файле RotationVectorDemo.java .

Используйте датчик движения.

Датчик значительного движения генерирует событие каждый раз, когда обнаруживается значительное движение, после чего отключается. Значительное движение — это движение, которое может привести к изменению местоположения пользователя; например, ходьба, езда на велосипеде или нахождение в движущемся автомобиле. Следующий код показывает, как получить экземпляр стандартного датчика значительного движения и как зарегистрировать обработчик событий:

Котлин

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)
}

Java

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 секунд), но более высокую точность, чем датчик определения шагов.

Примечание: Для использования этого датчика вашим приложением на устройствах под управлением Android 10 (уровень API 29) или выше необходимо объявить разрешение ACTIVITY_RECOGNITION .

Следующий код показывает, как получить экземпляр датчика счетчика шагов по умолчанию:

Котлин

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

Java

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

Для экономии заряда батареи на устройствах, на которых работает ваше приложение, следует использовать класс JobScheduler для получения текущего значения от датчика счетчика шагов с определенным интервалом. Хотя для разных типов приложений требуются разные интервалы считывания данных с датчика, этот интервал следует сделать как можно более длительным, если только вашему приложению не требуются данные с датчика в режиме реального времени.

Используйте датчик шага

Датчик шага срабатывает каждый раз, когда пользователь делает шаг. Ожидается, что задержка составит менее 2 секунд.

Примечание: Для использования этого датчика вашим приложением на устройствах под управлением Android 10 (уровень API 29) или выше необходимо объявить разрешение ACTIVITY_RECOGNITION .

Следующий код показывает, как получить экземпляр датчика шага по умолчанию:

Котлин

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

Java

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

Работа с необработанными данными

Следующие датчики предоставляют вашему приложению необработанные данные о линейных и вращательных силах, действующих на устройство. Для эффективного использования значений этих датчиков необходимо отфильтровать факторы окружающей среды, такие как гравитация. Также может потребоваться применение алгоритма сглаживания к тренду значений для уменьшения шума.

Используйте акселерометр

Датчик ускорения измеряет ускорение, приложенное к устройству, включая силу тяжести. Следующий код показывает, как получить экземпляр стандартного датчика ускорения:

Котлин

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

Java

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

Примечание: Если ваше приложение ориентировано на Android 12 (уровень API 31) или выше, использование этого датчика будет ограничено по частоте запросов .

В концептуальном плане датчик ускорения определяет ускорение, приложенное к устройству (A d ), измеряя силы, приложенные к самому датчику (F s ), используя следующее соотношение:

A_D=-(1/масса)∑F_S

Однако сила гравитации всегда влияет на измеряемое ускорение в соответствии со следующим соотношением:

A_D = -g - (1/масса) ∑F_S

По этой причине, когда устройство находится на столе (и не ускоряется), акселерометр показывает величину g = 9,81 м/ с² . Аналогично, когда устройство находится в свободном падении и, следовательно, быстро ускоряется к земле со скоростью 9,81 м/ с² , его акселерометр показывает величину g = 0 м/ с² . Поэтому, чтобы измерить реальное ускорение устройства, необходимо исключить влияние силы тяжести из данных акселерометра. Этого можно достичь, применив фильтр верхних частот. И наоборот, для выделения силы тяжести можно использовать фильтр нижних частот. Следующий пример показывает, как это можно сделать:

Котлин

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]
}

Java

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), которая является приблизительным представлением задержки, добавляемой фильтром к событиям датчика, и скорости доставки событий датчика (dt). В примере кода для демонстрационных целей используется значение альфа, равное 0,8. При использовании этого метода фильтрации вам может потребоваться выбрать другое значение альфа.

Акселерометры используют стандартную систему координат датчика. На практике это означает, что при нахождении устройства в горизонтальном положении на столе в его естественной ориентации выполняются следующие условия:

  • Если толкнуть устройство с левой стороны (так, чтобы оно сместилось вправо), значение ускорения по оси X будет положительным.
  • Если толкнуть устройство снизу (так, чтобы оно отдалилось от вас), значение ускорения по оси Y будет положительным.
  • Если толкнуть устройство вверх с ускорением A м/ с² , то значение ускорения по оси z будет равно A + 9,81, что соответствует ускорению устройства (+A м/ с² ) минус сила тяжести (-9,81 м/ с² ).
  • Неподвижное устройство будет иметь значение ускорения +9,81, что соответствует ускорению устройства (0 м/ с² минус сила тяжести, которая составляет -9,81 м/ с² ).

В целом, акселерометр — хороший датчик для мониторинга движения устройства. Практически каждый Android-смартфон и планшет оснащен акселерометром, и он потребляет примерно в 10 раз меньше энергии, чем другие датчики движения. Одним из недостатков является необходимость использования низкочастотных и высокочастотных фильтров для устранения влияния гравитации и снижения шума.

Используйте гироскоп

Гироскоп измеряет скорость вращения в рад/с вокруг осей x, y и z устройства. Следующий код показывает, как получить экземпляр стандартного гироскопа:

Котлин

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

Java

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

Примечание: Если ваше приложение ориентировано на Android 12 (уровень API 31) или выше, использование этого датчика будет ограничено по частоте запросов .

Система координат датчика совпадает с системой координат акселерометра. Вращение считается положительным в направлении против часовой стрелки; то есть наблюдатель, смотрящий из некоторой положительной точки на оси x, y или z на устройство, расположенное в начале координат, сообщит о положительном вращении, если устройство будет казаться вращающимся против часовой стрелки. Это стандартное математическое определение положительного вращения, и оно отличается от определения крена, используемого датчиком ориентации.

Обычно выходные данные гироскопа интегрируются по времени для вычисления вращения, описывающего изменение углов за временной шаг. Например:

Котлин

// 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;
}

Java

// 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

Примечание: Некалиброванные датчики дают больше исходных результатов и могут содержать некоторую погрешность, но их измерения содержат меньше скачков, вызванных корректировками, применяемыми в процессе калибровки. В некоторых приложениях некалиброванные результаты могут быть предпочтительнее, поскольку они более сглаженные и надежные. Например, если приложение пытается выполнить собственное объединение данных с датчиков, введение калибровок может фактически исказить результаты.

Помимо скорости вращения, некалиброванный гироскоп также предоставляет приблизительную оценку дрейфа вокруг каждой оси. Следующий код показывает, как получить экземпляр стандартного некалиброванного гироскопа:

Котлин

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

Java

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

Дополнительные примеры кода

Пример BatchStepSensor дополнительно демонстрирует использование API, описанных на этой странице.

Вам также следует прочитать