Question

I would like an action to take place when the phone is stationary for 2 seconds. I've searched for ages around google and stack overflow. I discovered that "Accelerometer DidAccelerate" has been depreciated and that CoreMotion is the replacement. Everything I have seen has been to do with the 'shaking' motion. I've tried reading through apple's documentation but It just confuses me!

Basically, I want the app to detect that the g-forces on the phone have remained within a small limit for a certain amount of time (suggesting that the phone has been laid down on a table or something) and for it to call and instance or make the app do something.

Any help would be greatly appreciated.

Was it helpful?

Solution

It's similar to the problem described in Simple iPhone motion detect. The basic setup for CMMotionManager is described in the Apple docs like Mike Pollard stated in his comment. I recommend especially the Handling Processed Device Motion Data section.

What you then need is CMDeviceMotion.userAcceleration which contains the pure acceleration without gravity.

CMMotionManager *motionManager = [[CMMotionManager alloc] init];
// UPDATE: set interval to 0.02 sec
motionManager.deviceMotionUpdateInterval = 1.0 / 50.0;
[motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] 
        withHandler:^(CMDeviceMotion *deviceMotion, NSError *error) {
    CMAcceleration userAcceleration = deviceMotion.userAcceleration;
    double totalAcceleration = sqrt(userAcceleration.x * userAcceleration.x + 
        userAcceleration.y * userAcceleration.y + userAcceleration.z * userAcceleration.z);
    // UPDATE: print debug information
    NSLog (@"total=%f x=%f y=%f z=%f", totalAcceleration, userAcceleration.x, userAcceleration.y, userAcceleration.z);
    // if(totalAcceleration < SOME_LIMIT) ...

Then proceed like codeplasma has described in his answer above.

Also be aware that the solution might not be precise if used in the underground, bus, etc. because of external accelerations.

OTHER TIPS

You can do something like this:

CMMotionManager *mManager = [[CMMotionManager alloc] init];

if ([mManager isAccelerometerAvailable] == YES) {
    __block float lastActivityBefore = 0.0;
    [mManager setAccelerometerUpdateInterval:0.1];
    [mManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {

        double totalAcceleration = sqrt(accelerometerData.acceleration.x * accelerometerData.acceleration.x + accelerometerData.acceleration.y * accelerometerData.acceleration.y + accelerometerData.acceleration.z * accelerometerData.acceleration.z);
        if(totalAcceleration < SOME_LIMIT)
            lastActivityBefore = lastActivityBefore + 0.1;
        else
            lastActivityBefore = 0.0;

        if(lastActivityBefore >= 2.0)
        {
            //do something
        }
    }];
}

Accelerometer will show some minimal acceleration even if your device is steady, so you should make a testing in order to determine SOME_LIMIT value.

Also be advised that you should have only one instance CMMotionManager class in your app, so you're better to put it in your AppDelegate and initialize it only once.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top