如何检测Android设备的移动?

时间:2013-01-29 02:51:50

标签: android sensor motion

我需要有关如何检测Android设备移动量的建议。假设我已将手机放在桌子或床上,然后如果有人敲击桌子或坐在或躺在床上,那么我想检测Android设备的移动。

实际上我知道android有运动传感器API,但我不知道使用哪种传感器以及哪种传感器类型最适合这种类型的运动检测。

如果有人可以分享一些基本的演示代码,我会很高兴。

6 个答案:

答案 0 :(得分:50)

绝对适用于加速度计:

// Start with some variables
private SensorManager sensorMan;
private Sensor accelerometer;

private float[] mGravity;
private float mAccel;
private float mAccelCurrent;
private float mAccelLast;

// In onCreate method
sensorMan = (SensorManager)getSystemService(SENSOR_SERVICE);
accelerometer = sensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mAccel = 0.00f;
mAccelCurrent = SensorManager.GRAVITY_EARTH;
mAccelLast = SensorManager.GRAVITY_EARTH;

// And these:

@Override
public void onResume() {
    super.onResume();
    sensorMan.registerListener(this, accelerometer,
        SensorManager.SENSOR_DELAY_UI);
}

@Override
protected void onPause() {
    super.onPause();
    sensorMan.unregisterListener(this);
}

@Override
public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
        mGravity = event.values.clone();
        // Shake detection
        float x = mGravity[0];
        float y = mGravity[1];
        float z = mGravity[2];
        mAccelLast = mAccelCurrent;
        mAccelCurrent = FloatMath.sqrt(x*x + y*y + z*z);
        float delta = mAccelCurrent - mAccelLast;
        mAccel = mAccel * 0.9f + delta;
            // Make this higher or lower according to how much
            // motion you want to detect
        if(mAccel > 3){ 
        // do something
        }
    }

}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
    // required method
}

答案 1 :(得分:17)

我使用了以下课程:

public class MovementDetector implements SensorEventListener {

protected final String TAG = getClass().getSimpleName();

private SensorManager sensorMan;
private Sensor accelerometer;

private MovementDetector() {
}

private static MovementDetector mInstance;

public static MovementDetector getInstance() {
    if (mInstance == null) {
        mInstance = new MovementDetector();
        mInstance.init();
    }
    return mInstance;
}

//////////////////////
private HashSet<Listener> mListeners = new HashSet<MovementDetector.Listener>();

private void init() {
    sensorMan = (SensorManager) GlobalData.getInstance().getContext().getSystemService(Context.SENSOR_SERVICE);
    accelerometer = sensorMan.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
}

public void start() {
    sensorMan.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}

public void stop() {
    sensorMan.unregisterListener(this);
}

public void addListener(Listener listener) {
    mListeners.add(listener);
}

/* (non-Javadoc)
 * @see android.hardware.SensorEventListener#onSensorChanged(android.hardware.SensorEvent)
 */
@Override
public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {

        float x = event.values[0];
        float y = event.values[1];
        float z = event.values[2];

        float diff = (float) Math.sqrt(x * x + y * y + z * z);
        if (diff > 0.5) // 0.5 is a threshold, you can test it and change it
            Log.d(TAG,"Device motion detected!!!!");
        for (Listener listener : mListeners) {
            listener.onMotionDetected(event, diff);
        }
    }

}

/* (non-Javadoc)
 * @see android.hardware.SensorEventListener#onAccuracyChanged(android.hardware.Sensor, int)
 */
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
    // TODO Auto-generated method stub

}

public interface Listener {
    void onMotionDetected(SensorEvent event, float acceleration);
    }
}

用法:

在我的活动onCrate()上:

        MovementDetector.getInstance().addListener(new MovementDetector.Listener() {

        @Override
        public void onMotionDetected(SensorEvent event, float acceleration) {

            mMotionDetectionTextView.setText("Acceleration: ["+String.format("%.3f",event.values[0])+","+String.format("%.3f",event.values[1])+","+String.format("%.3f",event.values[2])+"] "+String.format("%.3f", acceleration));
            if (acceleration > SettingsHelper.getInstance().getMotionDetectionThreshold()){
                mMotionDetectionTextView.setTextColor(Color.RED);
            } else {
                mMotionDetectionTextView.setTextColor(Color.WHITE);
            }

        }
    });

在我的活动onResume()上:

MovementDetector.getInstance().start();

在我的活动onPause()上:

MovementDetector.getInstance().stop();

答案 2 :(得分:3)

此代码用于步行检测(从@anthropomo代码修改)

获得更顺畅的价值。

//初始化

private SensorManager sensorMan;
private Sensor accelerometer;

