Up:[[Tutorial]] Previous:[[人間型エージェントの操作]] Next:[[視覚に関する操作]] ---- #contents *エージェント間でのメッセージのやり取り [#he80bd53] ※このチュートリアルはv2.1.0以降対応しています。 前回はクライアント(SIGViewer)からエージェントにメッセージを送信し、受信したエージェントはお辞儀をするというサンプルを紹介しました。今回はエージェント間でのやり取りを行うサンプルコードを紹介します。 **メッセージの送受信 [#v4c148e5] ***メッセージ送信者のコントローラ作成 [#pd6017d2] まずSIGVerse作業ディレクトリに移動し、メッセージの送信を行うコントローラを作成します。 $ 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の利用を宣言します 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秒ごとに上がった手を下げようとします。 それではコンパイルします。 $ ./sigmake.sh SendController.cpp RecvController.cpp ***世界ファイルの作成 [#me49924f] 次に世界ファイルを作成します。 $ 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の設定--> <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"/> <!--エージェントの位置(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="./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 SIGViewerで接続して、シミュレーションを開始するとonInitにより、人型エージェント(メッセージ送信者)が手を下して、後ろを振り返ります。そして1秒に一回ロボットが人間エージェントからメッセージを受信して手を挙げているのがわかります。 #ref(エージェント間のメッセージのやりとり(v2.0系)/mess_1.PNG,40%) **メッセージ送信範囲の指定 [#a561e72f] 次にメッセージ送信時にメッセージが届く範囲を指定するサンプルを紹介します。 ***テキスト送信者のコントローラ作成 [#wb648f75] メッセージを送信するコントローラを新しく作成します。 $ 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] コンパイルします。 $ ./sigmake.sh SendController2.cpp ***世界ファイルの編集 [#m7f88908] 次に世界ファイルを変更します。 $ emacs MessageWorld.xml MessageWorld.xml メッセージ送信者コントローラの修正 #highlight(xml:firstline[13]){{ <!--メッセージ送信者コントローラ指定--> <set-attr-value name="implementation" value="./SendController.so"/> }} ↓ #highlight(xml:firstline[13]){{ <!--メッセージ送信者コントローラ指定--> <set-attr-value name="implementation" value="./SendController2.so"/> }} ***起動 [#o073f136] それでは実行してみます。 $ sigserver.sh -w ./MessageWorld.xml SIGVierwerで接続して、シミュレーションを開始してみます。 #ref(エージェント間のメッセージのやりとり(v2.0系)/mess_3.PNG,40%) メッセージ送信者が遠ざかりながらメッセージを送信しているのがわかります。 エージェントのメッセージがどこまで届くのか確認してみてください。 **ビューワーへメッセージ送信 [#bb25270a] broadcastMsgを使用した場合、すべてのエンティティ、ビューワー、サービスにメッセージが届きます。メッセージを受信したビューワーはメッセージログとして表示します。 sendMsgを使ってコントローラ同様ビューワーにもメッセージを送信することができます。このときビューワーがサーバに接続する際に指定したサービス名をメッセージ送信先に指定します。 サービス名を"SIGViewer"と設定してサーバに接続した場合はSendMsg関数を以下のように修正します。 SendController.so #highlight(cpp:firstline[33]){{ sendMsg("robot_000",msg); }} ↓ #highlight(cpp:firstline[33]){{ sendMsg("SIGViewer",msg); }} #highlight(end) *Old Version [#f0b7d8c0] -[[エージェント間のメッセージのやりとり(v2.0系)]] -[[エージェント間のメッセージのやりとり(v120330, v1.4.8)]] -------- Up:[[Tutorial]] Previous:[[人間型エージェントの操作]] Next:[[視覚に関する操作]] [[English version>Samples/Communication between agents]]