ROS2の勉強　第6弾：actionを使う

# #プログラミング ROS2< actionを使う >

##はじめに
ROS2を難なく扱えるようになることが目的である．その第6弾として，「actionを使う」を扱う．

##環境
#####仮想環境
|||
|:-:|:--|
|ソフト|VMware Workstation 15|
|実装RAM|3 GB|
|OS|Ubuntu 64 ビット|
|isoファイル|ubuntu-20.04.3-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, バージョン：21H1)|

#####ROS2
|||
|:-:|:--|
|Distribution|foxy|

## action
### 概要
actionはserviceとも異なり，serviceのように何かしらの命令を出した後，その命令が完了するまで待たずともフィードバックを得ることができたり，命令を中断したり，新たな命令に切り替えることもできる．そういった点で，ロボットシステムにおいてナビゲーション機能にはactionが多用され，非常に重要なものとなっている．

そのイメージを以下に示す．
![Action-SingleActionClient.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/afc741a3-6346-f49c-6353-c6cb42ab74be.gif)
※引用：Understanding ROS 2 actions (2022/02/01)

今回はturtlesimの中で使われているactionを再現することでactionの使い方に触れる．

## プログラム: turtleの姿勢を変える
### turtlesimにおけるRotateAbsoluteアクション
まず，actionを使うにあたって，どのようなactionを使うのかということを知っておく必要がある．そこで，turtlesim_nodeを立ち上げた際に用意されるserviceを``ros2 action list -t``で確認した．tタグをつけることで，タイプも一緒に参照することができる．その時の様子を以下に示す．今回の対象を赤丸で示している．

![action_name_type.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/979a394c-046c-ae1e-cc1a-e856d43788f9.png)

この``/tutlesim/turtle1/rotate_absolute``という名前のactionを使う．どうやら，タイプは``/tutlesim/action/RotateAbsolute``というもののようだ．具体的な中身は以下に示す．

![action_detail.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/6887dc4b-90b2-fe2b-c590-35ae43417f0f.png)

``---``で区切られるが，上から順に，``Goal``（目標値：命令），``Result``（結果），``Feedback``（フィードバック）である．

以降ではこれらの情報を使って，組み立てていく．

<details><summary>**カメの姿勢を変えるプログラム**</summary><div>

```python:rotateTurtle.py
from argparse import Action
from re import S
import rclpy
from rclpy.node import Node
from rclpy.action import ActionClient
from turtlesim.action import RotateAbsolute

class RotateTurtle(Node):
    def __init__(self):
        super().__init__('rotate_turtle')

        self.action_client = ActionClient(
            self,                               # node 
            RotateAbsolute,                     # action type
            'turtlesim/turtle1/rotate_absolute' # action name to treat
        )

    def send_goal(self, theta):
        goal_msg = RotateAbsolute.Goal()    # prepare RotateAbsolute.Goal() to access the messages
        goal_msg.theta = theta              # set theta value to goal_msg.theta

        self.action_client.wait_for_server()            # wait until action server begins

        self.action_client.send_goal_async(goal_msg)    # send goal Asynchronously
    
def main(args=None):
    rclpy.init(args=args)

    action_client = RotateTurtle()

    theta = 1.57    # 90 degrees
    action_client.send_goal(theta)

if __name__ == '__main__':
    main()
```
</details></div>

### ビルドの準備
#### setup.pyの編集
基本的にビルドに関する情報はsetup.pyの中に記述されている．

<details><summary>**setup.pyの編集**</summary><div>

```python:setup.py
from setuptools import setup

package_name = 'action_lesson'

setup(
    name=package_name,
    version='0.0.0',
    packages=[package_name],
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='Yuya Shimizu',
    maintainer_email='yuya@example.com',
    description='a package for practice action',
    license='BSD',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'rotate = action_lesson.rotateTurtle:main'
        ],
    },
)
```
</details></div>

#### ビルド
```bash:ビルド
cd ~/ros2_ws
colcon build
```

#### 実行コマンド
```bash:terminal_1
ros2 launch turtlesim_test myTurtlesim.launch.py
```

```bash:terminal_2
ros2 run action1_lesson rotate
```


#### 実行の様子

![action.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/923dfec4-f7f9-8cc5-d56f-01e8397e3d2a.gif)

今回のプログラムはカメをある姿勢にできれば終了というものであるため，アクションのやり取りが一度行われた時点でプログラムは終了している．また，カメの姿勢はソースコード内で1つに決めてしまっている（今回は1.57 rad: およそ90度）．

今回はアクションの``Goal``しか使っていないが，``Feedback``を使って，遷移の様子を見ることもできるし，その遷移に応じて何か組み込むこともできる．ここで実装はしないが，``Goal``，``Result``，``Feedback``を使いこなせば，より充実したシステムを構築できそうである．

##感想
とりあえず，ROS2でも基本的なデータのやり取りに欠かせない，topic, service, actionの使い方を学ぶことができた．ここからは，経験を積む中で技術を磨いて，ROS2を難なく使いこなせるようになっていく必要がある．それのスタートラインに立つことができた．次回からは，turtlebotをシミュレーション上で扱ってカメではなく，ロボットベースでの学習ができればと思う．

##参考
- ロボットプログラミングROS2入門　玉川大学　岡田浩之　著，科学情報出版株式会社

- Understanding ROS 2 actions

https://docs.ros.org/en/foxy/Tutorials/Understanding-ROS2-Actions.html#ros2-action-info