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

----
#contents

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

**メッセージの送受信 [#v4c148e5]
※This tutorial is valid only for later than v2.1.0.

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

まずメッセージの送信を行うコントローラを作成します。
** Sending and receiving messages [#d353e783]

 $ cd ~/sigverse-<version>/bin/NewWorld
 $ emacs SendController.cpp
*** Controller of message sender [#zd064119]

SendController.cpp
#highlight(cpp){{
#include "Controller.h"
#include "Logger.h"
#include "ControllerEvent.h"
Create a controller for sending messages.

#define PI 3.141592
#define DEG2RAD(DEG) ( (PI) * (DEG) / 180.0 )
#define ARY_SIZE(ARY) ( (int)(sizeof(ARY)/sizeof(ARY[0])) )
 $ cd ~/MyWorld
 $ emacs SendController.cpp

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

void SendController::onInit(InitEvent &evt)
{
  SimObj *my = getObj(myname());
This controller send a message "Hello!" to the robot agent every second.

  //右手、左手を下げ、体全体を180(deg)後ろに回転させます
  my->setJointAngle("LARM_JOINT2", DEG2RAD(-90));
  my->setJointAngle("RARM_JOINT2", DEG2RAD(90));
  my->setAxisAndAngle(0, 1.0, 0, DEG2RAD(180));
}
If you want to send a message to all of the agents in the world, you should use broadcastMsg instead of sendMsg.

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]){{
Old
#highlight(cpp:firstline[38]){{
 sendMsg("robot_000",msg);
}}
         ↓
#highlight(cpp:firstline[33]){{
New
#highlight(cpp:firstline[38]){{
 broadcastMsg(msg);
}}

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

Create a controller to receive messages.

 $ emacs RecvController.cpp

RecvController.cpp

#highlight(cpp){{
#include <string>
#include "Controller.h"
#include "Logger.h"
#include "ControllerEvent.h"
#gist(sigverse-git/dfd3d5c6d9d64180ca9eb8ffba54d544);

#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);
This controller put the agent's hand up if a message "Hello!!" comes.
The agent will put the hand down every 0.5 second.

private:
  bool raise_hand;
};

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

  //上がった手を下げます。
  if(raise_hand)
    my->setJointAngle("LARM_JOINT2", DEG2RAD(0));
 $ ./sigmake.sh SendController.cpp RecvController.cpp

  return 0.5;
}

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

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

  // 文字列を取得
  std::string msg = evt.getMsg();
  LOG_MSG(("message : %s", msg.c_str()));
#gist(sigverse-git/008dee0218d42c41388f7e02a2fe09c5);

  //メッセージが"Hello!!"なら手を上げます
  if(msg == "Hello!!") {
    my->setJointAngle("LARM_JOINT2", DEG2RAD(180));
    raise_hand = true;
  }
}
In this controller, a human avator will send a message to a humanoid agent.

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

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

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

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 $@   $< 
First, the avatar agent put a hand down and turn back by onInit function.
Then, you can see that the agent put it's hand up every second with receiving a message.

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

 $ make

***世界ファイルの作成 [#me49924f]
** Specification of message reachable area [#a22b41bf]

次に世界ファイルを作成します。
This part explains how to specify the maximum length of the reachable area of the message sending function.

 $ cd ..
 $ emacs xml/MessageWorld.xml
*** Controller of text message sender [#we283cc2]

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]
Create another controller to send messages.

起動して見てみましょう。
 $ emacs SendController2.cpp 

 $ ./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])) )
#gist(sigverse-git/8a057f168978dd46bb2c48ae5c912a11);

class SendController : public Controller
{
public:
  //シミュレーション開始時に一度だけ呼出される関数onInitの利用を宣言します
  void onInit(InitEvent &evt);
  double onAction(ActionEvent &evt);
};
The second argument of the broadcastMsg, 300, means that the maximum distance of the message reachable area is 3 meters.
If you omit the secnod argument, the message will be reached to all of the agents irrespective of the distance.

void SendController::onInit(InitEvent &evt)
{
  SimObj *my = getObj(myname());
This agent keeps on sending a message and moving to z-axis.

  //右手、左手を下げ、体全体を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);
*** Compiling [#k7a9b5fc]

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

  //メッセージを作成します
  std::string msg = "Hello!!";
*** Modification of the world file [#s62dc619]

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

  //1秒おきにonActionが呼び出されます
  return 1.0;
}
Modify the MessageWorld.xml to change the controller for sending agent

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

メッセージ送信者コントローラの修正
Old
#highlight(xml:firstline[13]){{
 <!--メッセージ送信者コントローラ指定-->
       <set-attr-value name="implementation"
 value="./NewWorld/SendController.so"/>
       <set-attr-value name="implementation" value="./SendController.so"/>
}}
    ↓

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

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

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

メッセージ送信者が遠ざかりながらメッセージを送信しているのがわかります。
エージェントの声がどこまで届くのか確認してみてください。
You can see the agent sending messages with backing away from the receiver.
Please check how far the message reaches to the receiver.

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

sendMsgを使ってコントローラ同様ビューワーにもメッセージを送信することができます。このときビューワーがサーバに接続する際に指定したサービス名をメッセージ送信先に指定します。
サービス名を"SIGViewer"と設定してサーバに接続した場合はSendMsg関数を以下のように修正します。
** Sending message to the SIGViewer [#sa02f588]
If the broadcastMsg is used, the message will be reached to all of the agents, SIGViewer and SIGVerse services.
The SIGViewer will show the received message as log message.

You can send messages to the SIGViewer using sendMsg.
In this case, you should specify a service name which is determined when the SIGViewer connected to the SIGverse server.
If the service name is "SIGViewer", the following modification will change the sending target from the agent to the SIGViewer.

SendController.so

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



#highlight(end)

*Old Version [#f0b7d8c0]
-[[エージェント間のメッセージのやりとり(v120330, v1.4.8)]]
Up:[[Tutorial]]     Previous:[[Humanoid agent operations]]     Next:[[Vision sensor]]

#counter

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

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


Front page   New List of pages Search Recent changes   Help   RSS of recent changes