Android:使用加速计检测轻弹

时间:2013-09-03 20:27:35

标签: android accelerometer

我正在尝试开发一个应用程序,用户可以使用手机的动作击中隐形鼓。因此,当手机向下轻弹时,在轻弹结束时会响起鼓声。

通过检测大型快速移动突然停止的时间,我已经成功完成了90%的工作。但是虽然在轻弹(好)之后鼓声响起,但是在拉动结束时也会发出声音(不理想)。

通过轻弹我的意思是手机正在向前和向下轻弹,好像你用它敲击鼓,而拉我的意思是你将手臂放回到起始位置。

有没有人知道确定何时发生轻弹而不是推动的有效方法?

任何想法都将被感激不尽。

由于

现有代码:

package com.example.testaccelerometer;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity implements SensorEventListener{

    public static TextView results;

    public static TextView clickresults;

    StringBuilder builder = new StringBuilder();

      private float mAccelNoGrav;
      private float mAccelWithGrav;
      private float mLastAccelWithGrav;

    public static boolean shakeIsHappening;
    public static int beatnumber = 0;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        results = (TextView) findViewById(R.id.results);
        clickresults = (TextView) findViewById(R.id.clickresults);

        SensorManager manager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        Sensor accelerometer = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

        if(!manager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_FASTEST)){
            builder.append("Problem with Accelerometer - Shaking will not work");
        };


        mAccelNoGrav = 0.00f;
        mAccelWithGrav = SensorManager.GRAVITY_EARTH;
        mLastAccelWithGrav = SensorManager.GRAVITY_EARTH;



    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        builder.setLength(0);
        builder.append("X " + event.values[0] + "\nY " + event.values[1] + "\nZ " + event.values[2]);
    results.setText(builder.toString());


        float x = event.values[0];
          float y = event.values[1];
          float z = event.values[2];
          mLastAccelWithGrav = mAccelWithGrav;
          mAccelWithGrav = android.util.FloatMath.sqrt(x*x + y*y + z*z);
          float delta = mAccelWithGrav - mLastAccelWithGrav;
          mAccelNoGrav = mAccelNoGrav * 0.9f + delta;

    if (mAccelNoGrav >8.5) {
        shakeIsHappening = true;
        //clickresults.append(" click " + mAccel);
    }

    if (shakeIsHappening == true && mAccelNoGrav <2) {
        beatnumber++;
clickresults.append(" click number: " + beatnumber + "\n" + "PA: " + mLastAccelWithGrav + " CA:" + mAccelNoGrav + "\n ");
shakeIsHappening = false;
    }

    }


    @Override
    protected void onResume() {
      super.onResume();
    // YOU DO NEED TO TRY AND REREGISTER IT NOW
    }

    @Override
    protected void onPause() {
        // YOU DO NEED TO TRY AND UNREGISTER IT NOW
      super.onPause();
    }


}

2 个答案:

答案 0 :(得分:1)

您可以将地磁传感器与加速计传感器结合使用,以确定设备的哪个边缘朝向地面,然后排除任何相反方向的加速度事件

http://developer.android.com/reference/android/hardware/SensorManager.html#getOrientation(love [],float [])

答案 1 :(得分:0)

我最终想出了如何解决这个问题,只需使用z轴来确定运动是否朝向地面。

z轴数据被送入z阵列(减去重力)。当加速度超过一定水平时,我们记录最高数字,highZ和最低数字,lowZ。这些标出了高点和低点之间的手部运动范围。当加速度低于2时,我们检查Z阵列中的最新数据位是否等于高点或低点,这告诉我们这个动作是轻弹还是拉动。

这可能不是最有效的解决方法,但它现在正在工作,所以我很开心。感谢大家的帮助。

这是我完成的代码:

public class MainActivity extends Activity implements SensorEventListener {

    private float mAccelNoGrav;
    private float mAccelWithGrav;
    private float mLastAccelWithGrav;

    ArrayList<Float> z = new ArrayList<Float>();

    public static float finalZ;

    public static boolean shakeIsHappening;
    public static int beatnumber = 0;
    public static float highZ;
    public static float lowZ;
    public static boolean flick;
    public static boolean pull;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        results = (TextView) findViewById(R.id.results);
        clickresults = (TextView) findViewById(R.id.clickresults);

        SensorManager manager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        Sensor accelerometer = manager
                .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

        if (!manager.registerListener(this, accelerometer,
                SensorManager.SENSOR_DELAY_FASTEST)) {
            builder.append("Problem with Accelerometer - Shaking will not work");
        }
        ;

        mAccelNoGrav = 0.00f;
        mAccelWithGrav = SensorManager.GRAVITY_EARTH;
        mLastAccelWithGrav = SensorManager.GRAVITY_EARTH;

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onSensorChanged(SensorEvent event) {


        float x = event.values[0];
        float y = event.values[1];
        z.add((event.values[2])-SensorManager.GRAVITY_EARTH);
        mLastAccelWithGrav = mAccelWithGrav;
        mAccelWithGrav = android.util.FloatMath.sqrt(x * x + y * y + z.indexOf(z.size()-1) * z.indexOf(z.size()-1));
        float delta = mAccelWithGrav - mLastAccelWithGrav;
        mAccelNoGrav = mAccelNoGrav * 0.9f + delta; // Low-cut filter

        if (mAccelNoGrav > 8.5) {
            shakeIsHappening = true;

            z.clear();

            if  (z.indexOf(z.size()-2) > z.indexOf(z.size()-1)) {
                clickresults.append(" Z shrinking" + z);
            } else if (z.indexOf(z.size()-2) < z.indexOf(z.size()-1)) {
                clickresults.append(" Z growing" + z);
            }

        } 




        if (shakeIsHappening == true && mAccelNoGrav < 2) {

            finalZ = z.get(z.size()-1);
            highZ= z.get(z.size()-1);
            lowZ= z.get(z.size()-1);
            for (int i = 0; i < z.size(); i++) {
                if (z.get(i) > highZ) {
                    highZ = z.get(i);
                } else if ((z.get(i) < lowZ)) {
                    lowZ = z.get(i);
            }
            if (highZ==finalZ) {
                flick = true;
                pull = false;
            } else if (lowZ==finalZ) {
                flick = false;
                pull = true;

            }

            if (flick) {
            beatnumber++;
            clickresults.append(" click number: " + beatnumber + "\n" + "PA: "
                    + mLastAccelWithGrav + " CA:" + mAccelNoGrav + "\n " + "Lz " + z.indexOf(z.size()-2) +"z " + z.indexOf(z.size()-1) + "\n" + "\n");
            shakeIsHappening = false;
            }

            z.clear();

        } }

    }

    @Override
    protected void onResume() {
        super.onResume();
        // YOU DO NEED TO TRY AND REREGISTER IT NOW
    }

    @Override
    protected void onPause() {
        // YOU DO NEED TO TRY AND UNREGISTER IT NOW
        super.onPause();
    }

}