How can I get device header with CMDeviceMotion in iOS 5

I am developing an AR application using a gyroscope. I am using apple pARk sample code. It uses the rotation matrix to calculate the position of the coordinate, and that’s really good, but now I'm trying to implement a “radar”, and I need to rotate it in the device header function. I use the CLLocationManager header, but this is incorrect.

The question is, how can I get the device header using CMAttitude to accurately reflect what I get on the screen?

I am new to rotation matrix and such things.

This is part of the code used to calculate AR coordinates. Update CameraTransform with the ratio:

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 a pitch angle. Movement updates start from the north:

 [motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical]; 

So, I think it should be possible to get the “roll” / title of the device in any position (with any step and jerk ...), but I don’t know how to do it.

+4
source share
1 answer

There are several ways to calculate the header from the rotation matrix returned by CMDeviceMotion. This assumes that you are using the same definition of the Apple compass, where the + y direction (top of the iPhone) pointing north returns 0, and turning iPhone right increases the title, so East is 90, south is 180, and t .d.

First, be sure to check if the headers are available when starting updates:

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

Then, when you start the motion controller, ask for the relationship as a turn from X indicating true north (or magnetic north if you need it for some reason):

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

When the motion controller reports a motion update, you want to know how much the device is rotated in the XY plane. Since we are interested in the top of the iPhone, we will select a point in this 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] 

Funky brackets are matrices; this is the best i can do using ASCII. :)

The heading is the angle between the rotating point and true north. We can use the X and Y coordinates of the rotated point to extract the tangent of the arc, which gives the angle between the point and the X axis. This is actually 180 degrees from what we want, so we need to adjust accordingly. The resulting code is as follows:

 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); } }; 

There is one question: if the top of the iPhone is straight or straight down, the direction is undefined. As a result, m21 and m22 are zero or very close to it. You need to decide what this means for your application and handle the condition accordingly. For example, you can switch to a title based on the -Z axis (behind the iPhone) when m12 * m12 + m22 * m22 is close to zero.


All of this assumes that you want to rotate around the XY plane, as Apple usually does for its compass. This works because you use the rotation matrix returned by the motion controller to rotate the vector directed along the Y axis, which is this matrix:

 [0] [1] [0] 

To rotate another vector - for example, one pointed along -Z - use another matrix, for example

 [0] [0] [-1] 

Of course, you also need to take the tangent arc in another plane, so instead of

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

would you use

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

to get a turn in the XZ plane.

+15
source

Source: https://habr.com/ru/post/1397188/


All Articles