- The added line is THIS COLOR.
- The deleted line is THIS COLOR.
Up:[[Tutorial]] Previous:[[サービスプロバイダの使用方法]] Next:[[エージェントの衝突]]
----
#contents
*エージェント視点の画像取得 (captureView)[#g547d565]
ここではサービスプロバイダ機能を使用しエージェントに設置されたカメラ画像のデータをコントローラが取得するサンプルを紹介します。
※SSH接続によりSIGVerseを利用している場合は前ページ同様追加でポートフォワーディングの設定が必要です。詳しくは前ページ[[サービスプロバイダの使用方法]]を参照ください。
**コントローラ作成 [#n54bccbb]
まずコントローラを作成します。
$ cd ~/sigverse-<version>/bin/NewWorld
$ emacs captureView.cpp
captureView.cpp
#highlight(cpp){{
#include <Controller.h>
#include <ControllerEvent.h>
#include <Logger.h>
#include <ViewImage.h>
#include <math.h>
#define PI 3.141592
#define DEG2RAD(DEG) ( (PI) * (DEG) / 180.0 )
class RobotController : public Controller
{
public:
void onInit(InitEvent &evt);
double onAction(ActionEvent &evt);
void onRecvMsg(RecvMsgEvent &evt);
private:
ViewService* m_view;
double vel;
};
void RobotController::onInit(InitEvent &evt)
{
// 移動速度
vel = 10.0;
// サービスに接続
m_view = (ViewService*)connectToService("SIGViewer", 9005);
}
//定期的に呼び出される関数
double RobotController::onAction(ActionEvent &evt)
{
return 10.0;
}
//メッセージ受信時に呼び出される関数
void RobotController::onRecvMsg(RecvMsgEvent &evt)
{
static int iImage = 0;
//取得したメッセージを表示します
std::string msg = evt.getMsg();
LOG_MSG(("msg : %s", msg.c_str()));
//メッセージ"capture"を受信するとcaptureViewを行います
if (msg == "capture") {
if(m_view != NULL) {
// ビット深度24,画像サイズ320X240の画像を取得します
ViewImage *img = m_view->captureView(2, COLORBIT_24, IMAGE_320X240);
if (img != NULL) {
// 画像データを取得します
char *buf = img->getBuffer();
//Windows BMP 形式で保存します
char fname[256];
sprintf(fname, "view%03d.bmp", iImage++);
img->saveAsWindowsBMP(fname);
//必要なくなったら削除します
delete img;
}
}
}
//メッセージ"rotation"を受信すると回転します
if (msg == "rotation"){
SimObj *my = getObj(myname());
// 自分のy軸周りの回転を得ます(クオータニオン)
double qy = my->qy();
//くオータニオンから回転角(ラジアン)を導出します
double theta = 2*asin(qy);
//体全体を回転させます
double y = theta + DEG2RAD(45);
if( y >= PI)
y = y - 2 * PI;
my->setAxisAndAngle(0, 1.0, 0, y);
}
//メッセージ"move"を受信すると自分の向いている方向に進みます
if (msg == "move"){
SimObj *my = getObj(myname());
//自分の位置を得ます
Vector3d pos;
my->getPosition(pos);
//y軸周りの自分の回転を得ます(クオータニオン)
double qy = my->qy();
//クオータニオンから回転角を導出します
double theta = 2*asin(qy);
//移動距離
double dx = 0.0;
double dz = 0.0;
//移動する方向を決定します
dx = sin(theta) * vel;
dz = cos(theta) * vel;
//移動します
my->setPosition( pos.x() + dx, pos.y() , pos.z() + dz );
}
}
extern "C" Controller * createController ()
{
return new RobotController;
}
}}
***captureView [#i5b342d8]
50行目の関数captureViewで画像データをビューワーから取得します。
#highlight(cpp:firstline[50]){{
ViewImage *img = m_view->captureView(2, COLORBIT_24, IMAGE_320X240);
}}
1番目の引数は取得したいカメラのID番号を指定します。ここではID番号2を指定しました。2番目と3番目に1ピクセルあたりのビット深度と画像サイズを指定します。(※v121029, v2.0.1ではビット深度24, 画像サイズ320×240のみ取得可)
取得したViewImageから画像データを取り出すには関数getBuffer()を用います。
このサンプルではエージェントに"capture"というメッセージを送信するとエージェントは画像を取得することができます。
captureViewが成功すると実行ディレクトリにview000.bmp, view001.bmp...というようにbmp形式の画像ファイルが保存されます。
***エージェントの移動 [#w6371583]
このエージェントはメッセージ"move"を受信すると現在向いている方向に進みます。"rotation"を受信するとエージェントは向きを変えます。
**コンパイル [#m203eb4f]
Makefileの変数OBJSにcaptureView.soを追加してコンパイルします。
**世界ファイル作成 [#u5216d9d]
$ cd ..
$ emacs xml/captureView.xml
世界ファイルは前ページ[[視覚に関する操作]]で使用したリビングルームの世界ファイルとほとんど同じものを使います。
captureView.xml
#highlight(xml){{
<?xml version="1.0" encoding="utf8"?>
<world name="myworld5">
<gravity x="0.0" y="-980.7" z="0.0"/>
<!--エージェントRobot-niiの設定-->
<instanciate class="Robot-nii.xml">
<!--エージェント名-->
<set-attr-value name="name" value="robot_000"/>
<!--C++言語の指定-->
<set-attr-value name="language" value="c++"/>
<!--コントローラの指定-->
<set-attr-value name="implementation"
value="./NewWorld/captureView.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="54.0"/>
<set-attr-value name="z" value="-40.0"/>
<!--カメラのID番号,リンク名、方向、位置の設定-->
<camera id="1"
link="HEAD_LINK"
direction="0.1 0 1"
position="-2.0 0.0 7.0"/>
<camera id="2"
link="HEAD_LINK"
direction="-0.1 0 1"
position="2.0 0.0 7.0"/>
</instanciate>
<!--リビングルーム-->
<instanciate class="seTV.xml">
<set-attr-value name="name" value="TV_0"/>
<set-attr-value name="dynamics" value="false"/>
<set-attr-value name="x" value="-20.0"/>
<set-attr-value name="y" value="62.0"/>
<set-attr-value name="z" value="-250.0"/>
<set-attr-value name="visStateAttrName" value="switch"/>
<set-attr-value name="switch" value="on"/>
</instanciate>
<instanciate class="seDoll_Bear.xml">
<set-attr-value name="name" value="kuma_0"/>
<set-attr-value name="dynamics" value="false"/>
<set-attr-value name="x" value="0.0"/>
<set-attr-value name="y" value="9.0"/>
<set-attr-value name="z" value="10.0"/>
</instanciate>
<instanciate class="seToy_D.xml">
<set-attr-value name="name" value="penguin_0"/>
<set-attr-value name="dynamics" value="false"/>
<set-attr-value name="x" value="50.0"/>
<set-attr-value name="y" value="7.0"/>
<set-attr-value name="z" value="-40.0"/>
</instanciate>
<instanciate class="seSofa_2seater.xml">
<set-attr-value name="name" value="sofa_0"/>
<set-attr-value name="dynamics" value="false"/>
<set-attr-value name="x" value="-200.0"/>
<set-attr-value name="y" value="30.0"/>
<set-attr-value name="z" value="-100.0"/>
<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"/>
</instanciate>
<instanciate class="seTVbass_B.xml">
<set-attr-value name="name" value="TVdai_0"/>
<set-attr-value name="dynamics" value="false"/>
<set-attr-value name="x" value="-20.0"/>
<set-attr-value name="y" value="8.0"/>
<set-attr-value name="z" value="-250.0"/>
</instanciate>
<instanciate class="sePlant_B.xml">
<set-attr-value name="name" value="ki_0"/>
<set-attr-value name="dynamics" value="false"/>
<set-attr-value name="x" value="100.0"/>
<set-attr-value name="y" value="35.0"/>
<set-attr-value name="z" value="-250.0"/>
</instanciate>
<instanciate class="seSidetable_B.xml">
<set-attr-value name="name" value="sidetable_0"/>
<set-attr-value name="dynamics" value="false"/>
<set-attr-value name="x" value="-100.0"/>
<set-attr-value name="y" value="23.0"/>
<set-attr-value name="z" value="-100.0"/>
<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"/>
</instanciate>
<instanciate class="seApple.xml">
<set-attr-value name="name" value="apple_0"/>
<set-attr-value name="dynamics" value="false"/>
<set-attr-value name="x" value="-50.0"/>
<set-attr-value name="y" value="3.0"/>
<set-attr-value name="z" value="30.0"/>
</instanciate>
<instanciate class="seOrange.xml">
<set-attr-value name="name" value="orange_0"/>
<set-attr-value name="dynamics" value="false"/>
<set-attr-value name="x" value="70.0"/>
<set-attr-value name="y" value="2.0"/>
<set-attr-value name="z" value="-30.0"/>
</instanciate>
</world>
}}
エージェントに2つのカメラを設置し、2つのカメラで微妙に位置と方向をずらしました。
カメラID番号1が右目、2が左目に相当します。
**画像取得 [#j88e8a70]
それでは実行してみましょう
$ ./sigserver.sh -p 9001 -w captureView.xml
SIGViewerで接続してみるとリビングルームにロボットが立っているのが見えます。
シミュレーションを開始して"rotation"や"move"などのメッセージを送信するとエージェントが向きを変えたり、移動したりして自由に部屋の中を移動できるようになります。
キャプチャしたいタイミングで"capture"を送信するとエージェントに設置されたカメラ(ID番号2)で撮影した画像が得られます。
#ref(./capture_1.PNG,40%)
サーバ側の実行ディレクトリにカメラ2でcaptureした画像ファイルが保存されていれば成功です。
#highlight(end)
*Old Version [#m54d69a2]
-[[エージェント視点の画像取得(v120330, v1.4.8)]]
----
Up:[[Tutorial]] Previous:[[サービスプロバイダの使用方法]] Next:[[エージェントの衝突]]