CMMotionManager vs. UIAccelerometer Efficiency

I have been working on the AR framework for some time and have been trying to upgrade from UIAccelerometer (deprecated) to CMMotionManager , but have I encountered some performance issues?

Basically, it seems that the CMMotionManager is much larger and slower than the UIAccelerometer. Has anyone encountered performance issues with CMMotionManager before?


As you can see here , I had this:

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

and

 -(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); } 

and everything works fine even on "old" devices such as the iPhone 4 (not very old, but yes ...).

But when trying to use the same code, but with CMMotionManager:

 motionManager = [[CMMotionManager alloc] init]; 

with

 [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); }]; 

Math seems to slow down shit. I say this because when I delete the entire math part, it works great.

The iPhone 5 will work fine, but the iPhone 4S will show signs of lag, and the iPhone 4 will just freeze ...

(I can give you more details if you want, but relatively difficult to explain)

+4
source share
2 answers

I had the same problem, and do not you know this, the solution was in the documentation;)

The problem is the block format. All tutorials seem to favor this method, but Apple recommends periodically polling the CMMotionManager as a more performance-oriented approach. The block format adds overhead.

From the CMMotionManager reference:

To process motion data using periodic sampling, the application calls "start", the method takes no arguments and periodically accesses the motion data held by the property for data such as motion data. This approach is the recommended approach for applications such as games. handling the accelerometer data in the unit introduces additional overhead, and most gaming applications are only interested in the latest sample motion data when they create the frame.

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

Call startAccelerometerUpdates to start updates and periodically access the CMAccelerometerDate objects by reading the accelerometerDate property.

Something in this direction

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

Then in some periodic update method of your choice:

 CMMotionManager *mManager = [(SEPAppDelegate *)[[UIApplication sharedApplication] delegate] sharedManager]; CMAccelerometerData *aData = mManager.accelerometerData; 

This solution works the same as the UIAccelerometer on the iPhone 4 from the limited testing I did.

+7
source

I am using CADisplayLink .

First configure the CMMotionManager instance.

 -(void)viewDidLoad { [super viewDidLoad]; self.motionManager = [[CMMotionManager alloc]init]; if(self.motionManager.isDeviceMotionAvailable) { [self.motionManager startDeviceMotionUpdates]; } [self setupDisplayLink]; } 

Secondly, configure the displaylink , for example:

 -(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]; } 

The displayed link is an object that is connected to the screen of your device and which can trigger the specified selector with a given frame rate; More about them here

Third, you must implement the update: the method that you specified as the image link selector.

 -(void)update:(CADisplayLink *)displayLink { // handle new accelerometer data here CMDeviceMotion *deviceMotion = self.motionManager.deviceMotion; NSLog(@"Acceleration: %@", deviceMotion.accelerometerData.acceleration); } 
+3
source

Source: https://habr.com/ru/post/1491484/


All Articles