Swift: get values from Accelerometer and Gyroscope via CMMotionManager

To access data from Accelerometer and Gyroscope we are going to use CMMotionManager.
Here’s the class what wraps everything related to motion API (CMMotionManager).
And here’s the code:

//
//  MotionObservable.swift
//  spinner
//
//  Created by Mikita Manko on 5/21/17.
//  Copyright © 2017 Mikita Manko. All rights reserved.
//
 
import Foundation
import CoreMotion
 
let Fps60 = 0.016
 
class MotionObservable {
 
    let motionManager: CMMotionManager
    let updateInterval: Double = Fps60
 
    var gyroObservers = [(Double, Double, Double) -> Void]()
    var accelerometerObservers = [(Double, Double, Double) -> Void]()
 
    // MARK: Public interface
 
    init() {
        motionManager = CMMotionManager()
        initMotionEvents()
    }
 
    func addGyroObserver(observer: @escaping (Double, Double, Double) -> Void) {
        gyroObservers.append(observer)
    }
 
    func addAccelerometerObserver(observer: @escaping (Double, Double, Double) -> Void) {
        accelerometerObservers.append(observer)
    }
 
    func clearObservers() {
        gyroObservers.removeAll()
        accelerometerObservers.removeAll()
    }
 
    // MARK: Internal methods
 
    private func notifyGyroObservers(x: Double, y: Double, z: Double) {
        for observer in gyroObservers {
            observer(x, y, z)
        }
    }
 
    private func notifyAccelerometerObservers(x: Double, y: Double, z: Double) {
        for observer in accelerometerObservers {
            observer(x, y, z)
        }
    }
 
    private func roundDouble(value: Double) -> Double {
        return round(1000 * value)/100
    }
 
    private func initMotionEvents() {
        if motionManager.isGyroAvailable || motionManager.isAccelerometerAvailable {
            motionManager.deviceMotionUpdateInterval = updateInterval;
            motionManager.startDeviceMotionUpdates()
        }
 
 
        // Gyro
        if motionManager.isGyroAvailable {
            motionManager.gyroUpdateInterval = updateInterval
            motionManager.startGyroUpdates(to: OperationQueue.current!, withHandler: { (gyroData: CMGyroData?, NSError) -> Void in
                let rotation = gyroData!.rotationRate
                let x = self.roundDouble(value: rotation.x)
                let y = self.roundDouble(value: rotation.y)
                let z = self.roundDouble(value: rotation.z)
                self.notifyGyroObservers(x: x, y: y, z: z)
 
                if (NSError != nil){
                    print("\(String(describing: NSError))")
                }
            })
        } else {
            print("No gyro available")
        }
 
        // Accelerometer
        if motionManager.isAccelerometerAvailable {
            motionManager.accelerometerUpdateInterval = updateInterval
            motionManager.startAccelerometerUpdates(to: OperationQueue.current!) { (accelerometerData: CMAccelerometerData?, NSError) -> Void in
 
                if let acceleration = accelerometerData?.acceleration {
                    let x = self.roundDouble(value: acceleration.x)
                    let y = self.roundDouble(value: acceleration.y)
                    let z = self.roundDouble(value: acceleration.z)
                    self.notifyAccelerometerObservers(x: x, y: y, z: z)
                }
                if(NSError != nil) {
                    print("\(String(describing: NSError))")
                }
            }
        } else {
            print("No accelerometer available")
        }
    }
}

Now you just need to initialize this somewhere in your Scene class for example

internal let motion = MotionObservable()

And here’s the example how to get values from Accelerometer:

func initAccelGyro() {
    motion.addGyroObserver(observer: {(x: Double, y: Double, z: Double) -> Void in
        let summary = Int(abs(x) + abs(y) + abs(z))
        if IS_DEBUG { print("Gyro: \(summary)") }
    })
    //...
}

That’s pretty much it.
Based on this single line let summary = Int(abs(x) + abs(y) + abs(z)) I’ve created very strange game – “Shake it till you make it – shake your phone“, the idea is that user should shake the phone really hard for 10 seconds! The result is summary score, that’s it 🙂

Social Share Toolbar