Swift gyroscope yaw, pitch, roll

12,695

Solution 1

In these two lines you're working with implicitly unwrapped optionals: you use them without ? or !, but they'll crash your program if they're nil. In this case, motionManager.deviceMotion is nil because you haven't called motionManager.startDeviceMotionUpdates() prior to that access.

Your viewDidLoad method is the right place to do this:

override func viewDidLoad() {

    if motionManager.gyroAvailable {
        motionManager.deviceMotionUpdateInterval = 0.2;
        motionManager.startDeviceMotionUpdates()

        motionManager.gyroUpdateInterval = 0.2
        motionManager.startGyroUpdatesToQueue(NSOperationQueue.currentQueue()) {
           [weak self] (gyroData: CMGyroData!, error: NSError!) in

           self?.outputRotationData(gyroData.rotationRate)
           if error != nil {
               println("\(error)")
           }
        }
    } else {
        // alert message
    }

    super.viewDidLoad()
}

There are a few additional changes there:

  1. You don't need to call startGyroUpdates() before startGyroUpdatesToQueue().
  2. Swift uses trailing closures for completion handlers like this one - nicer to write and read.
  3. To avoid a reference cycle, declare self as weak inside a completion handler - this then requires using optional chaining when accessing self.

Solution 2

"guard", "if let", and optional chaining are the key to safely unwrap optionals, here is a Swift4 answer:

let motionManager = CMMotionManager()
    override func viewDidLoad() {
        if motionManager.isGyroAvailable {
            motionManager.deviceMotionUpdateInterval = 0.2;
            motionManager.startDeviceMotionUpdates()

            motionManager.gyroUpdateInterval = 0.2
            guard let currentQueue = OperationQueue.current else { return }
            motionManager.startGyroUpdates(to: currentQueue) { (gyroData, error) in

                // Do Something, call function, etc
                if let rotation = gyroData?.rotationRate {
                    print(rotation)
                    print(rotation.x)
                    print(rotation.y)
                    print(rotation.z)
                }

                if error != nil {
                    print("\(error)")
                }
            }
        }
    }
Share:
12,695
Moonwalker4z
Author by

Moonwalker4z

Updated on June 24, 2022

Comments

  • Moonwalker4z
    Moonwalker4z almost 2 years

    I'm doing a project for my school, for a programming subject. I'm working in Xcode in Swift. I would like to make an application that uses Gyroscope. I don't know but somehow it won't run on my iphone because of some errors in Xcode that I don't know how to fix.When I run the program is says "fatal error: unexpectedly found nil while unwrapping an Optional value (lldb)" The main thing of my project is to display rotations (yaw,pitch,roll) in degrees on iphone screen using gyroscope. I would be really grateful if someone help me with this. Thank you in advance.

    The code in my ViewController:

    import UIKit
    import CoreMotion
    
    class ViewController: UIViewController {
    
        var currentMaxRotX: Double = 0.0
        var currentMaxRotY: Double = 0.0
        var currentMaxRotZ: Double = 0.0
    
        let motionManager = CMMotionManager()
    
        @IBOutlet var rotX : UILabel! = nil
        @IBOutlet var rotY : UILabel! = nil
        @IBOutlet var rotZ : UILabel! = nil
    
        @IBOutlet var maxRotX : UILabel! = nil
        @IBOutlet var maxRotY : UILabel! = nil
        @IBOutlet var maxRotZ : UILabel! = nil
    
    
        @IBOutlet weak var RollLabel: UILabel! = nil
    
        @IBOutlet weak var PitchLabel: UILabel! = nil
    
        @IBOutlet weak var YawLabel: UILabel! = nil
    
        override func viewDidLoad() {
    
            if motionManager.gyroAvailable {
    
                if !motionManager.gyroActive {
                    motionManager.gyroUpdateInterval = 0.2
                    motionManager.startGyroUpdates()
                    //motionManager = [[CMMotionManager alloc]init]; should I use this ???
                    //motionManager.deviceMotionUpdateInterval = 0.2;
                    //motionManager.startDeviceMotionUpdates()
    
                     motionManager.startGyroUpdatesToQueue(NSOperationQueue.currentQueue(), withHandler: {(gyroData: CMGyroData!, error: NSError!)in
                         self.outputRotationData(gyroData.rotationRate)
                         if (error != nil)
                         {
                             println("\(error)")
                         }
                     })      
                }
           } else {
                  var alert = UIAlertController(title: "No gyro", message: "Get a Gyro", preferredStyle: UIAlertControllerStyle.Alert)
                  alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil))
                  self.presentViewController(alert, animated: true, completion: nil)
        }
    
    
         super.viewDidLoad()
        }
    
        // radians to degrees
        func radians(fromDegrees degrees: Double) -> Double {
            return 180 * degrees / M_PI
        }
    
        func outputRotationData(rotation:CMRotationRate)
        {
            rotX.text = NSString(format:"Rotation X: %.4f",rotation.x)
            if fabs(rotation.x) > fabs(currentMaxRotX)
            {
                currentMaxRotX = rotation.x
            }
    
            rotY.text = NSString(format:"Rotation Y: %.4f", rotation.y)
            if fabs(rotation.y) > fabs(currentMaxRotY)
            {
                currentMaxRotY = rotation.y
            }
            rotZ.text = NSString(format:"Rotation Z:%.4f", rotation.z)
            if fabs(rotation.z) > fabs(currentMaxRotZ)
            {
                currentMaxRotZ = rotation.z
            }
    
            maxRotX.text = NSString(format:"Max rotation X: %.4f", currentMaxRotX)
            maxRotY.text = NSString(format:"Max rotation Y:%.4f", currentMaxRotY)
            maxRotZ.text = NSString(format:"Max rotation Z:%.4f", currentMaxRotZ)
    
            var attitude = CMAttitude()
            var motion = CMDeviceMotion()
            motion = motionManager.deviceMotion
            attitude = motion.attitude
    
    
            YawLabel.text = NSString (format: "Yaw: %.2f", attitude.yaw)    //radians to degress NOT WORKING
            PitchLabel.text = NSString (format: "Pitch: %.2f", attitude.pitch)//radians to degress NOT WORKING
            RollLabel.text = NSString (format: "Roll: %.2f", attitude.roll)//radians to degress NOT WORKING
          }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    }