如何在iOS 5中使用CMDeviceMotion获取设备的标题 [英] how can i get the heading of the device with CMDeviceMotion in iOS 5

查看:155
本文介绍了如何在iOS 5中使用CMDeviceMotion获取设备的标题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用陀螺开发AR应用程序。我使用了一个苹果代码示例pARk。它使用旋转矩阵来计算坐标的位置并且它确实很好,但是现在我正在尝试实现雷达,我需要在设备标题的功能中旋转它。我正在使用CLLocationManager标题,但它不正确。

I'm developing an AR app using the gyro. I have use an apple code example pARk. It use the rotation matrix to calculate the position of the coordinate and it do really well, but now I'm trying to implement a "radar" and I need to rotate this in function of the device heading. I'm using the CLLocationManager heading but it's not correct.

问题是,如何使用CMAttitude获取设备的标题以准确反映我的内容屏幕??

The question is, how can I get the heading of the device using the CMAttitude to reflect exactly what I get in the screen??

我是新的旋转矩阵和那种东西。

I'm new with rotation matrix and that kind of things.

这是一部分用于计算AR坐标的代码。以态度更新cameraTransform:

This is part of the code used to calculate the AR coordinates. Update the cameraTransform with the attitude:

CMDeviceMotion *d = motionManager.deviceMotion;
if (d != nil) {
    CMRotationMatrix r = d.attitude.rotationMatrix;
    transformFromCMRotationMatrix(cameraTransform, &r);
[self setNeedsDisplay];
}

然后在drawRect代码中:

and then in the drawRect code:

mat4f_t projectionCameraTransform;
multiplyMatrixAndMatrix(projectionCameraTransform, projectionTransform, cameraTransform);

int i = 0;
for (PlaceOfInterest *poi in [placesOfInterest objectEnumerator]) {
    vec4f_t v;
    multiplyMatrixAndVector(v, projectionCameraTransform, placesOfInterestCoordinates[i]);

    float x = (v[0] / v[3] + 1.0f) * 0.5f;
    float y = (v[1] / v[3] + 1.0f) * 0.5f;

我还用俯仰角旋转视图。
动作更新使用北方开始:

I also rotate the view with the pitch angle. The motions updates are started using the north:

[motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical];

所以我认为必须能够在任何位置获得设备的滚动/标题(有任何俯仰和偏航...)但我不知道如何。

So I think that must be possible to get the "roll"/heading of the device in any position (with any pitch and yaw...) but I don't know how.

推荐答案

有几种计算方法从CMDeviceMotion返回的旋转矩阵开始。这假设您使用与Apple指南针相同的定义,其中指向正北的+ y方向(iPhone顶部)返回标题0,向右旋转iPhone会增加标题,因此East为90,South为180 ,等等。

There are a few ways to calculate heading from the rotation matrix returned by CMDeviceMotion. This assumes you use the same definition of Apple's compass, where the +y direction (top of the iPhone) pointing due north returns a heading of 0, and rotating the iPhone to the right increases the heading, so East is 90, South is 180, and so forth.

首先,当您开始更新时,请务必检查以确保标题可用:

First, when you start updates, be sure to check to make sure headings are available:

if (([CMMotionManager availableAttitudeReferenceFrames] & CMAttitudeReferenceFrameXTrueNorthZVertical) != 0) {
   ...
}

接下来,当你启动运动管理器时,要求态度为从X指向真北的旋转(或者如果由于某种原因你需要它则为磁北) ):

Next, when you start the motion manager, ask for attitude as a rotation from X pointing true North (or Magnetic North if you need that for some reason):

[motionManager startDeviceMotionUpdatesUsingReferenceFrame: CMAttitudeReferenceFrameXTrueNorthZVertical
                                                   toQueue: self.motionQueue
                                               withHandler: dmHandler];

当运动管理器报告动作更新时,您想知道设备已旋转了多少XY平面。由于我们对iPhone的顶部感兴趣,我们将在该方向上选择一个点并使用返回的旋转矩阵旋转它以获得旋转后的点:

When the motion manager reports a motion update, you want to find out how much the device has rotated in the X-Y plane. Since we are interested in the top of the iPhone, we'll pick a point in that direction and rotate it using the returned rotation matrix to get the point after rotation:

   [m11 m12 m13] [0]   [m12]
   [m21 m22 m23] [1] = [m22]
   [m31 m32 m33] [0]   [m32]

时髦的括号是矩阵;这是我用ASCII做的最好的。 :)

The funky brackets are matrices; it's the best I can do using ASCII. :)

标题是旋转点和真北之间的角度。我们可以使用旋转点的X和Y坐标来提取反正切,它提供了点和X轴之间的角度。这实际上与我们想要的相差180度,因此我们必须相应调整。结果代码如下所示:

The heading is the angle between the rotated point and true North. We can use the X and Y coordinates of the rotated point to extract the arc tangent, which gives the angle between the point and the X axis. This is actually 180 degrees off from what we want, so we have to adjust accordingly. The resulting code looks like this:

CMDeviceMotionHandler dmHandler = ^(CMDeviceMotion *aMotion, NSError *error) {
    // Check for an error.
    if (error) {
        // Add error handling here.
    } else {
        // Get the rotation matrix.
        CMAttitude *attitude = self.motionManager.deviceMotion.attitude;
        CMRotationMatrix rm = attitude.rotationMatrix;

        // Get the heading.
        double heading = PI + atan2(rm.m22, rm.m12);
        heading = heading*180/PI;
        printf("Heading: %5.0f\n", heading);
    }
};

有一个问题:如果iPhone的顶部笔直向上或笔直向下,方向未定义。结果是m21和m22为零或非常接近它。您需要确定这对您的应用程序意味着什么,并相应地处理条件。例如,当m12 * m12 + m22 * m22接近零时,您可能会切换到基于-Z轴(在iPhone后面)的标题。

There is one gotcha: If the top of the iPhone is pointed straight up or straight down, the direction is undefined. The result is m21 and m22 are zero, or very close to it. You need to decide what this means for your app and handle the condition accordingly. You might, for example, switch to a heading based on the -Z axis (behind the iPhone) when m12*m12 + m22*m22 is close to zero.

这一切都假设你想围绕XY平面旋转,就像Apple通常用于指南针一样。它的工作原理是因为您正在使用运动管理器返回的旋转矩阵来旋转沿Y轴指向的矢量,即此矩阵:

This all assumes you want to rotate about the X-Y plane, as Apple usually does for their compass. It works because you are using the rotation matrix returned by the motion manager to rotate a vector pointed along the Y axis, which is this matrix:

[0]
[1]
[0]

To旋转一个不同的向量 - 比如,一个指向-Z - 使用不同的矩阵,比如

To rotate a different vector--say, one pointed along -Z--use a different matrix, like

[0]
[0]
[-1]

当然,你还必须采取在另一个平面上的反正切,所以代替

Of course, you also have to take the arc tangent in a different plane, so instead of

double heading = PI + atan2(rm.m22, rm.m12);

您将使用

double heading = PI + atan2(-rm.m33, -rm.m13);

获取X-Z平面的旋转。

to get the rotation in the X-Z plane.

这篇关于如何在iOS 5中使用CMDeviceMotion获取设备的标题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