如何以固定速率记录Android Motion Sensors的数据

时间:2012-09-03 11:28:07

标签: java android android-sensors sensor-fusion

我正在学习Android编程的基础知识。

我有一个简单的Android测试应用程序,其中我将加速度计,磁力计和方向数据记录到外部文件,同时还显示它。我通过调用方法 initLogger ,单击开始按钮(相关传感器的registerListener)启动日志记录过程。

看起来与此类似......

public void initLogger(View view)
{
    boolean bFlag = false;

    Button btnStart = (Button)findViewById(R.id.btnStartLog);
    Button btnStop = (Button)findViewById(R.id.btnStopLog);

    btnStart.setEnabled(bFlag);
    btnStop.setEnabled(!bFlag);

    bEnableLogging = true;
    //Start reading the sensor values
    sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_UI);
    sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);

   //so on.... 

还有一个Stop按钮,它将停止记录过程(最后通过为每个传感器调用unregisterListener来取消注册)

数据检索过程发生在 onSensorChanged 处理程序中,该处理程序将从相关传感器检索数据,将值设置为相应的UI元素,最后将数据记录到外部.csv文件。

onSensorChanged eventhandler看起来像这样......

public void onSensorChanged(SensorEvent event) {


    // TODO Auto-generated method stub
    // accelerometer
    TextView tAX = (TextView) findViewById(R.id.txtViewAxValue);
    TextView tAY = (TextView) findViewById(R.id.txtViewAyValue);
    TextView tAZ = (TextView) findViewById(R.id.txtViewAzValue);

    // magnetic field
    TextView tMX = (TextView) findViewById(R.id.txtViewMx);
    TextView tMY = (TextView) findViewById(R.id.txtViewMy);
    TextView tMZ = (TextView) findViewById(R.id.txtViewMz);

    if (bEnableLogging) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

            accelerometerdata = event.values.clone();

            tAX.setText(Double.toString(accelerometerdata[0]));
            tAY.setText(Double.toString(accelerometerdata[1]));
            tAZ.setText(Double.toString(accelerometerdata[2]));


        }

        if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {

            magneticmatrixdata = event.values.clone();

            tMX.setText(Double.toString(magneticmatrixdata[0]));
            tMY.setText(Double.toString(magneticmatrixdata[1]));
            tMZ.setText(Double.toString(magneticmatrixdata[2]));

        }

               // so on ....

虽然我从所有配置的传感器接收数据,但我无法控制接收数据的速率。即

我知道当传感器数据发生变化时会触发SensorChanged事件。但是我希望以固定费率解雇此事件。 例如:每40毫秒

问题:

  1. 如何确保以恒定速率触发SensorChanged事件?
  2. 在这种情况下,Java中的类TimerTask是否有任何帮助?
  3. 专家在这里SO.Please帮助我:)

5 个答案:

答案 0 :(得分:3)

您可以通过更改注册传感器时的延迟来更改间隔。

int SENSOR_DELAY_FASTEST    get sensor data as fast as possible 
int SENSOR_DELAY_GAME       rate suitable for games 
int SENSOR_DELAY_NORMAL     rate (default) suitable for screen orientation changes
int SENSOR_DELAY_UI         rate suitable for the user interface

根据this,最快的延迟是你需要的,如果它没有足够快地改变,那是因为没有变化。没有getSensorData方法。

  

您可以指定其他数据延迟,例如SENSOR_DELAY_GAME(20,000   微秒延迟),SENSOR_DELAY_UI(60,000微秒延迟),或   SENSOR_DELAY_FASTEST(0微秒延迟)。从Android 3.0开始(API   等级11)你也可以将延迟指定为绝对值(in   微秒)。

     

您指定的延迟只是建议的延迟。 Android   系统和其他应用程序可以改变这种延迟。作为最好的   练习时,你应该指定最大的延迟,因为   系统通常使用比您指定的延迟更小的延迟   (也就是说,您应该选择仍然满足的最慢采样率   您的应用程序的需求)。使用较大的延迟会降低   加载到处理器上,因此耗电量更少。

