Как регистрировать данные с датчиков движения Android с фиксированной скоростью

Я изучаю основы программирования для Android.

У меня есть простое тестовое приложение для Android, в котором я регистрирую акселерометр, магнитометр и данные ориентации во внешнем файле, а также отображаю его. Я инициирую процесс регистрации нажатием кнопки Пуск (registerListener для соответствующих датчиков), вызывая метод initLogger.

Что-то похожее на это...

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

Также есть кнопка «Стоп», которая должна остановить процесс регистрации (и, наконец, отменить регистрацию, вызвав unregisterListener для каждого датчика).

Процесс извлечения данных происходит внутри обработчика onSensorChanged, который извлекает данные с соответствующих датчиков, устанавливает значение для соответствующих элементов пользовательского интерфейса и, наконец, записывает данные во внешний файл .csv.

Обработчик события 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 ....

Хотя я получаю данные от всех настроенных датчиков, я не могу контролировать скорость получения данных. то есть

Я знаю, что событие SensorChanged запускается при изменении данных датчика. Однако я хочу, чтобы это событие запускалось с фиксированной скоростью. Например: каждые 40 мс

Вопрос:

  1. Как обеспечить, чтобы событие SensorChanged запускалось с постоянной скоростью?
  2. Поможет ли в этом случае класс TimerTask на Java?

Эксперты здесь, в SO. Пожалуйста, помогите мне :)


person this-Me    schedule 03.09.2012    source источник
comment
так как вы хотите регистрировать данные через указанные вами интервалы, зачем запускать событие SensorChanged? почему бы не использовать какой-нибудь таймер и не запрашивать фактические значения по истечении указанного времени? или я что-то не так здесь?   -  person nurgan    schedule 03.09.2012
comment
@nurgan: событие SensorChanged запускается при изменении данных датчика. Я не имею никакого контроля над этим событием. Что касается вашего предложения прочитать/запросить фактические значения в указанное время.... это именно то, о чем я прошу. Как явно запросить данные датчика??   -  person this-Me    schedule 03.09.2012
comment
ну, согласно nininho, это кажется невозможным в Android. Но поскольку вы знаете, что если не было запущено событие SensorChanged, то изменений не было, вы можете просто использовать свое старое значение. Поскольку вы запросили данные LOG через определенные промежутки времени, я бы не стал делать никаких выводов в методе onSensorChanged, просто клонировал новые данные в вашу переменную данных акселерометра. И затем регистрируйте значение данных акселерометра каждые 40 мс. Таким образом, вы регистрируете фактическое значение каждые 40 мс, даже если данные не изменились....   -  person nurgan    schedule 03.09.2012
comment
@nurgan: На самом деле это то, что я сделал вчера. Похоже, мы оба находимся в одном ряду :) Можете ли вы опубликовать это как ответ, чтобы я мог его принять.   -  person this-Me    schedule 05.09.2012


Ответы (5)


Поскольку вы знаете, что если не было запущено событие SensorChanged, не было никаких изменений, вы можете просто использовать свое старое значение. Поскольку вы запрашивали данные LOG через определенные промежутки времени, я бы не стал делать никаких выводов в методе onSensorChanged, просто клонировал новые данные в вашу переменную данных акселерометра. И затем регистрируйте значение данных акселерометра каждые 40 мс. Таким образом, вы регистрируете фактическое значение каждые 40 мс, даже если данные не изменились....

Примечание. Согласно Ridcullys Answer, также представляется возможным получать данные датчика, «доставляемые» через определенные промежутки времени. Но так как на этих "Доставках" как всегда с сенсорными данными на Андроиде есть задержка, то с моим решением вы будете точнее на интервале 40мс. С другой стороны, может случиться так, что если данные датчика изменятся в момент регистрации, может случиться так, что вы задержите новые данные на один интервал. И я предполагаю (не уверен на этот счет) - поскольку речь идет только о ведении журнала, а не о чем-то вроде "получить как можно быстрее в реальном времени", так что это не требование - Timer-Solution вызывает меньшую загрузку ЦП.

