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

Платформа 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 Open Source Project

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)

Ява

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 м/ с² . Аналогично, когда устройство находится в свободном падении и, следовательно, быстро ускоряется к земле со скоростью 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]
}

Ява

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

Note: You can use many different techniques to filter sensor data. The code sample above uses a simple filter constant (alpha) to create a low-pass filter. This filter constant is derived from a time constant (t), which is a rough representation of the latency that the filter adds to the sensor events, and the sensor's event delivery rate (dt). The code sample uses an alpha value of 0.8 for demonstration purposes. If you use this filtering method you may need to choose a different alpha value.

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

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

Ява

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

Note: Uncalibrated sensors provide more raw results and may include some bias, but their measurements contain fewer jumps from corrections applied through calibration. Some applications may prefer these uncalibrated results as smoother and more reliable. For instance, if an application is attempting to conduct its own sensor fusion, introducing calibrations can actually distort results.

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

Котлин

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, описанных на этой странице.

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