【问题标题】:access (faster polling) accelerometer via NativeActivity NDK通过 NativeActivity NDK 访问(更快的轮询)加速度计
【发布时间】:2012-02-17 20:50:06
【问题描述】:

我已经搜索了有关使用 NDK 更快地轮询加速度计的教程/答案,但还没有找到求解器。刚刚找到一个androiddevelopers文档here

我需要的是每秒大约 100 个样本 (100Hz) 的轮询加速度,默认情况下,我的设备(带有姜饼 2.3.5 的三星 Galaxy SL i9003)默认 SENSOR_DELAY_FASTEST 每秒只能获得大约 60 个样本(60Hz)。 因此,我尝试使用 NDK 通过 NativeActivity 访问传感器,方法是生成我尝试基于 sensor.h 和 looper.h 制作的 .c 文件:

#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
#define SAMP_PER_SEC 100 //i've changed to 120, even 10, but nothing happen

void Java_azka_web_ndk_AcceleroNDKActivity_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/SAMP_PER_SEC)*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("aaaaaaa accelerometer X = %f y = %f z=%f ", event.acceleration.x, event.acceleration.y, event.acceleration.z);
                }
            }
        }
    }

}

到目前为止,我已经能够使用 NativeActivity 访问加速度计,但是采样的数量没有变化。即使我将 ASensorEventQueue_setEventRate 更改得足够大或足够小,加速度记录仍然约为每秒 60 个样本(每 15 毫秒 1 个样本)

我的代码有错误吗?还是我忘记的东西?

提前致谢

【问题讨论】:

  • 这个问题你解决了吗?

标签: android android-ndk native accelerometer sensors


【解决方案1】:

这是一个老问题,但鉴于缺乏文档和文章,我想我会分享我的经验。我在 Nexus 5X 上完成了所有测试。您的设备可能不同。

原始代码看起来正确。从文档中不明显的是,您只能在启用传感器后设置事件率,并且...

如果您重新启用传感器(例如,在 onPause() 和 onResume() 之后),您需要再次设置事件率。如果您像我一样进行了“双重启用”在我的代码中(init() 中的 enable()/setEventRate(),但仅 onResume() 中的 enable()),您将获得默认的轮询率。

