Core Motion:如何判断“向上”是哪条路?

Posted

技术标签:

【中文标题】Core Motion:如何判断“向上”是哪条路?【英文标题】:Core Motion: how to tell which way is "up"? 【发布时间】:2014-10-14 05:38:19 【问题描述】:

我正在尝试复制 Compass 应用程序中的功能 - 但我遇到了一个问题:如何确定界面中“向上”的方式?

我在屏幕上有一个标签,并且我有以下代码,可将其定向为在设备四处移动时保持水平:

self.motionManager = CMMotionManager()
self.motionManager?.gyroUpdateInterval = 1/100
self.motionManager?.startDeviceMotionUpdatesToQueue(NSOperationQueue.mainQueue(), withHandler:  (deviceMotion, error) -> Void in
  let roll = -deviceMotion.attitude.roll
  self.tiltLabel?.transform = CGAffineTransformRotate(CGAffineTransformIdentity, CGFloat(roll))
)

这个效果还不错,但也有一些地方是错误的——例如,当 iPhone 的闪电接头朝上时,标签会不规律地翻转。

如何使用 CoreMotion 始终如一地判断哪个方向是向上的?

更新: 显然,roll/pitch/yaw 是 Euler angles,它会受到 gimbal lock 的影响 - 所以我认为正确的解决方案可能涉及使用 quaternions,它不会受到影响这个问题,或者 CMAttitude 上的 rotationMatrix 可能会有所帮助:https://developer.apple.com/library/ios/documentation/CoreMotion/Reference/CMAttitude_Class/index.html

【问题讨论】:

【参考方案1】:

对于 2D 情况,它不需要那么复杂。 “上”的意思是“反重力”,所以:

motionManager.startDeviceMotionUpdatesToQueue(NSOperationQueue.mainQueue())  (motion, error) in
    // Gravity as a counterclockwise angle from the horizontal.
    let gravityAngle = atan2(Double(motion.gravity.y), Double(motion.gravity.x))

    // Negate and subtract π/2, because we want -π/2 ↦ 0 (home button down) and 0 ↦ -π/2 (home button left).
    self.tiltLabel.transform = CGAffineTransformMakeRotation(CGFloat(-gravityAngle - M_PI_2))

但是,如果您尝试在所有 3 个维度上执行此操作,则简单的“反重力”意义不大:重力方向不会告诉您手机的角度围绕重力矢量的任何信息(如果您的手机正面朝上,这是偏航角)。要在三个维度上进行校正,我们可以改用横滚、俯仰和偏航测量:

// Add some perspective so the label looks (roughly) the same,
// no matter what angle the device is held at.
var t = self.view.layer.sublayerTransform
t.m34 = 1/300
self.view.layer.sublayerTransform = t

motionManager.startDeviceMotionUpdatesToQueue(NSOperationQueue.mainQueue())  (motion, error) in
    let a = motion.attitude
    self.tiltLabel.layer.transform =
        CATransform3DRotate(
            CATransform3DRotate(
                CATransform3DRotate(
                    CATransform3DMakeRotation(CGFloat(a.roll), 0, -1, 0),
                    CGFloat(a.pitch), 1, 0, 0),
                CGFloat(a.yaw), 0, 0, 1),
            CGFloat(-M_PI_2), 1, 0, 0) // Extra pitch to make the label point "up" away from gravity

【讨论】:

我知道这是迟到的回应 - 但谢谢。几个月来我一直在盯着四元数***页面:)

以上是关于Core Motion:如何判断“向上”是哪条路?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查当前路线是哪条?

销售订单项目明细存储,走哪条路?

在 Linux 3D 编程中走哪条路? [关闭]

获取公共/外部 IP 地址?

如何提升工作效率?

201800624模拟赛T2——回家路上