34

iPhone でジャイロスコープを使用する際に助けが必要です。特定の状況でのピッチ、ロール、ヨーに関する CMAttitude の読み取り値を理解できません。

これは私のコードです

- (void)handleDeviceMotion:(CMDeviceMotion*)motion {

   NSLog(@"Yaw   %f ",attitude.yaw * 180 / M_PI);
   NSLog(@"Pitch %f ",attitude.pitch * 180 / M_PI);
   NSLog(@"Roll  %f ",attitude.roll * 180 / M_PI);
}

次の図のように、iPhone が平面に横たわっているとします。

ここに画像の説明を入力

ピッチ、ロール、ヨーは (ほぼ) 0 度であり、軸を中心に回転すると、理解できる読み取り値が返されます。たとえば、デバイスを右に回すと、ヨーは減少し、ピッチとロールは 0 のままです。

今、iPhone は次の位置にあります。

ここに画像の説明を入力

そして再び測定開始。

測定値: ヨー = 0、ピッチ = 90、ロール = 0

デバイスがこの軸を中心に回転するため、ピッチが増加します。

iPhone をこの位置に移動します。

ここに画像の説明を入力

測定値: ヨー = 30、ピッチ = 90、ロール = 0

繰り返しになりますが、デバイスはヨー軸を中心に回転するため、この値は変化しますが、他の値は変化しません。

ロール軸を中心にデバイスを移動します。

ここに画像の説明を入力

測定値は、ヨー = 0、ピッチ = 90、ロール = -20 です。

今、私が理解できないこと。次の図のように、半径 R (R > 0) の円の周りで iPhone を移動します。

ここに画像の説明を入力

ヨーは変化しますが、ピッチとロールは変化しません。

ヨーが変わらず、ロールが変わったと思っていたでしょう。

ユーザーが作成したヨー軸を中心とした回転にのみ関心があるため、これをどのように補正できますか?

私が抱えているもう1つの問題はドリフトです。iPhone は 2 番目の図のような位置にあり、手に持って長時間 (1 分以上) 静止しています。ヨーは常に増加します。ドリフトを補正する方法はありますか?

前もって感謝します

更新 Kay の提案に従いましたが、何も変わりません。私のコードの詳細。ユーザーがYaw軸を中心にデバイスを回転させた場合にのみ、Yawを使用してUIImageを回転させたいと思います。これは機能しますが、ユーザーが独自の垂直軸を中心に回転すると、ヨーが変化します。ユーザーが垂直軸を中心に移動すると、デバイスは独自のヨー軸を中心に回転しないため、これは正しくないと思います。私が間違っているかもしれません。これは私の元のコードです:

- (void)handleDeviceMotion:(CMDeviceMotion*)motion { 

   CMAttitude      *attitude = motion.attitude;

   NSLog(@"Yaw   %f ",attitude.yaw * 180 / M_PI);
   NSLog(@"Pitch %f ",attitude.pitch * 180 / M_PI);
   NSLog(@"Roll  %f ",attitude.roll * 180 / M_PI);

   image.transform = CGAffineTransformMakeRotation(-attitude.yaw);
}

これはKayの提案の後のコードです:

- (void)handleDeviceMotion:(CMDeviceMotion*)motion { 

   CMAttitude      *attitude = motion.attitude;        

   if (startAttitude == 0) {

      startAttitude = attitude;
   }

   [attitude multiplyByInverseOfAttitude:startAttitude];

   NSLog(@"Yaw   %f ",attitude.yaw * 180 / M_PI);
   NSLog(@"Pitch %f ",attitude.pitch * 180 / M_PI);
   NSLog(@"Roll  %f ",attitude.roll * 180 / M_PI);


   image.transform = CGAffineTransformMakeRotation(-attitude.yaw);
}

デバイスモーションの監視を開始します

 [motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryZVertical toQueue:[NSOperationQueue currentQueue]
                                                           withHandler: ^(CMDeviceMotion *motion, NSError *error){

                                                               [self performSelectorOnMainThread:@selector(handleDeviceMotion:) withObject:motion waitUntilDone:YES];
                                                           }];
4

1 に答える 1

6

[Completely revised]

(1) Strange Angles

At a first glance I mistook the situation as running into some typical problems related to Euler Angles. Because they are close to this problem area and really important to bear in mind, I leave this part of the original answer. Euler Angle problems are:

  • Ambiguity, as the relationship between rotation state and Euler Angles representation is not bijective i.e. a set of angles describes one rotation but a rotation can be represented by more than one set of Euler Angles. In your question's Fig. 3 you can achieve the same rotation by either 1: Yaw=30°, 2: Pitch=90° or by 1: Pitch=90°, 2: Roll=30°
  • Gimbal Lock problem: You may loose one degree of freedom and the device cannot rotate around one of the axes any longer. The solution is to use quaternions or rotation matrices.

But as you stated in your comment the true culprit seems to be the reference frame. Starting with iOS 5.0 Apple enhanced the sensor fusion algorithm and considers magnetic field data as well to calculate CMAttitude. Although there is still the old method startDeviceMotionUpdates, it now uses a default reference CMAttitudeReferenceFrameXArbitraryZVertical so that all measurement is related to "Z axis is vertical and the X axis points in an arbitrary direction in the horizontal plane".

In order to get your data in respect to the reference at start (or any other rotation) you need to store the CMAttitude instance you want as reference and then use CMAttitude's multiplyByInverseOfAttitude method to transform every new attitude i.e. at the beginning of your handleDeviceMotion method.

(2) Yaw Drifting

I think this is related to a bug in iOS 6 like the one I described in Drifting yaw angle after moving fast as it used to work fine in previous version. I filed a bug - let's see when they gonna fix it.


UPDATE 2

As comments and chat showed the goal was to control a robot by just tilting the device. In this case knowing the full rotation state of the device is messing up control when changing the walking direction. Thus a pure accelerometer based approach using CMDeviceMotion.gravity is far more convenient.

于 2013-01-25T20:24:56.203 に答える