Communication between agents

Sending and receiving messages

Controller to send and receive messages

First, create controller to send message

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

SendController.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:

 //Set of onInit function which is called only once at the initial phase.
  void onInit(InitEvent &evt);
  double onAction(ActionEvent &evt);
}; 

void SendController::onInit(InitEvent &evt)
{
  SimObj *my = getObj(myname());
  if (!my->dynamics()) {
    
    //右手、左手を下げ、体全体を180°後ろに回転させます。
     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)
{

  //Create message
  char *strs[] = {
    "Hello!!",
  };

  //Broadcast messages to all of the agents
  broadcastMessage(ARY_SIZE(strs),strs);

  //Time cycle of the sending message is 5 seconds
  return 5.0;
}

extern "C"  Controller * createController ()
{
  return new SendController;
}

This controller broadcast the message "Hello!" to all of the agents in every 5 seconds.

If you want to send message to a specific target, you can use sendMessage instead of broadcastMessage.

broadcastMessage(ARY_SIZE(strs),strs);

         ↓

sendMessaage("robot_000",ARY_SIZE(strs), strs);

In this example, the target of message sending was set as "robot_000".

Creation of controller of receiving messages

$ emacs RecvController.cpp

RecvController.cpp

#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);

  //Definition of onRecvMessage which is called when the agent receiving messages
  void onRecvMessage(RecvMessageEvent &evt);
};


double RecvController::onAction(ActionEvent &evt)
{
  SimObj *my = getObj(myname());
  if (!my->dynamics()) {
    
     //Let down the holding hand
     my->setJointAngle("LARM_JOINT2", DEG2RAD(0));
  }
  return 1.0;
}

//Receiving messages
void RecvController::onRecvMessage(RecvMessageEvent &evt)
{
 SimObj *my = getObj(myname());

 // print the name of the message sender
 LOG_MSG(("sender : %s", evt.getSender()));

 int n = evt.getSize();
 LOG_MSG(("# of string : %d", n));
 for (int i=0; i<n; i++) {

   // print out the messages
   LOG_MSG(("string[%d] : %s", i, evt.getString(i)));

   // Hold hand
   if (!my->dynamics() ) {
     my->setJointAngle("LARM_JOINT2", DEG2RAD(180));
   }
 } 
}

extern "C"  Controller * createController ()
{
  return new RecvController;
}

In this example, the agent hold its hand when it receives messages. The agent also downs hand in every 1 second by onAction.

Modify Makefile to compile this controller

$ emacs Makefile

Change

OBJS     = AgentController.so

into

OBJS     = SendController.so RecvController.so

SendController.so and RecvController.so are specified.

$ make

Creation of world file

$ cd ..
$ emacs xml/MessageWorld.xml

MessageWorld.xml

<?xml version="1.0" encoding="utf8"?>
<world name="VisTest2">

  <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"/>
        <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>

Human avatar agent sends messages to Humanoid robot agent

Execution

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

The human avatar agent (sender) down its hands and looks behind. Next, humanoid robot agent (receiver) should hold its hand with receiving messages.

mess_1.jpg

You can check the contents of the messages with clicking the message tab. Name of sender, number of characters and the contents are displayed.

mess_2.jpg

文字列の数(# of string)は1と表示されましたが、メッセージ作成時に以下のようにすることで、文字列は同時に複数送ることもできます。

  //メッセージを作成します。
  char *strs[] = {
    "Hello!!",
    "How are you",
  };

テキスト文字列の送受信

次にエージェント間でのテキスト文字列の送受信について説明します。テキスト文字列は人間が声を出すのと同じように、自分の声が届く範囲を指定することができます。

テキスト送信者のコントローラ作成

まずはテキストを送信するコントローラを作成します。

$ cd NewWorld
$ emacs SendText.cpp

SendText.cpp

#include "Controller.h"
#include "Logger.h"
#include "ControllerEvent.h"

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


class SendController : public Controller
{
public:
  void onInit(InitEvent &evt);
  double onAction(ActionEvent &evt);
};

void SendController::onInit(InitEvent &evt)
{
  SimObj *my = getObj(myname());
  if (!my->dynamics()) {
    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)
{

  try
  {
    SimObj *my = getObj(myname());

    //自分の位置を得ます。
     double x = my->x();
    double y = my->y();
    double z = my->z();

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

    //半径300.0以内のすべてのエージェントに対してテキスト"Hello!"を送ります。
    sendText(evt.time(), NULL, "Hello!", 300.0); 

  }catch(SimObj::Exception &) {
    ;
  }
  //3秒後にonActionが呼び出されます。
  return 3.0;
} 


extern "C"  Controller * createController ()
{
  return new SendController;
}

これは3秒に1回テキスト"Hello!"を送信するコントローラです。sendText関数でテキストを送信します。sendTextの2番目の引数がNULL、4番目の引数が300.0となっています。こうすることにより、テキストを送信する相手を指定せず、周囲300(cm)にいるすべてのエージェントにテキストを送信します。テキストを送信する相手を指定したい場合は2番目の引数に指定するエージェントの名前を入力します。

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

テキスト受信者のコントローラ作成

テキスト受信者のコントローラを作成します。

$ emacs RecvText.cpp

RecvText.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);

  //テキスト受信時に呼出される関数onRecvTextの利用を宣言します。
  void onRecvText(RecvTextEvent &evt);
};


double RecvController::onAction(ActionEvent &evt)
{
  SimObj *my = getObj(myname());
  if (!my->dynamics()) {
     my->setJointAngle("LARM_JOINT2", DEG2RAD(0));
  }
  return 1.0;
}

//テキスト受信時
void RecvController::onRecvText(RecvTextEvent &evt)
{
  //自分自身を取得します。
  SimObj *my = getObj(myname());

  // テキストの送り主を取得します。
  const char *caller = evt.getCaller();

  //テキストの内容を取得します。
  const char *text = evt.getText();

  //送り主と内容を表示します。
  LOG_MSG(("receive from %s : \"%s\"", caller, text));

  //手を挙げます。
  if (!my->dynamics()) {
    my->setJointAngle("LARM_JOINT2", DEG2RAD(180));
  }

}

extern "C"  Controller * createController ()
{
  return new RecvController;
}

先ほどと同様にテキスト受信時に手を上げます。

コンパイル

コンパイルします。

$ emacs Makefile

変更前

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

変更後

#オブジェクトファイルの指定
OBJS     = SendText.so RecvText.so
$ make

世界ファイルの編集

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

$ cd ..
$ emacs xml/MessageWorld.xml

変更前

            :
<!--メッセージ送信者コントローラ指定-->
      <set-attr-value name="implementation"
value="./NewWorld/SendController.so"/>
           :
<!--メッセージ受信者コントローラ指定-->
        <set-attr-value name="implementation"
value="./NewWorld/RecvController.so"/>
           :

変更後

             :
<!--メッセージ送信者コントローラ指定-->
      <set-attr-value name="implementation"
value="./NewWorld/SendText.so"/>
           :
<!--メッセージ受信者コントローラ指定-->
        <set-attr-value name="implementation"
value="./NewWorld/RecvText.so"/>
           :

起動

それでは実行してみます。

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

SIGVierwerで接続して、シミュレーションを開始してみます。

mess_3.jpg

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

戻る?
次へ

Japanese?


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