[Documentation] [TitleIndex] [WordIndex

(訳注:最新の情報は原文を参照してください.)

Note: This tutorial assumes that you have completed the previous tutorials: シンプルなPublisherとSubscriberを実行してみる.
(!) Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags.

C++でシンプルなサービスとクライアントを書く

Description: このチュートリアルではサービスとクライアントノードのC++での書き方を学びます

Tutorial Level: BEGINNER

Next Tutorial: シンプルなサービスとクライアントを実行してみる

シンプルなサービスとクライアントを書く (C++)

サービスノードを書く

さてここでは、("add_two_ints_server")という二つのintegerを受け取りその合計を戻り値にもつサービスノードを作っていきます。

ディレクトリを以前のチュートリアル(ROSパッケージを作る)で作成したbeginner_tutorialsのパッケージの中に移動させましょう。

roscd beginner_tutorials

以前catkinワークスペースで作成したbeginner_tutorialsパッケージに移動してください。

cd ~/catkin_ws/src/beginner_tutorials

このチュートリアルで必要なサービスを作る以前のチュートリアル(ROSのmsgやsrvなどを作る)の指示に従ったことを確認してください。

コード

src/add_two_ints_server.cppというファイルをbeginner_tutorialsの中につくり以下のコードを書き込んでください:

   1 #include "ros/ros.h"
   2 #include "beginner_tutorials/AddTwoInts.h"
   3 
   4 bool add(beginner_tutorials::AddTwoInts::Request  &req,
   5          beginner_tutorials::AddTwoInts::Response &res)
   6 {
   7   res.sum = req.a + req.b;
   8   ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
   9   ROS_INFO("sending back response: [%ld]", (long int)res.sum);
  10   return true;
  11 }
  12 
  13 int main(int argc, char **argv)
  14 {
  15   ros::init(argc, argv, "add_two_ints_server");
  16   ros::NodeHandle n;
  17 
  18   ros::ServiceServer service = n.advertiseService("add_two_ints", add);
  19   ROS_INFO("Ready to add two ints.");
  20   ros::spin();
  21 
  22   return 0;
  23 }

コード解説

さてコードを読み解いていきましょう。

   1 #include "ros/ros.h"
   2 #include "beginner_tutorials/AddTwoInts.h"
   3 

beginner_tutorials/AddTwoInts.hは以前作ったsrvファイルを作成したときに生成されたヘッダーファイルです。

   4 bool add(beginner_tutorials::AddTwoInts::Request  &req,
   5          beginner_tutorials::AddTwoInts::Response &res)

この関数は、2つのint型を足し合わせる働きのサービスで、srvファイルに定義されたリクエストとレスポンスのタイプを読み込み、booleanを返します。

   6 {
   7   res.sum = req.a + req.b;
   8   ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
   9   ROS_INFO("sending back response: [%ld]", (long int)res.sum);
  10   return true;
  11 }

ここでは、2つのintegerは加えられ、レスポンスの中に保管されます。その後、リクエストとレスポンスのいくらかの情報が、ログに残されます。最後に、サービスは完了したタイミングでtrueを返します。

  18   ros::ServiceServer service = n.advertiseService("add_two_ints", add);

ここでは、サービスが生成され、ROSにこのサービスが登録されます。

クライアントNodeを書く

コード

src/add_two_ints_client.cppというファイルをbeginner_tutorialsの中につくり以下のコードを書き込んでください:

   1 #include "ros/ros.h"
   2 #include "beginner_tutorials/AddTwoInts.h"
   3 #include <cstdlib>
   4 
   5 int main(int argc, char **argv)
   6 {
   7   ros::init(argc, argv, "add_two_ints_client");
   8   if (argc != 3)
   9   {
  10     ROS_INFO("usage: add_two_ints_client X Y");
  11     return 1;
  12   }
  13 
  14   ros::NodeHandle n;
  15   ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
  16   beginner_tutorials::AddTwoInts srv;
  17   srv.request.a = atoll(argv[1]);
  18   srv.request.b = atoll(argv[2]);
  19   if (client.call(srv))
  20   {
  21     ROS_INFO("Sum: %ld", (long int)srv.response.sum);
  22   }
  23   else
  24   {
  25     ROS_ERROR("Failed to call service add_two_ints");
  26     return 1;
  27   }
  28 
  29   return 0;
  30 }

コード解説

さて、コードを読み解いていきましょう。

  15   ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");

これは、add_two_intsサービスのためのクライアントを作成しています。 ros::ServiceClientオブジェクトは、サービスを後で呼び出すために使用します。

  16   beginner_tutorials::AddTwoInts srv;
  17   srv.request.a = atoll(argv[1]);
  18   srv.request.b = atoll(argv[2]);

ここで、自動生成されたサービスのクラスをインスタンス化し、そのリクエストのフィールドに値を代入します。サービスクラスは、二つのメンバーrequestresponseを持ちます。 これは二つのクラスの定義 RequestResponseも内包しています。

  19   if (client.call(srv))

これは、実際は、サービスを呼び出します。サービスの呼び出しは待機させられ、呼び出しが終わるとreturnします。サービスコールがうまくいけば、call()は、trueを返却し、srv.responseの中の値が使えます。もし呼び出しが失敗していたら、call()はfalseを返却し、srv.responseの中の値は、使えません。

nodeをビルドする

また、beginner_tutorialsのCMakeLists.txtを編集しましょう。

$ rosed beginner_tutorials CMakeLists.txt 

最後に以下を加えます。

rosbuild_add_executable(add_two_ints_server src/add_two_ints_server.cpp)
rosbuild_add_executable(add_two_ints_client src/add_two_ints_client.cpp)

これは、デフォルトでは、binディレクトリに格納される二つの実行ファイル"add_two_ints_server"と"add_two_ints_client"を生成します。

ROSでCMakeを利用するに当たりさらに情報がほしい場合は、CMakeListsをご覧ください。

さて、makeをしましょう。

$ make

サービスとクライアントのノードをビルドする

また、~/catkin_ws/src/beginner_tutorials/CMakeLists.txtにあるCMakeLists.txtを編集します。そして以下を最後に加えます: https://raw.github.com/ros/catkin_tutorials/master/create_package_srvclient/catkin_ws/src/beginner_tutorials/CMakeLists.txt

  27 add_executable(add_two_ints_server src/add_two_ints_server.cpp)
  28 target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
  29 add_dependencies(add_two_ints_server beginner_tutorials_gencpp)
  30 
  31 add_executable(add_two_ints_client src/add_two_ints_client.cpp)
  32 target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})
  33 add_dependencies(add_two_ints_client beginner_tutorials_gencpp)

