ROS講座20 複数のPCでROS接続1

# 環境
この記事は以下の環境で動いています。

| 項目 | 値 |
|:-:|:-:|
| CPU | Core i5-8250U |
| Ubuntu | 16.04 |
| ROS | Kinetic |

インストールについては[ROS講座02 インストール](https://qiita.com/srs/items/e0e0a9dc3f94c2d3348e)を参照してください。
またこの記事のプログラムはgithubにアップロードされています。[ROS講座11 gitリポジトリ](https://qiita.com/srs/items/25a56a6abda41dcf396e)を参照してください。

# 概要
ここまではROSを1つのPC上で動作させてきました。しかし、ロボット開発では複数のPCを使用することが多々あります。例えばロボットのコンピューターは貧弱なので、画像処理だけサーバーで行いたい時や、ロボットで動くROSの中身をノートパソコンのRvizで見たい時です。
そのような場合でもROSなら1つのPCで実行している時と変わらないように複数のPCでも動作させることができます。この設定を説明します。

# ROSの接続
基本的な構成ではROSは1つのPCで動きます。ROS講座2でも出てきたtalkerとlistenerの例では以下の図のようにmaster、talker、listenerの3つのプログラムが動作しています。masterはROSの起動後に必ず起動するプログラムでざっくりいうとROSノードの管理を行います。

## 単一PC内でのROS
1. ROSノードであるtalkerやlistenerは起動したらまず最初にmasterに接続して、そのROSノードのPublusherやSubscriberがどのROSノードと接続すべきかなどの情報を取得します（図中の点線）
2. その後にROSノード同士の通信を開始します（図中の実線）

![リモート1.png](https://qiita-image-store.s3.amazonaws.com/0/254442/7e1cfc26-bb08-f519-755c-718db318709d.png)

## 複数PC間でのROS
一方複数のPCにまたいだROSの実行でも基本的なことは変わりませんが、一部違うところがあります。便宜的に今回は手元のPCをnote1、リモートで操作するPCをrobot1と呼びます。

* robot1のROSノードが起動するときにnote1上で実行しているROS masterに接続すること
* note1のtalkerとrobot1のlistenerがPCをまたいだ通信を行うこと

![リモート2.png](https://qiita-image-store.s3.amazonaws.com/0/254442/c683c9d1-478f-b500-95ce-95b0419d9bad.png)

# ネットワーク構成
note1とrobot1はネットワークで接続する必要があります。これは有線(Ethernet)でも、無線(Wifi)でもかまいません。基本的にLAN内での通信でなら問題はありませんが、多くのポートでの通信があるためにインターネット越しでの通信はブロックされる可能性があるので難しいです。

1. 固定アドレスの場合  
各PCに固定アドレスを設定する場合です。通信するPCのIPアドレスが固定されるために構成が楽です。一方IPアドレス固定の作業が面倒、ネットワーク構成が変わった時への対処が面倒です。
2. DHCPの場合（PCのIPアドレスを固定する）  
DHCPを使いますがDHCPサーバーに設定をして、各PCのMacアドレスを見て固定のIPを設定する方法です。ネットワーク構成の変更が容易で、使いやすいですが、DHCPサーバーの設定をいじらないといけないです。
3. DHCPの場合（PCのIPアドレスを固定しない）
IPアドレスが固定されていないので名前解決をしなければなりません。これにはAvahiを使います。しかし、この方法はmulti castを行うためにネットワーク機器によってはブロックされてよく問題が起きる部分でトラブルの元です。

個人的には**(1)や(2)のアドレスを固定することを強く推奨**します。

#ネットワークの設定
以下の手順で複数PCでのROS通信を設定します。

## 各ノードのIPアドレスの確認

以下のコマンドを実行して

```shell:note1、robot1の両方のターミナルで
ifconfig
```

## pingで接続確認
以下の手順で通信ができるか確認します。

以下のコマンドを実行して

```shell:note1のターミナルで
ping 192.168.1.20
```

```shell:robot1のターミナルで
ping 192.168.1.10
```

## ROS通信の確認

ROSの通信を行うには環境変数の設定が必要です。

* `ROS_MASTER_URI`  
これは起動時に問い合わせるros masterのアドレスの設定です。デフォルトでは`http://localhost:11311`になっていて、自分のPC上のros masterに問い合わせます。今回robot1のROSノードはnote1のmasterに問い合わせるのでrobot1ではこの部分の書き換えを行います。
* `ROS_IP`  
これはROSの通信時に使う自分のマシンのIPアドレスです。デフォルトでは空欄でlocalhost内ならこれでも問題はないのですが、PC間をまたぐ通信を行う場合は双方で設定する必要があります。

合わせると以下のコマンドを打てばよくなります。今回はnote1でroscoreを立ち上げて、robot1からそのroscoreにアクセスしてみます。

```shell:note1のターミナルで
export ROS_IP=192.168.2.10
roscore
```

```shell:robot1のターミナルで
export ROS_MASTER_URI=http://192.168.2.10:11311
export ROS_IP=192.168.2.20
rosnode list
```

これらの設定はターミナルを閉じると消えてしまいます。ターミナルを開くごとに上記のコマンドを打つ必要があります。

## 自分のIPアドレスの自動取得
上記の例では`export ROS_IP=192.168.2.10`のように自分のIPアドレスをハードコーティングしています。しかしネットワーク接続が変わる（例えばwifi接続とEther接続の時）ことでIPアドレスも変わるので、できるだけハードコーティングは避けたいですね。そこで自分のアドレスをコマンドで取得します。
まず自分に割り振られているコマンド一覧を`hostname -I`で取得します。すると`192.168.2.10 192.168.2.52 2408:52:c731:0:1576:1344:65f6:7aab`のように割り当てられているアドレスがスペース区切りのリストとして来ます。これを`cut`コマンドを使って取り出します。

```shell:自分のIPアドレスを取得
hostname -I| cut -d' ' -f1
```
これで`192.168.2.10`のような値が取り出せます。
このコマンドを使うと上記のコマンドは

```shell:note1のターミナルで
export ROS_IP=`hostname -I | cut -d' ' -f1`
roscore
```

```shell:robot1のターミナルで
export ROS_MASTER_URI=http://192.168.2.10:11311
export ROS_IP=`hostname -I | cut -d' ' -f1`
rosnode list
```

と書けます。

# ROSの分散実行
まずnote1側でmasterを立てます。後はいつもと同じように実行するだけです。今回はROS講座03でも出てきたシンプルなpub,sub通信をします
なおnote1、robot1の両方で該当のROSノードを製作してsourceをしている必要があります。

```shell:note1の1つ目のターミナルで
roscore
```

```shell:note1の2つ目のターミナルで
rosrun basic_lecture basic_simple_talker 
```

```shell:robot1のターミナルで
export ROS_MASTER_URI=http://192.168.2.10:11311
rosrun basic_lecture basic_simple_listener 
```

# 目次ページへのリンク
[ROS講座の目次へのリンク](https://qiita.com/srs/items/5f44440afea0eb616b4a)