WSL2でROS環境構築01

# 1. はじめに
訳あってAutowareを扱うことになりました。
（Autowareは日本発のオープンソースな自動運転ソフトウェアで、自動運転の世界シェア1位なんだって。すごいね！）

Autowareを扱うにはベースになっているROSを理解しないと話にならないので、まずはWindows11にWSL2でUbuntu20.04の環境を構築して、@srsさんの [ROS講座00 目次](https://qiita.com/srs/items/5f44440afea0eb616b4a) を頭から順番に始めて、 [ROS講座07 joyプログラム](https://qiita.com/srs/items/9114bb3c27a148e0b855)  までこなしました。

なんで素のUbuntuをインストールしないのかというと、普段使いのPCが1台しかないのでWindowsとUbuntuのデュアルブートやわざわざ新規にUbuntuのPCを用意したくないという理由だけです。
（2023.03現在、N100の小型PCが2万円程度で購入できるのでUbuntu専用にしてしまってもいいのですが…）

ここまでで自分への備忘録も兼ねて手順を残しておきます。

ちなみに前提として環境は

* Windows11 home 23H2
 CPU: AMD Ryzen7 7735U 2.7GHz
 SSD: 512GB
 RAM: 16GB
 joypad: Microsoft Corp. Xbox360 Controller (ID 045e:028e) 
 ↑こんな古いコントローラ使ってる人少ないと思いますが、これが後のハマりポイントでした…

* WSL2 - Ubuntu20.04
* ROS(1) Noetic

です。


# 2. WSL2でUbuntu20.04のセットアップ
ぶっちゃけ、microsoftの公式ドキュメントを見るのが一番確実で間違いがないです。
[Linux 用 Windows サブシステム で Linux GUI アプリを実行する](https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/gui-apps)

気を付けるべきは、ROSのバージョンによって推奨されるUbuntuのバージョンがあるということです。
[ROS NoeticはUbuntu 20.04を対象にしている](http://wiki.ros.org/noetic)ので、素直にUbuntu 20.04をセットアップすべきでしょう。
まずは
```powershell:powershell
> wsl --set-default-version 2
```
で既定のWSL バージョンをWSL2に設定します。
そのあとにUbuntuをインストールしますが、

```powershell:powershell
> wsl --update
```
ではなく、
```powershell:powershell
> wsl --update --distribution Ubuntu-20.04
```
とディストリビューションを指定して実行するか、Microsoft Storeで Ubuntu 20.04.6 LTSをインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/82ac5734-09d0-7222-08da-ced95be0029a.png)

あとは
```bash:bash
$ sudo apt-get update
$ sudo apt update
$ sudo apt install x11-apps -y
```
でパッケージの更新とX11アプリをインストールし、GUIアプリのxeyesが動作確認できればとりあえずはOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/89105952-b2e0-f915-ff67-eaeac71790b7.png)

### 日本語化

