Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a stable way to detect shaking event?

I've tried to detect shaking event using accelerometer. I've found that when I give a contiuous shake to the phone, the value difference of the acceleration is quite stable. But when I rotate the phone, there's always a big change on the value( the value is usually bigger than "shaking without rotation"). I want to focus on the shaking event, not the rotation event. Is there a way to solve the problem?

here's my code for shaing detection

public void onSensorChanged(SensorEvent event)
    {
        if (event.sensor.getType() == SensorManager.SENSOR_ACCELEROMETER)
        {
            nowTime = System.currentTimeMillis();

            float x = event.values[SensorManager.DATA_X];
            float y = event.values[SensorManager.DATA_Y];
            float z = event.values[SensorManager.DATA_Z];
            nowAcc = Math.sqrt(x*x+y*y+z*z);
            accDiff = Math.abs(nowAcc - preAcc);
            timeDiff = (nowTime - preTime);
                        //  try to get the sum of 10 samplings of accDiff
            tempAccDiff10 = tempAccDiff9;
            tempAccDiff9 = tempAccDiff8;
            tempAccDiff8 = tempAccDiff7;
            tempAccDiff7 = tempAccDiff6;
            tempAccDiff6 = tempAccDiff5;
            tempAccDiff5 = tempAccDiff4;
            tempAccDiff4 = tempAccDiff3;
            tempAccDiff3 = tempAccDiff2;
            tempAccDiff2 = tempAccDiff1;
            tempAccDiff1 = accDiff;
            sumAcc = tempAccDiff10+tempAccDiff9+tempAccDiff8+tempAccDiff7+tempAccDiff6+
                     tempAccDiff5+tempAccDiff4+tempAccDiff3+tempAccDiff2+tempAccDiff1;
            Log.i("SSSS",String.valueOf(sumAcc));
                        //when I give the phone a big & continuous "shake", it returns
                        //a value about 30~40, but when I give the phone a small
                        //"rotation", it returns a value of 80~120
            preAcc = nowAcc;
            preTime = nowTime;
            if (sumAcc>100)
            {
                SM.unregisterListener(sensorListener, sensor);
            }

            //123
        }


    }//end of onSensorChanged();

is it possible to neglect the rotation event using accelerometer? Or should I try to get the orientation change and do some computations on the sumAcc?

like image 245
Jim31837 Avatar asked Oct 10 '22 19:10

Jim31837


2 Answers

You should use a filter to eliminate the influence of the gravity, there is some sort of tutorial on the docs to do so. I did something similar, in my case I was also trying to detect other movements, so your task seems a bit simpler. I can post the code next monday (If I remember).

Good luck!


I'm editing the answer to add you can use a Sensor TYPE_LINEAR_ACCELERATION if you're on Android 2.3 or higher. That is a normal acceleration sensor which discards the effect of gravity, which you definetely don't need to detect a shake event.

regards


Edit 13/06 -> I promised to post my code to detect shaking, but instead, I think it is a better idea to post this link, which gives sample pieces of code in a variety of responses. My code is very similar to one of those posted there.

Good luck!

like image 167
mdelolmo Avatar answered Oct 14 '22 04:10

mdelolmo


From the code point of view, you need to implement the SensorListener:

public class ShakeActivity extends Activity implements SensorListener

You will need to acquire a SensorManager:

sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);

And register this sensor with desired flags:

ensorMgr.registerListener(this,
SensorManager.SENSOR_ACCELEROMETER,
SensorManager.SENSOR_DELAY_GAME);

In your onSensorChange() method, you determine whether it’s a shake or not:

public void onSensorChanged(int sensor, float[] values) {
  if (sensor == SensorManager.SENSOR_ACCELEROMETER) {
    long curTime = System.currentTimeMillis();
    // only allow one update every 100ms.
    if ((curTime - lastUpdate) > 100) {
      long diffTime = (curTime - lastUpdate);
      lastUpdate = curTime;

      x = values[SensorManager.DATA_X];
      y = values[SensorManager.DATA_Y];
      z = values[SensorManager.DATA_Z];

      float speed = Math.abs(x+y+z – last_x – last_y – last_z) / diffTime * 10000;

      if (speed > SHAKE_THRESHOLD) {
        Log.d("sensor", "shake detected w/ speed: " + speed);
        Toast.makeText(this, "shake detected w/ speed: " + speed, Toast.LENGTH_SHORT).show();
      }
      last_x = x;
      last_y = y;
      last_z = z;
    }
  }
}

The shake threshold is defined as:

private static final int SHAKE_THRESHOLD = 800;

There are some other methods too, to detect shake motion. look at this link.(If that link does not work or link is dead, look at this web archive.).

Thanks.

like image 28
Harshal Doshi Jain Avatar answered Oct 14 '22 05:10

Harshal Doshi Jain