我有一个应用程序,当用户在对象周围走动时记录角度,同时将设备(最好)指向对象的中心。 角度会根据用户的命令重置 - 因此参考态度会重置。
使用欧拉角产生万向节锁定,所以我目前使用四元数并以这种方式计算角度:
double angleFromLastPosition = acos(fromLastPositionAttitude.quaternion.w) * 2.0f;
这样可以提供良好的精度,并且如果设备的俯仰和偏航不会改变,它可以很好地工作。换句话说,当角度显示360度时,我最终会与圆圈的开始位于同一位置。
问题1:如果设备的偏航和俯仰稍微改变(用户不直接指向物体的中心),则angleFromLastPosition也是如此。 我理解这一部分,因为我的角度公式只显示了3D空间中两个设备态度之间的角度。
情景:
问题1是,如何仅使用四元数计算设备的滚动,并忽略其他两个轴的变化(至少在某个合理的度数范围内)。
问题2:如果我旋转一点然后完全冻结设备(在三脚架上没有任何震动),angleFromLastPosition以每10-20秒左右1度的速度漂移,并且它似乎不是线性的。换句话说,它首先快速漂移,然后大幅减速。有时我根本没有漂移 - 如果设备静止,角度是坚如磐石的。这让我迷失了解正在发生的事情。
问题2,这里发生了什么,我该如何处理漂移?
我经历了相当多的文章和教程,目前四元数学已超出我的范围,希望有人能够提供一些提示,链接或几行代码。
答案 0 :(得分:4)
我已经对此进行了测试,它似乎可以根据您在问题1中找到的工作,Andrei。
我将homeangle设置为0,并在第一次传递后立即存储walkaroundAngleFromAttitude:fromHomeAngle:homeangle中返回的角度,以备将来使用。
我的测试包括使用参考框架启动设备更新:
[_motionManager
startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryZVertical
toQueue:operationQueue
withHandler:handler];
并使用在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;
}
这是使用Finding normal vector to iOS device
中的一些修改和扩展代码编辑处理问题2&amp;问题2:
这可能无法解决。我已经在其他应用程序(例如360 pano)中看到了它,并且已经阅读了有关陀螺仪等错误读数的信息。如果你试图弥补它,当然,当一些真实的旋转运动被补偿代码抛出时,你最终会有一种紧张的经历。就我过去几年的口译而言,这是一个基于硬件的问题。