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