DockerでGUIが使えるROS環境を構築するメモ

# はじめに

DockerでROS環境を作るときにDockerfileの書き方などで詰まることがあったので、ここにDockerfile, docker-compose.ymlの書き方などをメモしておく


# Dockerfileの作成

例としてubuntu20.04 ROS NoeticイメージにTurtlebot3のパッケージをインストールしたDocker イメージを作成し、
docker-composeでGazeboが起動するようなDockerfileを作成する。

以下Dockerfileのサンプル

```txt:Dockerfile
FROM osrf/ros:noetic-desktop-full

# キーボード設定の選択を聞かれないようにする
ARG DEBIAN_FRONTEND=noninteractive

# Install apt packages
RUN apt-get update && apt-get install -y \
git \
vim \
wget \
tmux \
terminator && \
apt-get clean && rm -rf /var/lib/apt/lists/*

# Install ROS packages
RUN apt-get update && apt-get install -y \
  ros-noetic-joy ros-noetic-teleop-twist-joy \
  ros-noetic-teleop-twist-keyboard ros-noetic-laser-proc \
  ros-noetic-rgbd-launch ros-noetic-rosserial-arduino \
  ros-noetic-rosserial-python ros-noetic-rosserial-client \
  ros-noetic-rosserial-msgs ros-noetic-amcl ros-noetic-map-server \
  ros-noetic-move-base ros-noetic-urdf ros-noetic-xacro \
  ros-noetic-compressed-image-transport ros-noetic-rqt* ros-noetic-rviz \
  ros-noetic-gmapping ros-noetic-navigation ros-noetic-interactive-markers \
  ros-noetic-dynamixel-sdk \
  ros-noetic-turtlebot3-msgs \
  ros-noetic-turtlebot3 && \
  apt-get clean && rm -rf /var/lib/apt/lists/*

# Create ROS workspace
RUN echo "source /opt/ros/noetic/setup.bash" >> /root/.bashrc
RUN mkdir -p /root/catkin_ws/src
RUN cd /root/catkin_ws && /bin/bash -c "source /opt/ros/noetic/setup.sh; catkin_make"
RUN echo "source /root/catkin_ws/devel/setup.bash" >> /root/.bashrc

RUN cd /root/catkin_ws/src && git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3_simulations.git
RUN cd /root/catkin_ws && /bin/bash -c "source /opt/ros/noetic/setup.bash; catkin_make"

```

以下Dockerfileの説明

```Dockerfile
FROM osrf/ros:noetic-desktop-full
```

ベースイメージはros:noetic-desktop-fullを使う、ubuntu20.04のイメージにROSをインストールする方法もあるが時間がかかるので特に理由がなければROS インストール済みのイメージを使う

```Dockerfile
RUN apt-get update && apt-get install -y \
  git \
  ...
apt-get clean && rm -rf /var/lib/apt/lists/*
```
gitやエディタなどよく使うものをインストールする。Dockerfile内でgit cloneをするのでgitは必ずここで入れておく

```Dockerfile
RUN apt-get update && apt-get install -y \
  ros-noetic-joy ros-noetic-teleop-twist-joy \
  ...
```

必要なROSパッケージをaptでインストールする

```Dockerfile
RUN echo "source /opt/ros/noetic/setup.bash" >> /root/.bashrc
RUN mkdir -p /root/catkin_ws/src
RUN cd /root/catkin_ws && /bin/bash -c "source /opt/ros/noetic/setup.sh; catkin_make"
RUN echo "source /root/catkin_ws/devel/setup.bash" >> /root/.bashrc
```

ROSワークスペースの作成、DockerfileのRUNは/bin/shで実行されるためsourceコマンドは/bin/bashで実行されるように書く

```Dockerfile
RUN cd /root/catkin_ws/src && git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3_simulations.git
RUN cd /root/catkin_ws && /bin/bash -c "source /opt/ros/noetic/setup.bash; catkin_make"
```

aptでインストールできないROSパッケージはcatkin_ws/src以下にcloneしてcatkin_makeする。

もしGithubやBitbucketのprivateリポジトリをcloneしたい場合、一度ホストPCにgit clone してCOPYコマンドでDockerの中にコピーするのがよい

