xcode Swift 陀螺仪偏航、俯仰、滚转

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27783658/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 06:27:05  来源:igfitidea点击:

Swift gyroscope yaw, pitch, roll

iosiphonexcodeswiftcore-motion

提问by Moonwalker4z

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.

我正在为我的学校做一个项目,一个编程主题。我正在 Swift 中使用 Xcode。我想做一个使用陀螺仪的应用程序。我不知道,但不知何故它无法在我的 iphone 上运行,因为我不知道如何修复 Xcode 中的一些错误。 (lldb)" 我项目的主要内容是使用陀螺仪在 iphone 屏幕上以度数显示旋转(偏航、俯仰、滚动)。如果有人帮助我,我将不胜感激。先感谢您。

The code in my ViewController:

我的 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.
    }
}

回答by Nate Cook

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.deviceMotionis nilbecause you haven't called motionManager.startDeviceMotionUpdates()prior to that access.

在这两行中,您使用的是隐式解包的可选项:您在不使用?或的情况下使用它们!,但是如果它们是 ,它们会使您的程序崩溃nil。在这种情况下,motionManager.deviceMotionnil因为您motionManager.startDeviceMotionUpdates()在该访问之前没有调用。

Your viewDidLoadmethod is the right place to do this:

您的viewDidLoad方法是执行此操作的正确位置:

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 closuresfor completion handlers like this one - nicer to write and read.
  3. To avoid a reference cycle, declare selfas weakinside a completion handler - this then requires using optional chaining when accessing self.
  1. 你不需要在startGyroUpdates()之前打电话startGyroUpdatesToQueue()
  2. Swift对像这样的完成处理程序使用尾随闭包- 更好地编写和阅读。
  3. 为避免引用循环,请在完成处理程序中声明selfweak- 这需要在访问self.

回答by Aaron Halvorsen

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

“guard”、“if let”和可选链是安全解包可选的关键,这里是 Swift4 的答案:

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)")
                }
            }
        }
    }