private float[] mGravity;
private double mAccel;
private double mAccelCurrent;
private double mAccelLast;

private boolean sensorRegistered = false;

// onCreate

    sensorMan = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
    accelerometer = sensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    mAccel = 0.00f;
    mAccelCurrent = SensorManager.GRAVITY_EARTH;
    mAccelLast = SensorManager.GRAVITY_EARTH;

    sensorMan.registerListener(this, accelerometer,
            SensorManager.SENSOR_DELAY_NORMAL);
    sensorRegistered = true;

// onSensorChanged

private int hitCount = 0;
private double hitSum = 0;
private double hitResult = 0;

private final int SAMPLE_SIZE = 50; // change this sample size as you want, higher is more precise but slow measure.
private final double THRESHOLD = 0.2; // change this threshold as you want, higher is more spike movement

@Override
public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        mGravity = event.values.clone();
        // Shake detection
        double x = mGravity[0];
        double y = mGravity[1];
        double z = mGravity[2];
        mAccelLast = mAccelCurrent;
        mAccelCurrent = Math.sqrt(x * x + y * y + z * z);
        double delta = mAccelCurrent - mAccelLast;
        mAccel = mAccel * 0.9f + delta;

        if (hitCount <= SAMPLE_SIZE) {
            hitCount++;
            hitSum += Math.abs(mAccel);
        } else {
            hitResult = hitSum / SAMPLE_SIZE;

            Log.d(TAG, String.valueOf(hitResult));

            if (hitResult > THRESHOLD) {
                Log.d(TAG, "Walking");
            } else {
                Log.d(TAG, "Stop Walking");
            }

            hitCount = 0;
            hitSum = 0;
            hitResult = 0;
        }
    }
}

答案 3 :(得分:0)

虽然我没有演示代码(因为你不够具体),但这里有一个好的开头:http://developer.android.com/guide/topics/sensors/sensors_motion.html(以及左边的其他项目)。

答案 4 :(得分:0)

如果您要查找手机的位移,则需要找到 作用在手机上的线性加速度而不是重力加速度

android有一个内置的转换器,可以在手机上找到LINEAR ACCELERATION

https://github.com/yuvaramsingh94/AndroidSensorTestCode/tree/master

这是一个代码,您可以在其中查看如何获取LINEAR ACCELERATION的原始值

答案 5 :(得分:0)

我一直在用类似的想法来测量手机的位移。我发现 LINEAR ACCELERATION (和 ACCELERATION )不够准确,无法正确测量位移。

此代码应该会更好一些:

(初始化)

private SensorManager sensorManager;
private Sensor accelerometer;
double[] maxAccelerations = new double[3];
double[] position = new double[3];
long[] times = new long[3];
// time combined with maxAcceleration can approximate the change in position,
// with the formula Δpos = (maxAcceleration * time ^ 2) / 6
long currentTime;

(onCreate)

sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION) != null) {
    accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
        sensorManager.registerListener(this, accelerometer, sensorManager.SENSOR_DELAY_FASTEST);
}
currentTime = System.currentTimeMillis();
for(int i=0;i<3;i++){
    times[i]=currentTime;
}
else{
    throw "Error";
    //Which will throw an error, if not the error that is expected. 
}

(onSensorChanged和onAccuracyChanged)

@Override
public void onAccuracyChanged(Sensor ignore, int thisFunction) {
}

@Override
public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
        for(int i=0;i<3;i++){
            if(Math.abs(event.values[i])<0.01){
                // Note: this is to try to prevent accelerating time from being counted when the phone is stationary. 0.01 should be
                // changed to an appropriate sensitivity level that can be calculated by finding an average noise level when the phone is stationary.
                times[i]=System.currentTimeMillis();
            }
            if(event.values[i]>maxAccelerations[i] && maxAccelerations[i]>=0){
                maxAccelerations[i]=event.values[i];
            }
            else if(event.values[i]<maxAccelerations[i] && maxAccelerations[i]<=0){
                maxAccelerations[i]=event.values[i];
            }
            else if(event.values[i]>0 && maxAccelerations[i]<0){
                currentTime = System.currentTimeMillis();
                position[i]+=maxAccelerations[i] * (times[i]-currentTime)*(times[i]-currentTime) / 6;
                times[i]=currentTime;
                maxAccelerations[i]=event.values[i];
            }
            else if(event.values[i]<0 && maxAccelerations[i]>0){
                currentTime = System.currentTimeMillis();
                position[i]+=maxAccelerations[i] * (times[i]-currentTime)*(times[i]-currentTime) / 6;
                times[i]=currentTime;
                maxAccelerations[i]=event.values[i];
            }
        }
    }
}