【发布时间】:2014-04-25 20:42:10
【问题描述】:
我正在尝试通过使用来自加速度计的数据和 onTouch 方法来检测敲击的力度。
据我所知,加速度计的最快采样频率是 200-202Hz,但是当我尝试匹配 onTouch 事件的时间戳和加速度计数据中的峰值时,这种可变性给我带来了问题。
有没有办法稳定加速度计的读数来避免这个问题?比如控制特定线程什么的?
【问题讨论】:
标签: android accelerometer sampling
我正在尝试通过使用来自加速度计的数据和 onTouch 方法来检测敲击的力度。
据我所知,加速度计的最快采样频率是 200-202Hz,但是当我尝试匹配 onTouch 事件的时间戳和加速度计数据中的峰值时,这种可变性给我带来了问题。
有没有办法稳定加速度计的读数来避免这个问题?比如控制特定线程什么的?
【问题讨论】:
标签: android accelerometer sampling
问题似乎是 Java 代码在 android 中运行的 Dalvik JVM 优先处理进程,所以如果应用程序不像设备正在运行的任何其他东西那么重要,它会将其搁置少量。我发现解决此问题的一种方法是在 NDK 上使用 C 或 C++,它直接在操作系统上运行,不依赖于 JVM。 这是我的 C++ 类的代码,你可以从 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);
}
}
}
}
}
}
此示例为您提供了 200Hz 的采样率,其变化非常非常小(每秒为您提供一到两个额外读数),可以通过代码消除。 开始使用 NDK 的一个好方法是阅读这本书,Android Native Development Kit Cookbook。
https://www.packtpub.com/application-development/android-native-development-kit-cookbook
【讨论】:
如果您想匹配硬件提供的时间(event.timestamp)和系统时间,您可以通过调整时间来做到这一点。
通常时间不一样,但它们只是相差恒定的毫秒数。我建议您将两次都打印出来并进行比较。然后你会注意到偏移量是什么:
在我的问题中,Ormi734 建议使用以下代码:
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
【讨论】: