Up:[[Tutorial]]     Previous:[[エージェント視点の画像取得]]     Next:[[物体を持つ動作]]
Up:[[Tutorial]]     Previous:[[Image capture from agent's perspective]]     Next:[[Grasping Function]]
-----

#contents
*エージェントの衝突 [#faf7135a]
ここではエージェントが衝突したときに衝突したエンティティを検出してUターンするサンプルを紹介します。

**コントローラ作成 [#b16b5ba2]
 $ cd ~/sigverse-<version>/bin/NewWorld
 $ emacs Colli.cpp
* Collision detection [#kb473d90]

Colli.cpp
A sample code in this tutorial make the agent detect collision event and turn around after the collision detection. 


** Creation of controller [#r1eb9ebf]

 $ cd ~/MyWorld
 $ emacs Collision.cpp

Collision.cpp

#highlight(cpp){{
#include "Controller.h"
#include "ControllerEvent.h"
#include "Logger.h"
#include "math.h"

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

using namespace std;

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

  void onInit(InitEvent &evt);

  //衝突時に呼出される関数onCollisionの利用を宣言します。
  // Callback function when the collision event happens
  void onCollision(CollisionEvent &evt);

private:

  //衝突フラグ
  bool Colli;
  int Colli_cnt;
  bool   Colli;
  int    Colli_cnt;
  double vel;
};

void AgentController::onInit(InitEvent &evt)
{
  Colli = false;
  Colli_cnt = 0;

  //"robot_000"の速度設定
  // Velocity of the "robot_000"
  if(strstr(myname() , "000")!= NULL)
    {
      vel = 5;
    }

  //"robot_001"の速度設定
  // Velocity of the "robot_001"
  else  if(strstr(myname() , "001")!= NULL)
    {
      vel = 7;
    }
  else
    vel = 0;
}
//衝突時に呼び出されます。

// Called when the collision is detected
void AgentController::onCollision(CollisionEvent &evt) {

  if (Colli == false && Colli_cnt == 0){

    const vector<string> & wname= evt.getWith();        // 衝突相手の名前を得る。
    const vector<string> & wparts = evt.getWithParts();  // 衝突した相手のパーツを得る
    const vector<string> & mparts = evt.getMyParts();    // 衝突した自分のパーツを得る
    const vector<string> & wname  = evt.getWith();       // Get a name of the other
    const vector<string> & wparts = evt.getWithParts();  // Get a parts name of the other's collision point
    const vector<string> & mparts = evt.getMyParts();    // Get a parts of collision point of myself

    for(int i = 0; i < wname.size(); i++)
      {
      //衝突相手の名前表示します。
      // Print the name of the other
      LOG_MSG(("\"%s\"", wname[i].c_str()));
      LOG_MSG(("\"%s\"", wparts[i].c_str()));
      LOG_MSG(("\"%s\"", mparts[i].c_str()));

      //LOG_MSG(("\"%s\"", myParts));
      SimObj *my = getObj(myname());

      // 自分のy軸周りの回転を得ます(クオータニオン)
      // Refer rotation (quaternion) around y-axis
      double qy = my->qy();

      //クオータニオンから回転角を導出します
      // Calculate joint angle from the quaternion
      double theta = 2*asin(qy);

      double dy = theta + DEG2RAD(-180);
      if (dy <= -PI) {
        dy = -1*dy - PI;
      }

      my->setAxisAndAngle(0, 1.0, 0, dy);
      Colli = true;
      Colli_cnt = 3;
    }
  }
}

double AgentController::onAction(ActionEvent &evt) {

  try {

    Controller * con;
    //SimObj *my1 = con->getObj(myname());
    SimObj *my = getObj(myname());

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

    //y軸周りの自分の回転を得ます。(クオータニオン)
    // Refer rotation (quaternion) around y-axis

    double qy = my->qy();

    //クオータニオンから回転角を導出します。
    // Calculate joint angle from the quaternion
    double theta = 2*asin(qy);

    double dx = 0;
    double dz = 0;

    //移動する方向を決定します。
    // Determine the moving direction
    dx = sin(theta) * vel;
    dz = cos(theta) * vel;

    //移動します。
    // Execute the movement
    my->setPosition( x + dx, y , z + dz );

    if (Colli_cnt > 0)
      {
        if (--Colli_cnt <=0)
          Colli = false;
      }

  } catch (SimObj::Exception &) {
  }

  return 0.5;

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



}}

This controller displays the name of other's agent name if a collision event is detected. After the collision detection, the agent will change the moving direction (making U-turn).
The callback function onCollision is called in the collision event. The function onAction keeps going forward to the current direction.
In this world file, two agents appear and they have different velocity.

このサンプルコードは衝突を検出したら衝突した相手のエンティティ名を表示して、Uターンするというものです。衝突時に関数onCollisionが呼び出され、体を180°後ろに体を回転させます。onActionでは常に自分の向いている方向に進みます。また、このサンプルコードは2体のロボットが登場することを想定して、2体のロボットにそれぞれ違った速度を設定しています。
** World file [#mfe1a036]

MakefileにColli.soを追加してコンパイルします。
Create a world file.

**世界ファイルの作成 [#v96d9bc1]
世界ファイルを作成します。
 $ cd ..
 $ emacs xml/ColliWorld.xml
 $ emacs ./CollisionWorld.xml

ColliWorld.xml
CollisionWorld.xml

#highlight(xml){{
<?xml version="1.0" encoding="utf8"?>
<world name="myworld8">

  <gravity x="0.0" y="-980.7" z="0.0"/>
  <instanciate class="Robot-nii.xml">
    <!--エージェント名-->
    <!-- Name of the first agent -->
    <set-attr-value name="name" value="robot_000"/>
    <set-attr-value name="language" value="c++"/>

    <!--オブジェクトファイルColli.soの指定-->
    <!-- Controller file-->
    <set-attr-value name="implementation"
                    value="./NewWorld/Colli.so"/>
                    value="./Collision.so"/>
    <set-attr-value name="dynamics" value="false"/>

    <!--エージェントの位置-->
    <!-- Position of the first agent -->
    <set-attr-value name="x" value="90.0"/>
    <set-attr-value name="y" value="60.0"/>
    <set-attr-value name="z" value="-90.0"/>

    <!--エージェントの向き(x,y,z)  -->
    <!-- Direction of the first agent (x,y,z)  -->
    <set-attr-value name="qw" value="0.707"/>
    <set-attr-value name="qx" value="0.0"/>
    <set-attr-value name="qy" value="-0.707"/>
    <set-attr-value name="qz" value="0.0"/>

    <!--衝突判定を行うためcollisionフラグをtrueにします  -->
    <!-- Set the flag of collision detection function to true -->
    <set-attr-value name="collision" value="true"/>
  </instanciate>

  <instanciate class="Robot-nii.xml">
    <!--エージェント名-->
    <!-- Name of the second agent -->
    <set-attr-value name="name" value="robot_001"/>
    <set-attr-value name="language" value="c++"/>

    <!--オブジェクトファイルColli.soの指定-->
    <!-- Controller file-->
    <set-attr-value name="implementation"
                    value="./NewWorld/Colli.so"/>
                    value="./Collision.so"/>
    <set-attr-value name="dynamics" value="false"/>

    <!--エージェントの位置-->
    <!-- Position of the second agent -->
    <set-attr-value name="x" value="30.0"/>
    <set-attr-value name="y" value="60.0"/>
    <set-attr-value name="z" value="-90.0"/>

    <!--エージェントの向き(x,y,z)  -->
    <!-- Orientation of the second agent (x,y,z)  -->
    <set-attr-value name="qw" value="0.707"/>
    <set-attr-value name="qx" value="0.0"/>
    <set-attr-value name="qy" value="-0.707"/>
    <set-attr-value name="qz" value="0.0"/>

    <!--衝突判定を行うためcollisionフラグをtrueにします-->
    <!-- Set the flag of collision detection function to true -->
    <set-attr-value name="collision" value="true"/>
  </instanciate>


  <!--エージェントMan-niiの設定-->
  <!-- Configuration of a human agent Man-nii -->
  <instanciate class="Man-nii.xml">

    <!--エージェント名-->
    <!-- Name of the avatar agent -->
    <set-attr-value name="name" value="man_000"/>
    <set-attr-value name="dynamics" value="false"/>

    <set-attr-value name="x" value="-60.0"/>
    <set-attr-value name="y" value="60.0"/>
    <set-attr-value name="z" value="-100.0"/>

    <!--エージェントの向き(x,y,z)  -->
    <!-- Orientation the avatar agent (x,y,z)  -->
    <set-attr-value name="qw" value="0.707"/>
    <set-attr-value name="qx" value="0.0"/>
    <set-attr-value name="qy" value="0.707"/>
    <set-attr-value name="qz" value="0.0"/>

    <!--衝突判定を行うためcollisionフラグをtrueにします-->
    <!-- Set the flag of collision detection function to true -->
    <set-attr-value name="collision" value="true"/>
  </instanciate>
</world>
}}

ここではロボットが2体登場します。それぞれ同じコントローラを割り当てます。
The two robot agents use the same controller "Collision.so"
The flag for collision detection should be set as "true" if you want to use the collision detection function.
Please be careful that the initial state of this flag is "false".

衝突判定を行いたいエンティティは以下のように属性"collision"を"true"に設定しておきます。デフォルトでは"false"となっているので注意が必要です。
#highlight(xml:firstline[27]){{
    <set-attr-value name="collision" value="true"/>
}}
**実行 [#ge5926ae]
それでは実行してみましょう。

 $ ./sigserver.sh -w ColliWorld.xml -p 9001
** Execution [#h3ae0c35]

 $ ./sigserver.sh -w CollisionWorld.xml

#ref(./Colli_1.PNG,40%)

サーバに接続するとロボットが2体いて、人間が通せんぼしているのがわかります。
それではシミュレーションを開始してみましょう。
Connect to the server with SIGViewer.

You will see two robots and a human avatar in the world. Let's push the start button to start the simulation.

#ref(./Colli_2.PNG,40%)
まず前にいるロボットが人間と衝突して前にいるロボットだけがUターンします。

First, a robot agent which stands in front of the human avatar will make U-turn after collides with the human avatar.

#ref(./Colli_3.PNG,40%)
次にロボット同士が衝突してそれぞれUターンします。

この後、先ほどと同様に前にいるロボットがまた人間と衝突してUターンして、後ろにいるロボットを追いかけますが、前にいるロボットのほうが速度を早く設定しているため、いずれ後ろのロボットに追い付きます。
Next, the robots collide each other, then make U-turn.

追い付いたロボット2体は再びUターンをして人間の方向に進みます。
After that, the two robots will repeat the U-turn behavior.

延々とこの動作を繰り返します。

* Addtion of attribute [#g0d29843]

*属性の追加 [#i5f76bfa]
上のサンプルコントローラではロボットのエージェントごとに速度が設定されています。パラメータの値を変えるたびにコンパイルするのは面倒なので、ここではエージェントに属性として速度を追加して、世界ファイルでパラメータの値を設定する方法を紹介します。
In the above controller samples, two velocity values are set to two robot agents respectively.
It is a little bit troublesome to change the velocity because the compilation is required.
So, the following section introduces how to change the velocity using attribution in the worldfile.

**エンティティファイルの編集 [#xcda9213]
世界ファイルが読み込むロボットの設定ファイルを編集します。
** Modification of entity file [#t32fe4bf]

 $ emacs -nw xml/Robot-nii.xml
First, copy the original file to your working space.

以下の行を追加します。
 $ cp ~/sigverse-<version>/share/sigverse/data/xml/Robot-nii.xml .

Edit the configuration of the robot agent.

 $ emacs ./Robot-nii.xml

Add the following line.

 <attr name="vel" type="double" group="velocity" value="0.0"/>

Robot-nii.xml
#highlight(xml){{
<?xml version="1.0" encoding="utf8"?>
 <define-class name="Robot" inherit="Agent.xml">
 
   <set-attr-value name="scalex" value="0.7"/>
   <set-attr-value name="scaley" value="0.7"/>
   <set-attr-value name="scalez" value="0.7"/>
 
   <!-- 属性"vel"を追加 -->
   <!-- Add an attribution "vel" -->
   <attr name="vel" type="double" group="velocity" value="0.0"/>
 
   <x3d>
       <filename>nii_robot.x3d</filename>
   </x3d>
 
</define-class>
}}

**世界ファイルの編集 [#l72a2513]
** Modification of the world file [#wb4c4814]

次に世界ファイルでエージェントごとに速度を設定します。
Next, set velocity values in the world file.

 $ emacs xml/ColliWorld.xml
 $ emacs CollisionWorld.xml

"robot_000"の属性の値を設定しているところ

Add the line

      <set-attr-value name="vel" value="5.0"/>

after the line which sets the the attribution of "robot_000"

#highlight(xml:firstline[26]){{
  <!--衝突判定を行うためcollisionフラグをtrueにします  -->  
   <set-attr-value name="collision" value="true"/> 
    <!-- Set the flag of collision detection function to true -->
    <set-attr-value name="collision" value="true"/>
    <set-attr-value name="vel" value="5.0"/>
}}
の下に以下の一行を加えます。


      <set-attr-value name="vel" value="5.0"/>
Add the following one line at set of attribution for "robot_001" as well as the above way.

同様に"robot_001"の属性値を設定している箇所に以下を追加します。

     <set-attr-value name="vel" value="7.0"/>

**コントローラの編集 [#v237b73a]
次にコントローラの編集を行います。
** Modification of controller [#hea86854]

速度パラメータvelは世界ファイルで設定を行ったので、onInit関数の中のvelの設定箇所を以下のように変更します。
Since the velocity is already set by the world file, remove the setting of velocity as follows:

 $ cd NewWorld
 $ emacs Colli.cpp
 $ emacs Collision.cpp

Colli.cpp
Collision.cpp

#highlight(cpp:firstline[28]){{
Old:

#highlight(cpp:firstline[27]){{
 void AgentController::onInit(InitEvent &evt)
 {
   Colli = false;
   Colli_cnt = 0; 
  
  //"robot_000"の速度設定 
  // Velocity of the "robot_000"
  if(strstr(myname() , "000")!= NULL)
    {
      vel = 5;
    }
 
  //"robot_001"の速度設定
  // Velocity of the "robot_001"
  else  if(strstr(myname() , "001")!= NULL)
    { 
    vel = 7;
    }
  else
    vel = 0;
 }
}}
     ↓

New:

#highlight(cpp:firstline[27]){{
void AgentController::onInit(InitEvent &evt)
{
   Colli = false;
   Colli_cnt = 0;
  
  //自分の速度を得ます。
  // Refer the velocity
  SimObj *my = getObj(myname());
  vel = my->getAttr("vel").value().getDouble();
}
}}
これでコンパイルするとエージェントの速度は世界ファイルで設定可能となります。

 $ make
After the compilation, the velocity could be set by the worldfile.

正常に動作することを確認してみてください。
 $ ./sigmake.sh Collision.cpp

Please test the behavior of the controller file and the world file.

*謝辞 [#ad94a306]
このサンプルは奈良先端技術大学院大学の柴田智広先生にアドバイスをいただきました。ありがとうございました。

#highlight(end)

*Old Version [#cf12fda7]
-[[エージェントの衝突(v120330, v1.4.8)]]
----
Up:[[Tutorial]]     Previous:[[エージェント視点の画像取得]]     Next:[[物体を持つ動作]]
Up:[[Tutorial]]     Previous:[[Image capture from agent's perspective]]     Next:[[Grasping Function]]

#counter


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