Aqoole_Hateenaの技術日記

vulkan+raytraceで色々描いてます

重力センサーの有効化と取得方法

結論

Androidの重力センサーの有効化と値の取得は、公式サンプルコードのままではうまくいかない。
サンプル: native-activity  |  Android NDK  |  Android Developers
先に結論を書くと、以下の過程が必要
(※ASensorEventQueue_enableSensor()は必須だが、ASensorEventQueue_registerSensor()は任意)

//initialize sensors
gSensors.gSensorManager = ASensorManager_getInstance();
gSensors.gSensorAccelerometer = ASensorManager_getDefaultSensor(gSensors.gSensorManager, ASENSOR_TYPE_ACCELEROMETER);
gSensors.gSensorGravity = ASensorManager_getDefaultSensor(gSensors.gSensorManager, ASENSOR_TYPE_GRAVITY);
gSensors.gSensorQueue = ASensorManager_createEventQueue(gSensors.gSensorManager, app->looper, LOOPER_ID_USER, NULL, NULL);
__android_log_print(ANDROID_LOG_DEBUG, "register sensor test",
                    std::to_string(ASensorEventQueue_registerSensor(gSensors.gSensorQueue, gSensors.gSensorAccelerometer, 10, 10)).c_str(), 0);
__android_log_print(ANDROID_LOG_DEBUG, "register sensor test gravity",
                    std::to_string(ASensorEventQueue_registerSensor(gSensors.gSensorQueue, gSensors.gSensorGravity, 10, 10)).c_str(), 0);
__android_log_print(ANDROID_LOG_DEBUG, "sensor test",
                    std::to_string(ASensorEventQueue_enableSensor(gSensors.gSensorQueue, gSensors.gSensorAccelerometer)).c_str(), 0);
__android_log_print(ANDROID_LOG_DEBUG, "sensor test gravity",
                    std::to_string(ASensorEventQueue_enableSensor(gSensors.gSensorQueue, gSensors.gSensorGravity)).c_str(), 0);

//main loop part
do {
  if ((ident = ALooper_pollAll(IsVulkanReady() ? 160 : -1, nullptr,
                      &events, (void**)&source)) >= 0) {
    if (source != NULL) source->process(app, source);
    if(ident == LOOPER_ID_USER)
    {
        __android_log_print(ANDROID_LOG_DEBUG, "gravity event count in loop = ", std::to_string(ASensorEventQueue_hasEvents(gSensors.gSensorQueue)).c_str(), 0);
        while(ASensorEventQueue_getEvents(gSensors.gSensorQueue, tempSensorEvent, 1) > 0) {
            gravityData.x = tempSensorEvent->vector.x;
            gravityData.y = tempSensorEvent->vector.y;
            gravityData.z = tempSensorEvent->vector.z;
            __android_log_print(ANDROID_LOG_DEBUG, "gravity2 :  ", (std::to_string(gravityData.x) + " " + std::to_string(gravityData.y) +
                                                                   " " + std::to_string(gravityData.z)).c_str(), 0);
        }
    }
  }
  __android_log_print(ANDROID_LOG_DEBUG, "gravity event count = ", std::to_string(ASensorEventQueue_hasEvents(gSensors.gSensorQueue)).c_str(),
                      0);
  // render if vulkan is ready
  if (IsVulkanReady()) {
    VulkanDrawFrame(currentFrame, isTouched, isFocused, touchPositions);
    currentFrame = (currentFrame + 1) % MAX_IN_FLIGHT;
  }
} while (app->destroyRequested == 0);

Androidのセンサーについて

使えるセンサーの一覧などがまとめられている。
モーション センサー  |  Android デベロッパー  |  Android Developers
ただNDKの観点では書かれていないので、C++で実装したい場合には別にまとめられているページを参照する。

Androidセンサー NDK

NDKの関数などが書かれている。
Sensor  |  Android NDK  |  Android Developers

注意事項

  • ASensorEventQueue_registerSensor()を用いる場合は、GradleのminSdkVersionが26以上であることが必要。

c++ - Android NDK undefined reference to ASensorEventQueue_registerSensor - Stack Overflow

The other possibility is that your minSdkVersion is lower than 26. ASensorEventQueue_registerSensor was not added until O, so it can't be linked unless your minSdkVersion is at least 26.

  • includeファイルは<android/sensor.h>

雑感とか

まとめるとたったこれだけのことなのだが、公式のコードでうまく動かないので、たどり着くまでにかなり時間がかかってしまった。
本当はlooperなど、色々調べたことも残したいが、とりあえずはこれで良いか。
公式を参照した後に、このメモを見てサクッとセンサーが使える人が増えることを願っています。