Up:[[Tutorial]]     Previous:[[メッセージ送受信]]
----
#contents


*画像データ取得 [#zc25bba0]

※このチュートリアルはSIGVerse v2.1.0以降対応です。

エンティティに設置されているカメラの画像データ、距離センサデータをサービスプロバイダで取得するサンプルを紹介します。

これによりクライアント側で画像処理ができるようになります。

**コントローラ作成 [#yed8a1c4]

サーバ側でコントローラを作成します。

 $ emacs captureService.cpp

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

class MyController : public Controller {
public:
  void onInit(InitEvent &evt);
  double onAction(ActionEvent&);
  void onRecvMsg(RecvMsgEvent &evt);
  void onCollision(CollisionEvent &evt);

private:
  BaseService *m_srv;
};

void MyController::onInit(InitEvent &evt) {
  m_srv = NULL;
  SimObj *my = getObj(myname());
}

double MyController::onAction(ActionEvent &evt) {
  if(m_srv == NULL){
    // サービスが使用可能かチェックする 
    bool available = checkService("MyService");
    if(available){
      // サービスプロバイダに接続  
      m_srv = connectToService("MyService");
    }
  }
  else{
    // サービスプロバイダにメッセージを送信します
    m_srv->sendMsgToSrv("capture");
  }
  return 1.0;
}

void MyController::onRecvMsg(RecvMsgEvent &evt) {
  // メッセージ送信元とメッセージを取得します   
  std::string sender = evt.getSender();
  std::string msg = evt.getMsg();
  LOG_MSG(("[%s] %s", sender.c_str(), msg.c_str()));
}

void MyController::onCollision(CollisionEvent &evt) {
}

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

}}

このコントローラは1秒ごとにサービスプロバイダに"capture"というメッセージを送信します。

コンパイルします。
 $ sigmake.sh captureService.cpp
 $ ./sigmake.sh captureService.cpp

**世界ファイル作成 [#f3f5ddf4]

世界ファイル作成します。
 $ emacs captureService.xml

#highlight(xml){{
<?xml version="1.0" encoding="utf8"?>
<world name="myworld1">
  <gravity x="0.0" y="-980.7" z="0.0"/>
  <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="./captureService.so"/>
    <set-attr-value name="dynamics" value="false"/>
    <set-attr-value name="x" value="0.0"/>
    <set-attr-value name="y" value="60.0"/>
    <set-attr-value name="z" value="0.0"/>
    <set-attr-value name="mass" value="1.0"/>
    <set-attr-value name="collision" value="true"/>

    <camera id="1"
            link="HEAD_LINK"
            direction="0 -1 1"
            aspectRatio="1.5"
            fov="45"
            position="0.0 0.0 5.0"/>

  </instanciate>
</world>
}}

ロボットだけが登場するシンプルな世界ファイルです。

**サービスサンプル [#ud190404]

クライアント側で[[サービスプロバイダの作成]]と同様、VC++2008を使って新しくプロジェクトを立ち上げます。

以下のソースコードを追加します。

MyService.cpp

#highlight(cpp){{
#include "SIGService.h"
#include <tchar.h>
#include <string>

// SIGServiceを継承したクラスを作成します
class MyService : public sigverse::SIGService
{

public:
	MyService(std::string name) : SIGService(name){};
	~MyService();
	// メッセージ受信時に呼び出される関数
	void onRecvMsg(sigverse::RecvMsgEvent &evt);
	// 定期的に呼び出される関数
	double onAction();
};

MyService::~MyService()
{
	// 切断します
	this->disconnect();
}

double MyService::onAction()
{
	return 1.0;
}

void MyService::onRecvMsg(sigverse::RecvMsgEvent &evt)
{
	// メッセージ送信元とメッセージを取得します
	std::string sender = evt.getSender();
	std::string msg = evt.getMsg();

	// メッセージが"capture"だった場合画像データを取得します
	if(msg == "capture") {
		sigverse::ViewImage *img = this->captureView(sender);

		// 画像データ保存
		if(img->saveAsWindowsBMP("test.bmp")){
			this->sendMsgToCtr(sender, "succeeded");
		}
		delete img;
	}
}

int main(int argc, char** argv)
{
	// クラスMyServiceのインスタンスを作成します
	MyService srv("MyService");
//	unsigned short port = (unsigned short)(atoi(argv[2]));
//	srv.connect(argv[1], port);

	// サーバに接続します
	srv.connect("hostname", 9001);

	// ビューワーに接続します
	if(srv.connectToViewer()){

		// ビューワーがサーバからdisconnectしたらloopを自動で抜けます
		srv.setAutoExitLoop(true);
	}
	// メインループをスタートさせます
	srv.startLoop();
	return 0;
}
}}
"hostname"は自分の環境に書き換えます。

このサービスプロバイダは"capture"というメッセージを受け取るとViewerにcaptureViewリクエストを送りカメラ画像データを取得します。そしてcaptureViewに成功すると"succeeded" というメッセージをコントローラに返します。

#ref(./captureService_1.png,40%)

captureViewの最初の引数にはカメラを持ったエンティティ名、2番目以降の引数はコントローラで使用するcaptureViewの1番目以降の引数と同じです。[[エージェント視点の画像取得]]参照。

**実行 [#nd1a153e]
それでは実行してみます。

 $ sigserver.sh -p 9001 -w ./captureService.xml

サーバを立ち上げた状態でビューワーで接続します。
シミュレーションをスタートした後、MyServiceを起動します。

サーバ側で以下のようなメッセージが表示されたら成功です。
 [MSG]  robot_000(0.0.0.0) [MyService] succeeded
 [MSG]  robot_000(0.0.0.0) [MyService] succeeded
 [MSG]  robot_000(0.0.0.0) [MyService] succeeded

サービスプロバイダ実行フォルダの中にtest.bmpが保存されていることを確認してみてください。

*距離センサ [#n1096574]

距離センサデータを取得する場合はMyServiceを以下のように修正します。
#highlight(cpp:firstline[37]){{
		sigverse::ViewImage *img = this->captureView(sender);

		// 画像データ保存
		if(img->saveAsWindowsBMP("test.bmp")){
			this->sendMsgToCtr(sender, "succeeded");
		}
		delete img;
}}

   ↓
#highlight(cpp:firstline[37]){{
		unsigned char distance = this->distanceSensor(sender);
		printf_s("distance %d\n", distance); 
}}


実行すると取得した距離データがクライアント側で表示されます。
 distance 155
 distance 155
 distancd 155

distanceSensor1D, distanceSensor2Dも同様にサービスプロバイダで利用できます。
第一引数にエンティティ名を指定するということ以外はコントローラAPIのdistanceSensor, distanceSensor1D, distanceSensor2Dと使い方は同じです([[距離センサ]] 参照)。
#highlight(end)

----
Up:[[Tutorial]]     Previous:[[メッセージ送受信]]
#counter

Front page   Edit Diff Backup Upload Copy Rename Reload   New List of pages Search Recent changes   Help   RSS of recent changes