ROS Service CPP勉強メモ

概要
=
ROSの中Topicの続きにもう一つ重要な通信道具Serviceについての勉強メモ。
Serviceは何に使うの？
ClientとServerを作り、Clientからリクエストを出し、Serverがそのリクエストに応じて処理、計算してレスポンスを返すとイメージ。
実際のロボット上では例えば、Client側から回転速のリクエストに対して、Server側がリクエストに応じてPWM制御し、実際の回転数をレスポンスとして返すシーンなどに使う。PID制御を使い、車速維持、目標車速の調整を実現するなどに使う。
Serviceの実現方法は基本Topicと似っている。

作成
=
１．ws/src/pkg/srvの下にsrvフィアルにてsrvの中身を定義する。（変数宣言みたいなもん）
srvフォルダは事前に作っておく。
![Screenshot from 2023-05-20 12-03-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3181208/76d7f111-af80-8872-5800-7c70c9a97c1b.png)

srvの中身について
---にて（上）リクエスト、（下）レスポンスの情報を区切っている。

２．package.xmlファイルにmsgを使うことをROSにわかってもらうため、下記内容を追加する（includ,buildするため必要な記述のイメージ）Topicと同じ内容は重複追加不要。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f333138313230382f33313561653039392d626335342d393865312d303439382d6134343162663961383261632e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3181208/1c27b7fe-3321-e11c-d237-251a6666da24.png)

３．cmakelists.txtファイルにmsgを使うことをROSにわかってもらうため、下記内容を追加する（buildするために必要な記述のイメージ）３箇所

１箇所目（message_generation追加）　Topicと同じ
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f333138313230382f62343964333934612d396234382d343930622d323331322d3161623763386535373233622e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3181208/465440db-5b0f-8a91-64f4-703693fcf0e5.png)

２箇所目(catkin情報の追加)　Topicと同じ
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f333138313230382f38373431323639622d643832662d343533612d383530332d3838633133383638313639352e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3181208/fa04c092-c8fb-ef16-1716-a80eb6499fc0.png)

３箇所目(msgファイル情報の追加)　Topicとほぼ同じ　同じ内容は重複追加不要。
![Screenshot from 2023-05-20 12-18-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3181208/a257c520-7c03-c4cc-845a-84f293e3ddc8.png)

これでsrvの追加編集の終わりましたので、buildすればsrvが使えるようになる。試して見る。ターミナルで下記コマンドを実行して確認する
~~~~~~~~~~~~~~~~~~~~~~
catkin_make
rossrv show learning_communication/AddTwoInts
~~~~~~~~~~~~~~~~~~~~~~

![Screenshot from 2023-05-20 12-23-28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3181208/06c342e3-b838-dcad-4132-1e64c2228969.png)

ROS上にsrvの情報を使えるように認識できたことをわかったので、今度定義したsrvを使ってnode間に通信して見る。

続いては定義したsrv情報を使いClientとServerを作り、Note間の通信をして見る。ここで作るのはClientから２つの数値、a,bをServerに渡し、Serverの方で合計してsumのレスポンスをするものになる。

1.Clientを作る。srcフォルダ内容にclient.cppを作る。（ファイル名はお好きに）
~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <cstdlib> //argc,argvを使いたいからincludeしている
#include "ros/ros.h"
#include "learning_communication/AddTwoInts.h"

int main(int argc, char **argv)
{
    ros::init(argc, argv, "add_two_ints_client");
    if (argc != 3)　//ターミナルからの入力数の正しさを検証する,入力が正しい場合Serverに送る情報送る
    {
        ROS_INFO("usage: add_two_ints_client X Y");
        return 1;
    }
    ros::NodeHandle n;
    ros::ServiceClient client = n.serviceClient<learning_communication::AddTwoInts>("add_two_ints");

    learning_communication::AddTwoInts srv;
    srv.request.a = atoll(argv[1]);
    srv.request.b = atoll(argv[2]);

    if (client.call(srv))
    {
        ROS_INFO("Sum: %ld", (long int)srv.response.sum);
    }
    else
    {
        ROS_ERROR("Failed to call service add_two_ints");
        return 1;
    }
    return 0;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~

２．Serverを作る。srcフォルダ内容にserver.cppを作る。
~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "ros/ros.h"
#include "learning_communication/AddTwoInts.h"

bool add(learning_communication::AddTwoInts::Request  &req,
         learning_communication::AddTwoInts::Response &res)
{
    res.sum = req.a + req.b;
    ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
    ROS_INFO("sending back response: [%ld]", (long int)res.sum);

    return true;
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "add_two_ints_server");
    ros::NodeHandle n;
    ros::ServiceServer service = n.advertiseService("add_two_ints", add);

    ROS_INFO("Ready to add two ints.");
    ros::spin();

    return 0;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

3.CmakeLists.txtに作成した２つのcppを登録し、ビルトしてもらえるようにする。ここもTopicとほぼ同じ内容。
![Screenshot from 2023-05-20 12-52-09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3181208/0ce07d5a-37d9-0340-d633-65c42c4fda05.png)

これで編集の部分が全部おわったので、catkin_makeして動かして見よう〜
Topicとほぼ同じだが、違いはa,bのパラメータを渡さないといけない、最後の返しsumがあるだけ。

テスト
=
ターミナル１
~~~~~~~~~~~~~~~~~
roscore
~~~~~~~~~~~~~~~~~

ターミナル２
~~~~~~~~~~~~~~~~~
rosrun learning_communication server
~~~~~~~~~~~~~~~~~

ターミナル3
~~~~~~~~~~~~~~~~~
rosrun learning_communication client 3 5
~~~~~~~~~~~~~~~~~

![Screenshot from 2023-05-20 13-38-52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3181208/a9baed83-80a2-fd2c-a916-ad89e2d7c61f.png)