person nurgan    schedule 05.09.2012
comment
Да, требование состоит не в том, чтобы данные датчиков были в режиме реального времени, а в том, чтобы данные были доступны (для запроса) с одинаковой скоростью. - person this-Me; 05.09.2012
comment
Я попробовал это решение, но оно не сработало для меня: \ Были созданы новые потоки, которые регистрируют неправильные данные через неправильные интервалы. Может ли кто-нибудь опубликовать фрагмент кода для этого решения? Спасибо в обе стороны :) - person Elshaer; 13.04.2013

Вы можете изменить интервал, изменив задержку при регистрации датчика.

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

Согласно этому, самая быстрая задержка — это то, что вам нужно, и если она не меняется достаточно быстро для вас, потому что не было никаких изменений. Метода getSensorData нет.

Вы можете указать другие задержки данных, такие как SENSOR_DELAY_GAME (задержка 20 000 микросекунд), SENSOR_DELAY_UI (задержка 60 000 микросекунд) или SENSOR_DELAY_FASTEST (задержка 0 микросекунд). Начиная с Android 3.0 (уровень API 11) вы также можете указать задержку как абсолютное значение (в микросекундах).

Указанная вами задержка является лишь предполагаемой задержкой. Система Android и другие приложения могут изменить эту задержку. Лучше всего указать максимально возможную задержку, поскольку система обычно использует меньшую задержку, чем указанная вами (то есть вам следует выбрать самую медленную частоту дискретизации, которая по-прежнему соответствует потребностям вашего приложения). Использование большей задержки снижает нагрузку на процессор и, следовательно, потребляет меньше энергии.

person Marcio Covre    schedule 03.09.2012
comment
Я ищу явный способ запросить данные датчика, а не конфигурацию скорости, с которой данные датчика передаются пользователю. - person this-Me; 03.09.2012

При регистрации прослушивателя в SensorManager с помощью registerListener вместо фиксированных констант SENSOR_DELAY_... можно передавать интервал в микросекундах, как описано в JavaDocs:

rate События датчика скорости доставляются при. Это только намек на систему. События могут быть получены быстрее или медленнее указанной скорости. Обычно события принимаются быстрее. Значение должно быть одним из SENSOR_DELAY_NORMAL, SENSOR_DELAY_UI, SENSOR_DELAY_GAME или SENSOR_DELAY_FASTEST или желаемой задержкой между событиями в микросекундах.

Итак, просто передайте 40000, чтобы соответствовать вашему примерному запросу, а также, как уже говорилось, это всего лишь подсказка, поэтому я бы не стал полагаться на получение значений в интервалах с точностью до микросекунд.

person Ridcully    schedule 03.09.2012

Я пытался выяснить, как у меня могут быть очень большие задержки с датчиками, и пока мне это удалось. В документации на 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 Sensors(20933): onSensorChanged вызывается, событие: android.hardware.SensorEvent@42849f70 01-14 06:58:07.268: D/IOE Sensors(20933): onSensorChanged вызывается , событие: android.hardware.SensorEvent@42849f70 01-14 06:58:07.448: D/IOE Sensors(20933): onSensorChanged вызвано, событие: android.hardware.SensorEvent@42849f70 01-14 06:58: 07.628: D/IOE Sensors(20933): onSensorChanged, событие: android.hardware.SensorEvent@42849f70 01-14 06:58:07.808: D/IOE Sensors(20933): onSensorChanged, событие: android. hardware.SensorEvent@42849f70 01-14 06:58:07.989: D/IOE Sensors(20933): onSensorChanged вызывается, событие: android.hardware.SensorEvent@42849f70 01-14 06:58:08.169: D/IOE Sensors( 20933): вызов onSensorChanged, событие: android.hardware.SensorEvent@42849f70

person Ashu Joshi    schedule 14.01.2014

Кажется, что скорость, с которой вызывается 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 будет вызываться много раз с ложным результатом.

person Pieter Heemeryck    schedule 20.07.2015