Как собрать данные сразу с нескольких мобильных датчиков на Java?

Я хочу собрать данные с акселерометра, гироскопа и магнитометра сразу. В настоящее время я использую службу SensorManager, основанную на SensorEvent. Проблема в том, что я могу получить данные только от 1 датчика в данный момент времени. Таким образом, во время t1 я получаю данные от ускорителя, в t2 я получаю данные от гироскопа, а в t3 я получаю данные от магнитометра.

Мой код выглядит следующим образом:

public void onSensorChanged(SensorEvent event) {
    if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
        sText.setText("S: " + event.sensor.getStringType());
    }
    else if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE){
        sText.setText("S: " + event.sensor.getStringType());
    } 
    else if(event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD){
        sText.setText("S: " + event.sensor.getStringType());
    }
}

Вместо того, чтобы работать с тремя датчиками в 3 разных промежутка времени, я хочу иметь возможность собирать данные со всех датчиков за один временной интервал. Это возможно?


person Dimitar Veljanovski    schedule 24.01.2020    source источник
comment
Как вы ожидаете, что это сработает, если все они используют одно и то же текстовое поле? 1 текстовое поле не может отображать 3 элемента одновременно   -  person Michael    schedule 24.01.2020
comment
Я не хочу просто печатать разные типы датчиков. Я хочу использовать собранные данные (в определенное время) для расчета позиционного и вращательного смещения от предыдущего состояния устройства. Проблема в том, что с SensorEvent я не могу получить доступ к каждому из датчиков в один и тот же интервал времени, поэтому мои расчеты неверны, так как собранные данные имеют разницу во времени.   -  person Dimitar Veljanovski    schedule 24.01.2020
comment
Вы, кажется, сделали предположение, что они не могут происходить одновременно, основываясь на отсутствии каких-либо доказательств. Вы зарегистрировали обратный звонок. Нельзя сказать, что один и тот же обратный вызов не может быть вызван из нескольких потоков и выполняться одновременно. Вы бы этого не заметили с вашей текущей реализацией, потому что все потоки конкурируют за установку одного и того же фрагмента текста. Шаг 1) прекратите это делать   -  person Michael    schedule 24.01.2020
comment
Ну, я разработчик C++, и я перешел на Java только потому, что это был самый простой способ доступа к данным датчиков мобильных устройств. Это помимо сути. Могу ли я получать данные всех датчиков сразу каждые 100 миллисекунд? Если бы я мог установить дельту времени как константу 100 мс, это сделало бы мои расчеты и интеграции значительно более точными.   -  person Dimitar Veljanovski    schedule 24.01.2020


Ответы (2)


При замене датчиков вы получите все события, связанные с каждым из них. Для каждого события будет вызываться onSensorChanged.

Если вы хотите получить доступ ко всем этим событиям одновременно, вы должны поместить их в некоторый буфер.

Один из способов сделать это следующим образом

// At class level
private Map<Integer, Stack<SensorEvent>> eventsBuffer = new HashMap<>();

// to be called from constructor
private void initEventsBuffer() { 
     eventsBuffer.put(Sensor.TYPE_ACCELEROMETER, new Stack<>());
}

public void onSensorChanged(SensorEvent event) {
    if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
        eventsBuffer.get(Sensor.TYPE_ACCELEROMETER).push(event);
    }
    else if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE){
        eventsBuffer.get(Sensor.TYPE_GYROSCOPE).push(event);
    } 
    else if(event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD){
        eventsBuffer.get(Sensor.TYPE_MAGNETIC_FIELD).push(event);
    }
   processEvents();
}

   private void processEvents() {
   // Start reading from the stack based on event type
       for (Map.Entry<Integer, Stack<SensorEvent>> entry : stack.entrySet()) {
            SensorEvent sensorEvent = entry.getValue().pop();
            Integer eventType = entry.getKey();
            // process now
        }
}
person Yogesh Badke    schedule 24.01.2020
comment
Но все же onSensorChanged будет вызываться в разное время для каждого события датчика (независимо от типа датчика). Так что, если я все еще не собираюсь получать показания данных датчика за один раз. Например, как мне получать данные каждого датчика каждые 100 миллисекунд? - person Dimitar Veljanovski; 24.01.2020
comment
Ну, это нажимной механизм. т. е. событие будет запущено только тогда, когда произошли изменения. То, что вам нужно, это тяговый механизм. Не уверен, что он поддерживается. - person Yogesh Badke; 24.01.2020
comment
так что я не могу буквально извлекать информацию из датчиков по желанию? Мне ждать обновления от сенсоров? - person Dimitar Veljanovski; 24.01.2020
comment
Боюсь, что так. Подробнее здесь: stackoverflow.com/questions/29052204/ - person Yogesh Badke; 24.01.2020

Немного поздно, но может быть полезно для других - вы можете использовать простой обходной путь:

выберите датчики с наибольшей частотой обновления и синхронизируйте с ними данные всех остальных датчиков через глобальные переменные. Например. (для акселерометра в качестве основного датчика):

...
float mAccX;
float mAccY;
float mAccZ;

float mGyroX;
float mGyroY;
float mGyroZ;

float mMagX;
float mMagY;
float mMagZ;

...

public void onSensorChanged(SensorEvent event) {
    if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
        sText.setText("S: " + event.sensor.getStringType());
        mAccX = event.values[0];
        mAccY = event.values[1];
        mAccZ = event.values[2]; 
        
        // use all sensors data here
        processAllSensorsData(mAccX, mAccY, mAccZ, 
                              mGyroX, mGyroY, mGyroZ,
                              mMagX, mMagY, mMagZ);
    }
    else if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE){
        sText.setText("S: " + event.sensor.getStringType());
        mGyroX = event.values[0];
        mGyroY = event.values[1];
        mGyroZ = event.values[2]; 
    } 
    else if(event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD){
        sText.setText("S: " + event.sensor.getStringType());
        mMagX = event.values[0];
        mMagY = event.values[1];
        mMagZ = event.values[2];
    }
}

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

А также использовать отдельные SensorEventListener для каждого датчика.

person Andrii Omelchenko    schedule 08.01.2021