```Dockerfile
COPY turtlebot3_simulations/ /root/catkin_ws/src/turtlebot3_simulations/
```


docker buildしてDockerイメージの作成

```bash
docker build -t turtlebot_ros:latest .
```



# docker-compose.ymlの作成

以下のようにdocker run を使ってDockerコンテナを作成、起動することもできるが、GUIを使う場合などコマンドが長くなってしまうのでdocker-compose.ymlを作ってdocker-compose upで起動するようにする。

```bash
docker run -it \
    --env="DISPLAY=$DISPLAY" \
    --env="QT_X11_NO_MITSHM=1" \
    --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \
    --name=turtlebot_ros \
    turtlebot_ros:latest \
    bash
```

以下Turtlebot3 Gazeboを起動するdocker-compose.ymlの例
GUIを表示するための環境変数などを追加、commandオプションで起動したあとに実行するコマンドを書く

```yml:docker-compose.yml
version: "3"

services:
  ros:
    image: turtlebot_ros:latest
    container_name: turtlebot_gazebo
    environment:
      - DISPLAY
      - QT_X11_NO_MITSHM=1
      - TURTLEBOT3_MODEL=burger
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix
    tty: true
    command: bash -c "source /root/catkin_ws/devel/setup.bash; roslaunch turtlebot3_gazebo turtlebot3_world.launch"
    network_mode: "host"
```

### docker-compose.ymlの説明


ベースイメージの名前とコンテナ名を指定。

```yml:docker-compose.yml
    image: turtlebot_ros:latest
    container_name: turtlebot_gazebo
```

環境変数の設定
ROS_MASTER_URI, ROS_IPなどを設定する場合はここに書く

```yml:docker-compose.yml
    environment:
      - DISPLAY
      - QT_X11_NO_MITSHM=1
      - TURTLEBOT3_MODEL=burger
```

ホストPCとvolumesを共有する設定。

```yml:docker-compose.yml
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix
```

コンテナ起動時に実行するコマンド
ここにroslaunchなどを書くことでdocker-compose upしたらROSノードが立ち上がる

```yml:docker-compose.yml
    command: bash -c "source /root/catkin_ws/devel/setup.bash; roslaunch turtlebot3_gazebo turtlebot3_world.launch"
```

使用するnetworkの設定
host とすることでホストPCとネットワークが共有されるので、別のPCからホストPCのIPアドレスを指定してROSトピックの通信することができる。デフォルトではdocker networkが使用される。

```docker-compose.yml
    network_mode: "host"
```

### dockerコンテナの起動と終了
docker-compose upでGazeboのturtlebot3_worldが起動する
downするとdockerコンテナが消えるので注意

```bash
docker-compose up 
```

```bash
docker-compose down
```

![Screenshot from 2022-12-23 22-12-24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399606/36d433b1-01e4-0899-49e4-6589ebcec975.png)

実行後にROSトピックを見たりファイル編集したい場合execコマンドでdocker コンテナに入る。
docker-composeでコンテナを作成するとdocker attachコマンドが使えないので注意。

```bash
docker exec -it turtlebot_gazebo bash
```

### その他

docker-compose.ymlの中で複数コンテナを立ち上げてコンテナ間で通信する場合、roscoreだけ立ち上げるコンテナを作成すると安定して動く（経験上）。詳細は参考のroswiki チュートリアルを参照

```bash
  ros-master:
    image: ros:kinetic-ros-core
    command: stdbuf -o L roscore
    networks:
      - ros
    restart: always
```

シリアル通信のデバイスを使う場合deviceオプションを使う
以下の例では/dev/ttyUSB0をコンテナ内の/dev/ttyUSB0にマウントする

```yaml:docker-compose.yml
    devices:
      - /dev/ttyUSB0:/dev/ttyUSB0
```

# 参考



https://emanual.robotis.com/docs/en/platform/turtlebot3/quick-start/#pc-setup


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


https://www.techlife-hacking.com/?p=1117


https://qiita.com/karaage0703/items/957bdc7b4dabfc6639da

https://qiita.com/yosuke@github/items/328dbd778047499828f2

ros wikiのdocker composeのチュートリアル

http://wiki.ros.org/docker/Tutorials/Compose