Up:[[Tutorial]]     Previous:[[人間型エージェントの操作]]     Next:[[視覚に関する操作]]
----
#contents

*エージェント間でのメッセージのやり取り [#he80bd53]
前回はクライアント(SIGViewer)からエージェントにメッセージを送信し、受信したエージェントはお辞儀をするというサンプルを紹介しました。今回はエージェント間でのやり取りを行うサンプルコードを紹介します。

**メッセージの送受信 [#v4c148e5]

***メッセージ送信者のコントローラ作成 [#pd6017d2]

まずメッセージの送信を行うコントローラを作成します。

 $ cd ~/sigverse-<version>/bin/NewWorld
 $ emacs SendController.cpp

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

#define PI 3.141592
#define DEG2RAD(DEG) ( (PI) * (DEG) / 180.0 )
#define ARY_SIZE(ARY) ( (int)(sizeof(ARY)/sizeof(ARY[0])) )

class SendController : public Controller
{
public:
  //シミュレーション開始時に一度だけ呼出される関数onInitの利用を宣言します
  void onInit(InitEvent &evt);
  double onAction(ActionEvent &evt);
};

void SendController::onInit(InitEvent &evt)
{
  SimObj *my = getObj(myname());

  //右手、左手を下げ、体全体を180(deg)後ろに回転させます
  my->setJointAngle("LARM_JOINT2", DEG2RAD(-90));
  my->setJointAngle("RARM_JOINT2", DEG2RAD(90));
  my->setAxisAndAngle(0, 1.0, 0, DEG2RAD(180));
}

double SendController::onAction(ActionEvent &evt)
{
  //メッセージを作成します
  std::string msg = "Hello!!";

  //"robot_000"にメッセージを送信します
  sendMsg("robot_000", msg);

  //1秒おきにonActionが呼び出されます
  return 1.0;
}

extern "C"  Controller * createController ()
{
  return new SendController;
}
}}
これは1秒おきにメッセージ"Hello!"を送信するコントローラのサンプルです。sendMsgでは最初の引数で送信先のエージェント名を指定します。

全エンティティ(ビューワーなどのサービスも含む)にメッセージを送信する場合はsendMsgの代わりにbroadcastMsgを用います。

#highlight(cpp:firstline[33]){{
 sendMsg("robot_000",msg);
}}
         ↓
#highlight(cpp:firstline[33]){{
 broadcastMsg(msg);
}}

***メッセージ受信者のコントローラ作成 [#sb6efc03]
次にメッセージの受信を行うエージェントコントローラを作成します。

 $ emacs RecvController.cpp

RecvController.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 )

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

  //メッセージ受信時に呼び出される関数onRecvMsgの利用を宣言します
  void onRecvMsg(RecvMsgEvent &evt);

private:
  bool raise_hand;
};

double RecvController::onAction(ActionEvent &evt)
{
  SimObj *my = getObj(myname());

  //上がった手を下げます。
  if(raise_hand)
    my->setJointAngle("LARM_JOINT2", DEG2RAD(0));

  return 0.5;
}

//メッセージ受信時
void RecvController::onRecvMsg(RecvMsgEvent &evt)
{
  //自分自身の取得
  SimObj *my = getObj(myname());

  // メッセージの送り主表示
  std::string sender = evt.getSender();
  LOG_MSG(("sender : %s", sender.c_str()));

  // 文字列を取得
  std::string msg = evt.getMsg();
  LOG_MSG(("message : %s", msg.c_str()));

  //メッセージが"Hello!!"なら手を上げます
  if(msg == "Hello!!") {
    my->setJointAngle("LARM_JOINT2", DEG2RAD(180));
    raise_hand = true;
  }
}

extern "C"  Controller * createController ()
{
  return new RecvController;
}
}}
これはメッセージを受信したら手を上げるというサンプルです。また、onActionで0.5秒ごとに上がった手を下げようとします。

それではコンパイルします。
まずMakefileに新しく作成したコントローラを追加します。
 $ emacs Makefile

変更後
 #オブジェクトファイルの指定
 OBJS     = SendController.so RecvController.so
共有オブジェクトにSendController.so, RecvController.soの2つを追加しました。

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


 $ make

