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

*エージェント間でのメッセージのやり取り [#he80bd53]
* Exchange of messages between agents. [#ia7882aa]

※このチュートリアルはv2.1.0以降対応しています。
※This tutorial is valid only for later than v2.1.0.

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

**メッセージの送受信 [#v4c148e5]
** Sending and receiving messages [#d353e783]

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

まずSIGVerse作業ディレクトリに移動し、メッセージの送信を行うコントローラを作成します。
Create a controller for sending messages.

 $ cd ~/MyWorld
 $ 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の利用を宣言します
  // Initialization of the controller
  void onInit(InitEvent &evt);
  double onAction(ActionEvent &evt);
};

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

  //右手、左手を下げ、体全体を180(deg)後ろに回転させます
  //Putting the both hands down; rorating the body 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)
{
  //メッセージを作成します
  // Message to be sent
  std::string msg = "Hello!!";

  //"robot_000"にメッセージを送信します
  // Sending the message to an agent "robot_000"
  sendMsg("robot_000", msg);

  //1秒おきにonActionが呼び出されます
  // onAction will be called again after 1 second
  return 1.0;
}

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

全エンティティ(ビューワーなどのサービスも含む)にメッセージを送信する場合はsendMsgの代わりにbroadcastMsgを用います。
This controller send a message "Hello!" to the robot agent every second.

If you want to send a message to all of the agents in the world, you should use broadcastMsg instead of sendMsg.

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

#define PI 3.141592
#define DEG2RAD(DEG) ( (PI) * (DEG) / 180.0 )

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

  //メッセージ受信時に呼び出される関数onRecvMsgの利用を宣言します
  // Registrate of a callback function onRecvMsg, which will be called when a message comes
  void onRecvMsg(RecvMsgEvent &evt);

private:
  bool raise_hand;
};

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

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

  return 0.5;
}

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

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

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

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

extern "C"  Controller * createController ()
{
  return new RecvController;
}
}}
これはメッセージを受信したら手を上げるというサンプルです。また、onActionで0.5秒ごとに上がった手を下げようとします。
This controller put the agent's hand up if a message "Hello!!" comes.
The agent will put the hand down every 0.5 second.

それではコンパイルします。

Compiling the controller.

 $ ./sigmake.sh SendController.cpp RecvController.cpp

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

次に世界ファイルを作成します。
*** Creating a worldfile [#w395fedb]

 $ emacs 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の設定-->
 <!--Setting of an avatar agent Man-nii who sends messages-->
   <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="./SendController.so"/>
 <!--setting of a controller for the avatar agent-->
         <set-attr-value name="implementation" value="./SendController.so"/>
 
 <!--エージェントの位置(x,y,z)-->
 <!--setting the initial position of the avatar agent (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の設定-->
 <!--setting of a humanoid agent Robot-nii who receives messages-->
   <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="./RecvController.so"/>
 <!--setting of a controller for the humanoid (receiver) agent-->
         <set-attr-value name="implementation" value="./RecvController.so"/>
 
 <!--動力学演算をfalseに設定-->
 <!--put the flag of dynamics to false-->
         <set-attr-value name="dynamics" value="false"/>
 
 <!--エージェントの位置(x,y,z)-->
 <!--setting the initial position of the humanoid agent (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]
In this controller, a human avator will send a message to a humanoid agent.

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

*** Execution [#tb38ac14]

 $ sigserver.sh -w ./MessageWorld.xml 

SIGViewerで接続して、シミュレーションを開始するとonInitにより、人型エージェント(メッセージ送信者)が手を下して、後ろを振り返ります。そして1秒に一回ロボットが人間エージェントからメッセージを受信して手を挙げているのがわかります。
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(エージェント間のメッセージのやりとり(v2.0系)/mess_1.PNG,40%)
#ref(./mess_1.PNG,40%)

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

次にメッセージ送信時にメッセージが届く範囲を指定するサンプルを紹介します。
** Specification of message reachable area [#a22b41bf]

***テキスト送信者のコントローラ作成 [#wb648f75]
メッセージを送信するコントローラを新しく作成します。
This part explains how to specify the maximum length of the reachable area of the message sending function.

*** Controller of text message sender [#we283cc2]

Create another controller to send messages.

 $ 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)後ろに回転させます
  // Putting the both hands and rotate the body 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移動します
  // Moving 20 to z-axis
  my->setPosition( vec.x(), vec.y(), vec.z() + 20 );

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

  //半径3m以内のすべてのエージェントに対してメッセージを送信します
  // Broadcasting the message to all of the agents within 3-meter radius from the agent
  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方向にどんどん移動しながらテキストを送信します。つまりメッセージを受信するエージェントからはどんどん遠ざかりながらテキストを送信します。
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.

This agent keeps on sending a message and moving to z-axis.

***コンパイル [#bbf536df]
コンパイルします。

 $ ./sigmake.sh SendController2.cpp

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

次に世界ファイルを変更します。
 $ ./sigmake.sh SendController2.cpp

*** Modification of the world file [#s62dc619]

 $ emacs MessageWorld.xml

MessageWorld.xml
Modify the MessageWorld.xml to change the controller for sending agent

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

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

 $ sigserver.sh -w ./MessageWorld.xml

SIGVierwerで接続して、シミュレーションを開始してみます。
#ref(エージェント間のメッセージのやりとり(v2.0系)/mess_3.PNG,40%)
#ref(./mess_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]
-[[エージェント間のメッセージのやりとり(v2.0系)]]
-[[エージェント間のメッセージのやりとり(v120330, v1.4.8)]]


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

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


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