iOS CoreMotion CMAttitude 相对于北极
我目前正在使用 CoreMotion 的 DeviceMotion 来获取 iPhone 的方向(滚动、俯仰、偏航)。现在我想要相对于地理北极的这些值;因此,我需要一个包含滚动、俯仰和偏航值的 CMAttitude 参考对象,如果 iPhone 背面面向北极(3D),则会报告这些值。 CLLocationManager 仅返回 Tesla 中的磁航向 (x, y, z)。
您知道如何将这些值转换为横滚、俯仰和偏航吗?
预先感谢,
亚历山大
I'm currently using CoreMotion's DeviceMotion to get the orientation (roll, pitch, yaw) of the iPhone. Now I would like to have these values relative to the geographic north pole; so I need a CMAttitude reference object containing the roll, pitch and yaw values, which would be reported, if the back of the iPhone would face to the north pole (3D). The CLLocationManager only returns the magnetic heading (x, y, z) in Tesla.
Do you have an idea of how to convert those values to roll, pitch and yaw?
Thanks in advance,
Alexander
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(4)
伪代码:
- 启动设备运动更新
- 在后台启动相机预览;)
- 从设备捕获当前重力读数作为 CMAcceleration...一旦您将重力存储在本地变量中。
- 然后你必须获取 2 个向量并获取它们之间的角度,在本例中为 (0,0,-1) 的设备重力和真实的重力向量...
- 然后我们将 theta 转换为 thetaPrime...一个变换与 CoreMotion 参考方向相匹配
- 设置一个计时器来制作动画....
- 在动画期间获取 MotionManager 的 deviceMotion 属性的旋转矩阵的倒数。
- 以正确的顺序应用变换来反映设备当前的姿态(欧拉模式下的偏航、俯仰、滚动或设备四元数旋转......基本上有 3 种不同的方式来表达同一件事)
以下是代码:
- (void) initMotionCapture
{
firstGravityReading = NO;
referenceAttitude = nil;
if (motionManager == nil)
{
self.motionManager = [CMMotionManager new];
}
motionManager.deviceMotionUpdateInterval = 0.01;
self.gravityTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 target:self selector:@selector(getFirstGravityReading) userInfo:nil repeats:YES];
}
- (void) getFirstGravityReading
{
CMAcceleration currentGravity;
CMDeviceMotion *dm = motionManager.deviceMotion;
referenceAttitude = dm.attitude;
currentGravity = dm.gravity;
[motionManager startDeviceMotionUpdates];
if (currentGravity.x !=0 && currentGravity.y !=0 && currentGravity.z !=0)
{
NSLog(@"Gravity = (%f,%f,%f)", currentGravity.x, currentGravity.y, currentGravity.z);
firstGravityReading = YES;
[gravityTimer invalidate];
self.gravityTimer = nil;
[self setupCompass];
}
}
- (void) setupCompass
{
//Draw your cube... I am using a quartz 3D perspective hack!
CATransform3D initialTransform = perspectiveTransformedLayer.sublayerTransform;
initialTransform.m34 = 1.0/-10000;
//HERE IS WHAT YOU GUYS NEED... the vector equations!
NSLog(@"Gravity = (%f,%f,%f)", currentGravity.x, currentGravity.y, currentGravity.z);
//we have current gravity vector and our device gravity vector of (0, 0, -1)
// get the dot product
float dotProduct = currentGravity.x*0 + currentGravity.y*0 + currentGravity.z*-1;
float innerMagnitudeProduct = currentGravity.x*currentGravity.x + currentGravity.y + currentGravity.y + currentGravity.z*currentGravity.z;
float magnitudeCurrentGravity = sqrt(innerMagnitudeProduct);
float magnitudeDeviceVector = 1; //since (0,0,-1) computes to: 0*0 + 0*0 + -1*-1 = 1
thetaOffset = acos(dotProduct/(magnitudeCurrentGravity*magnitudeDeviceVector));
NSLog(@"theta(degrees) = %f", thetaOffset*180.0/M_PI);
//Now we have the device angle to the gravity vector (0,0,-1)
//We must transform these coordinates to match our
//device's attitude by transforming to theta prime
float theta_deg = thetaOffset*180.0/M_PI;
float thetaPrime_deg = -theta_deg + 90; // ThetaPrime = -Theta + 90 <==> y=mx+b
NSLog(@"thetaPrime(degrees) = %f", thetaOffset*180.0/M_PI);
deviceOffsetRotation = CATransform3DMakeRotation((thetaPrime_deg) * M_PI / 180.0, 1, 0, 0);
initialTransform = CATransform3DConcat(deviceOffsetRotation, initialTransform);
perspectiveTransformedLayer.sublayerTransform = initialTransform;
self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 target:self selector:@selector(tick) userInfo:nil repeats:YES];
}
- (void) tick
{
CMRotationMatrix rotation;
CMDeviceMotion *deviceMotion = motionManager.deviceMotion;
CMAttitude *attitude = deviceMotion.attitude;
if (referenceAttitude != nil)
{
[attitude multiplyByInverseOfAttitude:referenceAttitude];
}
rotation = attitude.rotationMatrix;
CATransform3D rotationalTransform = perspectiveTransformedLayer.sublayerTransform;
//inverse (or called the transpose) of the attitude.rotationalMatrix
rotationalTransform.m11 = rotation.m11;
rotationalTransform.m12 = rotation.m21;
rotationalTransform.m13 = rotation.m31;
rotationalTransform.m21 = rotation.m12;
rotationalTransform.m22 = rotation.m22;
rotationalTransform.m23 = rotation.m32;
rotationalTransform.m31 = rotation.m13;
rotationalTransform.m32 = rotation.m23;
rotationalTransform.m33 = rotation.m33;
rotationalTransform = CATransform3DConcat(deviceOffsetRotation, rotationalTransform);
rotationalTransform = CATransform3DConcat(rotationalTransform, CATransform3DMakeScale(1.0, -1.0, 1.0));
perspectiveTransformedLayer.sublayerTransform = rotationalTransform;
}
您需要时不时地将偏航值校准到磁航向,以确保您处于正确的轨道上。查看有关如何补偿指南针抖动的说明:补偿指南针iPhone 4 上的陀螺仪滞后
特斯拉值是磁场强度,是三个轴中每个轴感受到的磁“拉力”大小的度量。只有将这些信息与加速度计数据结合起来,并进行一系列奇特的数学运算,您才能获得实际的航向(设备相对于磁北“指向”的方向)。然后添加来自 GPS 的信息并进行更多数学计算,以获得真实航向(相对于地理北极)。
长话短说,您可能不想自己做数学计算。幸运的是,iOS 在其 CLHeading 对象中提供了MagneticHeading 和 trueHeading,可从 CLLocationManager 标题属性获取。
为了获得描述设备如何倾斜的俯仰和滚动,还需要对来自磁力计和加速度计的相同原始数据进行数学计算。抱歉,我不知道有任何用于俯仰和横滚的 iOS API。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
iOS 5提供了指定方法。在开发人员文档中查找 CMAttitudeReferenceFrameXTrueNorthZVertical。
iOS 5 provides the designated method. Look for CMAttitudeReferenceFrameXTrueNorthZVertical in the developer documentation.