Docker + ROS(kinetic)でチュートリアル

## なにするの
ここではDockerをつかって、ROSのチュートリアルを動かしてみようと思います。
ROSをDocker上で動かすメリットとしては、以下があります。

- OSの環境を汚さない
- Dockerさえ動いていれば、環境／マシンが変わっても動作できる

デメリットとしては以下の問題もあります。

- マシンのリソースをフルに使えない

Docker上でROSを動作させることに魅力を感じるのであれば、この記事に納得できると思います！


## チュートリアルでやること
`master`, `talker`, `listener`の３つを動作させて、
talkerが発するメッセージをlistenerが聞くだけです。

もちろん、talkerとlistenerだけがいてもメッセージのやり取りはできないのでmasterが必要ですね。

# まずはdockerイメージのpullから
`docker pull ros:kinetic`

ドキュメント: https://hub.docker.com/r/_/ros/
pullするのは`ros`だけでも良いです。
たくさんのtagが用意されているので、お好きなディストリビューションのrosを入れましょう。
（kineticは2016/11/13現在で最新）

# tutorialsファイルをインストール
Dockerfileを作ってbuildします。

```Dockerfile
FROM ros:kinetic
# install ros tutorials packages
RUN apt-get update && apt-get install -y
RUN apt-get install -y ros-kinetic-ros-tutorials \
    ros-kinetic-common-tutorials \
    && rm -rf /var/lib/apt/lists/
```

> 注意：
> インストールするチュートリアルのパッケージは、
> ROSのディストリビューションによって名前が違います。
> 上の`Dockerfile`の例では`ros-kinetic-ros-tutorials`というように`kinetic`のものをインストールしています。
> indigoならindigoのものに書き換えましょう。

チュートリアルのインストールができたイメージは、元のイメージと区別するために`ros-tutorials`というtagをつけます。

`docker build --tag ros:ros-tutorials .`

# Dockerのネットワークを作成
これから動かす`master`, `talker`, `listener`を同じネットワークに入れたいです。
ここでは`rosnet`という名前でネットワークを作っておきましょう。
`docker network create rosnet`


# 起動してみましょう！
## masterを起動
hostをmasterにする必要があるため`-h master`をつけます。
また、`--net rosnet`で先程つくったネットワークに所属させましょう。
`docker run -it --rm --net rosnet --name master ros:ros-tutorials roscore`

## talkerを起動
masterとほぼ同じです。
`docker run -it --rm --net rosnet --name talker --env ROS_HOSTNAME=talker --env ROS_MASTER_URI=http://master:11311 ros:ros-tutorials rosrun roscpp_tutorials talker`

こんな出力が出ると思います

```
[ INFO] [1478972564.886917267]: hello world 0
[ INFO] [1478972564.987402593]: hello world 1
[ INFO] [1478972565.087038287]: hello world 2
[ INFO] [1478972565.187424574]: hello world 3
[ INFO] [1478972565.289820280]: hello world 4
[ INFO] [1478972565.388935922]: hello world 5
...
```

## listenerを起動
`docker run -it --rm --net rosnet --name listener --env ROS_HOSTNAME=listener --env ROS_MASTER_URI=http://master:11311 ros:ros-tutorials rosrun roscpp_tutorials listener`

先にtalkerを起動していれば、talkerのメッセージを受信して、
こんな出力が出ると思います。

```
[ INFO] [1478972565.088147030]: I heard: [hello world 2]
[ INFO] [1478972565.189187089]: I heard: [hello world 3]
[ INFO] [1478972565.291535690]: I heard: [hello world 4]
[ INFO] [1478972565.390682548]: I heard: [hello world 5]
...
```

これで疎通は確認できました！
チュートリアルとしては以上です、あとは自身のプログラムに載せ替えましょう！

# おまけ：Docker Composeする
同じマシンですべて起動するなら、docker-composeでぱぱっとやってしまうこともできます
docker-composeするとネットワークも自動でつくられ、全てのコンテナが作られたネットワークに入れられます。

以下のようなymlファイルをDockerfileと同じディレクトリに作成しましょう。

```docker-compose.yml
version: '2'
services:
  master:
    build: .
    container_name: master
    command:
      - roscore

  talker:
    build: .
    container_name: talker
    environment:
      - "ROS_HOSTNAME=talker"
      - "ROS_MASTER_URI=http://master:11311"
    command: rosrun roscpp_tutorials talker

  listener:
    build: .
    container_name: listener
    environment:
      - "ROS_HOSTNAME=listener"
      - "ROS_MASTER_URI=http://master:11311"
    command: rosrun roscpp_tutorials listener
```

作成できたら、
`docker-compose up`
で`docker build`から`run`までやってくれます！

# 参考文献
- [DockerHub - ros](https://hub.docker.com/r/_/ros/)
- [ROS + Dockerを使ったロボットアプリケーション入門（１）準備編](http://tech-sketch.jp/2015/10/ros-docker-1.html)
- [dockerでROSを試したい](http://qiita.com/akachochin/items/129181da9cbf23e8b22f)