【ROS/WSL2】WSL2上のROSと外部PCで通信してみたかった

# はじめに
先日Jetson Nanoを購入したり、WSL2上のROSにOpenRTM2.0をいれたりして遊んでいたのでせっかくならこれらの2台のPCでROSの通信できないかなと思いやってみました。

WSL2での遊びは以下を参考にしてください。
[【ROS/Unity/WSL】Windows上でmyCobotをROSとUnity上で動かす](https://qiita.com/koichi_baseball/items/dcc14a4c9fcc2ee854d9)
[【OpenRTM】OpenRTM-aist 2.0 (ROS transport含む)のインストール (ソースからのビルド)](https://qiita.com/koichi_baseball/items/23c880cbc67648a115f6)

# 結論

:::note warn
一応通信はできましたが、ROSのPC⇒WSL上のUbuntu方向のみ(それも通信自体が不安定)でした。これができて喜んでいたら逆方向はできなかったです。。rostopic echoで値が読めない
:::

2021/12/02 続きを書きました！

https://qiita.com/koichi_baseball/items/8d15a06d296c09908f5f


# 環境

 - PC1
   - Jetson Nano
   - ROS Melodic
 - PC2
    - Windows10
    - WSL2
    - ROS Melodic

PC1は普通のUbuntuのPCでも試しましたが、同じ結果でした。

# やったこと
やったこととしては、

**・Windows⇔WSLのポートフォワーディング**
**・ROS_HOSTNAMEなどの設定**
**・JesonNano⇔Windows⇔WSLの静的ルートの設定**

以上です。

# Windows⇔WSLのポートフォワーディング
## Windows PCでの作業
### ポートフォワーディング
主に以下の記事を参考にさせていただきました。今回は、SSHのために22ポートと、ROSの通信のために11311ポートをあけます。

https://qiita.com/yabeenico/items/15532c703974dc40a7f5

一部抜粋、追加して載せます。詳細は上の記事を読んでください。

Windows PCのPowerShellまたはコマンドプロンプトを**管理者権限**で起動して以下のコマンドを実行してください。

```bash:Windows上のポートフォワーディング設定
$ netsh.exe interface portproxy add v4tov4 listenport=22 connectaddress=(wsl -d Ubuntu-18.04 exec hostname -I).trimend()
$ netsh.exe interface portproxy add v4tov4 listenport=11311 connectaddress=(wsl -d Ubuntu-18.04 exec hostname -I).trimend()
```

以下のコマンドで状態の確認をすることができます。`172.~`がWSL2のIPアドレスです。
以下のような表示になっていれば設定が完了しています。

```bash:Windows上のポートフォワーディング設定の確認
$ netsh.exe interface portproxy show v4tov4
ipv4 をリッスンする:         ipv4 に接続する:

Address         Port        Address         Port
--------------- ----------  --------------- ----------
*               22          172.25.26.47    22
*               11311       172.25.26.47    11311
```

また、今設定したポートフォワーディングを動作させるには`IP Helper`を起動する必要があるため以下のコマンドを実行してください。

```bash:Windows上のポートフォワーディングの起動
$ sc.exe config iphlpsvc start=auto # ブート時の自動起動設定
$ sc.exe start  iphlpsvc            # サービスの起動
```

ポートフォワーディングのルールの削除は以下のコマンドです。22Portの方を削除する場合

```bash:Windows上のポートフォワーディング設定の削除
$ etsh.exe interface portproxy delete v4tov4 listenport=22 connectaddress=(wsl -d Ubuntu-18.04 exec hostname -I).trimend()
```

### ファイアウォールの設定
22と11311ポートをあけます。

```bash:Windows上のファイアフォール設定
$ New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort 22 -Action Allow -Protocol TCP
$ New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort 22 -Action Allow -Protocol TCP
$ New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort 11311 -Action Allow -Protocol TCP
$ New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort 11311 -Action Allow -Protocol TCP
```

削除する場合

```bash:Windows上のファイアフォール設定の削除
$ Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock'
```

## WSL2での作業
SSHのコンフィグの設定と再起動をします。
以下のコマンドでエディタを開いて、ポートとパスワード認証の設定を更新します。

```bash:WSL上でのSSH設定
$ sudo nano /etc/ssh/sshd_config
~~~~~ 一部抜粋
Port 22
#AddressFamily any
ListenAddress 0.0.0.0
ListenAddress ::1
~~~~~ 一部抜粋
PasswordAuthentication yes
```

それが終わったらSSHサービスを再起動します。

```bash:WSL上でのSSH再起動
$ sudo service ssh restart
```

:::note info
ここまでで、外部PCからSSH接続をすることができます。
Windows PCのIPアドレスを使用してSSH接続を行うと、WSL2で動いているUbuntuへ接続できます。
:::

# ROS_HOSTNAMEなどの設定
`~/.bashrc`に設定を追加します。
以前、以下の記事を書いた際は、`ROS_MASTERURI`と、`ROS_HOSTNAME`のみ追加しましたが、`ROS_IP`も追加した方がいいという記事もいくつかみました。調査中です。

また、Ubuntuが載っているPCの方で`roscore`を起動することとします。

https://qiita.com/koichi_baseball/items/ca63044d9d8baf05984d


```bash:UbuntuPCの~/.bashrcに追加
 export ROS_MASTER_URI=http://UbuntuPCのIPアドレス:11311
 export ROS_HOSTNAME=UbuntuPCのIPアドレス
 export ROS_IP=UbuntuPCのIPアドレス
```


```bash:WSL上のUbuntuの~/.bashrcに追加
 export ROS_MASTER_URI=http://UbuntuPCのIPアドレス:11311
 export ROS_HOSTNAME=WSL2のUbuntuのIPアドレス
 export ROS_IP=WSL2のUbuntuのIPアドレス
```


# ポートフォワーディング
ネットワーク関係はこのようになっているはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426354/ac3f4b4f-f377-baf3-583b-e079c127cf88.png)


2つのネットワークがあります。
 - Ubuntu PCとWindowsPCが載っているWiFi
 - Windows内部のWSL用の仮想ネットワーク
よって、これらを使用して通信できる用にネットワークの静的ルーティングを追加します。
以下のコマンドを使用します。

以下、上図のIPアドレスを使用します。
※Windows10のvEthernet(WSL)はWindowsから`ipconfig`コマンド等で見えるWSL2のアドレスです

```bash:静的ルーティングの追加
$ route add -net 宛先IPアドレス netmask 255.255.255.0 gw デフォルトゲートウェイ
```

WSL上で以下を追加します。

```bash:WSL上でのルーティング設定
$ sudo route add -net 192.168.11.0 netmask 255.255.255.0 gw 172.25.16.1
```

もう片方のPCで以下実行します。

```bash:UbuntuPCでのルーティング設定
$ sudo route add -net 172.25.26.0 netmask 255.255.255.0 gw 192.168.11.3
```

確認(上2つの項目はもとからあるもので、いちばん下の項目が今回追加したもの)

```bash:WSL上でのルーティング確認
$ netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         172.25.16.1     0.0.0.0         UG        0 0          0 eth0
172.25.16.0     0.0.0.0         255.255.240.0   U         0 0          0 eth0
192.168.11.0    172.26.16.1     255.255.255.0   UG        0 0          0 eth0
```

## ネットワークのルーティングの参考

https://risc.readthedocs.io/2-networking.html

https://answers.ros.org/question/256070/problems-with-communication-between-multiple-machines/

# 動作確認
## roscoreの起動
Ubuntu PCで`roscore`を起動します。

この時点で、どちらのPCからも`rostopic list`は確認することができました。

## WSL上でROSノードを起動
カメを起動しましょう

```bash:WSL上でカメを起動
$ rosrun turtlesim turtlesim_node
```

## Ubuntu PCから操作

```bash:UbuntuPCで操作
$ rosrun turtlesim turtle_teleop_key
```

自分の場合、この操作はできました。ただ、WSLの方から`rostopic echco`でトピックの通信を見ようとしたり、UbuntuからWSL上のROSノードがPublishしているトピックを見ようとしたりすると見えなかったです。

# さいごに
お騒がせしました。。。

たくさん調べていたらこんなものも見つかり、

https://github.com/FS-Driverless/Formula-Student-Driverless-Simulator/issues/227

なんだかそれ用のソフトウェアも公開されているみたいでした。試してはいないですが、WSL上のROSと通信するのは結構大変みたいでした。

https://github.com/RyanDraves/wsl2_ros_bridge

ちなみに、`ping`の疎通確認ですが、これは
WSL上UbuntuからUbuntuPCへ　⇒　通る〇
UbuntuPCからWSL上Ubuntuへ　⇒　通らない✖
となりました。片方は通っているのでルーティングの設定は合っているんじゃないかと思います。`netcat`コマンド等での疎通確認も同じ現象が起きます。

起きている現象としてはこれっぽかったです。

https://qiita.com/aecs4to55/items/30640c32995b64ca3a68

また何かわかったら追記します！