//&engpage("Controlling agent with Kinect"); Up:[[Tutorial]] Previous:[[眼球運動]] Next: [[HMD+KINECT]] ---- #contents *キネクトによるエージェントの操作 [#g847337f] ※このチュートリアルはv2.1.0以降で動作します。 キネクトを使ってSIGVerseの人間エージェントの体の動きを操作する方法を紹介します。 ※すでにOpenNIがクライアントpcにインストールされていて、サンプルコードNiUserTrackerが動作可能であることを前提条件とします。 **OpenNI動作確認バージョン [#w7344684] -OpenNI Stable Build for Windows x86 (32-bit) v1.5.2.23 Development Edition --ダウンロードは[[こちら>http://www.openni.org/openni-sdk/openni-sdk-history-2/]] -- (※ 最新版でも動作すると思いますが,正式な動作確認は未だです 2013-12-03現在) -PrimeSene NITE Stable Build for Windows x86 (32-bit) v1.5.2.21 Development --上と同じページのOpenNI Compliant Middleware Binariesを選択してダウンロード。 -PrimeSense Sensor Module for OpenNI Version 5.1.0.25 --ダウンロードは[[こちら>https://github.com/avin2/SensorKinect]]。 **クライアント側の準備 [#g906fc36] キネクトにより骨格を抽出するサンプルプログラムを利用し、関節の回転データ(クオータニオン)を計算し、SIGVerseサーバにデータを送信します。 ***ダウンロード [#a9563850] [[KINECTサービス]]からSIGNiUserTracker_<version>.zipをダウンロードします。 //#ref(SIGNiUserTracker.sig) //ソースコードは[[こちら>#j4c23122]] ***インストール [#m9903252] ダウンロードしたzipファイルを展開しSIGNiUserTracker.sigをOpenNIサンプルの実行ファイルがあるフォルダに置きます。デフォルトでは以下のフォルダです。 C:\Program Files (x86)\OpenNI\Samples\Bin\Release (※Windows7 64bitの場合) この状態でクライアントpcにキネクトを接続しておけば準備完了です。 **サーバ側の準備 [#y2f178b2] コントローラで関節データを受信し、関節を回転させます。 ***コントローラ [#w4aca122] まずコントローラを作成します。 $ emacs kinectController.cpp kinectController.cpp #highlight(cpp){{ #include <string> #include "Controller.h" #include "Logger.h" #include "ControllerEvent.h" #define PI 3.141592 #define DEG2RAD(DEG) ( (PI) * (DEG) / 180.0 ) using namespace std; class AgentController : public Controller { public: double onAction(ActionEvent &evt); void onRecvMsg(RecvMsgEvent &evt); void onInit(InitEvent &evt); private: //初期位置 double m_posx, m_posy, m_posz; double m_yrot; double m_range; //データ数(関節数)最大値 int m_maxsize; BaseService *m_kinect; }; void AgentController::onInit(InitEvent &evt) { // 初期化 m_kinect = NULL; SimObj *my = getObj(myname()); // 初期位置取得 Vector3d pos; my->getPosition(pos); m_posx = pos.x(); m_posy = pos.y(); m_posz = pos.z(); // 初期姿勢(回転)取得 Rotation rot; my->getRotation(rot); double qw = rot.qw(); double qy = rot.qy(); m_yrot = acos(fabs(qw))*2; if(qw*qy > 0) m_yrot = -1*m_yrot; m_range = 0.1; m_maxsize = 15; } double AgentController::onAction(ActionEvent &evt) { // サービスが使用可能か定期的にチェックする bool available = checkService("SIGKINECT"); // 使用可能 if(available && m_kinect == NULL){ // サービスに接続 m_kinect = connectToService("SIGKINECT"); } // 使用不可能 else if (!available && m_kinect != NULL){ m_kinect = NULL; } return 1.0; } void AgentController::onRecvMsg(RecvMsgEvent &evt) { std::string sender = evt.getSender(); //自分自身の取得 SimObj *my = getObj(myname()); //メッセージ取得 char *all_msg = (char*)evt.getMsg(); char *msg = strtok(all_msg," "); if(strcmp(msg,"KINECT_DATA") == 0) { int i = 0; while(true) { i++; if(i == m_maxsize+1) break; char *type = strtok(NULL,":"); //体の位置 if(strcmp(type,"POSITION") == 0) { double x = atof(strtok(NULL,",")); double y = atof(strtok(NULL,",")); double z = atof(strtok(NULL," ")); //キネクト座標からSIGVerse座標への変換 double gx = cos(m_yrot)*x - sin(m_yrot)*z; double gz = sin(m_yrot)*x + cos(m_yrot)*z; my->setPosition(m_posx+gx,m_posy+y,m_posz+gz); continue; } //体全体の回転 else if(strcmp(type,"WAIST") == 0) { double w = atof(strtok(NULL,",")); double x = atof(strtok(NULL,",")); double y = atof(strtok(NULL,",")); double z = atof(strtok(NULL," ")); my->setJointQuaternion("ROOT_JOINT0",w,x,y,z); continue; } else if(strcmp(type,"END") == 0) break; //関節の回転 else { double w = atof(strtok(NULL,",")); double x = atof(strtok(NULL,",")); double y = atof(strtok(NULL,",")); double z = atof(strtok(NULL," ")); double angle = acos(w)*2; double tmp = sin(angle/2); double vx = x/tmp; double vy = y/tmp; double vz = z/tmp; double len = sqrt(vx*vx+vy*vy+vz*vz); if(len < (1 - m_range) || (1 + m_range) < len) continue; my->setJointQuaternion(type,w,x,y,z); continue; } } } } extern "C" Controller * createController () { return new AgentController; } }} このコントローラではキネクトからデータを受け取り関節を回転させます。 コンパイルします。 $ ./sigmake.sh kinectController.cpp ***他のモデルのコントローラサンプル [#ra789b97] ※準備中 //-[[Robot-nii.xml>キネクトによるエージェントの操作(ロボット)]] //-[[Man-nii-v2.xml>キネクトによるエージェントの操作(Man-nii-v2.xml)]](エージェントの初期姿勢がz軸方向を向いていない場合に対応) ***世界ファイルの作成 [#wd8a8474] 次に世界ファイルを作成します。 $ emacs kinectWorld.xml kinectWorld.xml #highlight(xml){{ <?xml version="1.0" encoding="utf8"?> <world name="myworld2"> <!--重力の設定--> <gravity x="0.0" y="-980.7" z="0.0"/> <!--エージェントMan-niiの設定--> <instanciate class="Man-nii.xml"> <!--エージェント名--> <set-attr-value name="name" value="kinect_man"/> <!--C++言語の指定--> <set-attr-value name="language" value="c++"/> <!--オブジェクトファイルkinectController.soの指定--> <set-attr-value name="implementation" value="./kinectController.so"/> <!--動力学演算をfalseに設定--> <set-attr-value name="dynamics" value="false"/> <!--エージェントの位置(x,y,z)--> <set-attr-value name="x" value="0.0"/> <set-attr-value name="y" value="60.0"/> <set-attr-value name="z" value="0.0"/> </instanciate> </world> }} 人間のみが登場するシンプルな世界ファイルです。このサンプルではキネクトで操作できるエージェントは人間エージェントのみです。 **実行 [#scf358ac] それでは実行してみましょう。 ***SIGVerse起動 [#rebb6851] まずシグバースサーバを起動します。 $ sigserver.sh -w ./kinectWorld.xml 次にSIGViewerで起動したサーバに接続します。接続すると人間が立っているのが見えます。 ***サービスの登録 [#x7693c87] SIGViewerにサービスを登録します。左上のメニューのServiceのAddを選択します。 #ref(キネクトによるエージェントの操作(v2.0系)/SIGNi_1.PNG) すると以下のようなウィンドウが立ち上がるのでAddボタンを押して先ほどダウンロードしたSIGNiUserTracker.sigを読み込みます。 #ref(キネクトによるエージェントの操作(v2.0系)/SIGNi_2.PNG,80%) Service listにSIGNiUserTracker.sigが登録されたらOKボタンを押してウィンドウを閉じます。 次にメニューのService→Startをクリックし、先ほど登録したSIGNiUserTracker.sigをクリックします。 キネクトの深度画像ウィンドウが立ち上がり、サーバ側で [SYS] Service: "SIGKINECT" is available と表示されればキネクトサービスの立ち上げに成功です。 それでは"START"ボタンを押してシミュレーションを開始してみましょう。 キネクトの前で体を動かすと骨格が検出され、人間エージェントを操作することができるようになります。 #ref(キネクトによるエージェントの操作(v2.0系)/SIGNi_3.PNG,40%) **ソースコードのコンパイル [#rc3b6fdb] 次にクライアント側ので動くKINECTサービスのソースコードをコンパイルする方法を説明します。コンパイルする環境はVC++2008を前提としています。 ***ソースコード取得 [#j4c23122] [[KINECTサービス]]からソースコードを取得します。 //#ref(SIGNiUserTracker_1-0-0.zip) 展開したフォルダの中に入っているSIGNiUserTrackerフォルダをOpenNIのサンプルコードがおかれた以下のフォルダに移動します。 C:\Program Files (x86)\OpenNI\Samples ***コンパイル [#j1513ff2] 次にSIGNiUserTrackerフォルダの中のソリューションファイルをダブルクリックして起動します。(※このとき必ず管理者権限で実行します) ※バージョン1.0.0の場合はコンパイルにはboostライブラリのインストールが必要です。 boostのインストール方法とVC++の設定方法は省略します。 VC++が起動したらソリューションエクスプローラの中のソリューション名を右クリックしてビルドを選択します。ビルドが成功すると以下に実行ファイルSIGNiUserTracker.exeが作成されます。 C:\Program Files (x86)\OpenNI\Samples\Bin\Release 拡張子を.exeから.sigに変えることによりSIGViewerに登録可能となります。 *Old Version [#g8ea554a] -[[キネクトによるエージェントの操作(v2.0系)]] -[[キネクトによるエージェントの操作(v120330, v1.4.8)]] #highlight(end) ---- Up:[[Tutorial]] Previous:[[眼球運動]] Next: [[HMD+KINECT]] #counter