Up:[[Tutorial]]     Previous:[[動力学シミュレーションのサンプル]]     Next:[[エージェント間のメッセージのやりとり]]

#contents
*エージェントの動きに関する操作 [#v2485f29]
人間またはロボットの形をしたエージェントの関節の操作方法を説明します。

**関節の操作 [#f5cb7768]
人間が手を上げるサンプルコードを紹介します。
***コントローラの作成 [#oc032119]
NewWorldディレクトリに新しくAgentController.cppを作成します。
 $ cd ~/sigverse-<version>/bin/NewWorld
 $ emacs AgentController.cpp

AgentController.cpp

#highlight(cpp){{
#include "Controller.h"
#include "Logger.h"

#define PI 3.141592

//角度からラジアンに変換します。
#define DEG2RAD(DEG) ( (PI) * (DEG) / 180.0 ) 

class AgentController : public Controller
{
public:
  double onAction(ActionEvent &evt);
}; 


//定期的に呼び出される関数です。
double AgentController::onAction(ActionEvent &evt)
{
  try {
    // 自分自身を得る
    SimObj *my = getObj(myname());
    if (!my->dynamics()) { 

     // "LARM_JOINT2" を45度に設定する
      my->setJointAngle("LARM_JOINT2", DEG2RAD(45));

   }

 } catch(SimObj::Exception &) {
   ;
 }

 return 5.0;
}


extern "C"  Controller * createController ()
{
  return new AgentController;
}
}}
のサンプルはシミュレーション開始と同時に
my->setJointAngleでエージェントの左腕が上に45°に上がるというものです。

***コンパイル [#o78ee00f]
次にMakefileを変更します。

 $ emacs Makefile

変更前
// #自作コード
// CPP_SRCS = MoveController.cpp
// 
 #オブジェクトファイルの指定
 OBJS = MoveController.so
//
変更後
// #自作コード
// CPP_SRCS = AgentController.cpp/
// 

 #オブジェクトファイルの指定
 OBJS = AgentController.so

Makefile

 #SIGVerseソースの場所指定
 SIG_SRC  = /home/<username>/sigverse-<version>/include/sigverse
 
 #オブジェクトファイルの指定
 OBJS     = AgentController.so 
 
 all: $(OBJS)
 
 #コンパイルを行います。
 ./%.so: ./%.cpp
         g++ -DCONTROLLER -DNDEBUG -DUSE_ODE -DdDOUBLE -I$(SIG_SRC) -I$(SIG_SRC)/comm/controller  -fPIC -shared -o $@   $<


コンパイルします。
 $ make

***世界ファイル作成 [#l5dd7972]
次に世界ファイルを作成します。

//SIGVerse起動時に-wオプションで毎回世界ファイルを指定するのは面倒なので、MyWorld.xmlに記述します。

 $ cd ~/sigverse-<version>/bin
 $ ln -s ../share/sigverse/data/xml/ xml
xmlファイルがあるディレクトリまで遠いのでリンクを貼りました。
//$ cp xml/MyWorld.xml xml/MyWorld_org.xml
//念のためデフォルトのMyWorld.xmlファイルを残しておきました。

 $ emacs xml/AgentWorld.xml

AgentWorld.xml
#highlight(xml){{
<?xml version="1.0" encoding="utf8"?>
 <world name="myworld2">
 
 <!--重力の設定-->
   <gravity x="0.0" y="-9.8" z="0.0"/>  
 
 <!--エージェントMan-niiの設定-->
   <instanciate class="Man-nii.xml"> 
 
 <!--エージェント名-->
         <set-attr-value name="name" value="man_000"/> 
 
 <!--C++言語の指定-->
         <set-attr-value name="language" value="c++"/> 
 
 <!--オブジェクトファイルAgentController.soの指定-->
         <set-attr-value name="implementation"
 value="./NewWorld/AgentController.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="50.0"/>
        <set-attr-value name="z" value="0.0"/>
 
  </instanciate>
</world>
}}
エージェントとしてMan-nii.xmlを読み込むように設定し、動力学演算をfalseにしました。動力学演算をtrueにするとエージェントの関節角度などを直接指定することができないので注意が必要です。

***SIGVerse起動 [#g6cf60e0]
それではSIGVerseを起動してみましょう。
 $ ./sigserver.sh -w AgentWorld.xml -p 9001
SIGViewerを起動して見てみると人間のエージェントが手を広げてスタンバイしていると思います。
シミュレーションを開始するとエージェントの左腕が45°上がります。

#ref(man_1.jpg)

今回setJointAngleという関数を用いて"LARM_JOINT2" を45°にする設定を行いました。"LARM_JOINT2"は左肩のz軸での回転として定義された関節の名前です。同様に"LARM_JOINT0","LARM_JOINT1"はそれぞれ左肩のx軸、y軸の回転として定義されています。(エージェント座標系。)これらの関節名はsigverse-<version>/share/sigverse/data/shape/にあるx3dファイル(nii_man.x3d)で定義されています。サンプルモデルのジョイント名は[[Joint定義一覧]]を参照

AgentWorld.xmlファイルはMan-nii.xmlファイルを読み込みMan-nii.xmlファイルは人間型エージェントの形状を記述したnii_man.x3dを読み込んでいます。

**エージェントの属性 [#nb731d79]
***属性の確認 [#g984fed9]
SIGViewerでエージェントをクリックすると右のAttributesタブでエージェントの名前や位置(x,y,z)、エージェントの向き(qw,qx,qy,qz)、視点の位置(epx,epy,epz)などの属性を見ることができます。これらの属性の値はxmlファイルで設定されています。

#ref(attr_1.jpg)


人間型エージェントMan-niiはAgentクラスを継承したオブジェクトです。Agentクラスの属性のデフォルトの値はAgent.xmlで設定されています。見てみましょう。

 $ less xml/Agent.xml

#highlight(xml){{
<?xml version="1.0" encoding="utf8"?>
 
 <define-class name="Agent" inherit="Entity.xml">
 
 <attr name="language" type="string" group="model"/>
 <attr name="implementation" type="string" group="model"/>
 
 
    <!-- view point(agent coordinate) -->
 <attr name="vpx" type="double" group="viewpoint" value="0.0"/>
 <attr name="vpy" type="double" group="viewpoint" value="0.0"/>
 <attr name="vpz" type="double" group="viewpoint" value="0.0"/>
 
    <!-- view vector(view coordinate) -->
 <attr name="vvx" type="double" group="viewvector" value="0.0"/>
 <attr name="vvy" type="double" group="viewvector" value="0.0"/>
 <attr name="vvz" type="double" group="viewvector" value="-1.0"/>
}}
上で見たvpx,vvxなどの値が設定されているのがわかります。
さらにAgentクラスはEntityクラスを継承しています。Entityクラスは自律動作を行わない物体のクラスです。

***エージェント、エンティティの基本的な属性 [#g14c1ee2]
エンティティ、エージェントの基本的な属性を紹介します。

エンティティの属性
|属性名| 意味 | 備考|
|x,y,z|エンティティの位置 |グローバル座標。x軸は原点から緑矢印 ,y軸は赤矢印 z軸は黄色矢印で表示 |
|fx,fy,fz|エンティティにかかる力||
|vx,vy,vz|エンティティの速度||
|qw,qx,qy,qz|エンティティの向き|クオータニオン表記|
|scalex, scaley, scalez|エンティティの大きさ||
|collision|衝突判定フラグ(デフォルトはtrue)||

エージェントの属性
|属性名| 意味 | 備考|
|vpx,vpy,vpz|エージェントの視点の位置(ヒューマノイド以外) |エージェント座標、原点はエージェントの位置|
|vvx,vvy,vvz|視線の方向(ヒューマノイド以外)|ベクトル表記|
|elnk1,elnk2,...elnk9|視点(カメラ)を設置するリンク名(ヒューマノイドのみ)|elnk1はデフォルトでHEAD_LINKに設置されている。|
|epx1,epy1,epz1,...epx9, epy9, epz9|視点(カメラ)の位置(ヒューマノイドのみ)|原点はelnkで指定されたリンクの位置|
|evx1,evy1,evz1,...evx9, evy9, evz9|視点(カメラ)の方向(ヒューマノイドのみ)||
|FOV|エージェントの視野角(高さ)||
|voiceReachRadius|エージェント声が届く範囲||

これらの属性はすべて世界ファイルで設定が行えます。
**コマンドによるエージェントの操作 [#ta077379]
前回は定期的に呼び出されるonActionで手を上げるサンプルコードを紹介しました。次はSIGViewerからのメッセージを送信することによりエージェントがお辞儀をするようなサンプルコードを紹介します。

まずAgentController.cppを変更します。
 $ cd NewWorld
 $ emacs AgentController.cpp

AgetnController.cpp

#highlight(cpp){{
#include <string>  //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);

  // メッセージを受信したときの関数onRecvMessageの利用を宣言します。
  void onRecvMessage(RecvMessageEvent &evt);
};

double AgentController::onAction(ActionEvent &evt)
{
  try {
    SimObj *my = getObj(myname());
    if (!my->dynamics()) { 

      // 左手を下に下げます。
      my->setJointAngle("LARM_JOINT2", DEG2RAD(-90));

      // 右手を下に下げます。
     my->setJointAngle("RARM_JOINT2", DEG2RAD(90));

    }
  } catch(SimObj::Exception &) {
    ;
  }
  return 5.0;
}


void AgentController::onRecvMessage(RecvMessageEvent &evt)
{

  //自分自身の取得
  SimObj *my = getObj(myname());

  //string型のメッセージを取得します。
  string value(evt.getString(0)); 
  if (value =="Hello"){

    //腰の関節を45°曲げます。
    my->setJointAngle("WAIST_JOINT1", DEG2RAD(45));
  } 

}

extern "C"  Controller * createController ()
{
  return new AgentController;
}
}}
onActionで手を下げ、メッセージを受信したときに呼び出される関数onRecvMessageを追加しました。メッセージが"Hello"だったときにお辞儀をします。

コンパイルします。

 $ make

**実行 [#d5c0a11e]
次にエージェントの属性を編集します。

それでは実行してみましょう。
 $ cd ..
 $ ./sigserver.sh -w AgentWorld.xml -p 9001

SIGViewerで接続して、
sendボタンをクリックしてシミュレーションを開始すると、まずonActionが呼び出されて右手と左手を下に下げます。
#ref(man_2.jpg)
***メッセージ送信 [#hb68ba23]

まずSIGViewerの右上にあるCommandタブをクリックします。
一番上の入力欄でvoiceとgeneralが選択できるようになっています。ここではgeneralを選択します。次に送信対象選択ボタンをクリックして画面上のエージェントをクリックします。エージェント名が自動的に入力されると思います。そしてSendMessage引数のところにHelloと入力します。
#ref(man_3.jpg)
入力が完了したら、実行ボタンを押します。
#ref(man_4.jpg)
お辞儀をしました。

**クオータニオンによる関節の回転 [#ecbdc67b]
関節の回転はクオータニオンによって設定することもできます。(※バージョン110223以降で動作)


関節回転箇所を以下のように修正します。

AgentController.cpp

#highlight(cpp:firstline[51]){{
     //腰の関節を45°曲げます。
     my->setJointAngle("WAIST_JOINT1", DEG2RAD(45));
}}
   ↓
#highlight(cpp:firstline[51]){{
    //腰の関節をx軸周りに90°回転させます。
    my->setJointQuaternion("WAIST_JOINT1", 0.707, 0.707, 0.0, 0.0);
}}
setJointQuaternionという関数を使って関節のクオータニオンを設定します。引数で関節名の次にクオータニオンのw,x,y,z成分を指定します。

クオータニオンを指定した場合はあらかじめ設定されている関節の回転軸に関係なく回転します。
正常に関節が回転するか確認してみてください。

#highlight(end)

*更新履歴 [#rb3a986d]
-[[人間型エージェントの操作(v120330, v1.4.8)]]


Up:[[Tutorial]]     Previous:[[動力学シミュレーションのサンプル]]     Next:[[エージェント間のメッセージのやりとり]]

[[English version>Samples/Control of humanoid agent]]

Front page   Edit Diff Backup Upload Copy Rename Reload   New List of pages Search Recent changes   Help   RSS of recent changes