【讨论】:

    【解决方案2】:

    这个问题有点老了,但也许这两篇文章会对那些偶然发现这个问题并想知道为什么要麻烦,或者如何优化 NDK 中的示例的人有所帮助。

    这两篇短文列出了问题和潜在的解决方案(但没有完整的源解决方​​案)

    Java interfaced sensor performance

    Native Sampling Improvement

    【讨论】:

    • 链接已失效。请尝试将相关材料复制到您的答案中,以便保留信息。
    【解决方案3】:

    我还对传感器的采样率进行了一些尝试。我使用 Galaxy Nexus。 如果我只使用 Acc-Sensor 频率非常低(约 40Hz),但如果我使用 Acc-Sensor 加上磁传感器和陀螺传感器,每个传感器的采样率约为 100Hz。 我无法解释为什么会发生这种情况。另一个观察结果是传递给 ASensorEventQueue_setEventRate 的值无效。采样率始终相同。 SDK-Code 的行为完全相同。

    这是我用于基准测试的代码:

    #include <string.h>
    #include <jni.h>
    #include <android/sensor.h>
    #include <android/looper.h>
    #include <android/log.h>
    #include <time.h>
    #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "TestJNIActivity", __VA_ARGS__))
    #define LOOPER_ID 1
    #define SAMP_PER_SEC 100
    
    ASensorEventQueue* sensorEventQueue;
    
    int accCounter = 0;
    int64_t lastAccTime = 0;
    
    int gyroCounter = 0;
    int64_t lastGyroTime = 0;
    
    int magCounter = 0;
    int64_t lastMagTime = 0;
    
    /* This is a trivial JNI example where we use a native method
     * to return a new VM String. See the corresponding Java source
     * file located at:
     *
     *   apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java
     */
    
    static int get_sensor_events(int fd, int events, void* data);
    
    struct tm* start;
    struct tm* finish;
    
    
    jstring
    Java_de_tum_ndktest_TestJNIActivity_stringFromJNI( JNIEnv* env, jobject thiz )
    {
        LOGI("stringFromJNI");
        return (*env)->NewStringUTF(env,"Hello from JNI !");
    }
    
    void
    Java_de_tum_ndktest_TestJNIActivity_sensorValue( JNIEnv* env, jobject thiz ) {
    
        ASensorEvent event;
        int events, ident;
        ASensorManager* sensorManager;
        const ASensor* accSensor;
        const ASensor* gyroSensor;
        const ASensor* magSensor;
        void* sensor_data = malloc(1000);
    
        LOGI("sensorValue() - ALooper_forThread()");
    
        ALooper* looper = ALooper_forThread();
    
        if(looper == NULL)
        {
            looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
        }
    
        sensorManager = ASensorManager_getInstance();
    
        accSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
        gyroSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_GYROSCOPE);
        magSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_MAGNETIC_FIELD);
    
    
    
        sensorEventQueue = ASensorManager_createEventQueue(sensorManager, looper, 3, get_sensor_events, sensor_data);
    
        ASensorEventQueue_enableSensor(sensorEventQueue, accSensor);
        ASensorEventQueue_enableSensor(sensorEventQueue, gyroSensor);
        ASensorEventQueue_enableSensor(sensorEventQueue, magSensor);
    
        //Sampling rate: 100Hz
        int a = ASensor_getMinDelay(accSensor);
        int b = ASensor_getMinDelay(gyroSensor);
        int c = ASensor_getMinDelay(magSensor);
        LOGI("min-delay: %d, %d, %d",a,b,c);
        ASensorEventQueue_setEventRate(sensorEventQueue, accSensor, 100000);
        ASensorEventQueue_setEventRate(sensorEventQueue, gyroSensor, 100000);
        ASensorEventQueue_setEventRate(sensorEventQueue, magSensor, 100000);
    
        LOGI("sensorValue() - START");
    }
    
    
    
    static int get_sensor_events(int fd, int events, void* data) {
      ASensorEvent event;
      //ASensorEventQueue* sensorEventQueue;
      while (ASensorEventQueue_getEvents(sensorEventQueue, &event, 1) > 0) {
            if(event.type == ASENSOR_TYPE_ACCELEROMETER) {
                    //LOGI("accl(x,y,z,t): %f %f %f %lld", event.acceleration.x, event.acceleration.y, event.acceleration.z, event.timestamp);
                    if(accCounter == 0 || accCounter == 1000)
                        {
                         LOGI("Acc-Time: %lld (%f)", event.timestamp,((double)(event.timestamp-lastAccTime))/1000000000.0);
                         lastAccTime = event.timestamp;
                         accCounter = 0;
                        }
    
                    accCounter++;
            }
            else if(event.type == ASENSOR_TYPE_GYROSCOPE) {
                    //LOGI("accl(x,y,z,t): %f %f %f %lld", event.acceleration.x, event.acceleration.y, event.acceleration.z, event.timestamp);
                    if(gyroCounter == 0 || gyroCounter == 1000)
                        {
    
                         LOGI("Gyro-Time: %lld (%f)", event.timestamp,((double)(event.timestamp-lastGyroTime))/1000000000.0);
                         lastGyroTime = event.timestamp;
                         gyroCounter = 0;
                        }
    
                    gyroCounter++;
            }
            else if(event.type == ASENSOR_TYPE_MAGNETIC_FIELD) {
                    //LOGI("accl(x,y,z,t): %f %f %f %lld", event.acceleration.x, event.acceleration.y, event.acceleration.z, event.timestamp);
                    if(magCounter == 0 || magCounter == 1000)
                        {
                         LOGI("Mag-Time: %lld (%f)", event.timestamp,((double)(event.timestamp-lastMagTime))/1000000000.0);
                         lastMagTime = event.timestamp;
                         magCounter = 0;
                        }
    
                    magCounter++;
            }
    
      }
      //should return 1 to continue receiving callbacks, or 0 to unregister
      return 1;
    }
    

    【讨论】:

    • 您是否需要创建一个 Activity 来运行它?如果是这样,您能否发布该代码?
    • 对不起,我已经三年没做这个了。据我所知,我使用了一个 java-GUI,我从中调用了 JNI 函数。不幸的是我没有代码,但我认为这只是一个函数调用。最复杂的部分是在我的电脑(Eclipse)上设置 NDK。
    • 我想通了,谢谢。我可能会用一些指针来更新你的答案。
    • 它有效,但我们观察到加速度计保持唤醒锁!是否有意义 ?我认为只有“显着运动传感器”才能保持唤醒锁。
    【解决方案4】:

    您可能受到设备中加速度计硬件速度的限制。但是,您可以使用interpolation 来获取一些额外的数据点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-27
      • 1970-01-01
      • 1970-01-01
      • 2015-07-21
      • 2012-09-05
      • 1970-01-01
      • 2014-05-25
      • 1970-01-01
      相关资源
      最近更新 更多