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
iOS 5 provides the designated method. Look for CMAttitudeReferenceFrameXTrueNorthZVertical in the developer documentation.
Pseudo code:
Here is the code:
- (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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With