LoginSignup
3
1

More than 5 years have passed since last update.

Surface(Windows10)の加速度センサーの値をC++から取得する

Last updated at Posted at 2018-04-24

概略

Surface Pro 4に載っているセンサーの値を取得したいと思ったのですが、思ったより情報が少なかったので、共有させて頂きます。

経緯

普段、C++とopenFrameworksというライブラリを組み合わせて、プログラミングを使った動的なお絵描きを趣味にしています。下記は最近、SNSでリアクションが沢山いただけたものです。

こんな感じの動画を作ってはTwitter/Instagramへ投稿、Blogでソースコードを公開しております。こういったものにSurfaceのセンサーを応用すればインタラクティブなモノが作れるのではと思いって、調べてみました。

成果物

3軸加速度センサーの値を取得して、傾きを検出、X, Y, Zの値を文字として描写しています。それらの値を2次元の物理エンジンライブラリの重力として設定しているので、丸いオブジェクトは傾きにつられて動いています。

描写や物理エンジン関係の部分はopenFrameworksの話題になってしまうので、今回はX, Y, Zの値を取得する所までのお話です。

開発環境

Surface Pro 4
Windows 10
Visual Studio 2015(C++)

本編

まずはGoogle検索で関連していると思われる各種ワードで検索をしてみました。Microsoftオフィシャルだと下記のドキュメントが該当するようです。

Sensor API
https://msdn.microsoft.com/ja-jp/library/windows/desktop/dd318953(v=vs.85).aspx

ただ、言及されているOSがWindows7で若干古そうなのと、COMなどは普段業務などでもあまり触っていないので、もうちょっと情報が欲しいなと引き続き探した所、日本語で書かれているblogを発見出来ました。

WindowsでC++で加速度センサーの値をとりたい | かずきのBlog@hatena
http://blog.okazuki.jp/entry/2015/04/07/195929

今回やりたかった事のコードが、そのまま記載されていたので参考にさせて頂きました。

ちなみに、インクルードされているSensorApi.hやSensors.hですが、PC内をファイル検索かけた所、下記3か所のディレクトリに存在していました。(Sensorsapi.libも似たような形式で配置されていました)

C:\Program Files (x86)\Windows Kits\8.1\Include\um\
C:\Program Files (x86)\Windows Kits\10\Include\10.0.16299.0\um\
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\

私の開発環境にはVisual Studi2015以外にも2013と2017がインストールされている為かも知れません。Visual Studio2015の設定を確認すると、今回はWindows Kits 8.1のインクルードディレクトリのヘッダーを参照しているようです。

もし、この辺りのファイルが不足しているようであれば、別途Windows SDKをインストールする必要があると思います。おそらくVisual Studioをインストールがあればインストールされていると思います。

コード

これまでの情報をもとに、作成したコードが下記です。
センサの値をダンプするコンソールアプリになります。

選択C__Users_nakau_Desktop_SensorSample_Debug_SensorSample.exe 2018_04_24 11_20_53.png

---2018/04/25 追記 ---
msmaniaさんから教えて頂いたスマートポインタとFAILDマクロを取り入れさせて頂きました。
めっちゃスッキリして見やすくなりました。ありがとうございました!
元々記載していたコードは折りたたんで残しておきます

#include <iostream>
#include <atlbase.h>
#include <SensorsApi.h>
#include <sensors.h>
#pragma comment(lib, "Sensorsapi.lib")

void get_accelerometer_3d_value(float& rx, float& ry, float& rz) {

    rx = 0.f;
    ry = 0.f;
    rz = 0.f;

    CComPtr<ISensorManager> sensor_manager;
    CComPtr<ISensorCollection> sensor_collection ;
    CComPtr<ISensor> sensor;
    CComPtr<ISensorDataReport> data;

    if (FAILED(::CoInitializeEx(NULL, COINIT_MULTITHREADED))) {

        return;
    }

    if (FAILED(::CoCreateInstance(CLSID_SensorManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&sensor_manager)))) {

        return;
    }

    if (FAILED(sensor_manager->GetSensorsByCategory(SENSOR_TYPE_ACCELEROMETER_3D, &sensor_collection))) {

        return;
    }

    if (FAILED(sensor_collection->GetAt(0, &sensor))) {

        return;
    }

    if (FAILED(sensor->GetData(&data))) {

        return;
    }

    PROPVARIANT x = {};
    if (FAILED(data->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_X_G, &x))) {

        return;
    }

    PROPVARIANT y = {};
    if (FAILED(data->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Y_G, &y))) {

        return;
    }

    PROPVARIANT z = {};
    if (FAILED(data->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Z_G, &z))) {

        return;
    }

    rx = x.dblVal;
    ry = y.dblVal;
    rz = z.dblVal;
}

int main() {

    float x, y, z;
    while (true) {

        get_accelerometer_3d_value(x, y, z);
        std::cout << "X = " << x << " Y = " << y << " Z = " << z << std::endl;
    }
}

元々のコード
#include <iostream>
#include <SensorsApi.h>
#include <sensors.h>
#pragma comment(lib, "Sensorsapi.lib")

void get_accelerometer_3d_value(float& rx, float& ry, float& rz) {

    rx = 0.f;
    ry = 0.f;
    rz = 0.f;

    ISensorManager* sensor_manager = nullptr;
    ISensorCollection* sensor_collection = nullptr;
    ISensor* sensor = nullptr;
    ISensorDataReport* data = nullptr;

    if (!SUCCEEDED(::CoInitializeEx(NULL, COINIT_MULTITHREADED))) {

        return;
    }

    if (!SUCCEEDED(::CoCreateInstance(CLSID_SensorManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&sensor_manager)))) {

        return;
    }

    if (!SUCCEEDED(sensor_manager->GetSensorsByCategory(SENSOR_TYPE_ACCELEROMETER_3D, &sensor_collection))) {

        sensor_manager->Release();
        return;
    }

    if (!SUCCEEDED(sensor_collection->GetAt(0, &sensor))) {

        sensor_collection->Release();
        sensor_manager->Release();
        return;
    }

    if (!SUCCEEDED(sensor->GetData(&data))) {

        sensor->Release();
        sensor_collection->Release();
        sensor_manager->Release();
        return;
    }

    PROPVARIANT x = {};
    if (!SUCCEEDED(data->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_X_G, &x))) {

        data->Release();
        sensor->Release();
        sensor_collection->Release();
        sensor_manager->Release();
        return;
    }

    PROPVARIANT y = {};
    if (!SUCCEEDED(data->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Y_G, &y))) {

        data->Release();
        sensor->Release();
        sensor_collection->Release();
        sensor_manager->Release();
        return;
    }

    PROPVARIANT z = {};
    if (!SUCCEEDED(data->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Z_G, &z))) {

        data->Release();
        sensor->Release();
        sensor_collection->Release();
        sensor_manager->Release();
        return;
    }

    rx = x.dblVal;
    ry = y.dblVal;
    rz = z.dblVal;

    data->Release();
    sensor->Release();
    sensor_collection->Release();
    sensor_manager->Release();
}

int main() {

    float x, y, z;
    while (true) {

        get_accelerometer_3d_value(x, y, z);
        std::cout << "X = " << x << " Y = " << y << " Z = " << z << std::endl;
    }
}

おわり

普段、業務でもWindowsAPIやCOMは触らないので完全に理解できていない部分もありますが、何とか値の取得まではいけました。今後は扱えるセンサーの種類などを増やしていきたいです。

3
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1