Android accelerometer sampling rate/delay stabiliz

2019-06-02 19:37发布

问题:

I'm trying to detect the force strength of a tap by using the data from the accelerometer and with the method onTouch.

As far as I know, the fastest sampling frequency for the accelerometer is 200-202Hz, but this variability is giving me problems when trying to match the timestamps for the onTouch event and the peak in the accelerometer data.

Is there a way to stabilize the readings of the accelerometer to avoid this problem? Like controlling the specific thread or something?

回答1:

If you want to match the hardware-provided time (event.timestamp) and the System time you can do this by adjusting the times.

Usually the times are not the same, but they just differ by a constant amount of milliseconds. I suggest you to print out both times and compare them. You will then notice what the offset is:

In my question, Ormi734 suggested to use the following code:

private long timeDiff = 0l; // this will be used to adjust the offset between the times
private boolean offsetDetermined = false;

@Override
public void onSensorChanged(SensorEvent event) {

    // just determine the offset once, since it should remain constant
    // you could also adjust it every n samples if it needs to be really accurate
    if (!offsetDetermined) {
        long MiliTime = System.currentTimeMillis();
        long NanoTime = event.timestamp;
        timeDiff = MiliTime - NanoTime / 1000000;

        log.info("Synchornizing sensor clock. Current time= " + MiliTime+ ", difference between clocks = " + timeDiff);

        offsetDetermined = true;
    }

    float x = event.values[0];
    float y = event.values[1];
    float z = event.values[2];
    long ts = event.timestamp / 1000000 + timeDiff;

    // do your stuff here   
}

Accelerometer logger: experiencing occasional long delays between frames



回答2:

The problem seems to be that the Dalvik JVM in which the java code runs in android, prioritizes the processes, so if the application isn't as important as any other thing the device is running, it will put it on hold a bit. One way i found to resolve this is to use C or C++ on NDK which works directly over the OS and doesn't rely on the JVM. Here's the code of my C++ class that worked, you can call it from Java.

#include <jni.h>
#include <string.h>

#include <android/sensor.h>
#include <android/log.h>
#include <android/looper.h>

#define TAG "accelerondk"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)

#define LOOPER_ID 1


extern "C" {

void JNICALL Java_com_example_hellojni_PruebaHilo_startMonitoring(JNIEnv* env, jclass clazz) {
    ASensorManager* sensorManager = ASensorManager_getInstance();

    ALooper* looper = ALooper_forThread();
    if(looper == NULL)
        looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);

    ASensorRef accelerometerSensor = ASensorManager_getDefaultSensor(sensorManager,ASENSOR_TYPE_ACCELEROMETER);
    LOGI("accelerometerSensor: %s, vendor: %s", ASensor_getName(accelerometerSensor), ASensor_getVendor(accelerometerSensor));

    ASensorEventQueue* queue = ASensorManager_createEventQueue(sensorManager, looper, LOOPER_ID, NULL, NULL);

    ASensorEventQueue_enableSensor(queue, accelerometerSensor);
    ASensorEventQueue_setEventRate(queue, accelerometerSensor, (1000L/200)*1000);

    int ident;//identifier
    int events;
    while (1) {
        while ((ident=ALooper_pollAll(-1, NULL, &events, NULL) >= 0)) {
            // If a sensor has data, process it now.
            if (ident == LOOPER_ID) {
                ASensorEvent event;
                while (ASensorEventQueue_getEvents(queue, &event, 1) > 0) {
                    LOGI("accelerometer X = %f y = %f z= %f ", event.acceleration.x, event.acceleration.y, event.acceleration.z);
                }
            }
        }
    }
}
}

This example gives you a 200Hz Sample rate with very, very small variations (giving you one or two extra readings per second) which can be eliminated with code. A good way to start on NDK is with this book, Android Native Development Kit Cookbook.

https://www.packtpub.com/application-development/android-native-development-kit-cookbook