Датчики руху в Android: Sensor API, події, батчі

Перегрів пристрою через неправильну частоту опитування датчиків — типова проблема. Розряд батареї за годину замість дня. Ми стикалися з проектом, де sensor fusion видавав випадкові кватерніони на дешевих телефонах. Рішення — правильний вибір віртуальних датчиків та батч-оновлень. Більше 5 років досв

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Датчики руху в Android: Sensor API, події, батчі
Середній
від 1 дня до 3 днів

Наші компетенції:

Часті запитання

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    597

Перегрів пристрою через неправильну частоту опитування датчиків — типова проблема. Розряд батареї за годину замість дня. Ми стикалися з проектом, де sensor fusion видавав випадкові кватерніони на дешевих телефонах. Рішення — правильний вибір віртуальних датчиків та батч-оновлень. Більше 5 років досвіду та більше 20 проектів із датчиками руху — за нашими плечима.

Android Sensor Framework надає доступ до 13+ типів датчиків через єдиний SensorManager. Акселерометр та гіроскоп — апаратні. TYPE_LINEAR_ACCELERATION, TYPE_ROTATION_VECTOR, TYPE_GRAVITY — віртуальні: обчислюються з апаратних через sensor fusion у firmware. Різниця в тому, що віртуальні датчики споживають більше CPU при високій частоті та можуть бути недоступні на бюджетних пристроях. Детальніше — в Android Developer: Sensors Overview. Наш досвід показує: для точної орієнтації використовуйте TYPE_ROTATION_VECTOR, для лінійного прискорення — TYPE_LINEAR_ACCELERATION.

Реєстрація та життєвий цикл

class SensorViewModel(application: Application) : AndroidViewModel(application) { private val sensorManager = application.getSystemService(SENSOR_SERVICE) as SensorManager private val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) private val gyroscope = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) private val _sensorData = MutableStateFlow<SensorData>(SensorData.Empty) val sensorData: StateFlow<SensorData> = _sensorData.asStateFlow() private val sensorEventListener = object : SensorEventListener { override fun onSensorChanged(event: SensorEvent) { when (event.sensor.type) { Sensor.TYPE_ACCELEROMETER -> handleAccelerometer(event.values) Sensor.TYPE_GYROSCOPE -> handleGyroscope(event.values) } } override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {} } fun startListening() { accelerometer?.let { sensorManager.registerListener( sensorEventListener, it, SensorManager.SENSOR_DELAY_GAME // ~20ms ) } } fun stopListening() { sensorManager.unregisterListener(sensorEventListener) } override fun onCleared() { stopListening() } } 

Ключове: unregisterListener строго в onCleared() ViewModel або в onPause() Activity. Забутий listener працює у фоні, жере батарею та може крашити застосунок при знищенні Activity.

Частоти опитування: константи та реальність

Константа Номінальна затримка Реальна частота
SENSOR_DELAY_NORMAL 200 мс ~5 Гц
SENSOR_DELAY_UI 60 мс ~16 Гц
SENSOR_DELAY_GAME 20 мс ~50 Гц
SENSOR_DELAY_FASTEST 0 мс максимум заліза

З Android API 9 можна задавати довільний інтервал у мікросекундах через registerListener(listener, sensor, samplingPeriodUs). Наприклад, 10000 мкс = 100 Гц.

SENSOR_DELAY_FASTEST на Snapdragon 8 Gen 2 дає до 500 Гц на акселерометрі — це потрібно тільки для спеціалізованих застосунків (аналіз вібрацій, балансування). Для більшості задач 50–100 Гц достатньо.

Чому Sensor Fusion в Android вимагає калібрування?

Датчики на дешевих пристроях мають зсуви та шум. Віртуальні датчики (TYPE_ROTATION_VECTOR) використовують вбудоване калібрування firmware, але на старих ядрах можуть дрейфувати. Ми тестуємо на апаратах різних вендорів та при необхідності додаємо свій фільтр (Mahony/Madgwick) для корекції.

TYPE_ROTATION_VECTOR — кватерніон орієнтації пристрою, обчислений з акселерометра + гіроскопа + магнітометра. Точніше ніж робити fusion вручну:

val rotationVector = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR) // В onSensorChanged: val rotationMatrix = FloatArray(9) SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values) val orientationAngles = FloatArray(3) SensorManager.getOrientation(rotationMatrix, orientationAngles) val azimuth = Math.toDegrees(orientationAngles[0].toDouble()) // 0-360° від півночі val pitch = Math.toDegrees(orientationAngles[1].toDouble()) // -90 до +90° val roll = Math.toDegrees(orientationAngles[2].toDouble()) // -180 до +180° 

TYPE_LINEAR_ACCELERATION — акселерометр без гравітації (аналог userAcceleration в iOS CoreMotion). Використовуємо замість TYPE_ACCELEROMETER коли потрібно вимірювати тільки динамічне прискорення.

Як реалізувати детекцію падіння?

