Tutorial?

エージェント間でのメッセージのやり取り

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

メッセージ送信者のコントローラ作成

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

$ emacs SendController.cpp

SendController.cpp

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

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

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

  //メッセージを送信します。
  broadcastMessage(ARY_SIZE(strs),strs);

  //5秒置きにメッセージを送信します。
  return 5.0;
}

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

これは5秒置きにメッセージ"Hello!"を送信するコントローラのサンプルです。broadcastMessageではエージェント全員にメッセージを送信します。

メッセージを送る相手を指定したいときはbroadcastMessageの代わりにsendMessageを用いて以下のように、メッセージを送る相手を指定します。

broadcastMessage(ARY_SIZE(strs),strs);

         ↓

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

メッセージ受信者のコントローラ作成

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

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

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


double RecvController::onAction(ActionEvent &evt)
{
  SimObj *my = getObj(myname());
  if (!my->dynamics()) {
    
     //上がった手を下げます。
     my->setJointAngle("LARM_JOINT2", DEG2RAD(0));
  }
  return 1.0;
}

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

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

 // getSize で送られてきた文字列数を取得する
 int n = evt.getSize();
 LOG_MSG(("# of string : %d", n));
 for (int i=0; i<n; i++) {

   // 文字列を順に取得する
   LOG_MSG(("string[%d] : %s", i, evt.getString(i)));

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

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

これはメッセージを受信したら手を上げるというサンプルです。また、onActionで1秒ごとに上がった手を下げようとします。

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

$ make

世界ファイルの作成

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

$ cd ..
$ emacs xml/MyWorld.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++"/>

<!--オブジェクトファイルSendController.soの指定-->
        <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++"/>

<!--オブジェクトファイルRecvController.soの指定-->
        <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>

人型エージェントが、ヒューマノイド型エージェントにメッセージを送信します。

起動

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

$ ./sigserver.sh -p 9001

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

mess_1.jpg

SIGViewerの下のほうにあるmessagesタブをクリックします。するとロボットがメッセージに反応して送信者と、文字列数、とその内容が表示されます。

mess_2.jpg

文字列は同時に複数送ることができます。送信者コントローラのメッセージ作成時に以下のように記述します。

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

エージェント間でのテキスト文字列の送受信

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

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


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