GLKQuaternion转换的意外结果(来自CMQuaternion)

时间:2014-11-15 16:11:58

标签: ios rotation quaternions core-motion

我正在开发一款iOS应用程序,它将使用CoreMotion来计算运动范围。

由于万向节锁定,我很快就放弃了欧拉角。所以,现在我正在尝试使用四元数。

您可能知道,CMMotionManager通过CMDeviceMotion课程报告设备动态数据。这里的相关属性(出于我的目的)是attitude属性,CMAttitude的实例。当然,您可以访问pitchrollyaw。在记录结果时我仍然这样做是为了更好地了解从设备中传出的数据(因为这些值非常直观地设想)。它还提供quaternion属性,该属性是CMQuaternion的实例。

基于这里和其他地方的许多小时的研究,我确信使用四元数是在任何方向上获得正确结果的正确方法。问题是我发现CMQuaternion类/结构非常密集且难以理解。 Apple的文档稀疏,我无法从CMQuaternion中删除我认为是有效的轴角度表示。 (如果某人有计算CMQuaternion的轴角表示的数学计算,我全都耳朵!)

当我在他们的GLKit库中偶然发现Apple的GLKQuaternion结构时,我以为我解决了这个问题。 GLKit具有从GLKQuaternion的实例提供轴和角度的方法。甚至还有一个很好的构造方法:GLKQuaternionMake(x, y, z, w)

由于CMQuaternion具有x,y,z和w属性,我推断我可以使用此方法基本上在CMQuaternionGLKQuaternion的实例之间“强制转换”。我仍然不确定这是否正确。

无论如何,当我遇到一些特别奇怪的结果时,我正在从iPhone上记录结果。

我编写的代码具有预期目的,用于捕获初始姿态(当用户点击按钮时),然后对CoreMotion数据进行采样并确定起始位置与现在的位置。

以下是代码:

- (void)sampleDeviceMotion {
    // I've tested this, and "self.startingAttitude" is set/reset correctly
    if (self.startingAttitude == nil) {
        self.startingAttitude = self.motionManager.deviceMotion.attitude;
    }

    CMQuaternion quaternion1  = self.startingAttitude.quaternion;
    GLKQuaternion q1          = GLKQuaternionMake(quaternion1.x, quaternion1.y, quaternion1.z, quaternion1.w);
    GLKVector3 v1             = GLKQuaternionAxis(q1);
    float angle1              = GLKQuaternionAngle(q1);

    CMQuaternion quaternion2  = self.motionManager.deviceMotion.attitude.quaternion;
    GLKQuaternion q2          = GLKQuaternionMake(quaternion2.x, quaternion2.y, quaternion2.z, quaternion2.w);
    GLKVector3 v2             = GLKQuaternionAxis(q2);
    float angle2              = GLKQuaternionAngle(q2);

    float dotProduct          = GLKVector3DotProduct(v1, v2);
    float length1             = GLKVector3Length(v1);
    float length2             = GLKVector3Length(v2);
    float cosineOfTheta       = dotProduct / (length1 * length2);
    float theta               = acosf(cosineOfTheta);
    theta                     = radiansToDegrees(theta);

    float rotationDelta       = angle2 - angle1;
    rotationDelta             = radiansToDegrees(rotationDelta);

    printf("v1: (%.02f, %.02f, %.02f) v2: (%.02f, %.02f, %.02f) angle1: %.02f, angle2: %.02f - vectorDelta: %dº. rotationDelta: %dº (pitch: %.02f, roll: %.02f, yaw: %.02f)\n", v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, angle1, angle2, (int)theta, (int)rotationDelta, self.motionManager.deviceMotion.attitude.pitch, self.motionManager.deviceMotion.attitude.roll, self.motionManager.deviceMotion.attitude.yaw);

}

我看过那段代码超过20次,我看不到其中的任何缺陷,除非我对CMQuaternionGLKQuaternion之间移动能力的假设存在缺陷。

我希望当设备平放在桌子上时,点击按钮并让设备保持静止会给我q1q2基本相同的结果。我会理解数据中有少量“摆动”,但如果设备不移动,则不同四元数的轴和角度应该(几乎)相同。

有时我会得到它(当点击按钮并且设备保持静止时),但有时“初始”(self.startingAttitude)和后续值会大量关闭(40º-70º)。

此外,在初始值和后续值一致的情况下,当我尝试测量旋转时,我得到了一个奇怪的结果。

我“旋转”手机(围绕“Z”轴旋转),并得到以下结果:

BEFORE:

  

v1:( - 0.03,-0.03,-1.00)v2:(0.01,-0.04,-1.00)angle1:0.02,angle2:0.01 - vectorDelta:2º。 rotationDelta:0º(音高:0.00,滚动:-0.00,偏航:-0.01)

AFTER:

  

v1:( - 0.03,-0.03,-1.00)v2:( - 0.00,-0.01,1.00)angle1:0.02,angle2:0.14 - vectorDelta:176º。 rotationDelta:7º(音高:-0.00,翻滚:-0.00,偏航:0.14)

我认为俯仰/滚转/偏航数据两次都是正确的。也就是说,我向手机传递了少量的偏航旋转。那么,为什么Z轴完全翻转而只有很小的偏航变化?

0 个答案:

没有答案