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

Платформа 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 с открытым исходным кодом (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)

Ява

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

Единицы измерения такие же, как и в датчике ускорения (м/с 2 ), а система координат такая же, как и в датчике ускорения.

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

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

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

Котлин

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

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

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

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

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

Котлин

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

Три элемента вектора вращения равны трем последним компонентам единичного кватерниона (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)
}

Ява

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) или выше.

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

Котлин

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) или выше.

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

Котлин

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

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

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

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

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

Котлин

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) или более поздней версии, этот датчик имеет ограничение по скорости .

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

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

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

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

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

Котлин

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

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

  • Если вы толкнете устройство с левой стороны (чтобы оно переместилось вправо), значение ускорения x будет положительным.
  • Если вы толкнете устройство снизу (чтобы оно отодвинулось от вас), значение ускорения y станет положительным.
  • Если вы толкнете устройство к небу с ускорением A м/с 2 , значение ускорения z будет равно A + 9,81, что соответствует ускорению устройства (+A м/с 2 ) минус сила тяжести. (-9,81 м/с 2 ).
  • Стационарное устройство будет иметь значение ускорения +9,81, что соответствует ускорению устройства (0 м/с 2 минус сила тяжести, равная -9,81 м/с 2 ).

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

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

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

Котлин

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

Система координат датчика такая же, как и для датчика ускорения. Вращение положительное в направлении против часовой стрелки; то есть наблюдатель, смотрящий из некоторого положительного места на оси 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;
}

Ява

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

Ява

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

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

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

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