AWS RoboMaker入門 ~デモ起動からコード修正、実機デプロイまで~

# はじめに
AWS RoboMakerは、2018年11月25日〜11月30日に行われた re:invent で発表された新サービスです。今回は、AWS RoboMakerのデモアプリを元に、クラウド上でのシミュレーション実行からデモプログラムの修正と確認、及び実際のロボットへのデプロイまで行ってみたいと思います。

# AWS RoboMakerとROS
[AWSのドキュメント](https://docs.aws.amazon.com/robomaker/index.html#lang/en_us)によれば、AWS RoboMakerは「インテリジェントなロボットアプリケーションを容易に開発、シミュレート、デプロイできるサービス」とのことです。

> AWS RoboMaker is a service that makes it easy to develop, simulate, and deploy intelligent robotics applications at scale.

ここでいう「ロボットアプリケーション」は、[ROS](http://wiki.ros.org/)で書かれたアプリケーションを指します。ROSは世界で広く使われているロボットアプリケーション開発用のミドルウェアで、ハードウェアの抽象化やデバイスドライバ、メッセージ通信処理等のライブラリなど、ロボットアプリケーションを開発する上で必要になる様々な機能を提供します。

> ROS (Robot Operating System) provides libraries and tools to help software developers create robot applications. It provides hardware abstraction, device drivers, libraries, visualizers, message-passing, package management, and more. 

ロボットを動作させるためには様々なセンサーやモーター等を協調して動作させる必要がありますが、それらの制御を毎回モノリシックに実装するのは無理があります。そこで、それぞれの部品を制御する再利用性の高い小さなプログラムが、相互に必要なデータをメッセージとしてやり取りすることで分散協調動作を行い、全体としてロボットを適切に動作させることが最善となります。ROSを用いることで、このような分散アプリケーションを容易に実装できるようになります。

# Hello World デモを動かしてみよう
ということで、まずはAWS RoboMakerのサンプルアプリを動かしてみます。リージョンはバージニア北部にしました。（以下の手順や画像は、2018/12/11時点のものです。）

## AWS RoboMakerのコンソールを開く
ブラウザからAWS RoboMakerのコンソールを開きます。12/11時点で、Management ConsoleからRoboMakerのコンソールを検索できるようになっています。

![01.png](https://qiita-image-store.s3.amazonaws.com/0/37648/d5f8c178-c7e4-29a3-0ba6-2d090e198316.png)

## Hello World デモのシミュレーションコンテナを起動する
"Try sample application" から "Hello world" デモを選択し、画面下端の "Launch simulation job"をクリックします。

![02.png](https://qiita-image-store.s3.amazonaws.com/0/37648/e90fe363-8c9f-70f7-bd4b-09fe397b830d.png)
![03.png](https://qiita-image-store.s3.amazonaws.com/0/37648/097a8acf-352a-8644-2f94-244a9ff33c7f.png)
![04.png](https://qiita-image-store.s3.amazonaws.com/0/37648/f554a1e5-b807-8df5-5486-7964f7eba28e.png)

CloudFormationによって、Hello Worldデモ用のROSアプリケーションやシミュレーションジョブが準備されます。

![05.png](https://qiita-image-store.s3.amazonaws.com/0/37648/e3864d7c-c4d7-4ded-da72-982de5b78304.png)

CloudFormationが完了し、シミュレーションジョブが "Preparing" から "Running" になるのを待ちます。

![06.png](https://qiita-image-store.s3.amazonaws.com/0/37648/380f39e5-166e-96b2-cd09-6a12770f34d2.png)

この時点で、Hello worldデモのROSアプリケーションが準備され、RoboMakerに登録されています。その実体は、CloudFormationによって作成されたS3のバケットにアップロードされています。

![07.png](https://qiita-image-store.s3.amazonaws.com/0/37648/3ee3f238-fa34-b81f-7315-34eb9e6e0e55.png)

![08.png](https://qiita-image-store.s3.amazonaws.com/0/37648/b7eae069-3317-fc7a-e43e-c71fedae2b53.png)

また、Hello WorldデモのROSアプリケーションがどのように動作するのかをシミュレートするためのシミュレーションアプリケーションも準備されています。ROSアプリケーションと同様、実体はS3バケットにあります。

![09.png](https://qiita-image-store.s3.amazonaws.com/0/37648/b93b83d4-f196-2430-7920-6f6c3b7c77dc.png)

なおHello worldデモは、ROSで動作する教育用の自律移動ロボットである[Turtlebot3 Waffle Pi](http://emanual.robotis.com/docs/en/platform/turtlebot3/overview/)をロボットのモデルとして採用しているようです。
![Turtlebot3 Waffle Pi](http://emanual.robotis.com/assets/images/platform/turtlebot3/overview/turtlebot3_with_logo.png)

## シミュレーションでHello worldデモの動作を確認する
3クリックでシミュレーションコンテナが立ち上がったので、Hello worldデモでロボットがどのような動作をするのか確認してみます。

"Gazebo" をクリックし、コンテナ上で動作しているGazebo[^1]に接続します。新たにブラウザのウィンドウが立ち上がり、ブラウザ上にGazeboのGUIが表示されます[^2]。

![10.png](https://qiita-image-store.s3.amazonaws.com/0/37648/a65a34c1-0834-799b-4062-f2b0c0cddb7f.png)

GazeboのGUI上をしばらく眺めていると、Turtlebot3 Waffle Piがゆっくりと自転していることがわかります。Hello worldデモのROSアプリケーションは、ロボットをZ軸の周りに一定速度で自転させるような動作が実装されているようですね。

![robomaker_helloworld_1.gif](https://qiita-image-store.s3.amazonaws.com/0/37648/76466af8-f4b5-016b-fff6-60fcf0a0ccef.gif)

なおシミュレーション環境は、dockerコンテナとして動作している模様です。

![11.png](https://qiita-image-store.s3.amazonaws.com/0/37648/b870e9e3-8746-e3cd-95d6-8458ea125878.png)

[^1]: [Gazebo](http://gazebosim.org/)とは、オープンソースの3Dロボットシミュレータです。物理エンジンを持ち、ロボットが実際の環境でどのように動作するかをシミュレーションすることができます。
[^2]: ブラウザ上でコンテナ上のGazeboのGUIを表示する際には、AWSが買収した[NICE Desktop Cloud Visualization](https://aws.amazon.com/jp/about-aws/whats-new/2017/12/aws-and-nice-announce-the-general-availability-of-desktop-cloud-visualization-dcv-2017/)が使われているようです。

# Hello World デモのコードを修正する
では次に、このHello worldデモを改造してみましょう。ROSアプリケーションはPythonやC++で書くことが多いのですが、AWS RoboMakerは[Cloud9](https://aws.amazon.com/jp/cloud9/)を利用したブラウザ上で動作するROS開発環境も提供しているため、新たに開発環境を構築する必要はありません。便利ですね！

## VPCを作成する
RoboMakerのROS開発環境を入れておくためのVPCを作成しておきます。Public Subnetを一つ持つシンプルなVPCで十分です。

## ROS開発環境を起動する
"Development environments" から "Create environment" をクリックします。
![12.png](https://qiita-image-store.s3.amazonaws.com/0/37648/f562b27d-34a7-33be-c0af-145314e106d2.png)

ROS開発環境名とインスタンスタイプを入力し、さきほど作成したVPCを指定して "Create" をクリックします。
![13.png](https://qiita-image-store.s3.amazonaws.com/0/37648/0d2ff9a9-d1e0-e63b-25bc-1d6bba751f58.png)

CloudFormationによってEC2インスタンスが立ち上がり、Cloud9によるROS開発環境が起動します。"Open environment"をクリックすると、新たにブラウザのウィンドウが立ち上がります。
![14.png](https://qiita-image-store.s3.amazonaws.com/0/37648/c201436d-25d3-240c-41ff-32ceb9334ee1.png)

"AWS RoboMaker sample applications" から "Hello World" をクリックし、Hello worldデモのROSアプリケーションのうちロボットの動作を指示しているROSパッケージをROS開発環境に取り込みます[^3]。

[^3]: ROSのアプリケーションは、パッケージを基本として構成されます。ROSパッケージとは、ロボットのとある機能を簡単に再利用できるようにひとまとめにしたものです。Turtlebot3の動作を制御する機能はすでにROSパッケージとして公開されていますので、Hello worldデモではそのROSパッケージを再利用する形となっています。

![15.png](https://qiita-image-store.s3.amazonaws.com/0/37648/0456c973-cae2-a314-b8b8-c42fa13010ad.png)

![16.png](https://qiita-image-store.s3.amazonaws.com/0/37648/e78f5587-b544-ae46-8502-f40a61033a54.png)

## ROSワークスペースを初期化する
ROSでは、ワークスペースと呼ばれるディレクトリの配下で各々のパッケージのソースコードを実装していきます。RoboMakerでは "robot_ws" と "simulation_ws" という二つのワークスペースが使われますので、それぞれ初期化し、ビルドが通るか確認します[^4]。

![17.png](https://qiita-image-store.s3.amazonaws.com/0/37648/6f7873af-afbe-5020-20bf-93e02e231f92.png)

最下部の "bash" タブから、次のコマンドを実行します。エラーが発生せず、正常にビルドできたことを確認してください。

```bash
$ sudo apt update
$ sudo apt install python-rosinstall -y
$ rosdep update
$ cd $HOME/environment/HelloWorld/
$ cd robot_ws
$ rosws update
$ rosdep install --from-paths src --ignore-src -r -y
$ colcon build
$ cd ../simulation_ws/
$ rosws update
$ rosdep install --from-paths src --ignore-src -r -y
$ colcon build
```

[^4]: RoboMakerで使われているROS（Kinetic）では、通常ビルドコマンドとしては `catkin` が用いられます。RoboMakerで用いている [colcon](https://colcon.readthedocs.io/en/released/) は、ROS2（Bouncy）から採用されたビルドツールです。catkinにはROSパッケージ群をtarファイルとして一つにバンドルするような機能は無いため、あえてROS Kineticでは使われないcolconを採用したのでしょうか？ROS2やってない人にはツライ・・・

## Hello worldデモのソースコードを確認する
無事にビルドできたので、Hello worldデモのソースコードを読んでみます。Hello worldデモでロボットを操作しているROSパッケージは、Pythonで書かれています[^5]。そのため、ROSに詳しくなくても、読むのはそれほど難しくありません。次のPythonスクリプトを開いてください。

`$HOME/environment/HelloWorld/robot_ws/src/hello_world_robot/nodes/rotate`

![18.png](https://qiita-image-store.s3.amazonaws.com/0/37648/31964698-08c7-a54c-def4-2dc8b655c655.png)

[^5]: ROS（Kinetic）が提供するPythonライブラリは、OS（Ubuntu 16.04）のPython2.7を参照しています。あえて苦労したくない人は、Python2系で実装するのが無難です。

実はHello worldデモのROSパッケージは、この`rotate`というPythonスクリプトが全ての処理を担っています。ROS自体の解説はページが膨大になってしまうため割愛しますが、`rotate`がやってることは次の1点だけです。

* **0.1秒に1回、`/cmd_vel`というROS Topicへ、ロボットの並進速度と回転速度を定義した `Twist` という型のメッセージをpublishする**

```python:rotate
import rospy
from geometry_msgs.msg import Twist

class Rotator():
    def __init__(self):
        self._cmd_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)

    def rotate_forever(self):
        self.twist = Twist()

        r = rospy.Rate(10)
        while not rospy.is_shutdown():
            self.twist.angular.z = 0.1 # <- rotate velocity (rad/s)
            self._cmd_pub.publish(self.twist)
            rospy.loginfo("Rotating robot: %s", self.twist)
            r.sleep()


def main():
    rospy.init_node('rotate')
    try:
        rotator = Rotator()
        rotator.rotate_forever()
    except rospy.ROSInterruptException:
        pass

if __name__ == '__main__':
    main()
```

Turtlebot3のモーターを制御するROSパッケージは、この `/cmd_vel` をsubscribeしており、Twistで示された並進速度と回転速度になるように、イイカンジに動輪のモーターを制御してくれます。

Hello worldデモでは、 `self.twist.angular.z = 0.1` と **毎秒0.1ラジアンでz軸周りに回転する** ように指定しています。そのためシミュレーションで見たように、反時計回りでゆっくりとロボットが回転するのです。

## Hello worldデモのソースコードを修正する
ということで、次はロボットの動作を修正してみましょう。回転だけでなく、前（x軸正）にも 0.05 m/sで進むことにします。これにより、ロボットは直径1mの円を描いて反時計回りにゆっくり動くことになります。

```diff
@@ -10,6 +10,7 @@

         r = rospy.Rate(10)
         while not rospy.is_shutdown():
+            self.twist.linear.x = 0.05 # <- linear velocity (m/s)
             self.twist.angular.z = 0.1 # <- rotate velocity (rad/s)
             self._cmd_pub.publish(self.twist)
             rospy.loginfo("Rotating robot: %s", self.twist)
@@ -25,4 +26,4 @@
         pass
```

修正した `rotate` を保存し（Ctrl-SやCmd-S等のショートカットキーが使えます）、メニューバーの "RoboMaker Run > Build > HelloWorld Robot" でROSパッケージをビルドします。

![19.png](https://qiita-image-store.s3.amazonaws.com/0/37648/5725af61-511c-b2af-635c-23fb927ffbac.png)

シミュレーション用アプリケーションは修正していませんが、ついでに "RoboMaker Run > Build > HelloWorld Simulation" でビルドしておきます。

次に、シミュレーション環境にデプロイできるようにバンドルします。メニューバーの "RoboMaker Run > Bundle > HelloWorld Robot" から、ROSアプリケーションをバンドルしてください（初回は色々とライブラリをダウンロードしてくるため、時間がかかります）。
同様に、 "RoboMaker Run > Bundle > HelloWorld Simulation" からシミュレーションアプリケーションもバンドルしておきます。

## 修正したHello worldデモをシミュレートする
では、修正したROSパッケージをシミュレーションコンテナにデプロイし、ロボットの動作を確認しましょう。

RoboMakerのシミュレーションコンテナは、デフォルトでは1時間で終了します。最初に起動したシミュレーションコンテナが終了している場合、その環境をCloneして新たにシミュレーションコンテナを起動してください。

![20.png](https://qiita-image-store.s3.amazonaws.com/0/37648/18d3dcc6-93d3-1b85-01e2-92a6208b767b.png)
![21.png](https://qiita-image-store.s3.amazonaws.com/0/37648/78538970-74c1-9561-b9a8-bc628756c584.png)

シミュレーションコンテナが起動したら、ROS開発環境のメニューバーから "RoboMaker Simulation > Connect" でコンテナに接続します。

![22.png](https://qiita-image-store.s3.amazonaws.com/0/37648/9239ae83-9aff-513e-5b09-fee94e00cb7f.png)
![23.png](https://qiita-image-store.s3.amazonaws.com/0/37648/642240fb-ae72-8425-542f-9c286b85c0d5.png)

シミュレーションコンテナに接続したら、 "RoboMaker Simulation > Restart With New Bundles" で先ほどバンドルしたROSアプリケーションとシミュレーションアプリケーションをデプロイし、シミュレーションを再起動します（各バンドルのアップロードやコンテナの再起動を行うため、少し時間がかかります）。

![24.png](https://qiita-image-store.s3.amazonaws.com/0/37648/b20c73c3-fd5b-dd0d-a1c9-30cdd079bd63.png)
![25.png](https://qiita-image-store.s3.amazonaws.com/0/37648/026b8cf2-1614-9388-e195-1383ce4124c6.png)

シミュレーションコンテナのStatusが "Restarting" から "Running" になったら、準備完了です。Gazeboを開いてみましょう。

![robomaker_helloworld_2.gif](https://qiita-image-store.s3.amazonaws.com/0/37648/6d519252-6fcd-2c4f-e51f-3df311e1be3c.gif)

ロボットが直径1mの円を描いて移動するようになりました。

# 実機へデプロイする
最後に、修正したROSアプリケーションを[AWS Greengrass](https://aws.amazon.com/jp/greengrass/)を用いてTurtlebot3の実機へデプロイします。

**ただし私の手元にあるのがTurtlebot3 Waffle（ControllerにRaspberry PiではなくIntel Jouleを使ったモデル）のため、Turtlebot3 Waffle Piとは少し手順が異なります。**

## ロボットへROSアプリケーションをデプロイするための権限を設定する
まず最初に、インターネット越しにロボットへROSアプリケーションをデプロイできるようにするためのPolicyとRoleをIAMに設定します。

### IAM Policyを作成する
以下のjsonから "RoboMaker_HelloWorld_Qiita_Policy" という名前のPolicyを登録します。
**バケット名 `awsrobomakerhelloworld-999999999999-bundlesbucket-xxxxxxxxxxxx` は、CloudFormationが作成したS3のバケット名に置き換えてください。**

```json:RoboMaker_HelloWorld_Qiita_Policy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "robomaker:UpdateRobotDeployment"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:List*",
                "s3:Get*"
            ],
            "Resource": ["arn:aws:s3:::awsrobomakerhelloworld-999999999999-bundlesbucket-xxxxxxxxxxxx/*"]
        }
    ]
}
```

### IAM Roleを作成する
"RoboMaker_HelloWorld_Qiita_Role" という名前で、Greengrassを信頼するRoleを作成します。この際、先ほど作成した "RoboMaker_HelloWorld_Qiita_Policy" permission Policyを付与します。

![26.png](https://qiita-image-store.s3.amazonaws.com/0/37648/bf9dfcac-d041-056b-292a-9091bcd970c8.png)
![27.png](https://qiita-image-store.s3.amazonaws.com/0/37648/a14d0d9c-e796-2936-7606-252d8eb62737.png)
![28.png](https://qiita-image-store.s3.amazonaws.com/0/37648/bff8917e-6c05-7f7d-1587-8cc67037b87d.png)

作成された "RoboMaker_HelloWorld_Qiita_Role" を開き、 "Trust relationships" の "Edit trust relationship" をクリックします。

![29.png](https://qiita-image-store.s3.amazonaws.com/0/37648/9ea39c75-99da-4e9a-69f9-26c6fcba91e0.png)

次のように、greengrassに加えてlambdaも信頼関係に追加します。

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "lambda.amazonaws.com",
          "greengrass.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```
![30.png](https://qiita-image-store.s3.amazonaws.com/0/37648/2493c3ec-2dfc-831d-a5df-da2fcbc578b0.png)

## RoboManagerにRobotを登録する
次に、"Fleet managment > Robots > Create Robot" から、Robotを作成します。

![31.png](https://qiita-image-store.s3.amazonaws.com/0/37648/692e5cbc-1493-78de-4523-f53a20791c43.png)

今回デプロイするTurtlebot3 WaffleはIntel Jouleを用いているため、アーキテクチャは**X86_64**を選択しています（Turtlebot3 Waffle Piならば、 ARMHFになるはず）。
またIAM Roleには、先ほど作成したRoleを指定してください。

![32.png](https://qiita-image-store.s3.amazonaws.com/0/37648/a4e0eb4e-2cb1-6709-9842-bd54260775b6.png)

Robotを作成すると、AWS Greengrassのcore softwareと、Greengrassに接続するための秘密鍵をダウンロードできるようになります。
**注意： 秘密鍵は（おそらく）このページでしかダウンロードできないため、落とし忘れ無きように！！**

![33.png](https://qiita-image-store.s3.amazonaws.com/0/37648/6dd4d1fd-01ca-8cf7-81a8-9730deb2196c.png)

## greengrassのソフトウェアと秘密鍵をTurtlebot3 WaffleにSCPする
ダウンロードしたgreengrassのcoreソフトウェアと秘密鍵を、Turtlebot3 Waffleへscpします。

```bash
local:~$ scp ./Downloads/greengrass-linux-x86-64-1.7.0.tar.gz turtlebot3@turtlebot3.local:/home/turtlebot3
local:~$ scp ./Downloads/Turtlebot3_Waffle-setup.zip turtlebot3@turtlebot3.local:/home/turtlebot3
```

## Turtlebot3 WaffleにAWS Greengrass coreをセットアップする
Turtlebot3 WaffleにSSHして、AWS Greengrassに接続できるようにセットアップします。

### greengrass core用のuserとgroupを作成する
Greengrass coreは、`ggc_user`と`ggc_group`を使うようになっているため、あらかじめ作成しておきます。

```bash
turtlebot3@turtlebot3:~$ sudo adduser --system ggc_user
turtlebot3@turtlebot3:~$ sudo groupadd --system ggc_group
```

### ライブラリの存在を確認する
AWS Greengrass coreは、いくつかのライブラリが存在していることを前提としています。ロボットが要件を満たしているかを、ツールを使って確認します。

```bash
turtlebot3@turtlebot3:~$ cd /tmp
turtlebot3@turtlebot3:/tmp$ git clone https://github.com/aws-samples/aws-greengrass-samples.git
turtlebot3@turtlebot3:/tmp$ cd aws-greengrass-samples/greengrass-dependency-checker-GGCv1.7.0/
turtlebot3@turtlebot3:/tmp/aws-greengrass-samples/greengrass-dependency-checker-GGCv1.7.0$ sudo ./check_ggc_dependencies
```
エラーが出てないことを確認します。
（`nodejs6.10`や`java8`が無いという警告が出ますが、これは問題ありません。）

### AWS Greengrass coreと秘密鍵を展開する
scpしたAWS Greengrass coreのソフトウェアと秘密鍵を`/opt/greengrass`へ展開します。

```bash
turtlebot3@turtlebot3:~$ cd ~
turtlebot3@turtlebot3:~$ sudo tar -xzvf greengrass-linux-x86-64-1.7.0.tar.gz -C /opt/
turtlebot3@turtlebot3:~$ sudo unzip -o Turtlebot3_Waffle-setup.zip -d /opt/greengrass
```

またロボットがMQTT over TLSで[AWS IoT Core](https://aws.amazon.com/jp/iot-core/)に接続できるように、Root CAもダウンロードしておいてください。

```bash
turtlebot3@turtlebot3:~$ cd /opt/greengrass/certs/
turtlebot3@turtlebot3:/opt/greengrass/certs$ sudo wget -O root.ca.pem http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem
turtlebot3@turtlebot3:/opt/greengrass/certs$ wc /opt/greengrass/certs/root.ca.pem
  27   30 1758 /opt/greengrass/certs/root.ca.pem
```

### AWS Greengrass coreを起動する
`greengrassd start`コマンドで、AWS Greengrass coreのデーモンを起動してください。セットアップが上手く行っていれば、バックグラウンドでgreengrassのデーモンプロセスが起動しているはずです。

```bash
turtlebot3@turtlebot3:/opt/greengrass/certs$ cd /opt/greengrass/ggc/core/
turtlebot3@turtlebot3:/opt/greengrass/ggc/core$ sudo ./greengrassd start
Setting up greengrass daemon
Validating hardlink/softlink protection
Waiting for up to 40s for Daemon to start

Greengrass successfully started with PID: 15381
turtlebot3@turtlebot3:/opt/greengrass/ggc/core$ ps aux | grep greengrass
root     15381  0.6  0.4 384320 16824 pts/8    Sl   14:51   0:00 /opt/greengrass/ggc/packages/1.7.0/bin/daemon -core-dir /opt/greengrass/ggc/packages/1.7.0 -greengrassdPid 15376
turtleb+ 15407  0.0  0.0  15236  1024 pts/8    S+   14:51   0:00 grep --color=auto greengrass
```

## RoboManagerにFleetを登録する
Fleetは、Robotをグループ化するものです。FleetにRobotを登録することで、それらのロボットにROSアプリケーションをデプロイできるようになります。 "Fleets > Create fleet" をクリックします。
![34.png](https://qiita-image-store.s3.amazonaws.com/0/37648/7b612310-ef61-dbcd-f166-0d24872ef7b9.png)

"Turtlebot3_Waffle_fleet" という名前でFleetを作成します。
![35.png](https://qiita-image-store.s3.amazonaws.com/0/37648/68ad6efd-839a-0c41-0262-2f2c0d8bb19f.png)

作成されたFleetに、先ほど登録したRobotを追加します。まず "Register new" をクリックします。
![36.png](https://qiita-image-store.s3.amazonaws.com/0/37648/f483f3b0-c4b2-afdb-6d2e-36a90517d3c7.png)

登録したRobotを選択し、 "Register robot" をクリックします。
![37.png](https://qiita-image-store.s3.amazonaws.com/0/37648/b652473a-ff99-5d0c-d22e-e03b5daf3b9e.png)

FleetにRobotが追加されていることを確認します。
![38.png](https://qiita-image-store.s3.amazonaws.com/0/37648/31967e54-8319-3a88-c6c3-0640c56a0bd9.png)

## （必要であれば）ROSアプリケーションをクロスコンパイルする
Turtlebot3 WaffleはX86_64アーキテクチャなので不要ですが、Turtlebot3 Waffle PiなどCPUアーキテクチャが異なるロボットにアプリケーションをデプロイする場合は、CPUアーキテクチャに合わせてROSアプリケーションをクロスコンパイルしてバンドルし、S3バケットにアップロードする必要があります。

詳細は、RoboMakerのドキュメンテーション [Step 5: Deploy Robot Application To bundle and deploy the Hello World robot application](https://docs.aws.amazon.com/robomaker/latest/dg/gs-deploy.html#gs-deploy-bundle)の 1. ~ 4. を参照してください。

## Versionを作成する
RoboMakerは、ROSアプリケーションのバージョンを指定して実機へデプロイします。シミュレーションしか行っていない現時点ではバージョンが一つも作成されていないため、まずバージョンを作成します。

"RobotApplication" からROSアプリケーションを選択します。

![39.png](https://qiita-image-store.s3.amazonaws.com/0/37648/615d4313-8547-7ea1-c657-eed4c0620b17.png)

"Create new version" をクリックし、新しいバージョンを作成します。

![40.png](https://qiita-image-store.s3.amazonaws.com/0/37648/d1c50562-d216-f4c5-49d2-d1a7160fa8e1.png)
![41.png](https://qiita-image-store.s3.amazonaws.com/0/37648/1db464c2-bab4-61be-4555-88a930dcad7d.png)

今回は初回リリースなので、"1"というバージョンが作成されました。

![42.png](https://qiita-image-store.s3.amazonaws.com/0/37648/6dfba1c7-a1ba-1640-7401-18cc6400f1d8.png)

> もしX86_64以外のアーキテクチャのROSアプリケーションをデプロイしたい場合は、ROSアプリケーションを選択した後 "Actions > Update" をクリック、S3にアップロードしたバンドルファイルをsource fileとして指定してください。
> ![43.png](https://qiita-image-store.s3.amazonaws.com/0/37648/ba2af672-1a0d-bebc-79de-157024eae873.png)

## Deploymentを作成する
"Deployments > create deployment" から、Deploymentを作成します。

Turtlebot3 Waffle用に作成したFleetと、先ほど作成したバージョン "1" のRobot Applicationを指定します。
また、Package nameとして "hello_world_robot"を、Launch fileとして **"deploy_rotate.launch"** を入力し、 "Create" をクリックします。

![44.png](https://qiita-image-store.s3.amazonaws.com/0/37648/72ec884e-db37-c012-604b-20f90063b3b6.png)

指定したLaunch fileの実体は、 `$HOME/environment/HelloWorld/robot_ws/src/hello_world_robot/launch` 以下の`deploy_rotate.launch` です。

```xml:deploy_rotate.launch
<launch>
  <!-- bringup turtlebot3 -->
  <include file="$(find turtlebot3_bringup)/launch/turtlebot3_robot.launch"/>
  
  <!-- deploy rotate system -->
  <include file="$(find hello_world_robot)/launch/rotate.launch">
    <arg name="use_sim_time" value="false"/>
  </include>
</launch>
```

この `deploy_rotate.lauch` が呼び出されると、Turtlebot3の実機を動作させるためのROSパッケージ "turtlebot3_bringup" の `turtlebot3_robot.launch` と、今回改造した "hello_world_robot" パッケージの `rotate.launch` が起動します。

```xml:deploy.launch
<launch>
  <!-- 
       Using simulation time means nodes initialized after this
       will not use the system clock for its ROS clock and 
       instead wait for simulation ticks. 

       See http://wiki.ros.org/Clock

       Note: set to false for deploying to a real robot.
  -->
  <arg name="use_sim_time" default="true"/>
  <param name="use_sim_time" value="$(arg use_sim_time)"/>

  <!-- Rotate the robot on launch -->
  <node pkg="hello_world_robot" type="rotate" name="rotate" output="screen"/>
</launch>
```

`deploy.launch` は、先ほど修正した `rotate` スクリプトを実行します。これらが起動することで、指定したようにTurtlebot3が動き出すようになります。

## ROSアプリケーションをインターネット越しにリモートデプロイする
Deploymentが適切に作成されれば、ROSアプリケーションはTurtlebot3 Waffleの実機へ自動的にデプロイされ、指定した `deploy_rotate.launch` が自動起動してTurtlebot3 Waffleが動き出します。

![45.png](https://qiita-image-store.s3.amazonaws.com/0/37648/18299bb7-682c-79f8-ab8d-6d788e99b31c.png)

![turtlebot3_waffle.gif](https://qiita-image-store.s3.amazonaws.com/0/37648/55df6378-5872-0b7d-43c3-b8d579dbafd8.gif)

もし上手く動かなかった場合は、 `/opt/greengrass/ggc/var/log/user/<<region name>>/<<id>>/` 以下に作成されるログを確認してください。ROSアプリケーション起動失敗時のエラーが記録されているはずです。

## 注意点
1. ドキュメントの間違い
    * 2018/12/11時点でのRoboMakerの公式ドキュメントの [Step 5: Deploy Robot Application Bundle and deploy Hello World robot application](https://docs.aws.amazon.com/robomaker/latest/dg/gs-deploy.html#gs-deploy-bundle) では、Launch fileとして "rotate.launch" を指定するように記述されています。しかし"rotate.launch"を指定すると、ROSアプリケーションは正しくデプロイされますが、ロボットは動きません。これはTurtlebot3 Waffleのモーターなどを実際に動かすROSパッケージが起動されていないためです。
2. ストレージ容量
    * RoboMakerのROSアプリケーションバンドルには、ROSの実行ライブラリからTurtlebot3用のROSパッケージまで、環境一式がまるごと入っています。S3からダウンロードしたバンドルファイル自身やそれを展開したディレクトリの容量も計算すると、今回のHello worldデモで、ざっくり **4.3GB** の容量を費やしています。ストレージの空き容量には十分注意してください。
3. ネットワーク
    * RoboMakerは、ROS Masterの接続先としてホスト名を用います。そのため、ホスト名で名前解決できる（`$ ping $(hostname)` が返ってくる）ことを確認してください。

# まとめ
ということで、AWS RoboMakerを用いてデモを改造したROSアプリケーションを実際のロボットにデプロイすることができました。
ブラウザだけあればROSアプリケーションを書いてシミュレーションできること、またインターネット越しにロボットへROSアプリケーションをデプロイできるのは、面白い仕組みだと思います。

ただし、AWS RoboMakerで構築したROSアプリケーションは、ROSアプリケーション全体をまるっとデプロイする形になっているため、ロボットにすでにデプロイされているROSパッケージと連携する場合や、外部ですでに起動しているROS Masterに接続する場合など、実際のロボット開発で遭遇しそうなシチュエーションでは少し戸惑うことになる気がします。
（ROSパッケージも`catkin`ではなく`colcon`でビルドしているため、通常の`catkin`で作成されたROSワークスペースにそのままコピーすることもできませんし。）

このあたりは、今後もノウハウを蓄積する必要がありそうです。