aptpod Tech Blog

株式会社アプトポッドのテクノロジーブログです

【連載 ROS Tips】ROS開発におけるDocker活用テクニック

アプトポッド組み込みエンジニアの久保田です。

近年、ロボットやモビリティを動作させるためのプラットフォームとしてROSを採用することが多くなってきています。 通常、ROSは特定のUbuntuバージョンに対応したディストリビューションとしてリリースされていますので、ROSのディストリビューションを変更したい場合は、ホストOSも変更する必要があります。この制約を回避する方法として、Dockerというコンテナ技術を使う方法があります。Dockerを使えば、ホストOSを変更せず様々なROSディストリビューションを動かすことができるようになります。

また、Dockerの利用はホストOSのアップデートが難しいプラットフォームでROSを利用する際にも効果的です。例えば、当社で販売している車載向けエッジコンピュータEDGEPLANT T1はNVIDIA Jetson TX2を搭載していますが、JetsonシリーズはホストOSのアップデートが難しいため、使用可能なROSのディストリビューションを自由に選択することができません。Dockerコンテナを利用することにより様々なROSディストリビューションを動作させることができます。

連載ROS Tips第2回目となる今回は、ROS開発に便利なDockerコンテナの活用テクニックを紹介します。


なお、連載の予定として、以下のようなコンテンツを予定しております。(連載内容は、変更・追加の可能性があります。ご了承ください)


本連載の投稿済みの記事はこちらからご覧いただけます。

tech.aptpod.co.jp

tech.aptpod.co.jp


Dockerとは

Dockerは、アプリケーションとその動作に必要なすべてのファイルを「コンテナ」というパッケージにまとめる技術です。このコンテナは「仮想化」を利用して、異なる環境でも一貫した動作を実現します。つまり、Dockerは「どこでも同じ動きをするアプリケーション」を作るためのツールであり、その背後には仮想化技術が活用されています。

What is a Container? | Dockerより

ROSをDockerで利用する際のメリットとデメリットは次の通りです。

メリット:

  • 環境の統一: Dockerを使用すると、ROSの環境をコンテナ内に構築できるため、開発者間での環境の差異を気にすることなく、一貫した環境で作業することができます。
  • 移植性: Dockerコンテナは、異なるマシンやクラウド環境でも動作します。これにより、ROSのアプリケーションを簡単に移植やデプロイが可能となります。
  • バージョン管理: 異なるROSのバージョンを同時に実行することが容易になります。これは、特定のバージョンに依存するプロジェクトを管理する際に便利です。
  • 隔離: Dockerコンテナはホストシステムから隔離されているため、システムの設定や依存関係を変更してもホストシステムに影響を与えません。
  • セキュリティ: コンテナの隔離性により、潜在的なセキュリティリスクからホストシステムを保護することができます。

デメリット:

  • オーバーヘッド: Dockerを使用すると、一部のリソースオーバーヘッドが発生する可能性があります。特に、高いリアルタイム性を要求するアプリケーションには影響が出ることがあります。
  • ハードウェアアクセス: Dockerコンテナはホストのハードウェアに直接アクセスするのが難しい場合があります。これは、特定のロボットハードウェアやセンサーとの連携に制約をもたらすことがあります。
  • 学習コスト: Docker自体の学習や設定が必要です。ROSのみならず、Dockerの知識も必要となります。
  • ストレージサイズ: コンテナイメージのサイズが大きくなることがあり、ストレージの使用量が増加する可能性があります。

ROS Dockerコンテナイメージ

ROSが動作するDockerコンテナイメージは、Open Source Robotics Foundation (OSRF) が公式イメージを提供しています。イメージはROSディストリビューションの配布方法に準じて、core・base・desktopのイメージとして配布されています。

  • core: ROSメッセージをpub/subできる最低限のパッケージ
  • base: core + ロボットを動かすための最低限のパッケージ
  • desktop: base + GUIを含むパッケージ

詳細については以下のリンク先の情報からご確認いただけます

公式イメージは以下のサイトにて公開されています

イメージ提供サイト: Docker Containers for ROS

