ROS2環境のDockerイメージ作成


今回は，ROS2の開発環境 兼 実行環境を作ります．

# 1. はじめに
私のPCの中では複数の開発環境がPC内で混在しているため，Docker上で開発する環境を構築します．

### 環境
今回の環境は以下の通り．

- Ubuntu:20.04

### 先人の知恵

既に以下で，スクリプトを使ったDocker環境の構築方法やVNCを使ったGUI環境の提供方法が用意されている．ほとんど何も準備なく，環境構築できて素晴らしいと思いました．

https://github.com/Tiryoh/ros2_setup_scripts_ubuntu

https://github.com/Tiryoh/docker-ros2-desktop-vnc

しかしながら，私にとってVNCは過剰にリッチな環境に感じられた．以下の3点を実現したいと思い，環境を構築した．

1. 開発はVS CodeからDockerにRemote接続して行う
2. 実行は基本的にCUI上で行う
3. GUIは適宜ホスト側にアプリケーションとして展開する

これら3点の要望に答えた環境を作った．

# 2. 今回のコード

またかと思われるかもしれないが，仕事の終わりのスキマ時間で作ったので，テキトーな点は目をつぶってほしい．

https://github.com/Dorebom/ros2docker

# 3. コードの解説

### Dockerfile

Dockerの中に`developer`というアカウントを作成し，ROS2環境を作成する．
ROS2環境の作成には，`ros2_setup_scripts_ubuntu.sh`と`ros_entrypoint.sh`の中に内容が詰まってる．

```Dockerfile
FROM nvidia/cudagl:11.2.0-devel-ubuntu20.04
#FROM amd64/ubuntu:focal
LABEL maintainer="Dorebom<dorebom.b@gmail.com>"

ENV ROS_DISTRO foxy
ENV USER_NAME developer

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -q && \
    apt-get upgrade -yq && \
    apt-get install -yq \
            wget \
            curl \
            git \
            build-essential \
            vim \
            sudo \
            lsb-release \
            locales \
            bash-completion \
            glmark2 \
            tzdata && \
    rm -rf /var/lib/apt/lists/*

# Add user account
RUN useradd -m -d /home/${USER_NAME} ${USER_NAME} \
        -p $(perl -e 'print crypt("${USER_NAME}", "robot"),"\n"') && \
    echo "${USER_NAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
RUN locale-gen en_US.UTF-8
USER ${USER_NAME}
WORKDIR /home/${USER_NAME}
ENV HOME=/home/${USER_NAME}
ENV LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_ALL=en_US.UTF-8

# Install ROS2 packages and setting
COPY ./ros2_setup_scripts_ubuntu.sh /home/developer/ros2_setup_scripts_ubuntu.sh
RUN sed -e 's/^\(CHOOSE_ROS_DISTRO=.*\)/#\1\nCHOOSE_ROS_DISTRO=$ROS_DISTRO/g' -i ros2_setup_scripts_ubuntu.sh
RUN ./ros2_setup_scripts_ubuntu.sh && \
    sudo rm -rf /var/lib/apt/lists/*
COPY ./ros_entrypoint.sh /

RUN sudo apt-get update -q && \
    sudo apt-get upgrade -yq && \
    sudo apt-get install -yq \
            python3-dev \
            python3-pip

RUN pip3 install --upgrade pip
RUN pip3 install Pyserial

ENTRYPOINT ["/ros_entrypoint.sh"]
CMD ["/bin/bash"]
```
ここで，シリアル通信するセンサのROS2ノードを作りたかったので，`Pyserial`をpipインストールしている．

### ros2_setup_scripts_ubuntu.sh

ROS2ディストリビューションをインストールするために必要なものをインストールし，ROS2ディストリビューションとパッケージをインストールする．最後に，`.bashrc`にsetup.bashを呼び出すことを行う．

