RaspberryPi3とZumoとROSで半永久自走式充放電ロボを作成したい_003日目_独自Message・Service

#◆ 前回記事
[RaspberryPi3とZumoとROSで半永久自走式充放電ロボを作成したい\_002日目\_用語・TOPIC](https://qiita.com/PINTO/items/f6162219d2f17e2f1714)　の続き

#◆ はじめに
前回は Raspberry Pi へのROS環境の導入と、ROSの超基本 「TOPIC形式」 での公式サンプル実装を行ったため、今回は 「独自のMessage」 ならびに 「Service形式」 の実装を試行したい。

なお、以前に書いた記事の考え方の誤りや概念図の表現がマズいところは先へ進むごと、気付きを得ていくごと、に随時補正していこうと思う。
読者をミスリードするような記事は質が激低なことは重々承知のうえ、素人丸出しだが、極端なパターンでは同一記事内で表現を随時補正しながら進めていくものとする。

ROSに関する体系だった分かりやすく素晴らしいチュートリアル記事は Qiita内 に多数存在するため、「僕のロボット作成奮闘日記」 よろしく特定のモノを作ること、ではなく、ROSについてしっかり学びたい方は別のQiita記事、ROSの公式チュートリアルの参照を強く推奨する。
※例えば当記事の一番下のほうに表示されている関連記事フィードのリンクをたどる、など。

#◆ [振り返り] Service形式とは
前回記事の段階で自分なりに腹落ちさせていたイメージは下図のとおり。
NODE相互に同期方式で通信する。
NODE間で親子関係を持ち、子は親からコールされる。
親は呼び出し先の子の処理が終わるまで後続の処理を待機する。

|Service型の概念図|
|:-------:|
|![0002_Service.png](https://qiita-image-store.s3.amazonaws.com/0/194769/d9439573-459d-54b5-62ee-c1ba6ffa130a.png)|

#◆ 標準エディタの変更
今回は作業に掛かる前に環境を一部変更する。
今後登場するであろうROSの便利コマンド群を叩いたときにデフォルトで起動するテキストエディタを変更しておくことができるそうだ。
何もしなければ "Vim" というエディタが自動的に起動するが、手練の技術者ではないため、当面は NOTE PAD 感覚で使用できる初心者向けエディタ "nano" を選択しておくことにする。

```shell:エディタ変更
$ nano ~/.bashrc
export EDITOR='nano -w'  #<--- を追記

$ source ~/.bashrc
```

#◆ サンプルプログラムの作成と実行
さて、実際にサンプルを実装して動きを確認してみることにする。
##＊ プログラム作成先フォルダへの移動
手がコマンドを覚えるまで、しばらくの間は `source devel/setup.bash` を手で入力することにする。
ちなみに、 `source devel/setup.bash` を実行しておかないと `roscd` コマンド実行時、
`roscd: No such package/stack 'tutorials/src'`
という具合に、　パッケージが見つからない！　というエラーになる。
`roscd` コマンドは Linuxの `cd`コマンドとほぼ同じ挙動を示すため大差はないが、ROSのパッケージ階層を自動的に識別してTab補完が効くようになるため、覚えておくと少しだけ便利。

```shell:roscd実行
$ cd ~/catkin_ws
$ source devel/setup.bash
$ roscd tutorials
```

##＊ 独自メッセージの作成
前回、公式のサンプルプログラムを元にTOPIC形式で標準のメッセージをそのまま使用してみたが、今回はせっかくなので練習のために独自サービスに加えて独自メッセージも定義してみることにする。
メッセージの定義ファイルは、パッケージフォルダ直下に「msg」フォルダを作成し、その直下に拡張子 「.msg」 としてファイルを作成して配置するルールのようなので、 "Hello World" という文字列を格納するだけのごく単純なメッセージを定義してみる。
型と変数名だけ記入すれば良いらしい。
string型 の message変数 を１つだけ持つメッセージとする。

![0006_Workspace_00 (1).png](https://qiita-image-store.s3.amazonaws.com/0/194769/cbd262d0-19b8-1d6b-6eeb-3b419833e856.png)

![0005_Message.png](https://qiita-image-store.s3.amazonaws.com/0/194769/1419771b-6657-2543-1cc1-bcd624909eb7.png)


```shell:greet.msg作成
$ mkdir msg
$ roscd tutorials/msg
$ echo "string message" > greet.msg
```

または

```shell:greet.msg作成
$ mkdir msg
$ roscd tutorials/msg
$ nano greet.msg

string message
```

そして次に、チュートリアルどおりに読み進めているはずなのにいきなりハマる。
曰く、

```
package.xmlを開き、package.xml の中に以下の２行があることを確認して、コメントタグを外してください
  <build_depend>message_generation</build_depend>
  <run_depend>message_runtime</run_depend>
```

ということだが、 `<run_depend>`タグ が package.xml 内にどう見ても存在しない。
かなり悩んだが、英語原文のチュートリアルサイトを見ると正しく補正されている。
正しくは、 `<exec_depend>`タグ ということのようだ。
日本語チュートリアルは当てにならないことが分かったため、今後は英語原文のチュートリアルを見るようにしよう。

ともあれ、下図赤枠のファイルを開く。

![0003_Workspace_00.png](https://qiita-image-store.s3.amazonaws.com/0/194769/cc4a5dec-8c36-208c-e442-8e9564687723.png)


- **自前のメッセージをビルドする時には "message_generation" パラメータが有効になっている必要がある**
- **自前のメッセージを実行する時には "message_runtime" パラメータが有効化になっている必要がある**

ということなので、下記 xml全文 のとおり、"message_generation" と "message_runtime" のコメントタグ "<!-- -->" を除去。

<details><summary>**package.xml の全文**</summary><div>

```package.xml
<?xml version="1.0"?>
<package format="2">
  <name>tutorials</name>
  <version>0.0.0</version>
  <description>The tutorials package</description>

  <!-- One maintainer tag required, multiple allowed, one person per tag -->
  <!-- Example:  -->
  <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
  <maintainer email="pi@todo.todo">pi</maintainer>


  <!-- One license tag required, multiple allowed, one license per tag -->
  <!-- Commonly used license strings: -->
  <!--   BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
  <license>TODO</license>


  <!-- Url tags are optional, but multiple are allowed, one per tag -->
  <!-- Optional attribute type can be: website, bugtracker, or repository -->
  <!-- Example: -->
  <!-- <url type="website">http://wiki.ros.org/tutorials</url> -->


  <!-- Author tags are optional, multiple are allowed, one per tag -->
  <!-- Authors do not have to be maintainers, but could be -->
  <!-- Example: -->
  <!-- <author email="jane.doe@example.com">Jane Doe</author> -->


  <!-- The *depend tags are used to specify dependencies -->
  <!-- Dependencies can be catkin packages or system dependencies -->
  <!-- Examples: -->
  <!-- Use depend as a shortcut for packages that are both build and exec dependencies -->
  <!--   <depend>roscpp</depend> -->
  <!--   Note that this is equivalent to the following: -->
  <!--   <build_depend>roscpp</build_depend> -->
  <!--   <exec_depend>roscpp</exec_depend> -->
  <!-- Use build_depend for packages you need at compile time: -->
  <build_depend>message_generation</build_depend>
  <!-- Use build_export_depend for packages you need in order to build against this package: -->
  <!--   <build_export_depend>message_generation</build_export_depend> -->
  <!-- Use buildtool_depend for build tool packages: -->
  <!--   <buildtool_depend>catkin</buildtool_depend> -->
  <!-- Use exec_depend for packages you need at runtime: -->
  <exec_depend>message_runtime</exec_depend>
  <!-- Use test_depend for packages you need only for testing: -->
  <!--   <test_depend>gtest</test_depend> -->
  <!-- Use doc_depend for packages you need only for building documentation: -->
  <!--   <doc_depend>doxygen</doc_depend> -->
  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>
  <build_export_depend>roscpp</build_export_depend>
  <build_export_depend>rospy</build_export_depend>
  <build_export_depend>std_msgs</build_export_depend>
  <exec_depend>roscpp</exec_depend>
  <exec_depend>rospy</exec_depend>
  <exec_depend>std_msgs</exec_depend>


  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->

  </export>
</package>
```

</div></details>

続いて、 package.xml に加えて CMakeLists.txt を編集する必要があるそうだ。
色々な周辺事情を理解していないため、なにゆえ類似の修正を２枚のファイルに加えないとならないのか、疑問に感じてしまう。

![0003_Workspace_01.png](https://qiita-image-store.s3.amazonaws.com/0/194769/e3505929-beff-c3b8-6676-36ea1b7e623a.png)


ここで初めてのコマンド "rosed" を駆使する。
rosed ＝ roseditor あるいは rosedit か何かの略称かな？

とあるパッケージ配下の、とあるファイルを編集したいときに、深いフォルダ階層をいちいち掘っていかなくても、コマンド一発で スッ と探しだしたうえ、デフォルトのエディタで開いてくれるらしい。
また、パッケージ構成に基づいて lsコマンド よろしく Tab補完 が効いてくれるようだ。便利。
構文は下記のとおり。

```
$ rosed [package_name] [filename]
```

では、下記の通り指定して CMakeLists.txt を スッ と開いて編集する。

```shell:rosedの実行
$ rosed tutorials CMakeLists.txt
```

<details><summary>**CMakeLists.txt の全文**</summary><div>

```cmake:CMakeLists.txt
cmake_minimum_required(VERSION 2.8.3)
project(tutorials)

## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)

## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)

## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)


## Uncomment this if the package has a setup.py. This macro ensures
## modules and global scripts declared therein get installed
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
# catkin_python_setup()

################################################
## Declare ROS messages, services and actions ##
################################################

## To declare and build messages, services or actions from within this
## package, follow these steps:
## * Let MSG_DEP_SET be the set of packages whose message types you use in
##   your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
## * In the file package.xml:
##   * add a build_depend tag for "message_generation"
##   * add a build_depend and a run_depend tag for each package in MSG_DEP_SET
##   * If MSG_DEP_SET isn't empty the following dependency has been pulled in
##     but can be declared for certainty nonetheless:
##     * add a run_depend tag for "message_runtime"
## * In this file (CMakeLists.txt):
##   * add "message_generation" and every package in MSG_DEP_SET to
##     find_package(catkin REQUIRED COMPONENTS ...)
##   * add "message_runtime" and every package in MSG_DEP_SET to
##     catkin_package(CATKIN_DEPENDS ...)
##   * uncomment the add_*_files sections below as needed
##     and list every .msg/.srv/.action file to be processed
##   * uncomment the generate_messages entry below
##   * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)

## Generate messages in the 'msg' folder
add_message_files(
  FILES
  greet.msg
)

## Generate services in the 'srv' folder
add_service_files(
  FILES
  hello.srv
)

## Generate actions in the 'action' folder
# add_action_files(
#   FILES
#   Action1.action
#   Action2.action
# )

## Generate added messages and services with any dependencies listed here
generate_messages(
  DEPENDENCIES
  std_msgs
)

################################################
## Declare ROS dynamic reconfigure parameters ##
################################################

## To declare and build dynamic reconfigure parameters within this
## package, follow these steps:
## * In the file package.xml:
##   * add a build_depend and a run_depend tag for "dynamic_reconfigure"
## * In this file (CMakeLists.txt):
##   * add "dynamic_reconfigure" to
##     find_package(catkin REQUIRED COMPONENTS ...)
##   * uncomment the "generate_dynamic_reconfigure_options" section below
##     and list every .cfg file to be processed

## Generate dynamic reconfigure parameters in the 'cfg' folder
# generate_dynamic_reconfigure_options(
#   cfg/DynReconf1.cfg
#   cfg/DynReconf2.cfg
# )

###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if your package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES tutorials
#  CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
#  DEPENDS system_lib
)

###########
## Build ##
###########

## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
  ${catkin_INCLUDE_DIRS}
)

## Declare a C++ library
# add_library(${PROJECT_NAME}
#   src/${PROJECT_NAME}/tutorials.cpp
# )

## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
# add_executable(${PROJECT_NAME}_node src/tutorials_node.cpp)

## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use
## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")

## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

## Specify libraries to link a library or executable target against
# target_link_libraries(${PROJECT_NAME}_node
#   ${catkin_LIBRARIES}
# )

#############
## Install ##
#############

# all install targets should use catkin DESTINATION variables
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html

## Mark executable scripts (Python etc.) for installation
## in contrast to setup.py, you can choose the destination
# install(PROGRAMS
#   scripts/my_python_script
#   DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )

## Mark executables and/or libraries for installation
# install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node
#   ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
#   LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
#   RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )

## Mark cpp header files for installation
# install(DIRECTORY include/${PROJECT_NAME}/
#   DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
#   FILES_MATCHING PATTERN "*.h"
#   PATTERN ".svn" EXCLUDE
# )

## Mark other files for installation (e.g. launch and bag files, etc.)
# install(FILES
#   # myfile1
#   # myfile2
#   DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
# )

#############
## Testing ##
#############

## Add gtest based cpp test target and link libraries
# catkin_add_gtest(${PROJECT_NAME}-test test/test_tutorials.cpp)
# if(TARGET ${PROJECT_NAME}-test)
#   target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()

## Add folders to be run by python nosetests
# catkin_add_nosetests(test)
```

</div></details>

　
CMakeLists.txt の修正箇所は下記。

```cmake
find_package(catkin REQUIRED COMPONENTS
　　roscpp
　　rospy
　　std_msgs
　　message_generation　#<--- 追加
)
```
```cmake
add_message_files(
　　FILES
　　greet.msg　#<--- コメントアウトを解除して修正
)
```
```cmake
add_service_files(
　　FILES
　　hello.srv　#<--- コメントアウトを解除して修正　後続の手順で作成する独自サービスを先行して定義しておく
)
```
```cmake:全体をコメントアウト解除.
generate_messages(
　　DEPENDENCIES
　　std_msgs
)
```

むむむっ、何やら猛烈にチュートリアルが分かりづらい。
おかげで正しいかどうか悩みまくった。
自分だけなんだろうか。。。

##＊ 独自サービスの作成
さて、ようやく本題のService作成に掛かる。
Serviceに関する情報を読むと、

- 概念図上の親・・・Client、機能を使用する(呼び出す)側
- 概念図上の子・・・Service、機能を提供する(呼び出される)側

と表現するらしい。
直感的に逆ではないかと感じてしまったが、よくよく考えると正しい。
子(Service) は 親(Client) に言われたことを淡々とこなす、だけ。
現実世界の親子関係ならちょっと寂しい関係に見える。

サービスの定義ファイルは、パッケージフォルダ直下に「srv」フォルダを作成し、その直下に拡張子 「.srv」 としてファイルを作成して配置するルールのようなので、 "Hello World" という文字列を渡すと、 "Good evening World" と返すだけのごく単純なサービスを定義してみる。
呼び出し元からのリクエストで受け付けるデータ型と変数名のセット、呼び出し元へレスポンスで返すデータ型と変数名のセットを「---」で区切って２種類書くようだ。
今回の場合、
　リクエストで受け付ける部分を　string型 の request変数 で１つ
　レスポンスで返す部分を　string型 の response変数で１つ
定義する。
「メッセージ」 のときはデータの入れ物の型そのものを定義していたが、 「サービス」 は機能が提供するインタフェースだけを事前に定義する、というニュアンスかな。
当然、あとの工程で、サービスの実際の処理を書く作業が必要となる想定。

![0006_Workspace_01 (1).png](https://qiita-image-store.s3.amazonaws.com/0/194769/511837ab-1149-2c58-8fee-7be1d664c988.png)

![0007_Service.png](https://qiita-image-store.s3.amazonaws.com/0/194769/1422da97-4656-ace0-9dcd-3cba1f23d4c5.png)

```shell:hello.svrの作成
$ cd ~/catkin_ws
$ roscd tutorials
$ mkdir srv
$ roscd tutorials/srv
$ echo "string request" > hello.srv
$ echo "---" >> hello.srv
$ echo "string response" >> hello.srv
```

または

```shell:hello.svrの作成
$ cd ~/catkin_ws
$ roscd tutorials
$ mkdir srv
$ roscd tutorials/srv
$ nano hello.srv

string request
---
string response
```

##＊ パッケージ全体のリビルドとインストール
ようやくビルドまでこぎ着けた。。。
下記コマンドを実行して全体をビルド→インストールする。

```shell:catkin_make実行
$ cd ~/catkin_ws
$ catkin_make install
```

<details><summary>**実行ログ**</summary><div>

```cmake:実行ログ
Base path: /home/pi/catkin_ws
Source space: /home/pi/catkin_ws/src
Build space: /home/pi/catkin_ws/build
Devel space: /home/pi/catkin_ws/devel
Install space: /home/pi/catkin_ws/install
####
#### Running command: "make cmake_check_build_system" in "/home/pi/catkin_ws/build"
####
-- Using CATKIN_DEVEL_PREFIX: /home/pi/catkin_ws/devel
-- Using CMAKE_PREFIX_PATH: /home/pi/catkin_ws/devel;/opt/ros/kinetic
-- This workspace overlays: /home/pi/catkin_ws/devel;/opt/ros/kinetic
-- Using PYTHON_EXECUTABLE: /usr/bin/python
-- Using Debian Python package layout
-- Using empy: /usr/bin/empy
-- Using CATKIN_ENABLE_TESTING: ON
-- Call enable_testing()
-- Using CATKIN_TEST_RESULTS_DIR: /home/pi/catkin_ws/build/test_results
-- Found gtest sources under '/usr/src/gtest': gtests will be built
-- Using Python nosetests: /usr/bin/nosetests-2.7
-- catkin 0.7.8
-- BUILD_SHARED_LIBS is on
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~  traversing 1 packages in topological order:
-- ~~  - tutorials
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- +++ processing catkin package: 'tutorials'
-- ==> add_subdirectory(tutorials)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- tutorials: 1 messages, 1 services
-- Configuring done
-- Generating done
-- Build files have been written to: /home/pi/catkin_ws/build
####
#### Running command: "make install -j4 -l4" in "/home/pi/catkin_ws/build"
####
Scanning dependencies of target std_msgs_generate_messages_py
Scanning dependencies of target _tutorials_generate_messages_check_deps_greet
Scanning dependencies of target std_msgs_generate_messages_nodejs
Scanning dependencies of target _tutorials_generate_messages_check_deps_hello
[  0%] Built target std_msgs_generate_messages_py
[  0%] Built target std_msgs_generate_messages_nodejs
Scanning dependencies of target std_msgs_generate_messages_lisp
Scanning dependencies of target std_msgs_generate_messages_eus
[  0%] Built target std_msgs_generate_messages_eus
[  0%] Built target std_msgs_generate_messages_lisp
Scanning dependencies of target std_msgs_generate_messages_cpp
[  0%] Built target _tutorials_generate_messages_check_deps_greet
[  0%] Built target _tutorials_generate_messages_check_deps_hello
[  0%] Built target std_msgs_generate_messages_cpp
Scanning dependencies of target tutorials_generate_messages_nodejs
Scanning dependencies of target tutorials_generate_messages_py
Scanning dependencies of target tutorials_generate_messages_eus
Scanning dependencies of target tutorials_generate_messages_lisp
[  7%] Generating EusLisp code from tutorials/greet.msg
[ 15%] Generating Python from MSG tutorials/greet
[ 23%] Generating Javascript code from tutorials/greet.msg
[ 30%] Generating Lisp code from tutorials/greet.msg
[ 46%] Generating Javascript code from tutorials/hello.srv
[ 46%] Generating Lisp code from tutorials/hello.srv
[ 53%] Generating EusLisp code from tutorials/hello.srv
[ 53%] Built target tutorials_generate_messages_lisp
[ 53%] Built target tutorials_generate_messages_nodejs
[ 61%] Generating EusLisp manifest code for tutorials
[ 69%] Generating Python code from SRV tutorials/hello
Scanning dependencies of target tutorials_generate_messages_cpp
[ 76%] Generating C++ code from tutorials/greet.msg
[ 84%] Generating C++ code from tutorials/hello.srv
[ 92%] Generating Python msg __init__.py for tutorials
[100%] Generating Python srv __init__.py for tutorials
[100%] Built target tutorials_generate_messages_py
[100%] Built target tutorials_generate_messages_eus
[100%] Built target tutorials_generate_messages_cpp
Scanning dependencies of target tutorials_generate_messages
[100%] Built target tutorials_generate_messages
Install the project...
-- Install configuration: ""
-- Installing: /home/pi/catkin_ws/install/_setup_util.py
-- Up-to-date: /home/pi/catkin_ws/install/env.sh
-- Up-to-date: /home/pi/catkin_ws/install/setup.bash
-- Up-to-date: /home/pi/catkin_ws/install/setup.sh
-- Up-to-date: /home/pi/catkin_ws/install/setup.zsh
-- Up-to-date: /home/pi/catkin_ws/install/.rosinstall
-- Installing: /home/pi/catkin_ws/install/share/tutorials/msg/greet.msg
-- Up-to-date: /home/pi/catkin_ws/install/share/tutorials/srv/hello.srv
-- Installing: /home/pi/catkin_ws/install/share/tutorials/cmake/tutorials-msg-paths.cmake
-- Installing: /home/pi/catkin_ws/install/include/tutorials
-- Installing: /home/pi/catkin_ws/install/include/tutorials/hello.h
-- Installing: /home/pi/catkin_ws/install/include/tutorials/helloResponse.h
-- Installing: /home/pi/catkin_ws/install/include/tutorials/helloRequest.h
-- Installing: /home/pi/catkin_ws/install/include/tutorials/greet.h
-- Installing: /home/pi/catkin_ws/install/share/roseus/ros/tutorials
-- Installing: /home/pi/catkin_ws/install/share/roseus/ros/tutorials/manifest.l
-- Installing: /home/pi/catkin_ws/install/share/roseus/ros/tutorials/srv
-- Installing: /home/pi/catkin_ws/install/share/roseus/ros/tutorials/srv/hello.l
-- Installing: /home/pi/catkin_ws/install/share/roseus/ros/tutorials/msg
-- Installing: /home/pi/catkin_ws/install/share/roseus/ros/tutorials/msg/greet.l
-- Installing: /home/pi/catkin_ws/install/share/common-lisp/ros/tutorials
-- Installing: /home/pi/catkin_ws/install/share/common-lisp/ros/tutorials/srv
-- Installing: /home/pi/catkin_ws/install/share/common-lisp/ros/tutorials/srv/hello.lisp
-- Installing: /home/pi/catkin_ws/install/share/common-lisp/ros/tutorials/srv/_package.lisp
-- Installing: /home/pi/catkin_ws/install/share/common-lisp/ros/tutorials/srv/_package_hello.lisp
-- Installing: /home/pi/catkin_ws/install/share/common-lisp/ros/tutorials/srv/tutorials-srv.asd
-- Installing: /home/pi/catkin_ws/install/share/common-lisp/ros/tutorials/msg
-- Installing: /home/pi/catkin_ws/install/share/common-lisp/ros/tutorials/msg/_package.lisp
-- Installing: /home/pi/catkin_ws/install/share/common-lisp/ros/tutorials/msg/_package_greet.lisp
-- Installing: /home/pi/catkin_ws/install/share/common-lisp/ros/tutorials/msg/tutorials-msg.asd
-- Installing: /home/pi/catkin_ws/install/share/common-lisp/ros/tutorials/msg/greet.lisp
-- Installing: /home/pi/catkin_ws/install/share/gennodejs/ros/tutorials
-- Installing: /home/pi/catkin_ws/install/share/gennodejs/ros/tutorials/srv
-- Installing: /home/pi/catkin_ws/install/share/gennodejs/ros/tutorials/srv/hello.js
-- Installing: /home/pi/catkin_ws/install/share/gennodejs/ros/tutorials/srv/_index.js
-- Installing: /home/pi/catkin_ws/install/share/gennodejs/ros/tutorials/_index.js
-- Installing: /home/pi/catkin_ws/install/share/gennodejs/ros/tutorials/msg
-- Installing: /home/pi/catkin_ws/install/share/gennodejs/ros/tutorials/msg/_index.js
-- Installing: /home/pi/catkin_ws/install/share/gennodejs/ros/tutorials/msg/greet.js
Listing /home/pi/catkin_ws/devel/lib/python2.7/dist-packages/tutorials ...
Compiling /home/pi/catkin_ws/devel/lib/python2.7/dist-packages/tutorials/__init__.py ...
Listing /home/pi/catkin_ws/devel/lib/python2.7/dist-packages/tutorials/msg ...
Compiling /home/pi/catkin_ws/devel/lib/python2.7/dist-packages/tutorials/msg/__init__.py ...
Compiling /home/pi/catkin_ws/devel/lib/python2.7/dist-packages/tutorials/msg/_greet.py ...
Listing /home/pi/catkin_ws/devel/lib/python2.7/dist-packages/tutorials/srv ...
Compiling /home/pi/catkin_ws/devel/lib/python2.7/dist-packages/tutorials/srv/__init__.py ...
Compiling /home/pi/catkin_ws/devel/lib/python2.7/dist-packages/tutorials/srv/_hello.py ...
-- Installing: /home/pi/catkin_ws/install/lib/python2.7/dist-packages/tutorials
-- Installing: /home/pi/catkin_ws/install/lib/python2.7/dist-packages/tutorials/srv
-- Installing: /home/pi/catkin_ws/install/lib/python2.7/dist-packages/tutorials/srv/_hello.py
-- Installing: /home/pi/catkin_ws/install/lib/python2.7/dist-packages/tutorials/srv/__init__.pyc
-- Installing: /home/pi/catkin_ws/install/lib/python2.7/dist-packages/tutorials/srv/_hello.pyc
-- Installing: /home/pi/catkin_ws/install/lib/python2.7/dist-packages/tutorials/srv/__init__.py
-- Installing: /home/pi/catkin_ws/install/lib/python2.7/dist-packages/tutorials/__init__.pyc
-- Installing: /home/pi/catkin_ws/install/lib/python2.7/dist-packages/tutorials/__init__.py
-- Installing: /home/pi/catkin_ws/install/lib/python2.7/dist-packages/tutorials/msg
-- Installing: /home/pi/catkin_ws/install/lib/python2.7/dist-packages/tutorials/msg/_greet.py
-- Installing: /home/pi/catkin_ws/install/lib/python2.7/dist-packages/tutorials/msg/__init__.pyc
-- Installing: /home/pi/catkin_ws/install/lib/python2.7/dist-packages/tutorials/msg/_greet.pyc
-- Installing: /home/pi/catkin_ws/install/lib/python2.7/dist-packages/tutorials/msg/__init__.py
-- Installing: /home/pi/catkin_ws/install/lib/pkgconfig/tutorials.pc
-- Installing: /home/pi/catkin_ws/install/share/tutorials/cmake/tutorials-msg-extras.cmake
-- Installing: /home/pi/catkin_ws/install/share/tutorials/cmake/tutorialsConfig.cmake
-- Up-to-date: /home/pi/catkin_ws/install/share/tutorials/cmake/tutorialsConfig-version.cmake
-- Up-to-date: /home/pi/catkin_ws/install/share/tutorials/package.xml
```

</div></details>

ちなみに、カスタムメッセージのファイルとカスタムサービスのファイルの拡張子を除くファイル名部分を同じにすると、makeエラーとなって先に進めない。
ここでエラーメッセージの意味がすんなり理解できなくて **ガッツリ２時間** ハマってしまった。
それぐらい許してよ。。。
つまるところ、今後も同一パッケージ内で同じファイル名をつけてはダメ、ということだな。

||**.msg**|**.srv**|備考|
|:--:|:--:|:--:|:--|
|**ダメ例**|<font color="Red">hello</font>.msg|&nbsp;<font color="Red">hello</font>.srv&nbsp;|.msgと.srvのファイル名部同一|
|**良い例**|<font color="Red">greet</font>.msg|&nbsp;<font color="Red">hello</font>.srv&nbsp;|.msgと.srvのファイル名部違う|

<details><summary>**ダメな時の実行ログ**</summary><div>

```cmake:ダメな時の実行ログ
Base path: /home/pi/catkin_ws
Source space: /home/pi/catkin_ws/src
Build space: /home/pi/catkin_ws/build
Devel space: /home/pi/catkin_ws/devel
Install space: /home/pi/catkin_ws/install
####
#### Running command: "make cmake_check_build_system" in "/home/pi/catkin_ws/build"
####
-- Using CATKIN_DEVEL_PREFIX: /home/pi/catkin_ws/devel
-- Using CMAKE_PREFIX_PATH: /opt/ros/kinetic
-- This workspace overlays: /opt/ros/kinetic
-- Using PYTHON_EXECUTABLE: /usr/bin/python
-- Using Debian Python package layout
-- Using empy: /usr/bin/empy
-- Using CATKIN_ENABLE_TESTING: ON
-- Call enable_testing()
-- Using CATKIN_TEST_RESULTS_DIR: /home/pi/catkin_ws/build/test_results
-- Found gtest sources under '/usr/src/gtest': gtests will be built
-- Using Python nosetests: /usr/bin/nosetests-2.7
-- catkin 0.7.8
-- BUILD_SHARED_LIBS is on
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~  traversing 1 packages in topological order:
-- ~~  - tutorials
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- +++ processing catkin package: 'tutorials'
-- ==> add_subdirectory(tutorials)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- tutorials: 1 messages, 1 services
CMake Error at /home/pi/catkin_ws/build/tutorials/cmake/tutorials-genmsg.cmake:26 (add_custom_target):
  add_custom_target cannot create target
  "_tutorials_generate_messages_check_deps_hello" because another target with
  the same name already exists.  The existing target is a custom target
  created in source directory "/home/pi/catkin_ws/src/tutorials".  See
  documentation for policy CMP0002 for more details.
Call Stack (most recent call first):
  /opt/ros/kinetic/share/genmsg/cmake/genmsg-extras.cmake:307 (include)
  tutorials/CMakeLists.txt:70 (generate_messages)


CMake Error: Attempt to add a custom rule to output "/home/pi/catkin_ws/devel/include/tutorials/hello.h.rule" which already has a custom rule.
-- Configuring incomplete, errors occurred!
See also "/home/pi/catkin_ws/build/CMakeFiles/CMakeOutput.log".
See also "/home/pi/catkin_ws/build/CMakeFiles/CMakeError.log".
Makefile:500: ターゲット 'cmake_check_build_system' のレシピで失敗しました
make: *** [cmake_check_build_system] エラー 1
Invoking "make cmake_check_build_system" failed
```

</div></details>

##＊ Service と Client プログラム配置先概観
Service/Clientのプログラムソース本体は、パッケージフォルダ直下に「scripts」フォルダを作成し、その直下に作成して配置するルールのようなので下図のようにする。
![0006_Workspace_02.png](https://qiita-image-store.s3.amazonaws.com/0/194769/90de4356-a23a-4669-c517-589004c7763b.png)

##＊ Service本体のプログラム作成

```shell:Serviceプログラム作成
$ roscd tutorials
$ mkdir scripts;cd scripts
$ nano greetingreplyservice.py
```

```python:greetingreplyservice.py
#!/usr/bin/env python

from tutorials.srv import *
import rospy

def handle_greeting_reply(req):
    print "=> Received [%s]"%(req.request)
    return helloResponse("Good evening World")

def greeting_reply_server():
    # Initialize of NODE 
    rospy.init_node('greeting_reply_server')
    # rospy.Service('Service Name', Service Type, CallBack Function Name)
    s = rospy.Service('GreetingReply', hello, handle_greeting_reply)
    # Ready Message
    print "Ready to greeting reply."
    rospy.spin()

if __name__ == "__main__":
    greeting_reply_server()
```

```shell:実行権限の付与
$ chmod +x greetingreplyservice.py
```

##＊ Client本体のプログラム作成

```shell:Clientプログラム作成
$ roscd tutorials
$ cd scripts
$ nano greetingclient.py
```

```python:greetingclient.py
#!/usr/bin/env python

import sys
import rospy
from tutorials.srv import *

def greeting_client(s):
    # GreetingReply Service Init Wait
    rospy.wait_for_service('GreetingReply')
    try:
        # Handler "GreetingReply" Define
        greetingreplyhandle = rospy.ServiceProxy('GreetingReply', hello)
        # Handler Call
        res = greetingreplyhandle(s)
        # Retrun helloResponse Object of "response" variable
        return res.response
    except rospy.ServiceException, e:
        print "Service call failed: %s"%e

if __name__ == "__main__":
    print "=> Requesting [Hello World]"
    print "<= Reply [%s]"%(greeting_client("Hello World"))
```

```shell:実行権限の付与
$ chmod +x greetingclient.py
```

##＊ Service と Client プログラムのビルド

```shell:ビルドコマンド
$ cd ~/catkin_ws
$ catkin_make
```

<details><summary>**実行ログ**</summary><div>

```cmake:実行ログ
Base path: /home/pi/catkin_ws
Source space: /home/pi/catkin_ws/src
Build space: /home/pi/catkin_ws/build
Devel space: /home/pi/catkin_ws/devel
Install space: /home/pi/catkin_ws/install
####
#### Running command: "make cmake_check_build_system" in "/home/pi/catkin_ws/build"
####
####
#### Running command: "make -j4 -l4" in "/home/pi/catkin_ws/build"
####
[  0%] Built target std_msgs_generate_messages_py
[  0%] Built target std_msgs_generate_messages_nodejs
[  0%] Built target std_msgs_generate_messages_eus
[  0%] Built target std_msgs_generate_messages_lisp
[  0%] Built target _tutorials_generate_messages_check_deps_greet
[  0%] Built target _tutorials_generate_messages_check_deps_hello
[  0%] Built target std_msgs_generate_messages_cpp
[ 23%] Built target tutorials_generate_messages_eus
[ 53%] Built target tutorials_generate_messages_py
[ 69%] Built target tutorials_generate_messages_nodejs
[ 84%] Built target tutorials_generate_messages_lisp
[100%] Built target tutorials_generate_messages_cpp
[100%] Built target tutorials_generate_messages
```

</div></details>

##＊ Client ⇔ Service 間のやり取りを実行

```shell:Masterの起動
$ roscore
```
![0009.png](https://qiita-image-store.s3.amazonaws.com/0/194769/9fbb205d-1ef7-241c-0b40-175555cb1124.png)

```shell:Masterとは別のターミナルを起動してサービス側の起動.
$ cd ~/catkin_ws
$ source devel/setup.bash
$ rosrun tutorials greetingreplyservice.py
```
![0010.png](https://qiita-image-store.s3.amazonaws.com/0/194769/1f7538b7-a36a-3676-6b05-27488b15c5e0.png)

```shell:Masterとサービスとは別のターミナルを起動してクライアント側の起動.
$ cd ~/catkin_ws
$ source devel/setup.bash
$ rosrun tutorials greetingclient.py
```
![0012.png](https://qiita-image-store.s3.amazonaws.com/0/194769/045b0a00-e333-782c-4da3-fe9b02c1431c.png)
![0011.png](https://qiita-image-store.s3.amazonaws.com/0/194769/17d58c1d-ac3b-db09-6a70-40b3873f99c5.png)

来た来たー！
クライアント → サービス → クライアント の順にメッセージがやり取りされているのが見て取れる。

猛烈に疲れた。。。
ということで、カスタムメッセージを使用したTOPIC通信の動作確認は割愛する。

#◆ 本日のまとめ
- 独自メッセージ と 独自サービス の実装に成功
- 独自の定義を追加するときは CMakeLists.txt と package.xml を同時に編集する必要があることが分かった
- 同一パッケージ内で拡張子部分を除くファイル名が重複するとビルドエラーが発生する

#◆ 次回予告
チュートリアルを進めていくうちに、 「サービス」 の実行に時間がかかる場合、実行中に要求を取り消したり、要求の進行状況を定期的に調べることができる 「アクション」 という謎の通信形式があることに気づく。
ということで、次回は 「アクション」 の実装と試行を行い、その次の回あたりでモーターか何かのセンサー系制御にチャレンジしようと思う。

#◆ 次回記事
[RaspberryPi3とZumoとROSで半永久自走式充放電ロボを作成したい\_004日目\_Action](https://qiita.com/PINTO/items/12a7f86a7f8861a2ff83)　へ続く