Implementing Core Motion (Accelerometer, Gyroscope) in iOS Application
CoreMotion — a single point of access to inertial sensors on iPhone and iPad: accelerometer, gyroscope, magnetometer, barometer, Motion Coprocessor. Direct access to raw data at 100 Hz plus processed Device Motion data with gravity correction and gyroscope drift filtering. Most tasks are solved at the Device Motion level — no need to implement Madgwick or Mahony filters manually.
CMMotionManager: One Instance Per Application
This is not a recommendation — it's a requirement. Multiple CMMotionManager instances in different parts of the application lead to update conflicts and unpredictable behavior. The standard solution is a singleton through DI container or static property:
final class MotionManager {
static let shared = MotionManager()
let motion = CMMotionManager()
private init() {}
}
Device Motion vs Raw Accelerometer
Raw Accelerometer (startAccelerometerUpdates) — total acceleration: sum of gravity and linear acceleration from movement. On iPhone at rest on a table: (x: 0, y: 0, z: -1) approximately — this is g ≈ 9.81 m/s² along Z axis. When tilted — gravity projection changes along all axes.
Device Motion (startDeviceMotionUpdates) — acceleration already without gravity (userAcceleration), plus attitude (spatial orientation: pitch, roll, yaw), plus rotationRate with drift correction.
let manager = MotionManager.shared.motion
manager.deviceMotionUpdateInterval = 1.0 / 60.0 // 60 Hz
manager.startDeviceMotionUpdates(
using: .xMagneticNorthZVertical,
to: .main
) { [weak self] motion, error in
guard let motion = motion else { return }
let pitch = motion.attitude.pitch // forward/backward tilt (radians)
let roll = motion.attitude.roll // left/right tilt
let yaw = motion.attitude.yaw // rotation around vertical axis
let accel = motion.userAcceleration // linear acceleration without gravity
let rotation = motion.rotationRate // angular velocity rad/s
}
CMAttitudeReferenceFrame.xMagneticNorthZVertical — orientation relative to magnetic north, Z up. For gaming and AR applications — the right choice. For simple gesture detection — xArbitraryZVertical (without magnetometer, less power consumption).
Practical Applications
Gesture Detection
Shake gesture is built into UIKit, but limited. For custom gestures — analyze userAcceleration. Shake pattern: acceleration peaks > 2.5g with alternating signs on one axis for < 500 ms.
var accelerationHistory: [Double] = []
// In device motion handler:
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()
}
Orientation and Tilt Detection
For level applications, AR annotation, camera control: attitude.pitch and attitude.roll are sufficiently accurate (error < 1° in stationary conditions).
Pedometry Without CMPedometer
On devices without CMPedometer support (iPod Touch without Motion Coprocessor) — step detection from accelerometer. Algorithm: low-pass filter on userAcceleration.y, peak detection > 0.2g with minimum interval 300 ms.
CMAltimeter: Barometric Altitude
CMAltimeter — separate class for barometer:
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 // meters from start
let pressure = data.pressure.doubleValue // kPa
}
relativeAltitude — altitude change from when updates started, not absolute elevation above sea level. Accuracy: ±0.1 m in stable weather conditions. Used for calculating floors in CMPedometer.floorsAscended and for fitness apps (altitude gain/loss on route).
Controlling Frequency and Battery
| Scenario | Frequency | Consumption |
|---|---|---|
| Gesture detection | 10–25 Hz | Low |
| Pedometer | 25–50 Hz | Medium |
| Game control | 60 Hz | Medium |
| AR/signal processing | 100 Hz | High |
Don't keep sensors active without need: stopDeviceMotionUpdates() in viewDidDisappear or when moving to background (if data in background not needed).
Timeline
Basic sensor integration (accelerometer, gyroscope, attitude) with specific use case — 3–7 working days. Complex signal processing algorithms (activity detection, gesture recognition, pedometry) — 2–4 weeks.