ros - Official Image | Docker Hub

最新の安定版(LTS)ディストリビューションのイメージ一覧

公式イメージとして、各ROSディストリビューションのイメージが公開されています。ここでは、代表的な最新安定版 (LTS) のイメージを紹介します。

ROSディストリビューション イメージ名 イメージに付けられたタグ
ROS Noetic ros-core ros:noetic-ros-core
ros-base ros:noetic
ros-desktop osrf/ros:noetic-desktop
ROS 2 Humble ros-core ros:humble-ros-core
ros-base ros:humble
ros-desktop osrf/ros:humble-desktop

(desktopは amd64のみ, arm64の場合、ros-baseイメージにて apt install ros-<distribution name>-desktop を実行することにより同等のイメージとなります )

DockerコンテナでROSを実行する

提供されているDockerコンテナイメージをダウンロードすることにより、簡単にROSを試すことができます。ここでは、簡単なStringのpublish/subscribeを試してみます。

docker/Tutorials/Docker - ROS Wiki

ROS

Dockerコンテナイメージをダウンロード

pullコマンドにて、イメージをダウンロードします。

$ docker pull ros:noetic

ROSマスターを起動

runコマンドにて、ROSマスターとなるコンテナ (コンテナ名: rosmaster) を起動します

$ docker run -it --rm --name=rosmaster \
    --net=host \
    ros:noetic \
    roscore
... logging to /root/.ros/log/7f4ee758-512e-11ee-862e-00155d66fab1/roslaunch-localhost-1.log
Checking log directory for disk usage. This may take a while.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.

started roslaunch server http://localhost:40991/
ros_comm version 1.16.0


SUMMARY
========

PARAMETERS
 * /rosdistro: noetic
 * /rosversion: 1.16.0

NODES

auto-starting new master
process[master]: started with pid [32]
ROS_MASTER_URI=http://localhost:11311/

setting /run_id to 7f4ee758-512e-11ee-862e-00155d66fab1
process[rosout-1]: started with pid [42]
started core service [/rosout]

ROSメッセージをpublish

runコマンドにて、ROSメッセージをpublishするコンテナ (コンテナ名: rospub) を起動します

$  docker run -it --rm --name rospub \
    --net=host \
    ros:noetic \
    rostopic pub -r 1 /my_topic std_msgs/String '{data: "hello"}'

ROSメッセージをsubscribe

runコマンドにて、ROSメッセージをsubscribeするコンテナ (コンテナ名: rossub) を起動します

$ docker run -it --rm --name rossub \
    --net=host \
    ros:noetic \
    rostopic echo /my_topic
data: "hello"
---
data: "hello"
---
data: "hello"
---


ROS 2

Dockerコンテナイメージをダウンロード

pullコマンドにて、イメージをダウンロードします。

$ docker pull ros:humble

ROSメッセージをpublish

runコマンドにて、ROSメッセージをpublishするコンテナ (コンテナ名: rospub) を起動します

$ docker run -it --rm --name rospub \
    --net=host \
    --ipc=host \
    ros:humble \
    ros2 topic pub /my_topic std_msgs/msg/String '{data: "hello"}'
publisher: beginning loop
publishing #1: std_msgs.msg.String(data='hello')

publishing #2: std_msgs.msg.String(data='hello')

publishing #3: std_msgs.msg.String(data='hello')

ROSメッセージをsubscribe

runコマンドにて、ROSメッセージをsubscribeするコンテナ (コンテナ名: rossub) を起動します

$ docker run -it --rm --name rossub \
    --net=host \
    --ipc=host \
    ros:humble \
    ros2 topic echo /my_topic
data: hello
---
data: hello
---
data: hello
---

Docker活用テクニック① コンテナ間ネットワークの設定

Dockerコンテナはデフォルトでブリッジネットワークを使用します。これはホストOSとは独立したプライベートなネットワーク空間です。コンテナ間では、コンテナの動作している筐体に合わせてネットワーク設定します。

ホスト内通信 (同一筐体内通信)

ホスト内通信

