java 如何以固定速率记录来自 Android 运动传感器的数据

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12246942/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 08:09:44  来源:igfitidea点击:

How to log data from Android Motion Sensors at a fixed rate

javaandroidandroid-sensorssensor-fusion

提问by this-Me

I'm learning the Basics of Android programming.

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

I have a simple android test application in which i log the accelerometer,magnetometer and the orientation data to an external file while also displaying it. I initiate the logging process on click of a Startbutton (registerListener for relevant sensors) by calling a method initLogger.

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

Which looks something similar to this...

看起来与此类似...

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.... 

There is also a Stop button, which shall stop the logging process (and finally unregister by calling unregisterListener for each sensor)

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

The data retrieval process happens inside the onSensorChangedhandler which shall retrieve the data from the relevant sensors, sets the value to the respective UI elements and finally log the data to an external .csv file.

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

onSensorChangedeventhandler looks something like this ...

onSensorChanged事件处理程序看起来像这样......

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 ....

Although i receive the data from all the configured sensors, i do not have the control over the rate at which the data is received. i.e

尽管我从所有配置的传感器接收数据,但我无法控制接收数据的速率。IE

I know SensorChanged event is fired as and when the Sensor data is changed. However i want this event to be fired at a fixed rate. For ex: every 40ms

我知道 SensorChanged 事件会在传感器数据更改时触发。但是,我希望以固定速率触发此事件。例如:每 40 毫秒

Question:

问题:

  1. How to ensure the SensorChanged event is fired at constant rate ?
  2. Is the class TimerTask in Java of any help in this case ?
  1. 如何确保 SensorChanged 事件以恒定速率触发?
  2. 在这种情况下,Java 中的 TimerTask 类有帮助吗?

Experts out here in SO.Please help me :)

SO的专家请帮助我:)

采纳答案by nurgan

Since you know that if there was no SensorChanged Event fired, there was no change, you can just use your old value. As you asked for LOG data in specific intervals, i would not do any output in the onSensorChanged Method just clone the new data to your accelerometerdata variable. And than log the value of accelerometerdata every 40ms. This way you are logging the actual value every 40ms even if the data didnt change....

由于您知道如果没有触发 SensorChanged 事件,则没有变化,您可以使用旧值。当您要求在特定时间间隔的 LOG 数据时,我不会在 onSensorChanged 方法中做任何输出,只是将新数据克隆到您的加速度计数据变量。然后每 40 毫秒记录一次加速度计数据的值。这样即使数据没有改变,你也会每 40 毫秒记录一次实际值......

Note: According to Ridcullys Answer it also seem to be possible to get Sensor data "delivered" in specific time intervals. But since there is an delay on these "Deliveries" as always with sensor-data on Android, with my solution you will be more exactly on the 40ms interval. On the other hand it could happen that if the sensor data changes in the moment you log, it might happen that you delay the new data for one interval. And i guess (not sure about this point) - since its just about logging and not about sth like "get it as fast as possible in realtime", so this is not an requirement - the Timer-Solution causes less CPU-Load.

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

回答by Marcio Covre

You can change the interval by changing the delay when registering for the sensor.

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

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

According to this, the Fastest delay is what you would need and if it doesn't changes fast enough for you is because there were no changes. There is no getSensorData method.

根据这个,最快的延迟,你需要什么,如果不改变速度不够快,你是因为没有改变。没有 getSensorData 方法。

You can specify other data delays, such as SENSOR_DELAY_GAME (20,000 microsecond delay), SENSOR_DELAY_UI (60,000 microsecond delay), or SENSOR_DELAY_FASTEST (0 microsecond delay). As of Android 3.0 (API Level 11) you can also specify the delay as an absolute value (in microseconds).

The delay that you specify is only a suggested delay. The Android system and other applications can alter this delay. As a best practice, you should specify the largest delay that you can because the system typically uses a smaller delay than the one you specify (that is, you should choose the slowest sampling rate that still meets the needs of your application). Using a larger delay imposes a lower load on the processor and therefore uses less power.

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

您指定的延迟只是建议的延迟。Android 系统和其他应用程序可以更改此延迟。作为最佳实践,您应该指定最大延迟,因为系统通常使用比您指定的延迟更小的延迟(即,您应该选择仍然满足应用程序需求的最慢采样率)。使用更大的延迟会给处理器带来更低的负载,因此使用更少的功率。

回答by Ridcully

When registering your Listener with the SensorManagerusing registerListener, instead of the fixed constants SENSOR_DELAY_...you can pass the interval in microsecondsas described in the JavaDocs:

SensorManager使用 using registerListener注册您的 Listener 时,SENSOR_DELAY_...您可以按照 JavaDocs 中的描述传递以微秒单位的间隔,而不是固定常量:

rate The rate sensor events are delivered at. This is only a hint to the system. Events may be received faster or slower than the specified rate. Usually events are received faster. The value must be one of SENSOR_DELAY_NORMAL, SENSOR_DELAY_UI, SENSOR_DELAY_GAME, or SENSOR_DELAY_FASTEST or, the desired delay between events in microsecond.

rate 传送传感器事件的速率。这只是对系统的提示。事件的接收速度可能比指定的速率更快或更慢。通常事件接收得更快。该值必须是 SENSOR_DELAY_NORMAL、SENSOR_DELAY_UI、SENSOR_DELAY_GAME 或 SENSOR_DELAY_FASTEST 之一,或者事件之间所需的延迟(以微秒为单位)。

So, just pass 40000to match your example request, also, as stated, this in only a hint so I would not rely on getting the values in intervals exact to the microseconds.

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

回答by Ashu Joshi

I have been trying to figure out how can I have very long delays with sensors, and so far I have been successful. The documentation on the developer.android talks that the delay time can be specified in microseconds, below is a large number I tried:

我一直在试图弄清楚如何使用传感器有很长的延迟,到目前为止我已经成功了。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);

However note the LogCat dump below - the onSensorChanged() - gets called as many as 4 times a second... I am trying to figure out getting larger delays with no success so far!!!

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

01-14 06:58:07.088: D/IOE Sensors(20933): onSensorChanged called, the event is: android.hardware.SensorEvent@42849f70 01-14 06:58:07.268: D/IOE Sensors(20933): onSensorChanged called, the event is: android.hardware.SensorEvent@42849f70 01-14 06:58:07.448: D/IOE Sensors(20933): onSensorChanged called, the event is: android.hardware.SensorEvent@42849f70 01-14 06:58:07.628: D/IOE Sensors(20933): onSensorChanged called, the event is: android.hardware.SensorEvent@42849f70 01-14 06:58:07.808: D/IOE Sensors(20933): onSensorChanged called, the event is: android.hardware.SensorEvent@42849f70 01-14 06:58:07.989: D/IOE Sensors(20933): onSensorChanged called, the event is: android.hardware.SensorEvent@42849f70 01-14 06:58:08.169: D/IOE Sensors(20933): onSensorChanged called, the event is: android.hardware.SensorEvent@42849f70

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

回答by pursang

It seems that the rate at which onSensorChanged is called has to be one of the 4 suggested values.

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

What you can do for 'slow reads' is use SENSOR_DELAY_UI and (in onSensorChanged) measure the time that has passed since the last time you read the sensordata:

您可以为“慢速读取”做的是使用 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
        }

The only disadvantage I see here is that the if statement will be called many times with a false outcome.

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