自分の場合はわかりやすいように [Win11のWSL2 (WSLg)を日本語化 & Mozcで日本語入力](https://astherier.com/blog/2021/07/windows11-wsl2-wslg-japanese/) をそのまま実施して日本語化しています。

# 3. ROSのインストール
[ROS講座02 インストール](https://qiita.com/srs/items/e0e0a9dc3f94c2d3348e) を順番にこなします。
記事作成時にROS KineticだったところをNoeticに修正されているので、一部修正漏れの部分があります。

```diff_shell:ros_noetic_install.sh
#!/bin/sh

sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
sudo apt install curl # if you haven't already installed curl
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -

sudo apt update
sudo apt install ros-noetic-desktop-full
apt search ros-noetic

- sudo apt-get install python-rosdep
+ sudo apt-get install python3-rosdep
sudo rosdep init
rosdep update

echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
source ~/.bashrc
source /opt/ros/noetic/setup.bash

- sudo apt-get -y install python-rosinstall
+ sudo apt-get -y install python3-rosinstall
sudo apt-get install -y python3-catkin-tools

+ mkdir -p ~/catkin_ws/src
+ cd ~/catkin_ws/src
+ catkin init
+ cd ~/catkin_ws
+ catkin build
+ echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc
+ source ~/.bashrc
```

```shell:make_ros_package.sh
cd ~/catkin_ws/src
catkin_create_pkg rospackage_test roscpp rospy std_msgs tf 
```

```diff_shell: ros_noetic_add_packages.sh
- sudo apt-get install -y ros-kinetic-joystick-drivers
- sudo apt-get install -y ros-kinetic-jsk-visualizationフォルダ
- sudo apt-get install -y ros-kinetic-image-proc
+ sudo apt-get install -y ros-noetic-joy
+ sudo apt-get install -y ros-noetic-jsk-visualization
+ sudo apt-get install -y ros-noetic-image-proc

+ sudo apt-get install -y git
+ sudo apt-get install -y vim
+ sudo apt-get install -y nano
```

# 4. 課題をこなす
基本的には講座の順番通りやっていけば食い違いはないですが、 [ROS講座11 gitリポジトリ](https://qiita.com/srs/items/25a56a6abda41dcf396e) を先に実施しておけばサンプルコードを取得できるので楽です。

# 5. Xbox360 コントローラのセットアップ(ハマりポイント)
[ROS講座07 joyプログラム](https://qiita.com/srs/items/9114bb3c27a148e0b855) でPS3のコントローラでウインドウ上の亀さんを動かします。
自分の場合は昔買ったXbox360のUSB接続のコントローラがあったのでこれを使ったのですが、最初はUbuntuで認識されず4時間ほど格闘する羽目になったので、手順を書き残しておきます。

### 5.1. Ubuntuのカーネルに手を加える
最終的に解決したのは 
[Gamepad support in WSL2 (/dev/jsx)](https://github.com/microsoft/WSL/issues/7747#issuecomment-1328217406) のフォーラムを見つけたのがきっかけでした。

まずは一旦、WSL2を終了します。
```powershell:powershell
> wsl --shutdown
```
https://github.com/microsoft/WSL/files/10098043/kernel-xpad.zip をダウンロードし解凍します。
解凍してできたbzImageとconfig-wslの2つのファイルはwindowsの%UserProfile%フォルダに移動しておきましょう。
bzImageへのパスは.wslconfigファイルに記述します。なければこのタイミングで作ります。
ついでに [.wslconfig で WSL2 が使用するCPU/メモリを制限する](https://scrapbox.io/snaka/.wslconfig_%E3%81%A7_WSL2_%E3%81%8C%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8BCPU%2F%E3%83%A1%E3%83%A2%E3%83%AA%E3%82%92%E5%88%B6%E9%99%90%E3%81%99%E3%82%8B) を参考に、CPUのコア数・メモリ使用量を制限してもいいと思います。

```.wslconfig
[wsl2]
memory=8GB
kernel=C:\\Users\\ユーザー名\\bzImage
```

最終的にフォルダ構成はこのようになります。

```windows11:windows11
C:
└── Users
    └── ユーザー名
        ├── .wslconfig
        ├── bzImage
        └── config-wsl
```
ここまでできたらWSL2を起動してもいいです。

### 5.2. Xbox360コントローラをUbuntuにマウントする
[USB デバイスを接続する
](https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb) が参考になりますが、一部コマンドが変わる部分があります。

まずはusbipd-winプロジェクトをインストールします。

```powershell:powershell
> winget install --interactive --exact dorssel.usbipd-win
```

インストールできたら```usbipd list```コマンドでデバイスとバスIDを確認します。
```powershell:powershell
> usbipd list
Connected:
BUSID  VID:PID    DEVICE                                                        STATE
1-3    04f2:b760  HP Wide Vision HD Camera, Camera DFU Device                   Not shared
1-4    04f3:0c00  ELAN WBF Fingerprint Sensor                                   Not shared
2-1    045e:028e  XBOX 360 Controller For Windows                               Not shared
2-3    0489:e0f2  MediaTek Bluetooth Adapter                                    Not shared
```
XBOX 360 Controllerは認識されていますが、STATEがNot sharedなのでWSL2とは共有もしくはアクセス権を渡せていない状態です。
なので、WSL2が起動した状態で```usbipd bind --busid [バスID]```コマンドでデバイスを共有します。
多くの記事では
```powershell:powershell
> usbipd bind --busid 2-1
usbipd: warning: A reboot may be required before the changes take effect.

> usbipd list
Connected:
BUSID  VID:PID    DEVICE                                                        STATE
1-3    04f2:b760  HP Wide Vision HD Camera, Camera DFU Device                   Not shared
1-4    04f3:0c00  ELAN WBF Fingerprint Sensor                                   Not shared
2-1    045e:028e  XBOX 360 Controller For Windows                               Shared
2-3    0489:e0f2  MediaTek Bluetooth Adapter                                    Not shared
```
にすればUbuntu側でも使用できるような記述でしたが、自分の環境では```usbipd bind```コマンドに```--force```オプションを追加してホストからアクセス不可にしないとUbuntu側で認識できませんでした。
※なお、```usbipd list```コマンドは記事上でステータスの確認のために記述しているので、毎回実施する必要はないです。
```powershell:powershell
> usbipd bind --force --busid 2-1
usbipd: warning: A reboot may be required before the changes take effect.

> usbipd list
Connected:
BUSID  VID:PID    DEVICE                                                        STATE
1-3    04f2:b760  HP Wide Vision HD Camera, Camera DFU Device                   Not shared
1-4    04f3:0c00  ELAN WBF Fingerprint Sensor                                   Not shared
2-1    045e:028e  XBOX 360 Controller For Windows                               Shared (forced)
2-3    0489:e0f2  MediaTek Bluetooth Adapter                                    Not shared
```
ここまで実施できれば、WSL2のUbuntuで```lsusb```コマンドを実行すればデバイスが認識できているのが確認できると思います。
```bash:bash
$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 045e:028e Microsoft Corp. Xbox360 Controller
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
```

### 5.3.  Xbox360コントローラのドライバをセットアップする

[Making an Xbox Controller work on Ubuntu!](https://forum.arduino.cc/t/making-an-xbox-controller-work-on-ubuntu/1134394) というそのものずばりなタイトルのフォーラムの内容を実施します。
まずはxboxdrv(Linux 用のXbox/Xbox360コントローラドライバ)をインストールします。
ついでに、joystick の動作確認ができるGUIソフトのjstest-gtkもインストールしましょう。
```bash:bash
sudo apt-get install xboxdrv jstest-gtk
```
xboxdrv を動作させるには毎回 xpad を削除する必要があるそうです。
```bash:bash
sudo rmmod xpad
```
これを回避するためには```blacklist xpad```の一文をブラックリストの末尾に追記します。
(編集にはroot権限が必要です)
```diff_shell:/etc/modprobe.d/blacklist.conf
+ blacklist xpad
```

これで xboxdrv を実行できるようになり、```sudo xboxdrv```コマンドを実行するとコントローラにキーマップの割り当てられ、さらに```jstest-gtk```を実行するとボタン・ジョイスティックの状態をGUIで確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/c3524ee6-ec02-9f4c-41d0-8d3112d34921.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/3b9ae0b0-6cca-9eb6-9e50-49daea95dec4.png)

なお、```sudo xboxdrv```の```sudo```を回避するには、```/etc/udev/rules.d```ディレクトリ内にルールファイルを作ればよいみたいです。
```/etc/udev/rules.d/51-xboxdrvRule.rules
SUBSYSTEM=="usb", ACTION=="add", ATTRS{idVendor}=="045e", ATTRS{idProduct}=="028e", GROUP="plugdev", MODE="660"
KERNEL=="uinput", MODE="0666"
```
### 5.4. ROS講座07の完走
これでようやく、[ROS講座07 joyプログラム](https://qiita.com/srs/items/9114bb3c27a148e0b855) をWSL2のUbuntu上でXbox360コントローラを使って完走できます・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/d87c6343-ce76-0282-3a24-2cf732f0c713.png)

お疲れさまでした。

# 6. 参考資料
http://wiki.ros.org/noetic

https://qiita.com/srs/items/5f44440afea0eb616b4a

https://qiita.com/srs/items/e0e0a9dc3f94c2d3348e

https://qiita.com/srs/items/25a56a6abda41dcf396e

https://qiita.com/srs/items/9114bb3c27a148e0b855

https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/gui-apps

https://astherier.com/blog/2021/07/windows11-wsl2-wslg-japanese/

https://github.com/microsoft/WSL/issues/7747#issuecomment-1328217406

https://scrapbox.io/snaka/.wslconfig_%E3%81%A7_WSL2_%E3%81%8C%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8BCPU%2F%E3%83%A1%E3%83%A2%E3%83%AA%E3%82%92%E5%88%B6%E9%99%90%E3%81%99%E3%82%8B

https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb

https://forum.arduino.cc/t/making-an-xbox-controller-work-on-ubuntu/1134394