vscode+Remote-ContainersでROS2開発環境を構築してみた


はじめに

2020年のGWは外出自粛なので、なかなか手が出なかったROS2に手を付けることにしました。

そこでどうせならとdocker使ってみることにしたのですが、簡単なpackageを作ろうとするとContainer内でのROS2のソース編集が面倒だったので、vscodeのRemote-ContainersというExtensionを使ってみました。

これはDockerのContainer内をホストPCのvscodeでそのまま編集できる拡張機能になります。(vscodeはこういう機能強いですね。)

Remote-Containersを使うとvscodeのterminalでros2のコマンド実行と、ソース編集は普段のvscodeをそのまま使ってでき、Container内であることをあまり意識しないで開発出来そうです。(ただ後述しますが、まだまだうまく使いこなせていない状況です。)

環境構築ばっかりして全然ROS2開発的なことは進んでないのですが(汗)、折角なのでその使用方法について備忘録的にまとめてみました。

環境

以下のVersionを使用しています。

  • Ubuntu : 18.04
    • arch : x86_64
  • Docker : 18.09.7
  • vscode : 1.44.2
  • (vscode extension)remote container : 0.112.0

Install

Docker, vscodeのInstall方法は割愛します。
Remote-ContainersはvscodeのEXTENSIONSを選択、"remote containers"と入力してInstallしてください。

Remote-Containersの設定

Remote-Containersの使い方はこちらの記事を参考にしました。

VS CodeでDocker開発コンテナを便利に使おう

.devcontainerというディレクトリ以下に
- Dockerfile
- devcontainer.json
の2つのファイルを用意します。

Dockerfile

これは通常のDockerfileと同じフォーマットです。

一部をmicrosoftのサンプルをベースに変更を加えました。

参考:vscode-dev-containers/containers/ubuntu-18.04-git/.devcontainer/

変更箇所は↓こちらです。

ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID

# Set to false to skip installing zsh and Oh My ZSH!
ARG INSTALL_ZSH="true"

# Location and expected SHA for common setup script - SHA generated on release
ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/v0.112.0/script-library/common-debian.sh"
ARG COMMON_SCRIPT_SHA="28e3d552a08e0d82935ad7335837f354809bec9856a3e0c2855f17bfe3a19523"


# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive

# Configure apt and install packages
RUN apt-get update \
    && apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
    #
    # Verify git, common tools / libs installed, add/modify non-root user, optionally install zsh
    && wget -q -O /tmp/common-setup.sh $COMMON_SCRIPT_SOURCE \
    && if [ "$COMMON_SCRIPT_SHA" != "dev-mode" ]; then echo "$COMMON_SCRIPT_SHA /tmp/common-setup.sh" | sha256sum -c - ; fi \
    && /bin/bash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \
    && rm /tmp/common-setup.sh \
    #
    # Clean up
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*

FROMで設定するbase imageはROS2のeloquentのイメージとしています。
https://hub.docker.com/r/osrf/ros/

FROM osrf/ros:eloquent-desktop

このFROMの指定先を環境に合わせて変更する必要はあります。(例えばarm64v8は別)

公式のros2のimageは入っていない機能もあったりするらしいので、FROMはrosのimageにするのをやめて、Docker build時にインストールコマンドでROS2をインストールするような形としても使えると思われます。

参考:Docker上でGUIのROS1/ROS2を一瞬でセットアップする方法

devcontainer.json

こちらはcppのサンプルをベースにしています。

devcontainer.json
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.112.0/containers/cpp
{
    "name": "ros2_docker_ws",
    "dockerFile": "Dockerfile",
    "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined", "--net=host"],

    // Set *default* container specific settings.json values on container create.
    "settings": { 
        "terminal.integrated.shell.linux": "/bin/bash"
    },

    // Add the IDs of extensions you want installed when the container is created.
    "extensions": [
        "ms-vscode.cpptools"
    ],

    // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
    "remoteUser": "vscode",

    "workspaceFolder": "/home/vscode/ros2_vscode_ws/",
    "workspaceMount": "type=bind,source=${localWorkspaceFolder},target=/home/vscode/ros2_vscode_ws/"
}

"runArgs"でdocker run時のオプションが追加できるのですが、なぜか"-e"でENVの追加は反映されませんでした。
Container内でのマウント先は"workspaceFolder","workspaceMount"で設定し、私の場合は/home/vscode/ros2_vscode_ws/としています。(追記:最初に記事を書いたときは/home直下に配置していましたが気持ちわるいので変更しました。)

devcontainer.json
   "workspaceFolder": "/home/vscode/ros2_vscode_ws/",
    "workspaceMount": "type=bind,source=${localWorkspaceFolder},target=/home/vscode/ros2_vscode_ws/"

私の設定ファイル例はこちらにあります。こちらのrepoをそのままcloneしてもらっても試すことは可能です。
ros2_vscode_ws

