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".
$ 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
$ 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
$ ./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.
You can check the contents of the messages with clicking the message tab. Name of sender, number of characters and the contents are displayed.
文字列の数(# of string)は1と表示されましたが、メッセージ作成時に以下のようにすることで、文字列は同時に複数送ることもできます。
//メッセージを作成します。 char *strs[] = { "Hello!!", "How are you", };
次にエージェント間でのテキスト文字列の送受信について説明します。テキスト文字列は人間が声を出すのと同じように、自分の声が届く範囲を指定することができます。
まずはテキストを送信するコントローラを作成します。
$ cd NewWorld $ emacs 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で接続して、シミュレーションを開始してみます。
テキスト送信者が遠ざかりながらテキストを送信しているのがわかります。 エージェントの声がどこまで届くのか確認してみてください。
Japanese?