```ros2_setup_scripts_ubuntu.sh
#!/usr/bin/env bash
set -eu

# REF: https://index.ros.org/doc/ros2/Installation/Linux-Install-Debians/
# by Open Robotics, licensed under CC-BY-4.0
# source: https://github.com/ros2/ros2_documentation

# REF: https://github.com/Tiryoh/ros2_setup_scripts_ubuntu/blob/master/run.sh
# by https://github.com/Tiryoh, Apache-2.0 License

# REF https://gbiggs.github.io/rosjp_ros2_intro/computer_prep_linux.html

CHOOSE_ROS_DISTRO=foxy # or dashing
INSTALL_PACKAGE=desktop # or ros-base

export DEBIAN_FRONTEND=noninteractive
sudo apt-get update
sudo -E apt-get install -yq \
		curl \
		gnupg2 \
		lsb-release \
		bash-completion \
		build-essential \
		locales \
		tmux \
		x11-apps \
		eog && \
		sudo rm -rf /var/lib/apt/lists/*

sudo apt-get install -yq \
        google-mock \
        libceres-dev \
        liblua5.3-dev \
        libboost-dev \
        libboost-iostreams-dev \
        libprotobuf-dev \
        protobuf-compiler \
        libcairo2-dev \
        libpcl-dev \
        python-sphinx && \
		sudo rm -rf /var/lib/apt/lists/*

# Install ROS2 packages
curl -Ls https://raw.githubusercontent.com/ros/rosdistro/master/ros.key | sudo apt-key add -
sudo sh -c 'echo "deb [arch=$(dpkg --print-architecture)] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/ros2-latest.list'
sudo apt-get  update
sudo apt-get  install -y ros-$CHOOSE_ROS_DISTRO-$INSTALL_PACKAGE
sudo apt-get  install -y python3-argcomplete
sudo apt-get  install -y python3-colcon-common-extensions
if [ "$(lsb_release -cs)" = "bionic" ]; then
	sudo apt-get  install -y python-rosdep python3-vcstool # https://index.ros.org/doc/ros2/Installation/Linux-Development-Setup/
elif [ "$(lsb_release -cs)" = "focal" ]; then
	sudo apt-get  install -y python3-rosdep python3-vcstool # https://index.ros.org/doc/ros2/Installation/Linux-Development-Setup/
fi

sudo apt-get install -yq \
		ros-$CHOOSE_ROS_DISTRO-gazebo-ros-* \
		ros-$CHOOSE_ROS_DISTRO-turtlesim \
        ros-$CHOOSE_ROS_DISTRO-cartographer \
        ros-$CHOOSE_ROS_DISTRO-cartographer-ros \
        ros-$CHOOSE_ROS_DISTRO-navigation2 \
        ros-$CHOOSE_ROS_DISTRO-nav2-bringup

# Add ROS2 env values in bash
grep -F "source /opt/ros/$CHOOSE_ROS_DISTRO/setup.bash" ~/.bashrc ||
echo "source /opt/ros/$CHOOSE_ROS_DISTRO/setup.bash" >> ~/.bashrc

set +u

# Set ROS2 env values
source /opt/ros/$CHOOSE_ROS_DISTRO/setup.bash

echo "success installing ROS2 $CHOOSE_ROS_DISTRO"
echo "Run 'source /opt/ros/$CHOOSE_ROS_DISTRO/setup.bash'"
```

# 4. Build

実行権限を2つのファイルに付与して，`docker build`する．

```build.sh
chmod 777 ros_entrypoint.sh
chmod 777 ros2_setup_scripts_ubuntu.sh

docker build -t ros2docker:foxy .
```
ビルド方法は，以下である．

```
sh build.sh
```


# 5. Run

Dockerコンテナ内のファイルを永続化するために，ホスト側のアカウントとディレクトリを設定し，`docker run`する．

```run.sh

USER_NAME=<ホストのユーザーアカウント名>
WORKSPACE=<ホストのディレクトリ名>

docker run --rm -it --privileged \
        --gpus all \
        --device=/dev/ttyUSB0:/dev/ttyUSB0 \
        -v /tmp/.X11-unix:/tmp/.X11-unix \
        -v /etc/localtime:/etc/localtime \
        -v /home/$USER_NAME/$WORKSPACE:/home/developer/ros2_ws \
        -e DISPLAY=$DISPLAY \
        --name glvnd \
        ros2docker:foxy
```

実行方法は，以下である．

```
sh run.sh
```

# 参考にしたページ

https://github.com/Tiryoh/ros2_setup_scripts_ubuntu

https://github.com/Tiryoh/docker-ros2-desktop-vnc

https://index.ros.org/doc/ros2/Installation/Linux-Install-Debians/

https://github.com/ros2/ros2_documentation

https://gbiggs.github.io/rosjp_ros2_intro/computer_prep_linux.html