Платформа 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 Скалярный компонент является необязательным значением.
Датчик вектора вращения и датчик силы тяжести являются наиболее часто используемыми датчиками для обнаружения и мониторинга движения. Датчик вектора вращения особенно универсален и может использоваться для широкого спектра задач, связанных с движением, таких как обнаружение жестов, мониторинг угловых изменений и мониторинг изменений относительной ориентации. Например, датчик вектора вращения идеально подходит, если вы разрабатываете игру, приложение дополненной реальности, 2-мерный или 3-мерный компас или приложение для стабилизации камеры. В большинстве случаев использование этих датчиков является лучшим выбором, чем использование акселерометра и датчика геомагнитного поля или датчика ориентации.
Датчики 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);
Три элемента вектора вращения выражаются следующим образом:

Где величина вектора вращения равна 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 ), используя следующее соотношение:

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

По этой причине, когда устройство находится на столе (и не ускоряется), акселерометр показывает величину 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, описанных на этой странице.
Вам также следует прочитать
,Платформа 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 Скалярный компонент является необязательным значением.
Датчик вектора вращения и датчик силы тяжести являются наиболее часто используемыми датчиками для обнаружения и мониторинга движения. Датчик вектора вращения особенно универсален и может использоваться для широкого спектра задач, связанных с движением, таких как обнаружение жестов, мониторинг угловых изменений и мониторинг изменений относительной ориентации. Например, датчик вектора вращения идеально подходит, если вы разрабатываете игру, приложение дополненной реальности, 2-мерный или 3-мерный компас или приложение для стабилизации камеры. В большинстве случаев использование этих датчиков является лучшим выбором, чем использование акселерометра и датчика геомагнитного поля или датчика ориентации.
Датчики 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);
Три элемента вектора вращения выражаются следующим образом:

Где величина вектора вращения равна 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 ), используя следующее соотношение:

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

По этой причине, когда устройство находится на столе (и не ускоряется), акселерометр показывает величину 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);
Дополнительные примеры кода
Образец Backstepsensor дополнительно демонстрирует использование API, охватываемых на этой странице.