4

私はしばらくAR フレームワークに取り組んでおり、 UIAccelerometer (非推奨) から CMMotionManager に更新しようとしていますが、効率の問題が発生していますか?

基本的に、CMMotionManager は UIAccelerometer よりもはるかに大きく、遅いようです。以前に CMMotionManager でパフォーマンスの問題を経験した人はいますか?


ここでわかるように、私はこれを持っていました:

accelerometer = [UIAccelerometer sharedAccelerometer];
accelerometer.updateInterval = 0.01;
[accelerometer setDelegate:self];

-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    rollingZ  = (acceleration.z * kFilteringFactor) + (rollingZ  * (1.0 - kFilteringFactor));
    rollingX = (acceleration.y * kFilteringFactor) + (rollingX * (1.0 - kFilteringFactor));

    if (rollingZ > 0.0)      currentInclination = inc_avg(atan(rollingX / rollingZ) + M_PI / 2.0);
    else if (rollingZ < 0.0) currentInclination = inc_avg(atan(rollingX / rollingZ) - M_PI / 2.0);
    else if (rollingX < 0)   currentInclination = inc_avg(M_PI/2.0);
    else if (rollingX >= 0)  currentInclination = inc_avg(3 * M_PI/2.0);
}

iPhone 4 のような「古い」デバイスでもすべてうまく動作します (それほど古いものではありませんが...)。

しかし、CMMotionManager を使用してまったく同じコードを試すと、次のようになります。

motionManager = [[CMMotionManager alloc] init];

[motionManager setAccelerometerUpdateInterval:0.01];
[motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue]
                                    withHandler: ^(CMAccelerometerData *accelerometerData, NSError *error){

                                        rollingZ = (accelerometerData.acceleration.z * kFilteringFactor) + (rollingZ  * (1.0 - kFilteringFactor));
                                        rollingX = (accelerometerData.acceleration.y * kFilteringFactor) + (rollingX * (1.0 - kFilteringFactor));

                                        if (rollingZ > 0.0)      currentInclination = inc_avg(atan(rollingX / rollingZ) + M_PI / 2.0);
                                        else if (rollingZ < 0.0) currentInclination = inc_avg(atan(rollingX / rollingZ) - M_PI / 2.0);
                                        else if (rollingX < 0)   currentInclination = inc_avg(M_PI/2.0);
                                        else if (rollingX >= 0)  currentInclination = inc_avg(3 * M_PI/2.0);
                                    }];

数学はそれからがらくたを遅らせるようです..! これは、すべての数学部分を削除するとうまく機能するためです。

iPhone 5 は問題なく動作しますが、iPhone 4S は遅延の兆候を示し、iPhone 4 はフリーズするだけです...

(必要に応じて詳細を説明できますが、説明するのは比較的複雑です)

4

2 に答える 2

7

I was just having this same problem, and wouldn't you know it, the solution was in the documentation ;)

The problem is with the block format. All of the tutorials seem to favor that method, but Apple recommends periodic polling of the CMMotionManager as a more performance oriented approach. The block format adds overhead.

From the CMMotionManager Class Reference:

To handle motion data by periodic sampling, the app calls a “start” method taking no arguments and periodically accesses the motion data held by a property for a given type of motion data. This approach is the recommended approach for apps such as games. Handling accelerometer data in a block introduces additional overhead, and most game apps are interested only the latest sample of motion data when they render a frame.

So what you want to do, from the docs again:

Call startAccelerometerUpdates to begin updates and periodically access CMAccelerometerData objects by reading the accelerometerData property.

Something along these lines

CMMotionManager *mManager = [(AppDelegate *)[[UIApplication sharedApplication] delegate] sharedManager];

[mManager startAccelerometerUpdates];

Then, in some sort of periodically updating method of your choosing:

CMMotionManager *mManager = [(SEPAppDelegate *)[[UIApplication sharedApplication] delegate] sharedManager];

CMAccelerometerData *aData = mManager.accelerometerData;

This solution appears to work as well as UIAccelerometer on an iPhone 4 from the limited testing I've done.

于 2013-07-18T06:46:17.047 に答える
4

CADisplayLinkを使用しています。

まず、CMMotionManagerインスタンスをセットアップします。

-(void)viewDidLoad
{
    [super viewDidLoad];

    self.motionManager = [[CMMotionManager alloc]init];

    if(self.motionManager.isDeviceMotionAvailable)
    {
        [self.motionManager startDeviceMotionUpdates];
    }


    [self setupDisplayLink];
}

次に、次のようにdisplaylinkインスタンスをセットアップします。

-(void)setupDisplayLink
{
    CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(update:)];
    displayLink.frameInterval = 10;// how many frames to skip before next update
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}

表示リンクは、デバイス画面に接続されているオブジェクトであり、指定されたフレーム レートで指定されたセレクターを実行できます。詳細はこちら

3 番目に、表示リンク セレクターとして指定した update: メソッドを実装する必要があります。

-(void)update:(CADisplayLink *)displayLink
{
    // handle new accelerometer data here
    CMDeviceMotion *deviceMotion = self.motionManager.deviceMotion;
    NSLog(@"Acceleration: %@", deviceMotion.accelerometerData.acceleration);
}
于 2013-11-20T12:48:12.660 に答える