Реализация Core Motion (акселерометр, гироскоп) в iOS-приложении
CoreMotion — единая точка входа к инерциальным датчикам iPhone и iPad: акселерометр, гироскоп, магнитометр, барометр, Motion Coprocessor. Прямой доступ к «сырым» данным с 100 Гц плюс обработанные данные Device Motion с коррекцией гравитации и фильтрацией дрейфа гироскопа. Большинство задач решается на уровне Device Motion — не нужно реализовывать Madgwick или Mahony фильтр вручную.
CMMotionManager: один экземпляр на приложение
Это не рекомендация — это требование. Несколько экземпляров CMMotionManager в разных частях приложения приводят к конфликту обновлений и непредсказуемому поведению. Стандартное решение — singleton через DI-контейнер или статическое свойство:
final class MotionManager {
static let shared = MotionManager()
let motion = CMMotionManager()
private init() {}
}
Device Motion vs Raw Accelerometer
Raw Accelerometer (startAccelerometerUpdates) — полное ускорение: сумма гравитации и линейного ускорения от движения. На iPhone в покое на столе: (x: 0, y: 0, z: -1) приблизительно — это g ≈ 9.81 м/с² по оси Z. При наклоне — проекция гравитации меняется по всем осям.
Device Motion (startDeviceMotionUpdates) — ускорение уже без гравитации (userAcceleration), плюс attitude (ориентация в пространстве: pitch, roll, yaw), плюс rotationRate с коррекцией дрейфа.
let manager = MotionManager.shared.motion
manager.deviceMotionUpdateInterval = 1.0 / 60.0 // 60 Гц
manager.startDeviceMotionUpdates(
using: .xMagneticNorthZVertical,
to: .main
) { [weak self] motion, error in
guard let motion = motion else { return }
let pitch = motion.attitude.pitch // наклон вперёд/назад (радианы)
let roll = motion.attitude.roll // наклон влево/вправо
let yaw = motion.attitude.yaw // поворот вокруг вертикальной оси
let accel = motion.userAcceleration // линейное ускорение без гравитации
let rotation = motion.rotationRate // угловая скорость рад/с
}
CMAttitudeReferenceFrame.xMagneticNorthZVertical — ориентация относительно магнитного севера, Z вверх. Для игровых приложений и AR — правильный выбор. Для простой детекции жестов — xArbitraryZVertical (без магнитометра, меньше потребление).
Практические применения
Детекция жестов
Shake gesture встроен в UIKit, но ограничен. Для кастомных жестов — анализ userAcceleration. Паттерн встряхивания: пики ускорения > 2.5g с чередованием знаков на одной оси за < 500 мс.
var accelerationHistory: [Double] = []
// В обработчике device motion:
let magnitude = sqrt(
pow(motion.userAcceleration.x, 2) +
pow(motion.userAcceleration.y, 2) +
pow(motion.userAcceleration.z, 2)
)
accelerationHistory.append(magnitude)
if accelerationHistory.count > 30 { accelerationHistory.removeFirst() }
let peakCount = accelerationHistory.filter { $0 > 2.5 }.count
if peakCount >= 3 {
triggerShakeAction()
accelerationHistory.removeAll()
}
Определение ориентации и наклона
Для приложений-уровней, AR-разметки, управления камерой: attitude.pitch и attitude.roll достаточно точны (ошибка < 1° в стационарных условиях).
Педометрия без CMPedometer
На устройствах без поддержки CMPedometer (iPod Touch без Motion Coprocessor) — детекция шагов из акселерометра. Алгоритм: low-pass фильтр на userAcceleration.y, детекция пиков > 0.2g с минимальным интервалом 300 мс.
CMAltimeter: барометрическая высота
CMAltimeter — отдельный класс для барометра:
let altimeter = CMAltimeter()
guard CMAltimeter.isRelativeAltitudeAvailable() else { return }
altimeter.startRelativeAltitudeUpdates(to: .main) { data, error in
guard let data = data else { return }
let relativeAltitude = data.relativeAltitude.doubleValue // метры от старта
let pressure = data.pressure.doubleValue // кПа
}
relativeAltitude — изменение высоты от момента старта обновлений, не абсолютная высота над уровнем моря. Точность: ±0.1 м в стабильных погодных условиях. Используется для подсчёта этажей в CMPedometer.floorsAscended и для фитнес-приложений (набор/сброс высоты на маршруте).
Управление частотой и батарея
| Сценарий | Частота | Потребление |
|---|---|---|
| Детекция жестов | 10–25 Гц | Низкое |
| Шагомер | 25–50 Гц | Среднее |
| Игровое управление | 60 Гц | Среднее |
| AR/обработка сигналов | 100 Гц | Высокое |
Не держать датчики активными без необходимости: stopDeviceMotionUpdates() в viewDidDisappear или при переходе в фон (если данные в фоне не нужны).
Сроки
Интеграция базовых датчиков (акселерометр, гироскоп, attitude) с конкретным прикладным сценарием — 3–7 рабочих дней. Сложные алгоритмы обработки сигналов (детекция активностей, жестов, педометрия) — 2–4 недели.







