这取决于您想对收集的数据做什么,以及用户将如何使用她/他的口袋里的录音 iPhone。原因是欧拉角不是安全的,尤其是没有唯一的方式来表达旋转。考虑这样一种情况,用户将手机直立放入牛仔裤的后口袋,然后向左转约 90°。因为 CMAttitude 与平放在桌子上的设备有关,所以根据 picture,您有两个后续旋转 (pitch=x, roll=y, yaw=z):
- 倾斜 +90° 让手机直立 => (90, 0, 0)
- 滚动 +90° 左转 => (90, 90, 0)
但是你可以通过以下方式获得相同的位置:
- yaw +90° 向左转动手机 (0, 0, 90)
- 俯仰 -90° 使手机直立(-90、0、90)
您会看到两种不同的表示 (90, 90, 0) 和 (-90, 0, 90) 来获得相同的旋转,而且还有更多。所以你按下开始按钮,做一些花哨的旋转把手机放进口袋里,你就有麻烦了,因为在做更复杂的动作时你不能依赖欧拉角(s.gimbal lock 对此更头疼;-)
现在好消息:你说得对,线性代数可以胜任。您可以做的是强迫您的用户将手机始终放在相同的位置,例如垂直固定在右后袋中,并通过从CMDeviceMotion g = (x, y, z) 和位置构建重力矢量dot product 来计算相对于地面的角度向量 p 是 -Y 轴 (0, -1, 0) 的直立位置:
g • x = x*0 + y*(-1) + z*0 = -y = ||g||*1*cos (alpha)
=> alpha = arccos (-y/9.81) 作为总角度。请注意,重力加速度 g 始终约为 9.81
为了得到左右倾斜角度和前后角度,我们使用切线:
alphaLR = arctan (x/y)
alphaFB = arctan (z/y)
[更新:]
如果您不能将手机置于上述等式中的 (0, -1, 0) 之类的预定义位置,则只能计算总角度,而不能计算特定的 alphaLR 和 alphaFB。原因是你只有一个新坐标系的轴,你需要其中的两个。新的 Y 轴 y' 将被定义为平均重力矢量,但您不知道新的 X 轴,因为垂直于 y' 的每个矢量都是有效的。
因此,您必须提供更多信息,例如让用户在一个方向上走更长的距离而不偏离,并使用 GPS 和磁力计数据来获取第二轴 z'。在实践中听起来很容易出错。
总角度没问题,我们可以将(0, -1, 0)换成平均重力向量(pX, pY, pZ):
g•p = xpX + ypY + zpZ = ||g||||p||*cos(alpha) = ||g| |^2*cos(alpha)
alpha = arccos ((xpX + ypY + z*pZ) / 9.81^2)
还有两点要记住:
- 不同的人穿着不同的裤子,不同的口袋。因此,即使是同一个人穿着其他衣服,重力矢量也会有所不同,您可能需要某种归一化
- CMMotionManager 无法在后台运行,即用户不得按下待机按钮