在Android中准确地使用加速度计检测运动

8
我正在实现一个带有振动的演示TIMER,并在特定条件下使用它,当我按下开始按钮后,我的计时器开始运行...当我使用停止按钮停止它时,它就会简单地停止。
现在我需要集成一种功能,在人们移动设备(计时器正在运行期间)之后,它应该重置计时器。它的工作非常良好,但加速度计功能并不是完全准确的。它需要一个快速的抽拉来重置计时器。
请为此提供一个好的解决方案。
以下是我的代码:
public class SensorAccelerometer implements SensorEventListener {

    private Context context;
    private SensorManager sensorManager;
    private Sensor accelerometer;
    private TextView timelabel;
    private Handler mHandler;
    Runnable run;

    private float mLastX, mLastY, mLastZ;
    private final float NOISE = (float) 3.0;

    public SensorAccelerometer(Context context) {

    }


    public SensorAccelerometer(Context context,TextView timelabel, Handler mHandler2, Runnable mUpdateTimeTask) {
        // TODO Auto-generated constructor stub

        this.context = context;
        this.timelabel = timelabel;
        this.mHandler = mHandler2;
        this.run = mUpdateTimeTask;

        initialiseSensor();
    }


    public void initialiseSensor(){
        sensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
        accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);
        sensorManager.registerListener(this, accelerometer,SensorManager.SENSOR_DELAY_NORMAL);
    }

    public void unregisterSensor(){
        sensorManager.unregisterListener(this);
        Toast.makeText(context, "Sensor Stopped..", Toast.LENGTH_SHORT).show();
    }


    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    public void onSensorChanged(SensorEvent event) {
    float x = event.values[0];
    float y = event.values[1];
    float z = event.values[2];

    mAccelLast=mAccelCurrent;

    mAccelCurrent = FloatMath.sqrt(x*x + y*y + z*z);
    float delta = mAccelCurrent - mAccelLast;
    mAccel = mAccel * 0.9f + delta;

    if(mAccel>0.5){
        TimerActivity.mStartTime = SystemClock.uptimeMillis();
        mHandler.removeCallbacks(run);
        mHandler.postDelayed(run, 100);
    }

计时器活动

定时器活动

public class TimerActivity extends Activity {

    public static long mStartTime = 0L;
    private TextView mTimerLabel;

    private Handler mHandler = new Handler();

    String timerStop1;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mTimerLabel = (TextView) findViewById(R.id.textTimer);

        Button timerStartButton = (Button) findViewById(R.id.btnTimer);       
        timerStartButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view){

                if(mStartTime == 0L){
                    mStartTime = SystemClock.uptimeMillis();
                    mHandler.removeCallbacks(mUpdateTimeTask);
                    mHandler.postDelayed(mUpdateTimeTask, 100);

                    //activating the sensor and the acclerometer
                    SensorAccelerometer acc = new SensorAccelerometer(view.getContext(), mTimerLabel,mHandler,mUpdateTimeTask);
                }                                   
            }
        }); 

        Button timerStopButton = (Button) findViewById(R.id.btnTimerStop);       
        timerStopButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view){

                mHandler.removeCallbacks(mUpdateTimeTask);
                mTimerLabel.setText(timerStop1);
                mStartTime = 0L;

                SensorAccelerometer scc = new SensorAccelerometer(view.getContext(),mTimerLabel,mHandler,mUpdateTimeTask);
                scc.unregisterSensor();
            }
        }); 

    } 


    private Runnable mUpdateTimeTask = new Runnable(){

        public void run() {

            final long start = mStartTime;
            long millis = SystemClock.uptimeMillis()- start;

            int seconds = (int) (millis / 1000);
            int minutes = seconds / 60;
            seconds = seconds % 60;

            mTimerLabel.setText("" + minutes + ":"
                                  + String.format("%02d", seconds));                    

            timerStop1 = minutes + ":"
                      + String.format("%02d", seconds);

            mHandler.postDelayed(this, 200);            

        }   
    }; 

    protected void onPause() {
        super.onPause();
        SensorAccelerometer scc = new SensorAccelerometer(this,mTimerLabel,mHandler,mUpdateTimeTask);
        scc.unregisterSensor();
    };

} 
3个回答