  1. Використовуйте акселерометр із частотою 50 Гц.
  2. Застосуйте високочастотний фільтр для відділення гравітації:
    val gravity = FloatArray(3) val linearAccel = FloatArray(3) val alpha = 0.8f // В onSensorChanged для TYPE_ACCELEROMETER: 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] linearAccel[0] = event.values[0] - gravity[0] linearAccel[1] = event.values[1] - gravity[1] linearAccel[2] = event.values[2] - gravity[2] val magnitude = sqrt( linearAccel[0].pow(2) + linearAccel[1].pow(2) + linearAccel[2].pow(2) ) 

    Для носимих пристроїв (літні люди, шахтарі) цей метод чудово працює.

    Як організувати фоновий моніторинг без перевитрати батареї?

    Використовуйте батч-оновлення (maxReportLatencyUs) та JobScheduler для періодичної обробки. Віртуальні датчики у фоні краще не використовувати — вони споживають CPU постійно. Для простої детекції активності (кроки, спокій) достатньо акселерометра з частотою 5-10 Гц та батчем в 1 секунду (1000 мс).

    Класифікація активностей

    Паттерни: ходьба — регулярні піки 1.5–2.5 м/с² з частотою 1.5–2.5 Гц. Їзда — низькочастотні вібрації < 0.5 Гц. Спокій — magnitude < 0.1 м/с². Для класифікації використовуйте простий пороговий детектор або модель машинного навчання (наприклад, випадковий ліс) — це покращує точність до 95%.

    Батч-оновлення (Android 4.4+)

    SensorManager.flush() та параметр maxReportLatencyUs в registerListener дозволяють накопичувати дані в hardware FIFO та отримувати пачками. Корисно для фонових застосунків — сенсор копить дані, поки CPU спить, прокидається раз на N секунд, віддає все одразу:

    sensorManager.registerListener( listener, accelerometer, 10_000, // samplingPeriodUs = 100 Гц 500_000 // maxReportLatencyUs = 500 мс batch ) 

    Об'єм FIFO у різних чипсетів різний (512–4096 семплів). При переповненні старі дані витісняються — враховуйте при тривалих сесіях.

    Що входить у роботу з інтеграції датчиків

    • Аналіз — вибір датчиків під сценарій (навігація, трекінг активності, носимі пристрої)
    • Архітектура — ViewModel/Service, обробка lifecycle, сенсорна оптимізація батареї
    • Реалізація — реєстрація, фільтрація, класифікація подій (падіння, кроки, повороти)
    • Тестування — на реальних пристроях (5+ моделей з різними чипсетами)
    • Підтримка — документація API, навчання команди, гарантія на код до 6 місяців

    Порівняння підходів до sensor fusion

    Характеристика TYPE_ROTATION_VECTOR (вбудований) Ручний Madgwick/Mahony
    Точність на дорогих пристроях ±1° ±2-3° після калібрування
    Споживання CPU Низьке Високе (оновлення 200+ раз/с)
    Підтримка на бюджетних телефонах Часто немає Працює всюди
    Складність інтеграції Мінімальна Потрібне налаштування параметрів

    Наш досвід: для 90% проектів вистачає вбудованих віртуальних датчиків. Ручний fusion потрібний тільки для AR/VR або роботи з застарілими SoC.

    Терміни

    Базова інтеграція 1–2 датчиків з обробкою даних — від 3 до 5 робочих днів. Багатодатчиковий алгоритм із класифікацією активностей, фоновим записом та аналітикою — від 2 до 4 тижнів. Вартість розраховується індивідуально після аналізу вимог. Часові рамки уточнюємо після аудиту вашого проекту.

    Наша команда — більше 5 років досвіду та більше 20 успішних проектів із датчиками руху. Замовте консультацію — оцінимо feasibility та запропонуємо архітектуру під ваш сценарій. Отримайте якісну інтеграцію з гарантією на код до 6 місяців.

    Детальніше про Sensor API читайте в офіційній документації Android.