Blog
シームレスな統合:Docker環境で効率的にROS2を実行する(2/2)
2024/08/10
SHARE
開発環境の構築
以下に示す構造のように、DockerとROS2環境を構築するためのワークスペースと関連ファイルを作成します。
workspace/
├─ packages/ # 開発するROS2プロジェクトをこのフォルダに保存します
│ ├─ publisher/ # メッセージを送信するROS2プロジェクト
| ├─ subscriber/ # メッセージを受信するROS2プロジェクト
├─ Dockerfile # Dockerイメージを作成するためのファイル
├─ docker-compose.yaml # Docker Composeを使用して各コンテナを管理するファイル
├─ .env # イメージの作成と使用中に必要な各種環境変数を定義します
Dockerfileの説明
上記のファイルとフォルダを作成したら、お好きなエディタでDockerfileファイルを開き、以下の内容をコピー&ペーストします。各部分の役割はコメントで説明しています。
# Ubuntu 22.04 をベースイメージとして使用する
FROM ubuntu:22.04
# ビルド時に渡すことができるパラメータを定義する
ARG ROS_DISTRO
ARG PYTHON_VERSION=python3
ARG UID
ARG GID
ARG USER_NAME
ARG GROUP_NAME
ARG CUDA_ENABLE
# 環境変数を設定し、非対話型フロントエンド、言語およびタイムゾーンを設定する
ENV DEBIAN_FRONTEND=noninteractive
ENV LANG=en_US.UTF-8
ENV TZ=Asia/Tokyo
ENV NVIDIA_VISIBLE_DEVICES=all
ENV NVIDIA_DRIVER_CAPABILITIES=all
# 開発環境の構成に必要なライブラリをインストールする
RUN apt-get update \
&& apt-get install -y –no-install-recommends \
locales sudo \
software-properties-common tzdata \
&& locale-gen en_US en_US.UTF-8 \
&& update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 \
&& add-apt-repository universe
# 主にソフトウェア開発をサポートするための追加のライブラリをインストールする
RUN apt-get update \
&& apt-get install -y –no-install-recommends \
build-essential ca-certificates pkg-config curl gnupg2 lsb-release wget \
cmake usbutils g++ gfortran yasm git checkinstall unzip less \
libgtk-3-dev libv4l-dev v4l-utils openssh-client \
$PYTHON_VERSION-pip $PYTHON_VERSION-dev $PYTHON_VERSION-numpy $PYTHON_VERSION-matplotlib \
lib$PYTHON_VERSION-dev $PYTHON_VERSION-empy $PYTHON_VERSION-tk \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
libopenmpi-dev openmpi-bin openmpi-common \
libpostproc-dev libeigen3-dev libglew-dev \
libhdf5-dev libprotobuf-dev protobuf-compiler libboost-all-dev \
libgoogle-glog-dev
# .env ファイルで CUDA_ENABLE が “ON” に設定されている場合、Nvidia ツールキットをインストールする。例えば、ROS の rviz ツールのようなグラフィカルインターフェースを加速するために使用できる
RUN if [ $CUDA_ENABLE = ON ]; then \
distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
&& curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | apt-key add – \
&& curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
tee /etc/apt/sources.list.d/nvidia-container-toolkit.list; \
else \
echo “CUDA_ENABLE is OFF” && sleep 3; \
fi
RUN if [ $CUDA_ENABLE = ON ]; then \
apt-get update \
&& apt-get install -y –no-install-recommends nvidia-container-toolkit; \
else \
echo “CUDA_ENABLE is OFF” && sleep 3; \
fi
# ROS2 の GPG 鍵とソフトウェアソースを追加する
RUN 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 $(lsb_release -cs) main” | tee /etc/apt/sources.list.d/ros2.list > /dev/null
# .env ファイルで指定された ROS2 のバージョンに基づいて、ROS2 と関連するソフトウェアパッケージをインストールする
RUN apt-get update && apt-get install -y –no-install-recommends \
ros-${ROS_DISTRO}-desktop \
ros-${ROS_DISTRO}-rqt* \
ros-${ROS_DISTRO}-rviz2 \
ros-${ROS_DISTRO}-joint-state-publisher \
ros-${ROS_DISTRO}-joint-state-publisher-gui \
ros-${ROS_DISTRO}-v4l2-camera \
ros-${ROS_DISTRO}-librealsense2* \
ros-${ROS_DISTRO}-realsense2-camera \
${PYTHON_VERSION}-colcon-common-extensions \
${PYTHON_VERSION}-colcon-argcomplete \
${PYTHON_VERSION}-rosdep
# ユーザーとグループを追加し、開発を容易にするために追加したユーザーの権限を解除する
RUN groupadd -g $GID $GROUP_NAME
RUN useradd -u $UID -g $GID -s /bin/bash -m $USER_NAME
RUN usermod -a -G video $USER_NAME
RUN echo “${USER_NAME} ALL=(ALL) NOPASSWD: ALL” > /etc/sudoers && chmod 0440 /etc/sudoers && chmod g+w /etc/passwd
USER $USER_NAME
# 作業ディレクトリを設定し、ファイルをコンテナにコピーする
WORKDIR /app
COPY ./packages /app
# 各インターフェース以外のROS2项目のROS2プロジェクトの setup.py ファイルをスキャンして、プロジェクトに必要な Python ツールパッケージをインストールする
RUN sh -c “find . -maxdepth 1 -type d ! -path ‘*_interfaces’ ! -path ‘.’ -exec pip install {} \;”
# ユーザーの作業ディレクトリを設定し、ROS2 プロジェクトのコード用の src ディレクトリを作成する
WORKDIR /home/${USER_NAME}/workspace
RUN mkdir src
# /app 内のディレクトリを src にリンクする
# リンクの目的は、colcon build コマンドでプロジェクトをビルドする際に生成されたファイルがローカル環境に保存されないようにすることです
RUN sh -c “find /app -maxdepth 1 -type d ! -path ‘/app’ -exec ln -sf {} ./src \;”
# デフォルトのシェルを bash に設定し、ROS 環境を初期化する
SHELL [“/bin/bash”, “-c”]
RUN source /opt/ros/${ROS_DISTRO}/setup.bash \
&& sudo apt-get update \
&& sudo rosdep init \
&& rosdep update \
&& rosdep install –from-paths src –rosdistro ${ROS_DISTRO} -i -y
# リンクされた ROS2 プロジェクトパッケージをビルドする
SHELL [“/bin/bash”, “-c”]
RUN source /opt/ros/${ROS_DISTRO}/setup.bash \
&& colcon build –symlink-install –packages-select mrobo_system_data_manager_interfaces \
&& source install/setup.bash \
&& colcon build –symlink-install
# ROS2 および作業スペース環境設定をユーザーの bash 設定ファイルに追加する
# こうすることで、コンテナにログインするたびに ROS の開発環境を手動でソースする必要がなくなる
RUN echo “source ${PWD}/install/setup.bash” >> /home/${USER_NAME}/.bashrc
RUN echo “source /opt/ros/${ROS_DISTRO}/setup.bash” >> /home/${USER_NAME}/.bashrc
RUN echo “ulimit -n 4096” >> /home/${USER_NAME}/.bashrc
# キャッシュをクリアしてイメージのサイズを減らする
RUN sudo rm -rf /var/lib/apt/lists/*
Dockerイメージをビルドする
workspaceのルートディレクトリで以下のコマンドを実行すると、ros2_projectと名付けられたDockerイメージを取得できます。
docker build -t ros2_project:latest .
そして、以下のコマンドを利用して、あるコンテナを作成し、開発するためにログインすることができます。これはまるであなたがローカルで開発しているかのようです。図1のように、コンテナにログインした後、ROS2のコマンドを利用してインストール済みのパッケージを確認することができます。
docker run -it –rm ros2_project:latest /bin/bash
図.1 ros2 pkg list コマンドを実行した結果
次の章「マルチコンテナデプロイ」では、Docker Composeツールを使ってDockerイメージを便利にコンパイルし、コンテナを作成し、アプリケーションを実行する方法を紹介します。これはROS2の開発とデプロイに非常に有利で、ロボット開発プロジェクトでは、たとえばドライバーモジュール、ビジョンモジュール、プランニングモジュールなど、複数のROS2アプリケーションが同時に実行されることがよくあります。
env 環境設定ファイル
Docker Composeツールを使用してDockerイメージを作成する場合、envファイルが必要となり、環境変数パラメータを渡します。Docker Composeツールを使用する前に、以下のコードを.envファイルにコピーしてください。
# Docker コンテナから GUI を表示するオプション。
QT_X11_NO_MITSHM=1
DISPLAY=${DISPLAY}
# システムのユーザー名とグループ名を Docker の環境変数に渡します。
USER_NAME=${USER}
GROUP_NAME=${USER}
UID=1000
GID=1000
# GPU 環境が必要な場合は ON に設定、そうでない場合は OFF に設定します。
CUDA_ENABLE=ON
# ROS のバージョン名。
ROS_DISTRO=humble
# ソースコードのディレクトリ
PACKAGES=./packages
# ROS2 ドメイン ID
ROS_DOMAIN_ID=1
# ROS2 の通信をローカルネットワーク全体ではなく、localhost のみで制限します。
ROS_LOCALHOST_ONLY=1
## アプリケーションのランタイム環境変数。
# ここに何かを追加します…
マルチコンテナデプロイ
Docker Composeは、複数のコンテナのDockerアプリケーションを定義して実行するためのツールです。YAMLファイルを使用してアプリケーションに必要なすべてのサービスを設定し、一つのコマンドですべてのサービスを作成・実行します。
Docker Composeの詳細な紹介、およびそれらのインストールと使用方法については、公式ウェブサイトを参照してください。
- DockerCompose:https://docs.docker.jp/compose/toc.html
Docker Composeの主な利点:
- マルチコンテナアプリケーションのオーケストレーションを簡素化: Docker Composeを使用すると、複数のコンテナを一つのアプリケーションに組み合わせ、シンプルなコマンドで管理することができます。
- 開発効率の向上: Docker Composeを使用すると、コンテナを素早く作成・破棄でき、開発者がアプリケーションのテストとデバッグを容易に行うことができます。
- アプリケーションの移植性の向上: Docker Composeの設定ファイルは、開発環境、テスト環境、本番環境など、異なる環境に簡単に移植することができます。
Docker Composeの仕組み:
- Docker Compose設定ファイルを作成する: YAMLファイルを使用してアプリケーションのすべてのサービスを定義します。これには、各サービスのイメージ、ポートマッピング、環境変数などが含まれます。
Docker Composeコマンドを実行する: docker-compose upコマンドを使用してすべてのサービスを起動します。または、docker-compose psコマンドを使用して実行中のサービスを表示します。または、docker-compose stopコマンドを使用してすべてのサービスを停止します。
Docker Composeを使用して複数のROS2ノードのオーケストレーション
Docker Composeツールを使用する前に、以下のコードをdocker-compose.yamlにコピーし、自分の使用シーンに応じて各種パラメータを追加または変更します。
Docker Composeファイルの構造を説明する
x-container: &base # 各サービスが共通で使える部分を定義
image: ros2_project:latest # イメージは ros2_project:latest を使用
build:
context: ./ # ビルドコンテキストは現在のディレクトリ
dockerfile: Dockerfile # 使用する Dockerfile
args:
– USER_NAME=${USER_NAME} # ユーザー名の引数
– GROUP_NAME=${USER_NAME} # グループ名の引数
– UID=${UID} # ユーザーIDの引数
– GID=${GID} # グループIDの引数
– CUDA_ENABLE=${CUDA_ENABLE} # CUDAの有効化設定の引数
– ROS_DISTRO=${ROS_DISTRO} # ROSディストリビューションの引数
ipc: host # ホストのIPC設定を使用
tty: true # TTYを有効にする
network_mode: host # ホストネットワークモードを使用
privileged: true # 特権モードを有効にする
user: “${UID}:${GID}” # ユーザーとグループの設定
env_file:
– .env # 環境変数ファイルの指定
deploy:
resources:
reservations:
devices:
– driver: nvidia # NVIDIAドライバを使用
device_ids: [‘0’] # デバイスIDの指定
capabilities: [gpu] # GPUの能力を指定
volumes:
– /tmp/.X11-unix:/tmp/.X11-unix # X11のボリュームマウント
– $HOME/.Xauthority/:/root/.Xauthority # Xauthorityのボリュームマウント
– ./packages:/app # パッケージのボリュームマウント
services:
dev:
<<: *base
container_name: ros2_project.dev # コンテナ名を ros2_project.dev に設定
## 通常のユーザーとしてこのサービスにログイン
entrypoint: [“su”, “-“, “${USER}”]
ros2_publisher:
<<: *base
container_name: ros2_project.publisher # コンテナ名を ros2_project.publisher に設定
entrypoint:
– /bin/bash # エントリーポイントを /bin/bash に設定
– -c
– |
source /opt/ros/humble/setup.bash # ROS環境をソース
source install/setup.bash # インストールされた環境をソース
ros2 launch publisher launch.py # publisher ノードを起動、結果は図2のようになる
ros2_subscriber:
<<: *base
container_name: ros2_project.subscriber # コンテナ名を ros2_project.subscriber に設定
entrypoint:
– /bin/bash # エントリーポイントを /bin/bash に設定
– -c
– |
source /opt/ros/humble/setup.bash # ROS環境をソース
source install/setup.bash # インストールされた環境をソース
ros2 launch subscriber launch.py # subscriber ノードを起動、結果は図3のようになる
図.2 ros2_publisherサービスを実行した後に、「Hello World」カウントのメッセージが送信される。
図.3 ros2_subscriberサービスを実行した後に、「Hello World」カウントのメッセージを受信する。
結論
本稿では、ロボットアプリケーションの開発と配布におけるDockerとROS2の使用方法を主に紹介しました。まず、DockerとROS2の基本知識、機能、利点、応用分野について詳しく説明しました。その後、DockerとROS2を組み合わせて使用する利点、環境の一貫性問題の解決、依存管理の簡素化、便利なデプロイと拡張などについて詳しく説明しました。次に、Dockerを使用してROS2の開発を行う方法、作業スペースの作成、Dockerfileの作成、Dockerイメージのコンパイルなどの手順について詳しく説明しました。最後に、Docker Composeツールを使用してマルチコンテナをデプロイする方法、Docker Composeの主な利点と動作原理について紹介しました。
これらのポイントを網羅することで、私のブログが読者にとって包括的なガイドとなり、実際のプロジェクトでDockerとROS2を使用する際の助けになることを期待しています。詳細なコード例やその他の質問があれば、いつでもお気軽にご連絡ください!