Open Container

設定ファイルは用意できたので、vscodeを操作してDocker buildし、Containerを立ち上げます。

まずRemote-Containersをインストール済みであれば、vscodeの左下にこの緑色のアイコンがあるのでそれをクリックして、

Open Folder in Container...を選択し、.devcontainerが配置されたディレクトリを選択します。
ros2_vscode_wsをcloneしている場合は、そのままros2_vscode_wsディレクトリを選択します。

そうするとDocker buildが始まります。
進捗状況は右下のダイアログのStarting with Dev containerをクリックするとvscodeのterminalに表示されます。

何かエラーがあるとこちらで確認し、Dockerfileやdevcontainer.jsonを修正して再度Openします。

Build中はvscodeの左下がOpeining Remote..の表示になっています。

Docker build完了して正常にrunされるとDev Containerという表示に切り替わります。

ここまでくるとDocker runは出来た状態です。

ROS2 pub/sub確認

+アイコンでterminalを追加するとコンテナ内で操作が行えます。

vscodeのterminal側と別で立ち上げたPC側のターミナルでdocker runしてpub/sub通信出来るか確認します。

vscode側Terminal

export ROS_DOMAIN_ID=1
source /opt/ros/eloquent/setup.bash
ros2 run demo_nodes_cpp listener

PC側Terminal

$ docker run -it --rm -e ROS_DOMAIN_ID=1 osrf/ros:eloquent-desktop ros2 run demo_nodes_cpp talker

vscode側のterminalでlisnterを立ち上げており、そこで受信したtopicが表示されたので無事通信出来ました。

# ros2 run demo_nodes_cpp listener
[INFO] [listener]: I heard: [Hello World: 93]
[INFO] [listener]: I heard: [Hello World: 94]
[INFO] [listener]: I heard: [Hello World: 95]
[INFO] [listener]: I heard: [Hello World: 96]
[INFO] [listener]: I heard: [Hello World: 97]
[INFO] [listener]: I heard: [Hello World: 98]
[INFO] [listener]: I heard: [Hello World: 99]
[INFO] [listener]: I heard: [Hello World: 100]

Sample pkgのCreate

Smaple的なpkgをcreateしました。

$ cd ~/ros2_vscode_ws/src
$ ros2 pkg create --build-type ament_cmake --node-name hello_world ros2_training

そうすると、vscodeのEXPLORER側にファイルが追加されました。

cppファイルの追加や編集もvscode上で出来ますので普段通りにできました。

さいごに

vscodeのRemote-Containersを使って普段のvscodeを使ってContainer内でのROS2開発ができる環境を作ってみました。簡単な開発やPCの環境に影響を与えずにROS2を試すのには便利そうです。

ただ、いくつか課題というか、まだどうやっていくか決めかねている点や確認出来ていない点があります。

vscodeのworkspaceで指定するディレクトリをどうするか

今回はcolcon build実行する~/ros2_ws相当をworkspaceとしていますが、本来開発するのは~/ros2_ws/src以下に配置されるros pkg単位になるので、本来はその単位でマウントした方が良いか、現状のままでsubmodule的に扱うのが良いか、よくわかっていないです。

公式の情報をみるともう少し見解出せるかもしれないです。
Developing inside a Container

HWリソースのアクセスは未確認

通常のDockerと同じように使用出来ていると思いますが、HWリソース周りが動作するかは未確認です。

ネットワーク上の他マシンとの通信

ros2でdocker runして他マシンと通信する場合はoptionで--net=hostが追加必要ですが、
Docker runのargが恐らくうまく反映されていないので今のままだと他マシンと通信できないかもしれないです。

ただDocker image自体にはvscode経由ではなくてもアクセスできるので、PC上のterminalから個別のdocker runして、その時に--net=hostを追加するという回避策は出来そうです。

$ docker images
REPOSITORY                                                TAG                 IMAGE ID            CREATED             SIZE
vsc-ros2_vscode_ws-da058d6a6689661782fb9fdd8ebdc750-uid   latest              8128a9b74c56        3 hours ago         3.69GB
vsc-ros2_vscode_ws-da058d6a6689661782fb9fdd8ebdc750       latest              be56c327cf1d        3 hours ago         3.69GB
osrf/ros                                                  eloquent-desktop    8133230e6f08        3 months ago        2.6GB


余り詳しくないですが触ってみた的な記事なので、もっと良い手段があれば教えてください。

参考情報

ROS2 Docker通信

ROS2 Dashing Docker通信
ROS複数Docker通信

Remote-Containers

VS CodeでDocker開発コンテナを便利に使おう
(公式)Developing inside a Container

Docker関連

正直Docker周りはあまり詳しくなかったので、この辺りをみてDockerfileの内容など調べました。

いまさらだけどDockerに入門したので分かりやすくまとめてみた
Dockerfile のベストプラクティス