Detect when an iphone has been bumped

2019-01-16 21:50发布

问题:

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?

回答1:

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.



回答2:

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


回答3:

I used this code:

#define kUpdateFrequency    100.0
#define kFilteringFactor    0.1
float accelZ;
int spikeZCount = 0; 

[[UIAccelerometer sharedAccelerometer] setUpdateInterval:1.0 / kUpdateFrequency];
    [[UIAccelerometer sharedAccelerometer] setDelegate:self];

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

    if (accelZ > 0.0f)
    {
        if (spikeZCount > 9)
        {
            //  NSLog(@"SPIKE!");
            [[UIAccelerometer sharedAccelerometer] setDelegate:nil];

            [self isBumped];
        }
        else
        {
            spikeZCount++;
            //  NSLog(@"spikeZCount %i",spikeZCount);
        }
    }
    else
    {
        // NSLog(@"spikeZCount Reset");
        spikeZCount = 0;
    }
}


回答4:

iPhone 3GS has Accelerometer but not Gyroscope. However, there is support for Gyroscope according to http://techcrunch.com/2010/06/18/iphone-4-gyroscope-perspectiverse/.



回答5:

It depends on different circumstances:

  1. Whether the phone is falling free in the air (or was thrown) i.e. you don't hold it in your hand anymore.
  2. If falling free my guess is it depends on the incident angle at the moment the phone is striking the obstacle. If the phone is falling exactly on one of its faces, the gyro won't report a rotation. But this will be hard to determine.
  3. The elasticity of the material you are bumping in.

I agree with Ali's answer regarding acceleration but not when throwing. But anyway bear in mind that an app that puts the users up to throw their iPhone won't have good chances to get app store approval ,-)