Docker（Windows）でROS2 Humbleを扱えるようにする

# Docker（Windows）でROS2 Humbleを扱えるようにする

## はじめに
ROS2はWindows上に直接構築することもできるが，やはりLinuxで動かしたい．Foxyについて一度だけWindowsに直接構築したが，使いにくい印象を受けた．また，環境構築も大変であった記憶がある．
今回は，ROS2にもLTS（Long-Term Support）が登場したということで，Ubuntu22.04上にROS2 Humbleを構築していきたい．ただ，UbuntuホストにするPCの余りもなく，かといって仮想環境だとGPU使いたいときに困るかもしれないので，今回は，以前の記事を参考にDocker（ホスト：Windows10 Home）上で構築していく．

https://qiita.com/Yuya-Shimizu/items/f0ace02062cc13e9d54b

https://qiita.com/Yuya-Shimizu/items/3d9fc18f42aee40f23b3

## Docker Hubでベースを探す
GPU使えるようにしたいなという思いから，Nvidiaが提供するUbuntuイメージファイルにUbunut22.04が無いか調べる．
1. Docker Hubにアクセス
1. nvidia/cudaと検索
1. TagsのところでUbuntu22.04と検索

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/258a20d3-03c0-3c12-5b02-893d02042407.png)

https://hub.docker.com/r/nvidia/cuda/tags?page=1&name=ubuntu22.04

今回はこれを使うこととする．

## ROS2 Humbleの構築手順の確認

https://qiita.com/porizou1/items/5dd915402e2990e4d95f

ROS2 Humbleのインストールについては，@porizou1さんの記事をそのまま引用する形となる．
ただ，Docker imageでエラーも避けながら，簡単にインストールできるように，シェルスクリプトを作成しておく．**※Dockerfileと同じディレクトリに置いておく．**

```shell:setup.sh
#!/bin/bash -e 

# ------------ apt-getリポジトリの追加
apt-get install curl gnupg lsb-release -y
curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg

# ------------ リポジトリをsource listに追加
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(source /etc/os-release && echo $UBUNTU_CODENAME) main" | tee /etc/apt/sources.list.d/ros2.list > /dev/null

# ------------ ROS2インストール
apt-get update
apt-get install ros-humble-desktop -y

# ------------ 環境設定
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc

# ------------ ワークスペースの作成
apt-get install python3-colcon-common-extensions -y
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/ && colcon build

# ------------ Gazeboのインストール
apt-get install gazebo -y
apt-get install ros-humble-gazebo-* -y

# ------------ 環境設定を反映
source ~/.bashrc
```

## Docker Imageの作成

```dockerfile:Dockerfile
# ------------ ベースとなるイメージファイル
FROM nvidia/cuda:11.7.0-devel-ubuntu22.04

# ------------ 環境設定
ENV LIBRARY_PATH /usr/local/cuda/lib64/stubs
ENV DISPLAY host.docker.internal:0.0
ENV DEBIAN_FRONTEND=noninteractive

# ------------ タイムゾーンの設定
RUN apt-get update && apt-get install -y tzdata
ENV TZ=Asia/Tokyo 

# ------------ ワークディレクトリの設定
WORKDIR /root

# ------------ Ubuntu上での環境構築
RUN apt-get update && apt-get upgrade -y
RUN apt-get install -y python3 python3-pip

# windows上でx-serverに接続するために必要なx11-appsのインストール
RUN apt-get install x11-apps -y

# gitのインストール（20.04以降はデフォルトでインストールされていない）
RUN apt-get install git -y

# matplotlibなどでの描画GUIに必要
RUN apt-get install python3-tk -y

# PyTorchのためのライブラリをインストール
RUN pip3 install torch torchvision

# ------------ ROS2のセットアップ
COPY setup.sh /root/
RUN bash ~/setup.sh
```

## コンテナの立ち上げ
### ディレクトリ構成
ここでディレクトリ構成について示しておく．以下に``tree /f``の結果を示す．

```bash:ディレクトリ構成
D:.
  Dockerfile
  setup.sh
```

### 立ち上げ
今回は，以前の記事を参考にVScode上でremote Containerを使って立ち上げている．
Docker Imageからコンテナを作成して立ち上げていくわけだが，初回は様々なものをインストールする関係から，割と時間がかかることが予想される．（とりあえず放っておくといつか終わるはず）

