Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect when an iphone has been bumped

I want to be able to detect if an iphone has been bumped into something...would it be best to listen to the gyroscope / accelerometer and judge how fast its moved or if its moved and stopped suddenly.

In fact how would I judge if the device has moved then stopped suddenly?

This answer is great but in reverse iOS: Accurately determining energy of a bump from accelerometer output - it smooths out the movement, if anything I want to detect a sharp movement.

Also are both the Gyroscope and Accelerometer available for 3GS ?

UPDATED WITH CODE

From the Apple doc http://developer.apple.com/library/iOS/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/MotionEvents/MotionEvents.html#//apple_ref/doc/uid/TP40009541-CH4-SW26

Isolating Instantaneous Motion from Acceleration Data If you are using accelerometer data to detect just the instant motion of a device, you need to be able to isolate sudden changes in movement from the constant effect of gravity. You can do that with a high-pass filter.

Listing 4-6 shows a simplified high-pass filter computation. The acceleration values from the previous event are stored in the accelX, accelY, and accelZ member variables of the class. This example computes the low-pass filter value and then subtracts it from the current value to obtain just the instantaneous component of motion.

Listing 4-6 Getting the instantaneous portion of movement from accelerometer data

define kFilteringFactor 0.1

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    // Subtract the low-pass value from the current value to get a simplified high-pass filter
    accelX = acceleration.x - ( (acceleration.x * kFilteringFactor) + (accelX * (1.0 - kFilteringFactor)) );
    accelY = acceleration.y - ( (acceleration.y * kFilteringFactor) + (accelY * (1.0 - kFilteringFactor)) );
    accelZ = acceleration.z - ( (acceleration.z * kFilteringFactor) + (accelZ * (1.0 - kFilteringFactor)) );

   // Use the acceleration data.
}

How would I then 'Use the acceleration data' to work out if an instantaneous motion is detected?

like image 418
daihovey Avatar asked Aug 04 '11 07:08

daihovey


2 Answers

The proper way would be to use a high-pass filter and linear acceleration after sensor fusion. Check Sensor.TYPE_LINEAR_ACCELERATION here, it is for Android. As far as I know iPhone does not have sensor fusion. As Kay pointed it out, Core Motion provides sensor fusion, see the comment below.

If you are interested, here is an excellent video on sensor fusion, start at 32:10.

A somewhat messy workaround is to use a high-pass filter and to use the accelerometer data without sensor fusion. If you bump to phone into something you might get spikes in the gyro data too but in my experience the accelerometers are better as they detect sudden velocity changes.

It is messy because you can fool this by quickly rotating the phone.

like image 179
Ali Avatar answered Sep 20 '22 17:09

Ali


From the previous answers, I generalized a bit to get the following which works pretty well:

// Isolate Instantaneous Motion from Acceleration Data
// (using a simplified high-pass filter)
CMAcceleration acceleration = accelerometerData.acceleration;
float prevAccelX = w_self.accelX;
float prevAccelY = w_self.accelY;
float prevAccelZ = w_self.accelZ;
w_self.accelX = acceleration.x - ( (acceleration.x * kFilteringFactor) +
                                   (w_self.accelX * (1.0 - kFilteringFactor)) );
w_self.accelY = acceleration.y - ( (acceleration.y * kFilteringFactor) +
                                   (w_self.accelY * (1.0 - kFilteringFactor)) );
w_self.accelZ = acceleration.z - ( (acceleration.z * kFilteringFactor) +  
                                   (w_self.accelZ * (1.0 - kFilteringFactor)) );

// Compute the derivative (which represents change in acceleration).
float deltaX = ABS((w_self.accelX - prevAccelX));
float deltaY = ABS((w_self.accelY - prevAccelY));
float deltaZ = ABS((w_self.accelZ - prevAccelZ));

// Check if the derivative exceeds some sensitivity threshold
// (Bigger value indicates stronger bump)
float sensitivityThreshold = 1.0;
float bumpVectorLength = sqrtf(deltaX*deltaX + deltaY*deltaY + deltaZ*deltaZ);
if ( bumpVectorLength > sensitivityThreshold ) {
    NSLog( @"BUMP:  |%.3f, %.3f, %.3f| = %.3f", deltaX, deltaY, deltaZ, bumpVectorLength);
}
like image 25
Chris Avatar answered Sep 21 '22 17:09

Chris