6

我认为你的应用程序发展的下一个阶段是查看电子表格中产生的加速度值。 我使用Excel进行此操作,但任何可以生成图形的工具都可以。 因此,请将onSensorChanged()更改为以下内容:

public void onSensorChanged(SensorEvent event) {
    float x = event.values[0];
    float y = event.values[1];
    float z = event.values[2];

    float mAccelCurrent = FloatMath.sqrt(x*x + y*y + z*z);
    float mAccel = mAccel * 0.9f + mAccelCurrent * 0.1f;
    Log.d("onSensorChanged",System.currentTimeMillis()+","+mAccelCurrent +","+mAccel);

}

然后,您可以将currentTime、mAccelCurrent和mAccel捕获到Android日志记录机制中。或者,创建自己的文本文件,写入这些值,并在能够生成图形的工具中打开该文件。通过这些图形,您可以决定要用于触发器的哪些值。


我的简单问题是如何检查倾斜数据(当设备被倾斜时),我想对其执行一组代码。您是否有关于上述代码的任何解决方案? - Deepak Sharma
@stochastically。我的问题与上述相同。 - Gaurav Arora
我以为你想要使用加速度计数据来检测运动。为了做到这一点,你需要理解这些数据,因此需要记录并查看它们。如果你只是想要检查设备何时倾斜,那就简单多了。例如,可以参考我的回答链接。俯仰角可能是你要找的东西。 - Stochastically

2

这里有两个建议和一个想法:

  1. 为了保持一致的行为,您应该查看event.values向量的长度,即 Math.sqrt(x*x+y*y+z*z),而不是每个值。从数学上讲,Math.sqrt(x*x+y*y+z*z)独立于您的坐标系,即设备相对于地面的方向等,而个别数字x、y、z则不独立。
  2. 您当前的应用程序寻找加速度变化。相反地,我认为您应该只寻找高加速度,即Math.sqrt(x*x+y*y+z*z)的大值。
  3. 最近我写了这个答案 ,关于使用加速度计作为计步器,我认为您可能会发现它很有趣。


你提供了一个非常好的答案,但我不知道该怎么做才能检查设备的运动。我应该在哪里更改我的代码,以便如果一个人稍微改变设备的位置,我就能得到它。 - Gaurav Arora
我的评论1和2都与您对onSensorChanged(SensorEvent event)的实现有关。您的前三行很好,其中设置了x、y和z,但是接下来您需要(1)获取len=Math.sqrt(x*x+y*y+z*z),并且(2)确定len是否比通常大得多等。 - Stochastically
3
我认为像那样编辑问题不是一个好主意,因为我的回答以及我们现在的对话对其他人来说就变得更加不合理了。此外,您的编辑是不完整的,因为像mAccel这样的变量没有在任何地方声明。如果您仍然有问题,您应该开始一个新的问题。话虽如此,看起来您正在以一种相当奇怪的方式尝试使mAccel成为mAccelCurrent的平滑值。我建议使用mAccel = mAccel * 0.9f + mAccelCurrent * 0.1f。除此之外,我认为您应该将mAccelmAccelCurrent记录到文件中,检查结果,并从中决定下一步的操作。 - Stochastically
我不太清楚你在说什么。如果你已经明白我的意思,请用代码的形式回答我,谢谢! - Gaurav Arora
@Stochastically,你能讨论一下使用加速度计计算距离的数学解决方案吗?我已经进行了计算,得出了sqrt((xx)+(yy)+(z*z)),现在我该如何计算用户行驶的距离?我只需要短时间间隔内的距离。 - Erum
显示剩余3条评论

1
要在特定方向上找到线性加速度,您也可以使用以下代码:
    @Override
public void onSensorChanged(SensorEvent event) {
// alpha is calculated as t / (t + dT)
// with t, the low-pass filter's time-constant
// and dT, the event delivery rate

final float alpha = 0.8f;

gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];

linear_acceleration[0] = event.values[0] - gravity[0];
linear_acceleration[1] = event.values[1] - gravity[1];
linear_acceleration[2] = event.values[2] - gravity[2];
}  

在计算线性加速度之后,您可以简单地使用“if”语句来检查您的急停是否强大![更高的值=更强大的急停]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接