実機環境やDocker、WSLを使用したROS2の環境構築【rqt対応】

# 前書き
研究室でROS2の勉強会をすることになりましたので環境構築についてまとめます。

勉強会では様々なOSを使用することを想定しているのですが、OSによってはROS2を直接インストールができません。
そのためDocker、WSLを用いてUbuntu環境を構築し、その後にROS2のインストールをすることにしました。

# 目的の環境
以下が使用できる環境を目的とします。
- ROS2(基本はFoxy)
- colcon
- GUIツール(本記事ではrqtを対象)

# インストール方法
環境構築の方法は下記のとおりです。
自分の使用OSにあった方法で環境構築をしてください。

1. 実機環境にROS2 Foxyをインストール(Ubuntu 20)
2. 実機環境にFoxy以外のバージョンのROS2をインストール(Ubuntu 22, 24)
3. WSLを使用する(Windows 10, 11)
4. Dockerを使用する(どのOSもOK)

## 方法1. 実機環境にROS2 Foxyをインストール
対象: Ubuntu 20

通常のROS2のインストールです。
詳しくは[公式ドキュメント](https://docs.ros.org/en/foxy/Installation/Ubuntu-Install-Debians.html)を参照ください。
```bash
# ROS2のaptリポジトリを追加
sudo apt install software-properties-common -y
sudo add-apt-repository universe

sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

# ROS2のインストール
sudo apt update && sudo apt upgrade -y

sudo apt install ros-foxy-desktop -y
sudo apt install python3-argcomplete -y
sudo apt install ros-dev-tools -y

# sourceコマンドをbashrcに追加(任意)
echo "source /opt/ros/foxy/setup.bash" >> ~/.bashrc
```

`~/.bashrc`にsourceコマンドを追加した方はターミナルを開き直してください。

## 方法2. 実機環境にFoxy以外のバージョンのROS2をインストール
対象: Ubuntu 22(未検証), Ubuntu 24(未検証)

Ubuntu 22, 24を使用しているのならば、ROS2の他のバージョンを入れるのが楽です。
22ならHumble([ドキュメント](https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debs.html))、24ならJazzy([ドキュメント](https://docs.ros.org/en/jazzy/Installation/Ubuntu-Install-Debs.html))をインストールしてください。

インストール方法はFoxyとほぼ差異は無く、foxyと書かれている部分をhumbleまたはjazzyに置き換えるだけです。

## 方法3. WSLを使用する
対象: Windows 10(未検証), Windows 11

以下の引用にあるとおり、WSLではWindows上でLinuxが動かせます。
> WSLを使うと、Windows コンピューター上で Linux 環境を実行でき、別の仮想マシンやデュアル ブートは必要ありません。 (Microsoft公式サイトより引用)

Windows上でUbuntuを動かし、そこでROS2をインストールします。
WSL2ならばGUIも動作するので、rqtなどのGUIツールも動きます。

### WSLのインストール

PowerShell上で以下のコマンドを実行してUbuntu 20.04をインストールします。
```powershell:powershell
wsl --install -d Ubuntu-20.04
```

※今後長くWSLを使用する場合は、Ubuntu 20ではなく22や24をインストールした方が良いかもしれません。

### WSLの起動

以下のコマンドからUbuntuに入ることができ、初回起動時には設定するユーザ名やパスワードが聞かれます。
```powershell:powershell
wsl
```

### ROS2のインストール

その後のインストールは[実機環境にROS2 Foxyをインストール](#方法1-実機環境にros2-foxyをインストール)と同様です。

## 方法4. Dockerを使用する
対象: Intel Mac, Apple Silicon Mac, Ubuntu(20のみ検証済み), Windows(未検証）, 他Dockerが動く環境?

以下の引用にあるとおり、Dockerを使用することで、仮想化したOSを実機のパソコン上で開発・実行できます。
> Dockerはコンテナ仮想化を用いた**OSレベルの仮想化**によりアプリケーションを開発・実行環境から隔離し、アプリケーションの素早い提供を可能にする。かつその環境自体をアプリケーションと同じようにコード（イメージ）として管理可能にする。(Wikipediaより引用)

Dockerを使用してROS2インストール済みのUbuntuを動かします。

ROS2のみの実行ならば既に`ros:foxy`というイメージがあるので問題がないのですが、
今回はrqtなどのGUIツールを動作させるために、色々と追加で記載しています。

### Dockerのインストール
以下を参考にDockerをインストールしてください。
Docker Desktopのインストールすると簡単に必要なDockerの機能がインストールされます。
https://docs.docker.com/engine/install/

### ワークスペースとDocker関連ファイルの作成
実機PC上で任意の名前のワークスペースを作成します。
```bash
mkdir workspace
cd workspace
```

workspaceの中に`Dockerfile`と`docker-compose.yml`を追加します。
```dockerfile:Dockerfile
FROM ros:foxy

RUN apt update

RUN apt install ros-foxy-rqt* -y
RUN apt install ros-foxy-turtlesim -y

RUN apt install nano curl -y
RUN apt install wget -y

RUN touch /root/.bashrc
RUN echo "umask 0000" >> /root/.bashrc
RUN echo "source /opt/ros/foxy/setup.bash" >> /root/.bashrc
```

```yaml:docker-compose.yml
services:
  ros2:
    container_name: ros2
    build: .
    environment:
      - DISPLAY=${DISPLAY} #Macの方はDISPLAY=host.docker.internal:0
      - QT_X11_NO_MITSHM=1
    volumes:
      - ./:/tmp/ros2_common_ws/
      - /tmp/.X11-unix:/tmp/.X11-unix:rw
    tty: true
    working_dir: /tmp/ros2_common_ws
    network_mode: host
```

ここまでのワークスペースの作成からDocker関連のファイル作成が面倒くさい人は以下のリポジトリをクローンしてください。
https://github.com/suzakutakumi/ros2_common_ws

### GUIを使用するための環境構築(Macのみ)
#### XQuartzのインストール・設定
下のURLからXQuartzのインストールを行ってください。
https://www.xquartz.org/

XQuartzの[設定]->[セキュリティ]からAllow connections from network clientsにチェックを入れてください。
その後、設定を反映させるためXQuartzを再起動してください。
※セキュリティを気にする方は、使用後はこの設定を元に戻してください。

#### docker-compose.ymlの変更

docker-compose.ymlのDISPLAYを以下のように変更してください。
```yaml
environment:
  - DISPLAY=host.docker.internal:0
  - QT_X11_NO_MITSHM=1
```

### ビルド

以下のコマンドを入力してビルドしてください。
```bash
docker compose build
```

### 起動(パソコン起動時に毎回実行)
パソコン起動時に必要な設定とコンテナの起動を行います。

以下のコマンドを入力してください。
```bash
xhost + local:root #Macの場合はxhost + localhost
docker compose up -d
```

次にDocker Desktopをインストールした方はDocker Desktop実行して、Dockerコマンドを使えるようにします。

### Ubnutuのターミナルに入る

以下のコマンドを実行するとROS2がインストールされたUbuntu内のターミナルに入れます。
```bash
docker compose exec ros2 /bin/bash
```
終了する場合はCtrl+Dやexitコマンドで終了できます。

### ファイルの同期
実機環境のワークスペース内と仮想環境の`/tmp/ros2_common_ws/`は同期しています。

例えば、実機環境でファイルを作成します。
```bash:実機環境(ワークスペース内)
echo "volume test" > volume_test.txt
cat volume_test.txt
```
すると、仮想環境内でもプログラムファイルが作成されます。
```bash:仮想環境
ls
cat volume_test.txt
```

これによって、実機環境でコーディングし、仮想環境で実行をすることができます。

### 余談
<details>
<summary>VSCodeのdevcontainerについて</summary>
VSCodeの拡張機能であるdevcontainerを使えば、仮想環境上でVSCodeを開くことができます。

devcontainerをインストール後に、ワークスペースで以下を実行します。
```bash
mkdir .devcontainer
touch devcontainer.json
```

そして、`.devcontainer/devcontainer.json`に以下の内容を書き込みます。
```json:devcontainer.json
{
	"dockerComposeFile": "../docker-compose.yml",
	"service": "ros2",
	"workspaceFolder": "/tmp/ros2_common_ws"
}
```

その後、VSCodeでワークスペースをディレクトリ指定して開きます。
開いたVSCodeの左下にある><マークをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467463/641d5c07-3f47-2b17-4ba3-49665f9156af.png)

Reopen in Containerをクリックすれば、VSCodeが再度開き直してコンテナ内のワークスペースになります。

VSCodeからターミナルを開けばコンテナ内のターミナルになるので、一々`docker compose exec`を打たずに済みます。

</details>

# 動作テスト
環境構築がうまく行ったかテストを行います。

## テストのための準備
プログラムのビルドや実行をするディレクトリであるワークスペースを作成します。
場所やディレクトリ名は任意です。
(Dockerでの環境構築をした方は作成済み)
```bash
mkdir workspace
cd workspace
```

ワークスペース内に、srcディレクトリを作成します。
```bash
mkdir src
```

## パッケージ作成
以下のコマンドを実行してパッケージを作成します。
```bash
cd src/
ros2 pkg create --build-type ament_python --node-name example_node example_pkg
```

`going to create a new package`から始まるメッセージが表示され、
src下に`example_pkg`というディレクトリが作成されれば正常に実行されています。

失敗した場合は、ros2コマンドのインストールがうまく行っていない可能性が高いです。

## ビルド
以下のコマンドからビルドを行ってください。
```bash
cd .. #srcにいる場合
colcon build
```

以下が表示され、エラーが出ていなければビルド成功です。
```
Starting >>> example_pkg
Finished <<< example_pkg [2.99s]

Summary: 1 packages finished [3.62s]
```

失敗した場合は、colconコマンドのインストールがうまく行っていない可能性が高いです。

## 実行
新しく開いたターミナルや新しいパッケージの作成後には以下のコマンドを実行してください。
```bash
source install/setup.bash
```

その後、サンプルプログラムの実行を行います。
```bash
ros2 run example_pkg example_node
```

`Hi from example_pkg.`と表示されれば無事実行されています。

## 実行2
今度は、PublishするプログラムとSubscribeするプログラムをそれぞれ起動させます。

srcに移動し、[テスト用パッケージのリポジトリ]()をクローンしてください。
```bash
cd src/
git clone https://github.com/suzakutakumi/pubsub_example.git
```

workspaceに移動してビルドを行います。
```bash
cd ..
colcon build
```

まずSubscribeするプログラムを実行します。
起動すると`Subscriber node has been started.`が表示されて待ち状態になります。
```bash:ターミナル1
source install/setup.bash
ros2 run pubsub_example subscriber_node
```

次にPublishするプログラムを実行します。
別ターミナルを起動して以下のコマンドを実行してください。
起動すると`Publisher node has been started.`が表示されて入力待ち状態になります。
```bash:ターミナル2
source install/setup.bash
ros2 run pubsub_example publisher_node
```

ターミナル2に文字列を入力してEnterを押し、ターミナル1にその文字列が表示されれば成功です。
実行を止める場合には、各ターミナルでCtrl+Cを押してください。

## rqtのテスト
実行テスト2の2つのプログラムを実行している状態で、別ターミナルで以下のコマンドを実行してください。
```bash:ターミナル3
rqt
```

画面が表示されたら、左上の[Plugins]->[Introspection]->[Node Graph]を押します。
そうすると以下のような画面が表示されます。
(表示されない場合はNodes onlyの左隣のボタンを押してください)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467463/b3a83d64-3c3d-a3f0-06e6-2d28924ff045.png)

# 最後に

勉強会のために作成したこの資料ですが、未検証の部分もまだあるので、問題があればご指摘ください。
また、Docker関連などの語彙や誤解を招く文章があれば、そちらも教えていただけるとありがたいです。