ROS

ROSマスター用のコンテナを立てて、アプリ側からはブリッジネットワーク内通信によってROSマスターに接続します。各コンテナはコンテナ名で名前解決できますのでROSマスターの指定にはコンテナ名を使用できます。環境変数にて、ROSホスト名(ROS_HOSTNAME)とROSマスターURI(ROS_MASTER_URI)を指定します。

ブリッジネットワーク作成 (ネットワーク名: rosnet)

$ docker network create rosnet

ROSマスターコンテナ (コンテナ名: rosmaster)

コンテナ名がネットワークホスト名となります。ブリッジネットワーク内のROSマスターURIは http://rosmaster:11311 です。

$ docker run -it --rm \
     --net=rosnet \
     --name rosmaster \
     ros:noetic \
     roscore

ROSアプリケーションコンテナ (コンテナ名: rosapp)

コンテナ名がネットワークホスト名となります。ROSホスト名(ROS_HOSTNAME)とコンテナ名を一致させてください。

$ docker run -it --rm \
     --net=rosnet \
     --env ROS_HOSTNAME=rosapp \
     --env ROS_MASTER_URI=http://rosmaster:11311 \
     --name rosapp \
     ros:noetic \
     rostopic pub -r 1 /my_topic std_msgs/String '{data: "hello"}'


ROS 2

ROS 2通信には、マスターは不要となっています。ホスト内通信ではプロセス間通信を利用するため、IPCの設定 (--ipc=host) をします。

1.1. Leveraging Fast DDS SHM in Docker deployments — Fast DDS 2.12.0 documentation

$ docker run -it --rm --name rospub \
    --net=host \
    --ipc=host \
    ros:humble \
    ros2 topic pub /my_topic std_msgs/msg/String '{data: "hello"}'

ホスト間通信 (別筐体間通信)

ホスト間通信

ROS

ホストのネットワークインターフェースを共有するように設定 ( --net=host ) します。

ROSマスターコンテナ (コンテナ名: rosmaster)

ROSマスターが動作している筐体のIPアドレスまたはホスト名を使用します。ここでは、ROSマスターが動作している筐体のIPアドレスを 192.168.0.1 とします。ROSマスターURIは http://192.168.0.1:11311 です。

$ docker run -it --rm \
     --net=host \
     --name rosmaster \
     ros:noetic \
     roscore

ROSアプリケーションコンテナ (コンテナ名: rosapp)

ROSホスト名(ROS_HOSTNAME)にROSアプリケーションが動作している筐体のIPアドレスを設定します。ここでは ROSアプリケーションが動作している筐体のIPアドレスを 192.168.0.2 とします。

$ docker run -it --rm \
     --net=host \
     --env ROS_HOSTNAME=192.168.0.2 \
     --env ROS_MASTER_URI=http://192.168.0.1:11311 \
     --name rosapp \
     ros:noetic \
     rostopic pub -r 1 /my_topic std_msgs/String '{data: "hello"}'


ROS 2

UDP通信の設定をします。コンテナ外との通信となるため、ホストのネットワークインターフェースを共有するように設定 ( --net=host ) します。

ROS 2は通信ミドルウェアに DDS(Data Distribution Service)を採用しており、UDP通信をするためにはDDSヘの設定が必要です。ここでは、DDSが Fast DDS の場合の設定を紹介します。Fast DDSの設定は、設定ファイルfastrtps-profile.xmlを作成し、環境変数 (FASTRTPS_DEFAULT_PROFILES_FILE) で指定します。

6.2. UDP Transport — Fast DDS 2.12.0 documentation

