前回はJNIを利用してJavaから人感センサを読み取ることに成功しました。今回はこれをVstoneMagicから呼び出してみたいと思います。

Jar(Javaライブラリ)の作成

まず、前回で作成したJavaのクラスをjar形式のライブラリにします。
jarファイルを作成するコマンドは「jar」です。Javaの各種コマンドを実行しているディレクトリに移動し(本記事の場合は/home/root/)、「jar -cvf Hiddata.jar lib/usb/*.class」というコマンドを実行します。

$ jar -cvf Hiddata.jar lib/usb/*.class

正常に処理が実行されると下記の表示が出て、Hiddata.jarというファイルが生成されます。もし何らかエラーが発生した場合、コマンドのオプションを間違えていないか、また、実行するカレントディレクトリなどを間違えていないかご確認ください。

jarコマンドでjarファイルを生成する。 Hiddata.jarというファイルが生成される

生成されたHiddata.jarは、VstoneMagicを使用するPC側にダウンロードしてください。

VstoneMagicの設定

続いて、VstoneMagicから新規にプロジェクトを作成し、生成したjarファイルが使えるように設定を行います。 まず適当な名前で新規プロジェクトを作成します。

プロジェクトを新規作成する

プロジェクトを作成したら、先ほど生成したHiddata.jarを、プロジェクトの「jar」に追加します。

Hiddata.jar をエクスプローラのjar内に追加

次に、共用ライブラリファイル(libHiddata.so)への参照を追加します。こちらのファイルはPC側には取り込まず、ロボット内に既に存在するファイルに対する参照を設定します。

前回は、Javaの実行時に「-Djava.library.path=./」というオプションを指定して共用ライブラリファイルを参照させましたが、VstoneMagicでも同じことを行います。
VstoneMagicにおけるJavaの実行時オプションの設定は、プロジェクトのexecOptionの項目で行います。execOptionの設定を開く手順は下記の通りです。

VstoneMagicにおけるJava実行時オプションの設定
execOptionにオプションを追加していく

設定を開いたら、「-Djava.library.path」の行が既に存在するので、この行を書き換えて libHiddata.so への参照も追加します。
設定行の末尾に:(コロン)を追加し、続いてlibHiddata.soが存在するディレクトリを入力します。

前回はすべてのファイルが同じディレクトリ上にあったため、カレントディレクトリを参照するために「./」と相対パスで設定しましたが、今回はどこでプログラムが実行されてもファイルを参照できるように絶対パスで指定します。本記事では/home/root/に存在するので、このディレクトリへの参照を追加します。

-Djava.library.path の設定行末尾に「:/home/root/」を追加

java.library.pathに複数のパスを設定する場合は、このように:で区切るようです(プラットフォームによって変わるようなので注意)。

以上でVstoneMagicから Hiddata.jar を呼び出す準備は完了です。続いて実際にセンサ値を読み出すプログラムを作成していきます。

センサ読み取りプログラムの実装

プログラムの内容は、一旦前回Javaで直接コーディングしたものを移植しますが、自由記述で済ませず、極力VstoneMagicのブロックに置き換える方向で進めていきます。

メンバ変数・オブジェクトの作成

まずmymain.javaを開き、クラスのメンバ変数・オブジェクトを作成します。今回は下記の5種類を作成します。

  • Hiddata hiddata … Hiddataクラスのインスタンス
  • int device … デバイスハンドル記録
  • byte[] buffer … 受信バッファ
  • int returnValue … 戻り値代入
  • int sensorValue … センサ値記録

変数ブロックをコンストラクタに5個追加し、それぞれのブロックを下図のように設定してください。Hiddata hiddataの設定では、typeの欄はプルダウンからの選択ではなく、直接「Hiddata」と入力してください。

メンバ変数・オブジェクトを変数ブロックでそれぞれ作成する
各ブロックのtype,name,isInitialize,initParamを設定する

Hiddata hiddataとbyte[] bufferのinitParamの設定は、それぞれ下記のようにします。

Hiddata hiddataのinitParamは「new Hiddata()」とする
byte[] bufferのinitParamは「new byte[17]」とする

センサの取得・解放処理の実装

次に mymain.javaのメインメソッドの内容を作成します。まず、センサと接続してデバイスを開く所までを作ります。

mainメソッドの冒頭に自由記述ブロックを追加し、「System.loadLibrary(“Hiddata”);」と記述してHiddata.soを参照させます。次に代入ブロックで、int deviceにhiddata.usbhidOpenDeviceを実行して得られるデバイスのハンドルを代入します。

続いて分岐ブロックでint deviceの値が0以外(センサ取得成功)か否かで分岐させ、成功時にhiddata.usbhidCloseDeviceでデバイスを閉じさせます。閉じる処理は自由記述ブロックで行います。
ついでに、それぞれの処理に分岐したことがわかるようにログ出力を加えます。

1.自由記述ブロックで「 System.loadLibrary(“Hiddata”); 」を実行
2.代入ブロックでhiddata.usbhidOpenDevice(0x16c0,0x05df)の内容を int deviceに 代入
3.ifブロックで deviceの値が0以外(センサ取得に成功)かどうかで分岐させる
4.センサ取得に成功した場合(分岐上側)だけ、自由記述ブロックで hiddata.usbhidCloseDevice()を実行(センサ解放)

プログラムを作成したら一度実行してみます。センサの有無によって、分岐先のメッセージがログに出力されれば成功です。

プログラムが正常に実行でき、センサを取得できた

実行時にUnsatisfiedLinkErrorというエラーが表示される場合は、libHiddata.soファイルへの参照がうまく行われていません。

センサ値読み取り部分の実装

続いて、センサの値を読み取ってログに表示するところも作成します。先ほどのプログラムの上側の分岐(センサの取得に成功した場合)にブロックを挿入していきます。

センサ読み取り部の流れは、前回のコーディング同様「forループで30回繰り返しを作り、0.5秒間隔でセンサ値を読み取ってログに出力する」と言うものにします。

まず、forループで30回の繰り返しを作り、その中に細かい処理を実装します。

代入ブロックでhiddata.usbhidGetReportメソッドの結果を returnValueに代入します。
続いてifブロックで、 returnValue の値が0(成功)かどうかで処理を分岐し、成功ならセンサ値をsensorValueに代入します。具体的には前回のJavaのコードと同様、buffer[1]がセンサ値に相当するため、この値をsensorValueに代入し、画面に表示させます。
returnValue の値が0以外(失敗)なら、失敗を表すメッセージをログ出力ブロックで 表示します。

1.forブロックで30回繰り返し
2. 代入ブロックでhiddata.usbhidGetReport(device,0,buffer ,buffer.length) の結果をreturnValueに代入
3.ifブロックでセンサ値取得成功(returnValue==0)か否かで分岐する
4.取得成功なら、代入ブロックで sensorValue にbuffer[2]の値を代入

プログラムを作成したら、再度実行してみます。実行すると、画面に取得したセンサ値が表示されます。

実行すると、コンソールウィンドウにセンサ値が表示される

以上で、人感センサをSotaから直接使う方法は終了です。本記事の内容を参考にすることで、人感センサ以外のUSB-HIDデバイスも制御できそうな雰囲気があります(USBマウス・ゲームパッド等)。また、JNIを用いたSotaのアプリ開発にも応用ができるかと思います。

今回のサンプルコードは以下のリポジトリに公開しています。ライセンスがGPL2なので、ご利用の際にはご注意ください。

https://github.com/vstoneofficial/HumanSensor_Sota