2011-03-03 42 views
2

我目前使用CoreMotion的DeviceMotion來獲取iPhone的方向(滾動,俯仰,偏航)。現在我想要把這些值與地理北極相對應;所以我需要一個包含滾動,俯仰和偏航值的CMAttitude參考對象,如果iPhone的背面將面對北極(3D),則會報告這些值。 CLLocationManager只返回Tesla中的磁頭(x,y,z)。iOS CoreMotion CMAttitude相對於北極

你有想法如何將這些值轉換爲滾動,俯仰和偏航?

由於提前,

亞歷山大

回答

-1

特斯拉值是磁場強度是多少磁「拉」覺得在三個軸的測量。只有將這些信息與加速度計數據結合起來,並進行一些花哨的數學運算,才能得到實際的航向(設備相對於磁北極「指向」的方式)。然後添加來自GPS的信息並進行更多的數學計算,以獲得真正的標題(相對於地理北極)。長話短說,你可能不想自己做數學。幸運的是,iOS在其CLHeading對象中提供了magneticHeading和trueHeading,可從CLLocationManager標題屬性中獲得。要獲得描述設備如何傾斜的俯仰和滾動,還需要對來自磁力計和加速度計的相同原始數據進行數學運算。對不起,我不知道任何iOS API的音調和滾動。

3

iOS 5提供了指定的方法。在開發人員文檔中查找CMAttitudeReferenceFrameXTrueNorthZVertical。

1

僞代碼:

  1. 啓動裝置運動的更新
  2. 在後臺啓動相機預覽;)
  3. 捕捉當前的重力讀數從設備作爲CMA加速...一旦你有重力將它存儲在局部變量中。
  4. 然後,你必須採取2個向量,並獲得他們之間的角度,在這種情況下,設備的重力(0,0,-1)和真實的重力矢量...
  5. 然後,我們把theta thetaPrime ...一個與CoreMotion參考方向相匹配的轉換
  6. 設置一個計時器以設置動畫....
  7. 動畫過程中獲取motionManager的deviceMotion屬性的rotationMatrix的反函數。
  8. 應用變換以正確的順序,以反映設備的當前態度(偏航,俯仰,滾轉歐拉模式或設備四元數旋轉... 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; 
} 
相關問題