設定ファイル (fastrtps-profile.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles" >
    <transport_descriptors>
        <transport_descriptor>
            <transport_id>CustomUdpTransport</transport_id>
            <type>UDPv4</type>
        </transport_descriptor>
    </transport_descriptors>

    <participant profile_name="participant_profile" is_default_profile="true">
        <rtps>
            <userTransports>
                <transport_id>CustomUdpTransport</transport_id>
            </userTransports>

            <useBuiltinTransports>false</useBuiltinTransports>
        </rtps>
    </participant>
</profiles>

設定ファイル反映 & コンテナ起動

$ docker run -it --rm --name rospub \
    --net=host \
    -e FASTRTPS_DEFAULT_PROFILES_FILE=/tmp/fastrtps-profile.xml \
    -v ./fastrtps-profile.xml:/tmp/fastrtps-profile.xml \
    ros:humble \
    ros2 topic pub /my_topic std_msgs/msg/String '{data: "hello"}'

Docker活用テクニック② Docker Composeで複数コンテナを起動する

Docker Composeとは

Docker Composeは、複数のDockerコンテナを定義し、連携させて実行するためのツールです。設定ファイル (docker-compose.yml) に、使用するコンテナの設定やネットワーク、ボリュームの情報などを記述することで、一つのコマンドで複数のコンテナを同時に起動・停止することができます。特に、複数のサービスが連携するアプリケーションの開発やテストにおいて、環境の構築や管理を簡単にするために利用されます。

ここでは、Dockerコンテナ実行で紹介したコマンドをDocker Compose で実行してみます。

docker/Tutorials/Compose - ROS Wiki

ROS

設定ファイル (docker-compose.yml)

version: '3'

networks:
  rosnet:
    driver: bridge

services:
  ros-master:
    container_name: rosmaster
    image: ros:noetic
    command: stdbuf -o L roscore
    networks:
      - rosnet
    restart: always

  ros-pub:
    container_name: rospub
    image: ros:noetic
    depends_on:
      - ros-master
    networks:
      - rosnet
    restart: always
    environment:
      - ROS_HOSTNAME=rospub
      - ROS_MASTER_URI=http://rosmaster:11311
    command: rostopic pub -r 1 /my_topic std_msgs/String "hello"

  ros-sub:
    container_name: rossub
    image: ros:noetic
    depends_on:
      - ros-master
    networks:
      - rosnet
    restart: always
    environment:
      - ROS_HOSTNAME=rossub
      - ROS_MASTER_URI=http://rosmaster:11311
    command: rostopic echo /my_topic

Dockerコンテナ起動

$ docker-compose -f ./docker-compose.yml up
[+] Building 0.0s (0/0)
[+] Running 4/4
 ✔ Network tmp_rosnet   Created                                                                                               0.1s
 ✔ Container rosmaster  Created                                                                                               0.1s
 ✔ Container rossub     Created                                                                                               0.1s
 ✔ Container rospub     Created                                                                                               0.1s
Attaching to rosmaster, rospub, rossub
rossub     | data: "hello"
rossub     | ---
rossub     | data: "hello"
rossub     | ---
rossub     | data: "hello"
rossub     | ---

(※) 停止はCtrl-C


Dockerコンテナ削除

$ docker-compose -f ./docker-compose.yml down
[+] Running 4/4
 ✔ Container rossub     Removed                                                                                               0.0s
 ✔ Container rospub     Removed                                                                                               0.0s
 ✔ Container rosmaster  Removed                                                                                               0.0s
 ✔ Network tmp_rosnet   Removed


ROS 2

設定ファイル (docker-compose.yml)

version: '3'

services:
  ros-pub:
    container_name: rospub
    image: ros:humble
    network_mode: "host"
    ipc: host
    command: >
      ros2 topic pub /my_topic std_msgs/msg/String '{data: "hello"}'

  ros-sub:
    container_name: rossub
    image: ros:humble
    network_mode: "host"
    ipc: host
    depends_on:
      - ros-pub
    command: ros2 topic echo /my_topic

Dockerコンテナ起動

$ docker compose -f docker-compose.yml up
[+] Building 0.0s (0/0)
[+] Running 2/2
 ✔ Container rospub  Created                                                                                                  0.1s
 ✔ Container rossub  Created                                                                                                  0.0s
Attaching to rospub, rossub
rospub  | publisher: beginning loop
rospub  | publishing #1: std_msgs.msg.String(data='hello')
rospub  |
rossub  | data: hello
rossub  | ---
rospub  | publishing #2: std_msgs.msg.String(data='hello')
rospub  |
rossub  | data: hello
rossub  | ---

(※) 停止はCtrl-C


Dockerコンテナ削除

$ docker compose -f docker-compose.yml down
[+] Running 2/0
 ✔ Container rossub  Removed                                                                                                  0.0s
 ✔ Container rospub  Removed

Docker活用テクニック③ コンテナでGUIを利用する

Docker with GUI

Dockerコンテナ内でGUIアプリケーションを利用するには、ホストでX Serverが必要となります。X ServerはLinuxデスクトップアプリケーションで利用されているWindowシステムです。

事前準備

ホストで X Server が動作していることを確認してください。多くの Linux ディストリビューションでは、デフォルトで X Server がインストールされています。 X Server のアクセス権をコンテナからの接続を許可するように設定します。

$ xhost +local:

GUIアプリケーション起動

Dockerコンテナを起動します。コンテナでGUIが利用できるように起動オプション (-e DISPLAY -e QT_X11_NO_MITSHM=1 -v /tmp/.X11-unix:/tmp/.X11-unix) を付加してください。

ここでは、ROS 2のための3D可視化ツールである rviz2 を起動します。

$ docker run -it --rm --name guitest \
    -e DISPLAY \
    -e QT_X11_NO_MITSHM=1 \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    osrf/ros:humble-desktop \
    rviz2

起動後、ホスト上にrviz2が表示されます。

Dockerコンテナ rviz2

Docker活用テクニック④ コンテナ内からWebカメラの映像を取得する

Docker with Web Camera

ROSでWebカメラ画像を取得するにはV4L2(Video4Linux version 2)を利用します。V4L2は、Linuxカーネル内のAPIであり、ビデオキャプチャと出力デバイスのサポートを提供します。

事前準備

WebカメラがV4L2でサポートされているかを確認してください。UVC(USB Video Class)規格のWebカメラは対応しています。

Webカメラ画像取得ノード

ROS

ノード提供サイト: ROS Camera driver for GStreamer-based video streams - branch: master

GitHub - ros-drivers/gscam: ROS Camera driver for GStreamer-based video streams.

ROS 2

ノード提供サイト: ROS Camera driver for GStreamer-based video streams - branch: ros2

GitHub - ros-drivers/gscam at ros2

Webカメラ画像取得

ここでは、ROS 2 で取得してみます。

Dockerコンテナを起動します。コンテナでWebカメラデバイスが利用できるように起動オプション (--privileged --device=/dev/video0:/dev/video0) を付加してください。

$ docker run -it --rm --name cameratest \
    --net=host \
    --privileged \
    --device=/dev/video0:/dev/video0 \
    osrf/ros:humble-desktop \
    /bin/bash

起動したDockerコンテナにログイン後、Webカメラ画像取得ノードをビルドします。ビルドが完了後、Webカメラ画像取得ノードを起動します。起動設定ファイルは次の通りです。

Webカメラ画像取得ノード設定ファイル (v4l.launch.xml)

<launch>
  <!-- This launchfile should bring up a node that broadcasts a ros image
       transport on /webcam/image_raw -->

  <arg name="DEVICE" default="/dev/video0"/>
  <!-- The GStreamer framerate needs to be an integral fraction -->
  <arg name="FPS" default="10/1"/>
  <arg name="PUBLISH_FRAME" default="false"/>

  <node namespace="v4l" name="gscam_driver_v4l" pkg="gscam" exec="gscam_node" output="screen">
    <param name="camera_name" value="default"/>
    <param name="camera_info_url" value="package://gscam/examples/uncalibrated_parameters.ini"/>
    <param name="gscam_config" value="v4l2src device=$(var DEVICE) ! video/x-raw,framerate=$(var FPS) ! videoconvert"/>
    <param name="frame_id" value="/v4l_frame"/>
    <param name="sync_sink" value="true"/>
  </node>

  <node if="$(var PUBLISH_FRAME)" name="v4l_transform" pkg="tf2_ros" exec="static_transform_publisher" args="1 2 3 0 -3.141 0 /world /v4l_frame"/>
</launch>


Webカメラ画像取得ノード起動後、トピック名が /v4l/camera/image_raw のROSメッセージが送信されます。

# ros2 launch ./v4l.launch.xml 
[INFO] [launch]: All log files can be found below /root/.ros/log/2023-09-13-07-37-40-455157-feb5b5ceb79d-2335
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [gscam_node-1]: process started with pid [2336]
[gscam_node-1] [INFO] [1694590661.146771024] [v4l.gscam_driver_v4l]: Using gstreamer config from rosparam: "v4l2src device=/dev/video0 ! video/x-raw,framerate=10/1 ! videoconvert"
[gscam_node-1] [INFO] [1694590661.147929610] [v4l.gscam_driver_v4l]: camera calibration URL: package://gscam/examples/uncalibrated_parameters.ini
[gscam_node-1] [INFO] [1694590661.148746118] [v4l.gscam_driver_v4l]: Loaded camera calibration from package://gscam/examples/uncalibrated_parameters.ini
[gscam_node-1] [INFO] [1694590663.558110687] [v4l.gscam_driver_v4l]: Time offset: 1694587415.451620
[gscam_node-1] [INFO] [1694590663.572234037] [v4l.gscam_driver_v4l]: Publishing stream...
[gscam_node-1] [INFO] [1694590663.572646995] [v4l.gscam_driver_v4l]: Started stream.


Webカメラ画像のROSメッセージを確認する場合、「Docker活用テクニック④ コンテナでGUIを利用する」で起動した rviz2 で表示します。

GSCam in Dockerコンテナ

まとめ

今回は、ROS開発に便利なDockerコンテナの活用テクニックを紹介しました。紹介した活用テクニックにより、ホストで使用する場合と同様の扱いができますので、ご活用ください。

冒頭にもご紹介した通り、当社は車載向けエッジコンピューターEDGEPLANT T1を販売しています。

aptpod,Inc. EDGEPLANT T1

EDGEPLANT T1

EDGEPLANT T1はNVIDIA® Jetson™ TX2を搭載したエッジコンピュータで、映像のエンコードやデコードなどGPUを使用する処理や、デバイスエッジでのAIモデルの実行用途にお使いいただけます。また、SIMスロット、GPSモジュールなど、IoT端末として必要な様々な機能を備えています。車載機器に求められるEMC規格(Eマーク)、信頼性規格(JASO D014)などにも準拠しており、ROSを使用したロボット開発、自動運転システムの開発にもおすすめです。

EDGEPLANT T1は、当社の販売パートナー様または、Amazon.co.jp からご購入いただけます。詳しくは、製品ページをご覧ください。

www.aptpod.co.jp

AI自動運転での活用例もございます。ご興味がございましたらこちらの記事もご覧ください。

tech.aptpod.co.jp

次回以降は

  • DockerでROSを利用する際に、GPUを使用する方法についての紹介
  • ROS 2を利用する上での大容量データ転送シナリオにおけるチューニングについての紹介

を予定しています。


当社プロダクトのご案内

先日行われた ROSConJP 2023 では、ROSの開発ワークフローを効率化するDXソリューションとして、新たなソリューションを発表いたしました。詳細については、ROSConJP 2023の参加報告記事をご覧ください。

tech.aptpod.co.jp

また、ROS開発において、当社プロダクトをどの様にご活用いただけるかは、連載1日目にて当社のVPoPがより詳しく紹介しておりますので、こちらもご覧ください。

tech.aptpod.co.jp

さらに、当社では、モビリティ・ロボットのフリート管理や遠隔監視、遠隔制御を実現するための管制制御システム向けのソリューションフレームワーク「intdash CONTROL CENTER」を提供しています。

tech.aptpod.co.jp

スマートシティにおける自動運転車、工場や物流倉庫における搬送ロボット、建設現場における建設機械など、モビリティ群の統合遠隔監視・管理、遠隔制御システムな どでお困りのことがあれば、ぜひお声掛けください。

お問合せフォームは こちら です。