为什么CMMotionManager停止重启后偏航报错?
Why does CMMotionManager report incorrect yaw after stopping and restarting?
我正在使用 CMMotionManager 获取设备姿态,运行 遇到一个奇怪的问题,它在第一次启动时运行良好,但在停止和启动后,偏航值增加了一倍。
我使用 startDeviceMotionUpdates(using: .xTrueNorthZVertical)
启动它并检查 SceneKit 场景的渲染循环中的偏航值。如果我将 phone 平放在 table 上并将其旋转 90°,它会显示偏航角发生 90° 的变化。完美。
如果我使用 stopDeviceMotionUpdates()
停止它,再次启动它并执行相同的 90° 旋转,我希望看到相同的 90° 变化。但相反,它显示了 180° 的旋转!
这似乎只有在第一次使用 (using:)
语法启动时才会发生。我正在 iPhone 5 和 iOS 10.0.2 上使用 xCode 8.0.
对其进行测试
要重新创建,请使用 "Game" 模板创建一个新项目,并将 GameViewController.swift 中的代码替换为以下代码:
import UIKit
import SceneKit
import CoreMotion
class GameViewController: UIViewController, SCNSceneRendererDelegate {
static let motionManager = CMMotionManager()
var scnView: SCNView!
var scnScene: SCNScene!
override func viewDidLoad() {
super.viewDidLoad()
scnView = self.view as! SCNView
scnView.delegate = self
scnScene = SCNScene()
scnView.scene = scnScene
scnView.isPlaying = true
GameViewController.motionManager.startDeviceMotionUpdates(using: .xTrueNorthZVertical)
// stop and start it again to cause doubling
GameViewController.motionManager.stopDeviceMotionUpdates()
GameViewController.motionManager.startDeviceMotionUpdates(using: .xTrueNorthZVertical)
}
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
if let motion = GameViewController.motionManager.deviceMotion {
print(Int(motion.attitude.yaw * 180/M_PI))
}
}
}
此代码启动 CMMotionManger,然后立即停止并再次启动。将 phone 旋转 90°,您会看到它显示 180° 偏航。显然这不是一个实际的例子,只是一个显示问题的简化版本。在我的实际用例中,当我在其中使用它的 SceneKit 视图被关闭时,我会停止 CMMotionManager,并在打开另一个 SceneKit 视图时重新启动它。
目前我的解决方法是一旦启动 CMMotionManager 就永远不要停止它。它有效,但文档特别说明 "You must call stopDeviceMotionUpdates() when you no longer want your app to process device-motion updates.",因此这似乎不是一个很好的解决方案。
为什么 CMMotionManager 在停止和启动后给出错误的值,我该如何解决?
CMMotion manager 给出调用start函数时的转角。
如果您需要更新,那么您不应该停止更新。当不需要关联之前的位置时停止它
此行为在安装 iOS 10.1 后消失,因此推测这是一个已修复的错误。
我正在使用 CMMotionManager 获取设备姿态,运行 遇到一个奇怪的问题,它在第一次启动时运行良好,但在停止和启动后,偏航值增加了一倍。
我使用 startDeviceMotionUpdates(using: .xTrueNorthZVertical)
启动它并检查 SceneKit 场景的渲染循环中的偏航值。如果我将 phone 平放在 table 上并将其旋转 90°,它会显示偏航角发生 90° 的变化。完美。
如果我使用 stopDeviceMotionUpdates()
停止它,再次启动它并执行相同的 90° 旋转,我希望看到相同的 90° 变化。但相反,它显示了 180° 的旋转!
这似乎只有在第一次使用 (using:)
语法启动时才会发生。我正在 iPhone 5 和 iOS 10.0.2 上使用 xCode 8.0.
要重新创建,请使用 "Game" 模板创建一个新项目,并将 GameViewController.swift 中的代码替换为以下代码:
import UIKit
import SceneKit
import CoreMotion
class GameViewController: UIViewController, SCNSceneRendererDelegate {
static let motionManager = CMMotionManager()
var scnView: SCNView!
var scnScene: SCNScene!
override func viewDidLoad() {
super.viewDidLoad()
scnView = self.view as! SCNView
scnView.delegate = self
scnScene = SCNScene()
scnView.scene = scnScene
scnView.isPlaying = true
GameViewController.motionManager.startDeviceMotionUpdates(using: .xTrueNorthZVertical)
// stop and start it again to cause doubling
GameViewController.motionManager.stopDeviceMotionUpdates()
GameViewController.motionManager.startDeviceMotionUpdates(using: .xTrueNorthZVertical)
}
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
if let motion = GameViewController.motionManager.deviceMotion {
print(Int(motion.attitude.yaw * 180/M_PI))
}
}
}
此代码启动 CMMotionManger,然后立即停止并再次启动。将 phone 旋转 90°,您会看到它显示 180° 偏航。显然这不是一个实际的例子,只是一个显示问题的简化版本。在我的实际用例中,当我在其中使用它的 SceneKit 视图被关闭时,我会停止 CMMotionManager,并在打开另一个 SceneKit 视图时重新启动它。
目前我的解决方法是一旦启动 CMMotionManager 就永远不要停止它。它有效,但文档特别说明 "You must call stopDeviceMotionUpdates() when you no longer want your app to process device-motion updates.",因此这似乎不是一个很好的解决方案。
为什么 CMMotionManager 在停止和启动后给出错误的值,我该如何解决?
CMMotion manager 给出调用start函数时的转角。
如果您需要更新,那么您不应该停止更新。当不需要关联之前的位置时停止它
此行为在安装 iOS 10.1 后消失,因此推测这是一个已修复的错误。