我如何在 iOS 5 中使用 CMDeviceMotion 获取设备的标题
我正在使用陀螺仪开发 AR 应用程序。我使用了苹果代码示例公园。它使用旋转矩阵来计算坐标的位置,并且效果非常好,但现在我正在尝试实现一个“雷达”,我需要根据设备航向来旋转它。我正在使用 CLLocationManager 标题,但它不正确。
问题是,如何使用 CMAttitude 获取设备的方向以准确反映我在屏幕上看到的内容?
我对旋转矩阵之类的东西很陌生。
这是用于计算 AR 坐标的代码的一部分。用姿态更新cameraTransform:
CMDeviceMotion *d = motionManager.deviceMotion;
if (d != nil) {
CMRotationMatrix r = d.attitude.rotationMatrix;
transformFromCMRotationMatrix(cameraTransform, &r);
[self setNeedsDisplay];
}
然后在drawRect代码中:
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;
我还用俯仰角旋转视图。 运动更新是从北开始的:
[motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical];
所以我认为必须有可能在任何位置(任何俯仰和偏航......)获得设备的“滚动”/航向,但我不知道如何。
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.
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.
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];
}
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
有几种方法可以根据 CMDeviceMotion 返回的旋转矩阵计算航向。假设您使用与 Apple 指南针相同的定义,其中 +y 方向(iPhone 顶部)指向正北返回航向 0,向右旋转 iPhone 会增加航向,因此东为 90,南为 180 ,等等。
首先,当您开始更新时,请务必检查以确保标题可用:
接下来,当您启动运动管理器时,询问姿态为从 X 指向真北(或磁北,如果您出于某种原因需要)的旋转:
当运动管理器报告运动更新时,您想要了解设备在 XY 平面中旋转了多少。由于我们对 iPhone 的顶部感兴趣,因此我们将在该方向上选取一个点,并使用返回的旋转矩阵对其进行旋转,以获得旋转后的点:
时髦的括号是矩阵;这是我能用 ASCII 做的最好的事情了。 :)
航向是旋转点与正北之间的角度。我们可以使用旋转点的 X 和 Y 坐标来提取反正切,从而给出该点与 X 轴之间的角度。这实际上与我们想要的有180度的偏差,因此我们必须进行相应的调整。生成的代码如下所示:
有一个陷阱:如果 iPhone 的顶部笔直向上或笔直向下,则方向未定义。结果是 m21 和 m22 为零或非常接近零。您需要确定这对您的应用意味着什么,并相应地处理这种情况。例如,当 m12*m12 + m22*m22 接近于零时,您可以切换到基于 -Z 轴(iPhone 后面)的航向。
这一切都假设您想要围绕 XY 平面旋转,就像 Apple 通常对其指南针所做的那样。它之所以有效,是因为您使用运动管理器返回的旋转矩阵来旋转沿 Y 轴指向的向量,即以下矩阵:
要旋转不同的向量(例如,沿 -Z 指向的向量),请使用不同的矩阵,当然
,您还必须在不同的平面中获取反正切,因此
您可以使用
XZ 平面中的旋转来代替。
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:
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):
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:
The funky brackets are matrices; it's the best I can do using ASCII. :)
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:
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.
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:
To rotate a different vector--say, one pointed along -Z--use a different matrix, like
Of course, you also have to take the arc tangent in a different plane, so instead of
you would use
to get the rotation in the X-Z plane.