***世界ファイルの作成 [#me49924f]

次に世界ファイルを作成します。

 $ cd ..
 $ emacs xml/MessageWorld.xml

MessageWorld.xml
#highlight(xml){{
<?xml version="1.0" encoding="utf8"?>
 <world name="myworld3">
 
   <gravity x="0.0" y="-980.7" z="0.0"/>
 
 <!--メッセージ送信エージェントMan-niiの設定-->
   <instanciate class="Man-nii.xml">
         <set-attr-value name="name" value="man_000"/>
         <set-attr-value name="dynamics" value="false"/>
         <set-attr-value name="language" value="c++"/>
 
 <!--メッセージ送信者のコントローラ指定-->
         <set-attr-value name="implementation"
 value="./NewWorld/SendController.so"/>
 
 <!--エージェントの位置(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="60.0"/>
 
   </instanciate>
 
 
 <!--メッセージ受信エージェントRobot-niiの設定-->
   <instanciate class="Robot-nii.xml">
 
         <set-attr-value name="name" value="robot_000"/>
         <set-attr-value name="language" value="c++"/>
 
 <!--メッセージ受信者のコントローラ指定-->
         <set-attr-value name="implementation"
 value="./NewWorld/RecvController.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="-60.0"/>
  
  </instanciate>
</world>
}}
人型エージェントが、ヒューマノイド型エージェントにメッセージを送信します。
***起動 [#k2bccc17]

起動して見てみましょう。

 $ ./sigserver.sh -w MessageWorld.xml -p 9001

SIGViewerで接続して、シミュレーションを開始するとonInitにより、人型エージェント(メッセージ送信者)が手を下して、後ろを振り返ります。そして1秒に一回ロボットが人間エージェントからメッセージを受信して手を挙げているのがわかります。

#ref(./mess_1.PNG,40%)

**メッセージ送信範囲の指定 [#a561e72f]

次にメッセージ送信時にメッセージが届く範囲を指定するサンプルを紹介します。

***テキスト送信者のコントローラ作成 [#wb648f75]
メッセージを送信するコントローラを新しく作成します。

 $ cd NewWorld
 $ emacs SendController2.cpp

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

#define PI 3.141592
#define DEG2RAD(DEG) ( (PI) * (DEG) / 180.0 )
#define ARY_SIZE(ARY) ( (int)(sizeof(ARY)/sizeof(ARY[0])) )

class SendController : public Controller
{
public:
  //シミュレーション開始時に一度だけ呼出される関数onInitの利用を宣言します
  void onInit(InitEvent &evt);
  double onAction(ActionEvent &evt);
};

void SendController::onInit(InitEvent &evt)
{
  SimObj *my = getObj(myname());

  //右手、左手を下げ、体全体を180(deg)後ろに回転させます
  my->setJointAngle("LARM_JOINT2", DEG2RAD(-90));
  my->setJointAngle("RARM_JOINT2", DEG2RAD(90));
  my->setAxisAndAngle(0, 1.0, 0, DEG2RAD(180));
}

double SendController::onAction(ActionEvent &evt)
{
  SimObj *my = getObj(myname());

  //自分の位置を得ます
  Vector3d vec;
  my->getPosition(vec);

  //z方向に20移動します
  my->setPosition( vec.x(), vec.y(), vec.z() + 20 );

  //メッセージを作成します
  std::string msg = "Hello!!";

  //半径3m以内のすべてのエージェントに対してメッセージを送信します
  broadcastMsg(msg, 300.0);

  //1秒おきにonActionが呼び出されます
  return 1.0;
}

extern "C"  Controller * createController ()
{
  return new SendController;
}
}}
こちらも先ほどのサンプルと同様1秒に1回"Hello!!"を送信するコントローラです。broadcastMsgの2番目の引数が300.0とすることによりメッセージが届く範囲を3mに指定しました。2番目の引数を指定しない場合は距離に関係なくメッセージが届きます。

このエージェントはz方向にどんどん移動しながらテキストを送信します。つまりメッセージを受信するエージェントからはどんどん遠ざかりながらテキストを送信します。


***コンパイル [#bbf536df]

MakefileにSendController2.soを追加してコンパイルします

 $ emacs Makefile
 
変更前
 #オブジェクトファイルの指定
 OBJS     = SendController.so RecvController.so

変更後
 #オブジェクトファイルの指定
 OBJS     = SendController.so RecvController.so SendController2.so


 $ make

***世界ファイルの編集 [#m7f88908]

次に世界ファイルを変更します。

 $ cd ..
 $ emacs xml/MessageWorld.xml

MessageWorld.xml

メッセージ送信者コントローラの修正
#highlight(xml:firstline[13]){{
 <!--メッセージ送信者コントローラ指定-->
       <set-attr-value name="implementation"
 value="./NewWorld/SendController.so"/>
}}
    ↓
#highlight(xml:firstline[13]){{        
 <!--メッセージ送信者コントローラ指定-->
       <set-attr-value name="implementation"
 value="./NewWorld/SendController2.so"/>
}}
 
***起動 [#o073f136]
それでは実行してみます。

 $ ./sigserver.sh -w MessageWorld.xml -p 9001

SIGVierwerで接続して、シミュレーションを開始してみます。
#ref(./mess_3.PNG,40%)

メッセージ送信者が遠ざかりながらメッセージを送信しているのがわかります。
エージェントの声がどこまで届くのか確認してみてください。

**ビューワーへメッセージ送信 [#bb25270a]
broadcastMsgを使用した場合ビューワーにもメッセージが届きます。メッセージを受信したビューワーはメッセージログとして表示します。

sendMsgを使ってコントローラ同様ビューワーにもメッセージを送信することができます。このときビューワーがサーバに接続する際に指定したサービス名をメッセージ送信先に指定します。
サービス名を"SIGViewer"と設定してサーバに接続した場合はSendMsg関数を以下のように修正します。

SendController.so

#highlight(cpp:firstline[33]){{
 sendMsg("robot_000",msg);
}}
         ↓
#highlight(cpp:firstline[33]){{
 broadcastMsg("SIGViewer",msg);
 sendMsg("SIGViewer",msg);
}}



#highlight(end)

*Old Version [#f0b7d8c0]
-[[エージェント間のメッセージのやりとり(v120330, v1.4.8)]]


--------
Up:[[Tutorial]]     Previous:[[人間型エージェントの操作]]     Next:[[視覚に関する操作]]

[[English version>Samples/Communication between agents]]

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