Core Motion и сенсоры iPhone: как использовать акселерометр в приложении
Акселерометр, гироскоп и магнетометр iPhone дают приложению ощущение движения и наклона — но доступ к ним устроен не так просто, как кажется: сырые данные с датчиков и «умный» device motion решают разные задачи. В студии oodot мы используем Core Motion в Glow Doodle и Light Painting для жестов, наклона кисти и калибровки движения — и при разработке мобильных приложений под ключ эта работа с датчиками часто становится ядром пользовательского опыта. В этой статье разберём, чем отличаются классы Core Motion, как запустить обновления акселерометра на Swift и как выбрать частоту без разряда батареи.

Что такое Core Motion и зачем он нужен приложению
Core Motion — системный фреймворк iOS, который собирает данные со всех датчиков движения iPhone: акселерометра, гироскопа, магнетометра и барометра — и отдаёт их приложению через единый API. Центральный объект здесь — CMMotionManager: он включает нужные сенсоры, задаёт частоту опроса и присылает замеры в обработчик (handler) на каждый цикл обновления.
На практике Core Motion используют для вещей, которые не решить без физических датчиков: shake-жесты (встряхнуть телефон для отмены действия), наклон экрана для управления интерфейсом, подсчёт шагов через CMPedometer, определение высоты через CMAltimeter, распознавание активности пользователя (ходьба, бег, в машине) через CMMotionActivityManager. Это и есть тот слой, который превращает iPhone из экрана с кнопками в устройство, реагирующее на движение в руке.
Для нашей студии это не абстрактная теория: когда в проекте нужна разработка мобильного приложения под ключ с жестовым управлением или интеграцией с датчиками, Core Motion почти всегда оказывается в основе технического решения — именно он даёт доступ к сырым и обработанным данным движения, без которых творческие механики (световая живопись, наклон кисти, калибровка жеста) просто не собрать.
Чем accelerometer отличается от gyroscope и deviceMotion?
Это три разных источника данных в Core Motion, и путаница между ними — частая причина багов в движении интерфейса. Разберём каждый.
CMAccelerometerData — сырое линейное ускорение
Акселерометр измеряет линейное ускорение вдоль трёх осей (x, y, z) в единицах g (гравитационное ускорение Земли). Данные в CMAccelerometerData сырые — они включают и ускорение от движения руки, и постоянную составляющую гравитации. Отделить одно от другого самостоятельно — отдельная задача фильтрации.
CMGyroData — угловая скорость (вращение)
Гироскоп измеряет угловую скорость вращения вокруг тех же трёх осей, в радианах в секунду. Он отвечает не «куда наклонился телефон», а «как быстро он сейчас вращается» — это другая физическая величина, и сама по себе она не даёт абсолютной ориентации устройства.
CMDeviceMotion — объединённые, отфильтрованные данные
CMDeviceMotion — это результат сенсорного фьюжна: система объединяет показания акселерометра, гироскопа и (при доступности) магнетометра и отдаёт уже разделённые gravity (вектор силы тяжести) и userAcceleration (ускорение именно от движения руки, без гравитации), а также ориентацию устройства в виде кватерниона. Для большинства прикладных задач — наклон, тряска, жесты — нужен именно этот объект, а не сырые данные акселерометра.
| Сенсор | Что измеряет | Класс Core Motion | Типичный кейс |
|---|---|---|---|
| Акселерометр | Линейное ускорение (движение + гравитация) | CMAccelerometerData | Shake-жест, грубое определение тряски |
| Гироскоп | Угловая скорость вращения | CMGyroData | Плавность вращения, стабилизация кадра |
| Device Motion | Gravity + userAcceleration + ориентация | CMDeviceMotion | Наклон интерфейса, жесты рисования, AR |
| Магнетометр | Магнитное поле (компас) | CMMagnetometerData | Направление, азимут, компас-режимы |
Разрешения и Info.plist
Хорошая новость: базовый доступ к акселерометру, гироскопу и device motion не требует запроса разрешения у пользователя и записи в Info.plist — Apple считает эти данные не настолько чувствительными, как геолокация или камера. Ключ NSMotionUsageDescription нужен только для более «личных» данных движения — CMMotionActivityManager (распознавание активности: ходьба, бег, транспорт) и CMPedometer (история шагов). Без этого ключа запрос на активность и шагомер завершится ошибкой, а не крашем — проверяйте это явно в коде, если используете эти API.
Запуск обновлений акселерометра — код на Swift
Базовый сценарий — создать CMMotionManager, задать частоту опроса и запустить обновления с обработчиком на отдельной очереди.
import CoreMotion
final class MotionViewModel: ObservableObject {
private let motionManager = CMMotionManager()
private let motionQueue = OperationQueue()
@Published var acceleration: CMAcceleration?
func startAccelerometerUpdates() {
guard motionManager.isAccelerometerAvailable else { return }
motionManager.accelerometerUpdateInterval = 1.0 / 60.0 // 60 Hz
motionManager.startAccelerometerUpdates(to: motionQueue) { [weak self] data, error in
guard let self, let data, error == nil else { return }
DispatchQueue.main.async {
self.acceleration = data.acceleration
}
}
}
func stopAccelerometerUpdates() {
motionManager.stopAccelerometerUpdates()
}
}
Обратите внимание: обработчик startAccelerometerUpdates(to:) вызывается на очереди, которую вы передали, а не на главном потоке — любое обновление UI нужно явно переносить через DispatchQueue.main.async, как в примере выше.
deviceMotion vs raw accelerometer — когда что использовать?
Если нужно просто отреагировать на резкий толчок (shake-to-undo) — хватит сырого акселерометра и простой проверки порога ускорения. Но если задача — наклон интерфейса, рисование жестом или любая механика, где важна именно ориентация устройства без шума от руки, — используйте CMDeviceMotion:
func startDeviceMotionUpdates() {
guard motionManager.isDeviceMotionAvailable else { return }
motionManager.deviceMotionUpdateInterval = 1.0 / 60.0
motionManager.startDeviceMotionUpdates(to: motionQueue) { [weak self] motion, error in
guard let self, let motion, error == nil else { return }
let gravity = motion.gravity // вектор силы тяжести
let userAccel = motion.userAcceleration // ускорение без гравитации
DispatchQueue.main.async {
self.handleTilt(gravity: gravity, userMotion: userAccel)
}
}
}
Разница на практике: сырой CMAccelerometerData.acceleration всегда содержит примесь гравитации — телефон, лежащий неподвижно экраном вверх, уже покажет ускорение около 1g по оси z. userAcceleration в device motion эту составляющую уже вычел, поэтому в состоянии покоя значения близки к нулю. Если ваша логика реагирует на «движение руки», а не на «положение телефона», берите userAcceleration, а не сырые данные.
Частота обновления и энергопотребление
Частота обновления (updateInterval) напрямую влияет на расход батареи: чем выше частота опроса датчиков, тем чаще система будит ядро обработки движения и будит ваш обработчик на CPU. Для большинства UI-задач — наклон, параллакс, индикаторы — достаточно 30–60 Hz; для точной рисовательной механики или анализа жеста (как в Glow Doodle) имеет смысл поднимать до 60–100 Hz, но не выше, если приложение не делает precision-трекинг для AR или спортивной аналитики.
Практическое правило: запускайте обновления датчиков только тогда, когда экран, которому они нужны, активен, и обязательно останавливайте через stop...Updates() при уходе с экрана или в фон. Постоянно работающий Core Motion на фоне — одна из частых причин жалоб на разряд батареи в отзывах на App Store, и это полностью на совести реализации, а не системы.
Практика: акселерометр в творческом приложении
В студии oodot сенсоры движения — не демо-функция, а часть основной механики продукта. Несколько примеров того, как это работает на уровне кода и UX:
Shake-to-undo. Простейший паттерн: слушаем userAcceleration из device motion, считаем магнитуду вектора (sqrt(x² + y² + z²)) и сравниваем с порогом (обычно 2.0–2.5g суммарной амплитуды за короткое окно). Превышение порога — триггер отмены последнего действия.
Наклон для управления светом или кистью. В световой живописи наклон телефона — это естественный аналог наклона реальной кисти. Берём gravity из device motion (он стабильнее сырого акселерометра, потому что уже отфильтрован от шума движения руки) и мапим угол наклона на толщину линии, яркость или цвет мазка.
Калибровка под жест. Перед началом сессии рисования полезно зафиксировать «нулевое» положение телефона в руке пользователя (у всех разный хват) и дальше считать наклон относительно этой калибровочной точки, а не абсолютной оси устройства — иначе приложение будет «неправильно» реагировать на естественный наклон в руке у разных людей.
Частые ошибки при работе с Core Motion
Несколько вещей, которые ломают приложения с датчиками даже у опытных разработчиков:
Не останавливать обновления. Забытый вызов stopAccelerometerUpdates() или stopDeviceMotionUpdates() при переходе на другой экран держит датчики активными впустую — это прямой расход батареи без пользы.
Не проверять доступность сенсора. Не на всех устройствах (и в Simulator) доступны все датчики — обязательно проверяйте isAccelerometerAvailable / isDeviceMotionAvailable перед стартом, иначе обработчик просто никогда не вызовется, и вы потратите время на поиск несуществующего бага.
Блокировать главный поток. Обработка данных движения (фильтрация, математика, обновление сложного UI) в обработчике обновлений не должна выполняться синхронно на главном потоке — переносите тяжёлые вычисления на фоновую очередь и возвращайтесь на DispatchQueue.main только для финального обновления интерфейса.
FAQ: частые вопросы про Core Motion и акселерометр iPhone
Нужно ли разрешение пользователя для доступа к акселерометру?
Нет — базовый доступ к акселерометру, гироскопу и device motion не требует системного запроса разрешения и записи в Info.plist. Разрешение (и ключ NSMotionUsageDescription) нужны только для распознавания активности (CMMotionActivityManager) и истории шагов (CMPedometer).
Какую частоту обновления выбрать для акселерометра?
Для UI-эффектов (наклон, параллакс) достаточно 30–60 Hz. Для точной рисовательной механики или жестового управления — 60–100 Hz. Выше без явной необходимости — лишний расход батареи, не дающий заметного прироста качества для большинства задач.
Чем CMDeviceMotion лучше сырого CMAccelerometerData?
CMDeviceMotion — результат сенсорного фьюжна акселерометра, гироскопа и магнетометра: он отдаёт уже разделённые gravity и userAcceleration, а сырой акселерометр всегда содержит примесь гравитации, которую нужно вычислять вручную.
Можно ли использовать Core Motion в iOS Simulator?
Частично. Device Motion и акселерометр в Simulator можно эмулировать через меню Features → симуляцию движения, но это упрощённые синтетические данные. Для реальной проверки чувствительности и качества жестов нужен физический iPhone.
Как определить, что iPhone лежит неподвижно?
Проверяйте userAcceleration из device motion — в покое все три оси близки к нулю (гравитация уже вычтена). Сырой акселерометр для этой задачи не подходит: в покое он всё равно показывает около 1g за счёт гравитации.
Почему данные акселерометра «дёргаются» и шумят?
Сырой акселерометр физически чувствителен к микровибрациям руки и окружения. Для сглаживания применяют низкочастотный фильтр (например, скользящее среднее) или используют CMDeviceMotion, где часть фильтрации уже выполнена системой на уровне сенсорного фьюжна.
Можно ли получать данные с акселерометра в фоновом режиме?
Обновления Core Motion останавливаются, когда приложение уходит в фон без специальных entitlement (например, для фитнес-трекеров). Для большинства творческих приложений это ожидаемое поведение — останавливайте обновления сами при переходе в фон, не дожидаясь системного прерывания.
Core Motion — один из тех фреймворков Apple, которые незаметны, пока работают правильно: пользователь просто чувствует, что приложение реагирует на движение естественно. Разница между CMAccelerometerData, CMGyroData и CMDeviceMotion, разумная частота обновления и аккуратная остановка сенсоров — три вещи, которые отделяют рабочую механику от разряженной батареи и дёрганого UI. Для нашей студии это рабочий инструмент в каждом проекте, где движение телефона становится частью интерфейса.