2

現在、CoreMotion の DeviceMotion を使用して、iPhone の向き (ロール、ピッチ、ヨー) を取得しています。ここで、地理的な北極を基準にしてこれらの値を取得したいと思います。そのため、ロール、ピッチ、ヨーの値を含む CMAttitude 参照オブジェクトが必要です。これは、iPhone の背面が北極 (3D) を向いている場合に報告されます。CLLocationManager はテスラで磁気方位 (x、y、z) のみを返します。

これらの値をロール、ピッチ、ヨーに変換する方法を知っていますか?

前もって感謝します、

アレクサンダー

4

4 に答える 4

3

iOS 5 は指定されたメソッドを提供します。開発者ドキュメントで CMAttitudeReferenceFrameXTrueNorthZVertical を探します。

于 2011-06-23T13:59:38.960 に答える
1

擬似コード:

  1. デバイスの動きの更新を開始する
  2. バックグラウンドでカメラのプレビューを開始します;)
  3. デバイスからの現在の重力の読み取り値を CMAcceleration としてキャプチャします... 重力をローカル変数に保存したら。
  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;
}
于 2012-05-27T13:51:47.777 に答える
0

正しい軌道に乗っていることを確認するために、ヨー値を時々磁針路に合わせて調整する必要があります。不安定なコンパスを補正する方法については、この説明を確認してください: iPhone 4 のジャイロスコープでコンパスの遅れを補正する

于 2011-08-25T14:39:39.840 に答える
-1

テスラの値は磁場の強さであり、3つの軸のそれぞれでどの程度の磁気の「引っ張り」が感じられるかの尺度です。この情報を加速度計のデータと組み合わせて、たくさんの凝った計算を行うことによってのみ、実際の方位を取得できます(つまり、デバイスは磁北に対して「指している」のです)。次に、GPSからの情報を追加し、さらに計算を行って、(地理的な北極に対して)真の方位を取得します。

簡単に言えば、あなたはおそらく自分で数学をしたくないでしょう。幸い、iOSはCLHeadingオブジェクトでmagneticHeadingとtrueHeadingの両方を提供しており、CLLocationManagerのheadingプロパティから利用できます。

デバイスがどのように傾いているかを説明するピッチとロールを取得するには、磁力計と加速度計からのこれらの同じ生データに対して計算を行うことも含まれます。申し訳ありませんが、ピッチアンドロール用のiOSAPIを知りません。

于 2011-03-03T16:11:24.783 に答える