令和最新版 ROS Noetic on Docker のすすめ
導入
こんにちは、CA技研でエンジニアをしているHiraiKyoです。
CA技研ではロボット開発フレームワーク「Robot Operating System (ROS)」を使用して製品開発しております。
弊社ではROS2への移行は検討段階で、現在も主にROS Noeticを使用しています。
この理由は、ROSのように様々な機器とのインテグレーションを前提としていると、どうしても機器側のROS2対応が行われるまでは移行しづらいためです。
しかし、ROS NoeticのEOLも目前に迫っています。
ROSは特定のUbuntuバージョンに対応してリリースされており、最新版のROS NoeticはUbuntu 20に対応しています。
そのUbuntu 20が2025年5月にサポート終了となります。(あと半年)
そこで弊社では、ROSをすべてDockerコンテナ内で実行する事で、メンテナビリティ向上に取り組みました。
もうちょっと掘り下げた経緯
Docker導入の経緯は、元々は以下の2点でした。
- ROS Kinetic用SDKを使用した機器が既に存在していた。
- その機器を使用しないシステムではROS Noetic, その機器を使用するシステムではROS Kineticを使用するという状況
- ROS KineticはUbuntu 16なため、Node.jsのバージョンを上げられず苦労した
- Ubuntu 16がEOLを迎えているため、カーネルレベルのエラー発生が増えていた
- Intel第12世代以降のCPUはLinux Kernel 6を要求するため、Ubuntu 24へのアップデートが必要だった
- ROS1最新版のROS NoeticですらUbuntu 20であり、最新ハードへの対応に迫られていた。
懸念材料には以下がありました。
- Docker導入による計算速度低下
- 点群処理や画像処理を行うため、高い演算能力が求められる
- 仮想化により計算速度が低下するのであれば、ROS NoeticをUbuntu 24環境下でビルドする方向もあった
- 仮想化で既存システムが本当に動作するのか
- 既存システムのシリアル通信やネットワーク周りがDocker対応できるか
結果として、これらは全てDocker導入により解決できました。
レポジトリ
https://github.com/CA-Giken/docker-noetic-capc
ROS on Docker 環境構築
前提
- Ubuntu 24
注意
当記事では、スタンドアローン環境での利用を想定しており、セキュリティ面は考慮していません。
ROS Noetic on Docker 基本方針
- Docker
- ホストネットワークを利用する
- スタンドアローン環境での利用なので
- GUIはXserverを利用する
- VNCはrvizの画面がリフレッシュされない現象に悩まされたので利用しない
- ホストネットワークを利用する
- ROSパッケージ開発
- serviceは利用せず、topicの送受のみを行う。
- RPCが利用できないため
- 独自メッセージ型を使用せず、基本型のみを利用する
- RPCが利用できないため
- serviceは利用せず、topicの送受のみを行う。
ディレクトリ構成
.
├── docker-noetic-capc
│ ├── kinetic
│ │ ├── Dockerfile
│ │ └── entrypoint.sh
│ ├── noetic
│ │ ├── Dockerfile
│ │ └── entrypoint.sh
│ └── docker-compose.yml
├── container1(今回はkineticと命名)
│ └── catkin_ws
│ └── src
└── container2(今回はnoeticと命名)
└── catkin_ws
└── src
Dockerをインストール
# 古いパッケージを削除
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done
# GPGキーを追加
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Dockerをレポジトリ一覧に追加
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$UBUNTU_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
# インストール
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# インストール確認テスト
sudo docker run hello-world
ROSをインストールするDockerfileを作成
今回はKinetic, Noeticを共存させるため、それぞれのDockerfileを作成します。
機器ごとにDockerfileを作成してもよいですし、その際にNoeticのコンテナが2つになってもいいです。
なお、異なるROSディストリビューションの共存については、ROS Cross-Distribution Communication対応表をご覧ください。
ROS Cross-Distribution Communication - General
FROM ubuntu:focal-20240427
WORKDIR /root/
ENV DEBIAN_FRONTEND=noninteractive
# Upgrade Packages
RUN apt-get update -q \
&& apt-get upgrade -y \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Utility packages
RUN apt-get update -q \
&& apt-get install -y software-properties-common \
&& add-apt-repository universe && apt-get update -q \
&& apt-get install -y git build-essential wget curl vim sudo lsb-release locales \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install X11 requirements
RUN apt-get update -q && apt-get install -y \
iputils-ping telnet x11-apps \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install Python
RUN apt-get update -q && apt-get install -y \
python3.8 python3-pip python3-dev python3-tk python-is-python3 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install ROS
ENV ROS_DISTRO noetic
RUN sh -c 'echo "deb http://packages.ros.org/ros/ubuntu focal main" > /etc/apt/sources.list.d/ros-latest.list'
RUN curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
RUN apt-get update -q \
&& apt-get install -y ros-noetic-desktop-full \
&& apt-get install -y python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential python3-catkin-tools \
&& rosdep init \
&& rosdep update \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Setting for Japanese
RUN apt-get update -q && apt-get install -y \
tzdata locales fonts-noto-cjk fcitx-mozc \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN ln -s -f /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
dpkg-reconfigure tzdata && \
locale-gen ja_JP.UTF-8
# Set user
ARG UID=1000
RUN useradd -m -u ${UID} ros
RUN sh -c 'echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc'
RUN sh -c 'echo "export ROS_HOSTNAME=localhost" >> ~/.bashrc'
RUN sh -c 'echo "export ROS_MASTER_URI=http://localhost:11311" >> ~/.bashrc'
RUN sh -c 'echo "export PYTHONPATH=/usr/local/lib/python3.8/dist-packages:$PYTHONPATH" >> ~/.bashrc'
# Command copy
COPY ./entrypoint.sh /app/
RUN chmod +x /app/entrypoint.sh
CMD ["/bin/sh", "-c", "./entrypoint.sh"]
FROM ubuntu:16.04
WORKDIR /root/
ENV DEBIAN_FRONTEND=noninteractive
# Upgrade Packages
RUN apt-get update -q \
&& apt-get upgrade -y \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Utility packages
RUN apt-get update -q \
&& apt-get install -y software-properties-common \
&& add-apt-repository universe && apt-get update -q \
&& apt-get install -y git build-essential wget curl vim sudo lsb-release locales \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install X11 requirements
RUN apt-get update -q && apt-get install -y \
iputils-ping telnet x11-apps \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install Python
RUN add-apt-repository universe && \
apt-get update -q && apt-get install -y \
python3-pip python3-dev python3-tk \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install ROS
ENV ROS_DISTRO kinetic
RUN sh -c 'echo "deb http://packages.ros.org/ros/ubuntu xenial main" > /etc/apt/sources.list.d/ros-latest.list'
RUN curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
RUN apt-get update -q \
&& apt-get install -y ros-kinetic-desktop-full \
&& apt-get install -y python-rosdep python-rosinstall python-rosinstall-generator python-wstool build-essential python-catkin-tools\
&& rosdep init \
&& rosdep update \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Setting for Japanese
RUN apt-get update -q && apt-get install -y \
tzdata locales fonts-noto-cjk fcitx-mozc \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN ln -s -f /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
dpkg-reconfigure tzdata && \
locale-gen ja_JP.UTF-8
# Set user
ARG UID=1000
RUN useradd -m -u ${UID} ros
RUN sh -c 'echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc'
RUN sh -c 'echo "export ROS_HOSTNAME=localhost" >> ~/.bashrc'
RUN sh -c 'echo "export ROS_MASTER_URI=http://localhost:11311" >> ~/.bashrc'
# Command copy
COPY ./entrypoint.sh /app/
CMD ["/bin/sh", "-c", "./entrypoint.sh"]
Docker compose を作成
Dockerfileを参照して、kinetic用とnoetic用の2つのコンテナを立ち上げます。
kineticコンテナはレガシー対応目的なので、roscoreはnoeticで立ち上げてkineticコンテナが接続しにいく形です。
version: "3.9"
services:
roskinetic:
container_name: roskinetic
hostname: roskinetic
privileged: true
build:
context: ./kinetic
dockerfile: Dockerfile
shm_size: 2gb
shm_size: 2gb
environment:
- DISPLAY=display:0
- QT_X11_NO_MITSHM=1
- ROS_MASTER_URI=http://localhost:11311
volumes:
- type: bind
source: ~/kinetic/catkin_ws/src
target: /root/catkin_ws/src
stdin_open: true
tty: true
extra_hosts:
- "display:host-gateway"
network_mode: host
rosnoetic:
container_name: rosnoetic
hostname: rosnoetic
build:
context: ./noetic
dockerfile: Dockerfile
environment:
- DISPLAY=display:0
working_dir: /root
volumes:
- type: bind
source: ~/noetic/catkin_ws/src
target: /root/catkin_ws/src
stdin_open: true
tty: true
ports:
- 11311:11311
extra_hosts:
- "display:host-gateway"
network_mode: host
ホスト側Xserverの設定
/etc/gdm/custom.confの変更
デフォルトでは外部からの接続(TCP)を受け付けないので変更が必要。
DisallowTCP=false
Linux Mintを利用している場合はLight Display Managerなので、/etc/lightdm/lightdm.conf
を変更します。
xserver-allow-tcp=true
PCを再起動し、接続確認
telnet localhost 6000
接続されれば外部接続が可能となっています(特に何も表示されない)。
表示テスト
export DISPLAY=localhost:0
xeyes
外部からのアクセス制御を許可
xhost +
使用方法
# Dockerコンテナにマウントするディレクトリを作成
mkdir -p ~/noetic/catkin_ws/src
mkdir -p ~/kinetic/catkin_ws/src
# Xserverの接続許可(PC起動ごとに必要)
xhost +
# コンテナ & roscore立ち上げ
docker compose up
docker compose exec rosnoetic bash -c "cd catkin_ws && catkin build && roscore"
これでKinetic用、Noetic用コンテナがそれぞれ起動します。
ホスト側の~/dist/catkin_ws/src
にROSパッケージを配置した後、コンテナに入ってビルドできます。
# Kineticコンテナで実行する例
docker compose exec roskinetic bash -c "cd catkin_ws && catkin build"
以上を実行すると、コンテナ内にdevel
, build
ディレクトリが作成されるので、あとは任意のlaunch
ファイルを実行するだけです。
# Noeticコンテナで実行する例
docker compose exec roskinetic bash -c "roslaunch xxx yyy.launch"
あとがき
現在はセンサ1機、アクチュエータ1機のシステムで使用していますが、今後センサやアクチュエータが増えた際にDockerコンテナを増やしていく形での対応を予定しています。
追記: WSL2対応
WindowsのWSL2環境でGUI表示するにはXserverをUbuntu上ではなくWindows上でホストし、
- 上記の
ホスト側Xserver
を行わない - VcXsrvを導入する。https://sourceforge.net/projects/vcxsrv/
すべて「次へ」連打でOKです。 - Windows上でVcXsrv -> XLaunchを実行する
- WSLのUbuntuにある
~/.bashrc
に以下を追加する
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0.0
export LIBGL_ALWAYS_INDIRECT=1
これでWindows環境からもRvizなどのGUIを見る事ができるようになります。
Discussion