これは、デフォルトではdevel spaceの下のパッケージディレクトリに行く二つの実行ファイル"add_two_ints_server" と "add_two_ints_client"を生成します。

これは、デフォルトでは~/catkin_ws/devel/lib/share/<package name>にあるdevel spaceの下のパッケージディレクトリに行く二つの実行ファイル"add_two_ints_server" と "add_two_ints_client"を生成します。実行ファイルを直接実行することも、rosrunを使って実行することもできます。それらは、ROSのシステムにあなたのパッケージをインストールするときにPATHの邪魔になってしまうので、'<prefix>/bin'の中には、置かれていません。インストール時に、PATHのなかに実行ファイルを入れたい場合は、インストール対象を準備することもできます。方法についてはcatkin/CMakeLists.txtを確認してください。

よりCMakeLists.txtファイルについて詳細を知りたい場合は、catkin/CMakeLists.txtを参照してください。

さてcatkin_makeをしましょう:

#catkin ワークスペースで
cd ~/catkin_ws
catkin_make

もし、なんらかの理由でビルドが失敗したなら、

  • rosls beginner_tutorials/srv_gen/cpp/include/beginner_tutorials/と打ち、.hファイルが、クライアントやサーバーの.cppファイルでインクルードしたものと一致するかを確認する

ここではシンプルなサービスとクライアントを書きました.次はシンプルなサービスとクライアントをテストしましょう


2019-10-19 12:46