ROSの勉強　第6弾：基礎的なアクションサーバの実装

# #プログラミング ROS< 基礎的なアクションサーバの実装 >

##はじめに
1つの参考書に沿って，ROS(Robot Operating System)を難なく扱えるようになることが目的である．その第6弾として，基礎的なアクションサーバの実装を扱う．


##環境
#####仮想環境
|||
|:-:|:--|
|ソフト|VMware Workstation 15|
|実装RAM|2 GB|
|OS|Ubuntu 64 ビット|
|isoファイル|ubuntu-mate-20.04.1-desktop-amd64.iso|

#####コンピュータ
|||
|:-:|:--|
|デバイス|MSI|
|プロセッサ|Intel(R) Core(TM) i5-7300HQ CPU @ 2.50GHz 2.50GHz|
|実装RAM|8.00 GB (7.89 GB 使用可能)|
|OS|Windows (Windows 10 Home, バージョン：1909)|

#####ROS
|||
|:-:|:--|
|Distribution|noetic|
|プログラミング言語|Python 3.8.5|

##実装
前回(https://qiita.com/Yuya-Shimizu/items/778774b30e5c75820a81) に定義したアクションを使って，タイマーの機能を持つアクションサーバの実装を通して，基礎的な部分の学習を進める．以下にソースコードを示す．なお，ソースコード内で，プログラムの説明は詳細に記述されている．

#####ソースコード
```python:action_simple_server.py
#! /usr/bin/env python3

import rospy

import time 		#タイマー作成時に必要となる
import actionlib	#SimpleActionServerクラスを提供　→　アクションのサーバ作成に必要と解釈
from action_lesson.msg import TimerAction, TimerGoal, TimerResult	#Timer.actionファイルから自動生成したメッセージクラスで必要なものを読み込む


def do_timer(goal):
	"""新しいゴール（目標）を受け取ったときに呼び出される関数"""

	start_time = time.time()
	time.sleep(goal.time_to_wait.to_sec())	#アクションファイルで定義したtime_to_waitはdurationであるため秒数変換する→to_sec()関数
	result = TimerResult()	#TimerResultの型のリザルトメッセージ(result)を作成　←これを作成しないと，定義ファイル内のリザルトの部分にアクセスできない
	result.time_elapsed = rospy.Duration.from_sec(time.time() - start_time)	#「現在時刻-開始時刻」をDuration(ROSで扱う期間)に変換してtime_elapsedフィールドに代入
	result.updates_sent = 0		#今回は0として，更新回数は考えないこととする．
	server.set_succeeded(result)	#resultを引数として，set_succeeded()関数を呼び出すことで，SimpleActionServerにゴールしたことを伝える．



rospy.init_node('timer_action_server')	#ノードの初期化

server = actionlib.SimpleActionServer('timer', TimerAction, do_timer, False)	#'timer'という名で，TimerActionというアクションの型　do_timerを実行．サーバの自動起動を無効にするためFalseを指定

server.start()	#サーバ生成後，明示的にサーバを開始する

rospy.spin()	#ループに入り，到着すべきゴールが送られるのを待つ
```

##結果
上のソースコードを実行した後，動作確認をターミナル(端末)で行った．その様子を以下に示す．
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/c61f6a44-ea84-81de-aee5-0d5dd8478ae5.png)
``/timer``に関するものが5つ動いていることが分かる．どれがどのような役割を担っているかは名前から察することができる．これらのトピックは**このアクションを管理するために内部的に使われているトピック**らしい．例えば，``/timer/goal``についてもう少し詳しく見ていく．その様子を以下に示す．
![キャプチャ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/2c7ca926-cce0-17cf-b1e6-fbfad69fc9c4.png)
上の図のような結果が得られた．型が``action_lesson/TimerActionGoal``で，配信者はいなく，購読者が``/timer_action_server``であるという．赤線でも強調したが，``TimerActionGoal``というのは知らない．そこで，さらに詳しく調べる．その様子を以下に示す．
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/53f3dd22-5365-5413-b61a-f8262a4aca32.png)
上図の赤で示したところは確かに定義したが，それ以外はどうやら**自動的に追加**されている．これらのフィールドは**アクションサーバとクライアント間で何か起きているかを管理するために内部的に使われる**らしい．しかしながら，実際にユーザが受け取るのは，次に示す部分となる．
![キャプチャ3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/c32ed776-fddc-5aae-888c-82e77bc46128.png)
つまり，管理のための情報は，受け取る時には自動的に削除されているらしい．一般には，**型名にActionと付いている自動生成メッセージにアクセスする必要はなく，Goal, Result, Feedbackメッセージだけで十分**らしい．

##感想
アクションを定義する際に，自動で生成されているものがあるのは知っていたが，その役割までは知らなかった．特に使うことはないが，管理に使われているんだということを知っておけばよいと学んだ．今回はアクションサーバの実装だけで，使用までは行っていないが，次回は実際に使用し，より理解を深められることを期待する．

##参考文献
プログラミングROS Pythonによるロボットアプリケーション開発
　　　　　　　　Morgan Quigley, Brian Gerkey, William D.Smart 著
　　　　　　　　　　　　　　　　　　　　　　　河田　卓志　監訳
　　　　　　　　　　  　松田　晃一，福地　正樹，由谷　哲夫　訳
　　　　　　　　　　　　　　　　　　オイラリー・ジャパン　発行