https://qiita.com/Yuya-Shimizu/items/22c6a2a473139d15857f

### JSONファイル
一度立ち上げると``.devcontainer/devcontainer.json``が生成される．
それはVScode上でremote containerを使って立ち上げる際の設定を記述するファイルである．
以下に最低限のjsonファイルを示しておく．

<details><summary>devcontainer.json</summary>

```json:devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.224.3/containers/docker-existing-dockerfile
{
	"name": "Existing Dockerfile",

	// Sets the run context to one level up instead of the .devcontainer folder.
	"context": "..",

	// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
	"dockerFile": "../Dockerfile",

	// Set *default* container specific settings.json values on container create.
	"settings": {},
	
	// Add the IDs of extensions you want installed when the container is created.
	"extensions": [
		"ms-python.python",
		"ms-python.vscode-pylance"
	],

	"workspaceFolder": "/root/",

	"mounts": [
		"source=${localWorkspaceFolder}/share,target=/root/share,type=bind",
	],
	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	// "forwardPorts": [],

	// Uncomment the next line to run commands after the container is created - for example installing curl.
	// "postCreateCommand": "apt-get update && apt-get install -y curl",

	// Uncomment when using a ptrace-based debugger like C++, Go, and Rust
	"runArgs": ["--gpus=all"],

	// Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker.
	// "mounts": ["source=../src/,target=/root/src,type=bind"],
	// "mounts": [ "source=../src,target=/root/src,type=bind" ],

	// Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root.
	// "remoteUser": "vscode"
}
```
</details>

jsonファイルの``mounts``というタグについては設定しなくてもよいが，ローカルとコンテナ間でのファイルのやり取り口となっている．Dockerfileを置いているディレクトリにshareというフォルダを作っておいて，そのshareフォルダとコンテナ内の/root/shareというところを結ぶという設定にしている．

この時のディレクトリ構成について以下に示す．

```bash:最終ディレクトリ構成
D:.
│  Dockerfile
│  setup.sh
│
├─.devcontainer
│      devcontainer.json
│
└─share
```

## 環境のテスト
### talker & listener

#### コマンド
```bash:talker_node
ros2 run demo_nodes_cpp talker
```
```bash:listener_node
ros2 run demo_nodes_cpp listener
```

#### 結果
![TalkerListener.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/f9b92236-f9aa-9e51-598f-df02f65e094e.gif)


### Rvizの立ち上げ
※GUIを必要とするものを扱うときは，Xserverを立ち上げておく必要がある．
（Windowsだと，Xlaunchが一番簡単だと思う．）
以下の記事にXlaunchのインストールと立ち上げ方について記述している．

https://qiita.com/Yuya-Shimizu/items/f0ace02062cc13e9d54b#windows%E4%B8%8A%E3%81%A7gui%E3%82%92%E6%9C%89%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AAxserver%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

#### コマンド
```bash:talker_node
ros2 run rviz2 rviz2
```

#### 結果
![Rviz2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/66ba5490-b5d5-326a-5aed-59f16ea7030f.gif)

### Gazeboの立ち上げ
#### コマンド
```bash:talker_node
ros2 launch gazebo_ros gazebo.launch.py
```

#### 結果
![Gazebo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/89bbc83c-7b18-03db-c6a5-79a89224684c.gif)


## 感想
NvidiaがUbuntu22.04のDocker imageを提供してくれていたおかげで，大きくつまづくこともなく，簡単にGPUも使えるROS2 Humble環境をDocker上に構築することができた．GPUの確認はPythonのインタラクティブシェルにて確認できた．
```bash:python
>> import torch
>> torch.cuda.is_available()
True
```
ROSは勉強してきたが，ROS2は触れる程度しかまだできていないため，この環境構築を機に，少しずつROS2も自在に扱えるようにしていきたい．

## 参考文献
https://qiita.com/Yuya-Shimizu/items/f0ace02062cc13e9d54b

https://qiita.com/Yuya-Shimizu/items/3d9fc18f42aee40f23b3

https://hub.docker.com/r/nvidia/cuda/tags?page=1&name=ubuntu22.04

https://qiita.com/porizou1/items/5dd915402e2990e4d95f

https://qiita.com/Yuya-Shimizu/items/22c6a2a473139d15857f