态度变化 - 角度和轴问题 - 四元数数学

11

我有一个应用程序,可以在用户围绕物体行走时记录角度,同时将设备(最好是)指向物体的中心。 在用户命令下,角度会被重置-因此参考姿态会被重置。

使用欧拉角会产生万向锁,所以我目前正在使用四元数,并通过以下方式计算角度:

double angleFromLastPosition = acos(fromLastPositionAttitude.quaternion.w) * 2.0f;

如果设备的俯仰角和偏航角没有变化,那么它具有良好的精度并且可以完美地工作。换句话说,当角度显示为360度时,我最终会停留在圆的起始位置。

问题1:如果设备的偏航角和俯仰角稍微改变(用户未直接指向对象中心),则角度也会随之改变。我理解这一点,因为我的角度公式只是显示3D空间中两个设备姿态之间的角度。

场景:

  • 我标记旋转姿态的起始点,并在指向中心的情况下开始沿着对象周围作圆形移动
  • 我停在45度处,并通过将设备指向更高或更低来改变俯仰角。相应地改变角度。
  • 我希望看到的是:即使俯仰角或偏航角发生变化,角度仍保持在45度。

问题1是,如何使用四元数仅计算设备的Roll,并忽略其他两个轴(至少在某些合理的角度范围内)。

问题2:如果我旋转一段时间然后完全固定设备(在三脚架上,因此完全没有晃动),那么距上一个位置的角度会以每10-20秒约1度的速率漂移,而且似乎不是线性的。换句话说,它一开始漂移得很快,然后明显减缓。有时我根本没有漂移 - 如果设备静止,则角度非常稳定。这使我迷失了解发生了什么。

问题2是,发生了什么,如何解决漂移问题?

我查阅了很多文章和教程,但四元数数学目前对我来说还超出了我的能力范围,希望有人能够通过提示、链接或几行代码来帮助我。


漂移是否与漂移偏航角有关?如果是,找到问题1的公式将同时解决这两个问题 :) - Andrei G.
如果您正在使用CMAttitude,有没有特别的原因不能只使用fromLastPositionAttitude.roll来获取设备的roll?我知道这不是使用四元数属性,但它可以使用! - David Doyle
是的,我已经开始使用欧拉角,但这会导致万向锁和自由度的丢失。当设备未与Z轴对齐时,完整旋转不是360度。至少这是我对该效应的理解... - Andrei G.
1个回答

4
我已经测试过了,根据你在问题1中的需求,这似乎可以正常工作,Andrei。
我最初将homeangle设为0,并在第一次通过后立即将从walkaroundAngleFromAttitude:fromHomeAngle:返回的角度存储在homeangle中,以供将来使用。
我的测试包括使用参考框架启动设备更新:
[_motionManager 
startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryZVertical 
toQueue:operationQueue 
withHandler:handler];

并在处理程序内使用以下方法:

- (CMQuaternion) multiplyQuanternion:(CMQuaternion)left withRight:(CMQuaternion)right {

    CMQuaternion newQ;
    newQ.w = left.w*right.w - left.x*right.x - left.y*right.y - left.z*right.z;
    newQ.x = left.w*right.x + left.x*right.w + left.y*right.z - left.z*right.y;
    newQ.y = left.w*right.y + left.y*right.w + left.z*right.x - left.x*right.z;
    newQ.z = left.w*right.z + left.z*right.w + left.x*right.y - left.y*right.x;

    return newQ;
}

-(float)walkaroundRawAngleFromAttitude:(CMAttitude*)attitude {

    CMQuaternion e =  (CMQuaternion){0,0,1,1};
    CMQuaternion quatConj = attitude.quaternion;
    quatConj.x *= -1; quatConj.y *= -1; quatConj.z *= -1;
    CMQuaternion quat1 = attitude.quaternion;
    CMQuaternion quat2 = [self multiplyQuanternion:quat1 withRight:e];
    CMQuaternion quat3 = [self multiplyQuanternion:quat2 withRight:quatConj];

    return atan2f(quat3.y, quat3.x);
}
-(float)walkaroundAngleFromAttitude:(CMAttitude*)attitude fromHomeAngle:(float)homeangle {

    float rawangle = [self walkaroundRawAngleFromAttitude:attitude];
    if (rawangle <0) rawangle += M_PI *2;
    if (homeangle < 0) homeangle += M_PI *2;
    float finalangle = rawangle - homeangle;
    if (finalangle < 0) finalangle += M_PI *2;

    return finalangle;
}

这里使用了一些修改和扩展的代码,来自找到iOS设备的法向量

编辑以应对问题2和难题2:

这可能无法解决。我在其他应用程序(例如360全景)中看到过它,并读到陀螺仪等故障读数的问题。如果您试图进行补偿,则当某些真实的旋转运动被补偿代码抛弃时,您将最终得到一个抖动的体验。就我过去几年一直在理解的方式而言,这是一个基于硬件的问题。


感谢您的帮助,经过一些调整,我成功地让您的代码运行,并解决了我的问题_1。需要更多时间来测试和调整,但我确信我已经拥有完成它所需的一切。现在漂移的表现不同了,它会漂移几度然后停止 - 角度非常稳定,只有十分之一度的变化。这对于这个应用程序来说是完全可以接受的。我会继续尝试并发布结果,如果我找出它取决于什么,那就好了,直到那时,它就在硬件故障箱中,已经足够好了 :) 干杯 - Andrei G.
@AndreiG。好东西,很高兴我能帮到你。同时,这也让我有了重新学习四元数数学的必要锻炼 :) 干杯 - Tom Pace
@TomPace 你好,我也在尝试寻找类似的解决方案,能否请您看一下我的问题:链接。我认为我已经找到了角度变化部分,但不确定是否正确。我仍需要弄清如何在不同轴上跟踪手机运动。我的当前进展在这里。提前致谢。 - iSeeker
@iSeeker 我可能会尝试为此创建一个新的GitHub项目。 - Tom Pace
@TomPace 非常好!我很感激:)。那么是否可以获取并测量 iPhone 在不同轴上的运动,就像我发现的角度一样? - iSeeker
@TomPace 你好,我还在期待你说要创建的 GitHub 项目.. 如果你已经完成了,能否给我链接呢? :) - iSeeker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接