答案 1 :(得分:2)

由于您知道如果没有触发SensorChanged事件,则没有任何更改,您可以使用旧值。 当您在特定时间间隔内询问LOG数据时,我不会在onSensorChanged方法中执行任何输出,只需将新数据克隆到accelerometerdata变量即可。 而且每40ms记录一次accelerometerdata的值。这样,即使数据没有改变,您也会每40ms记录一次实际值....

注意:根据Ridcullys的回答,似乎也可以在特定的时间间隔内“传递”传感器数据。但是由于这些“交付”的延迟与Android上的传感器数据一样,使用我的解决方案,您将更精确地在40毫秒间隔。另一方面,如果传感器数据在您记录的那一刻发生变化,则可能会发生延迟新数据一个时间间隔的情况。 我猜(不确定这一点) - 因为它只是关于记录而不是像“尽可能快地实时获取”,所以这不是一个要求 - 定时器解决方案导致更少的CPU负载。 / p>

答案 2 :(得分:1)

使用registerListener使用SensorManager注册您的监听器,而不是固定常量SENSOR_DELAY_...,您可以传递微秒的间隔,如JavaDocs中所述:

  

rate速率传感器事件的传递时间为。这只是一个暗示   系统。可以比指定的更快或更慢地接收事件   率。通常会更快地收到事件。该值必须是其中之一   SENSOR_DELAY_NORMAL,SENSOR_DELAY_UI,SENSOR_DELAY_GAME,或   SENSOR_DELAY_FASTEST或,事件之间所需的延迟   微秒。

所以,只需传递 40000 来匹配您的示例请求,同样,如上所述,这只是一个提示,所以我不会依赖于精确到微秒的间隔获取值。

答案 3 :(得分:0)

我一直试图弄清楚如何使用传感器进行很长时间的延迟,到目前为止我已经成功了。关于developer.android的文档说明延迟时间可以用微秒来指定,下面是我试过的大量数据:

// Initialize in onCreate
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE)
mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);

// Register the listener, and play around with delay
mSensorManager.registerListener(this, mLight, 200000000);

但请注意下面的LogCat转储 - onSensorChanged() - 每秒被调用多达4次......我试图找出更大的延迟但到目前为止没有成功!!!

01-14 06:58:07.088:D / IOE传感器(20933):onSensorChanged被调用,事件是:android.hardware.SensorEvent@42849f70 01-14:58:07.268:D / IOE Sensors(20933):onSensorChanged调用,事件为:android.hardware.SensorEvent@42849f70 01-14:58:07.448:D / IOE传感器(20933):onSensorChanged调用,事件为:android.hardware.SensorEvent@42849f70 01-14:58:07.628:D / IOE Sensors(20933):onSensorChanged调用,事件为:android.hardware.SensorEvent@42849f70 01-14:58:07.808:D / IOE传感器(20933):onSensorChanged调用,事件为:android.hardware.SensorEvent@42849f70 01-14:58:07.989:D / IOE传感器(20933):onSensorChanged调用,事件为:android.hardware.SensorEvent@42849f70 01-14 06:58:08.169:D / IOE Sensors(20933):onSensorChanged调用,事件为:android.hardware.SensorEvent@42849f70

答案 4 :(得分:0)

似乎调用onSensorChanged的速率必须是4个建议值之一。

你可以做些什么来慢慢阅读'是使用SENSOR_DELAY_UI和(在onSensorChanged中)测量自上次读取感应数据以来经过的时间:

long lastUpdate = System.currentTimeMillis();

// In onSensorChanged:
long curTime = System.currentTimeMillis();

        if ((curTime - lastUpdate) > 500){ // only reads data twice per second
            lastUpdate = curTime;
            // do stuff
        }

我在这里看到的唯一缺点是if语句将被多次调用并带有错误结果。