Windows10環境で,ROS2のパッケージ開発をDocker上で行うための手順をまとめます.
頻繁にROSを使わないので直接環境にROSを入れるのは抵抗感があり...... でもROS2を使ってみたい!ということで,ローカルにROS2環境を入れずに開発を行う,dockerでの開発フローを整えてみました.
具体的には,以下のようにして実現します.
- ROS2の開発用のDockerイメージを作成
- 開発用Dockerコンテナに,ホスト(Win)上にあるROS nodeのソースコードをマウント
- vscodeで開発用Dockerコンテナ内のROS nodeのソースコードを編集
- WinにROS環境が入っていなくてもコンテナ内には環境があるので,IntelliSenseなどは有効です
- 開発用Dockerコンテナ内でビルド・動作確認
- 開発したROS nodeの実行に必要最低限の環境が入ったリリース用Dockerイメージの作成
また,一応 rqt, rviz2 のGUIも開発用コンテナで出せるようにしています(あると開発中は便利なので).
GUIありROSのdocker環境の構築については,以下の記事などVNCでやってる人は見つけられたのですが,開発用のエディタまでVNC上で動かすことになるならちょっと微妙だなぁと...
ROSではない開発と同様に,ホスト上で動くvscodeを使ったリモート開発でやりたかった,というモチベーションがありました.
前提
WSL2, Docker, vscode での一般的な開発環境の準備,具体的には以下の2点がなされている状態を前提とします.
- WSL2/DockerのインストールとWSL2上でDockerが使える
- vscodeのインストールとWSL上での開発ができる
両方とも以下に詳しい説明がありますし,ググればいろいろ情報は出ると思います.
また,DockerやROS2の基本的な使い方の説明は省きます(このへんある程度わかっている人でないと,ROS2をdockerで動かしたいという人はいないと思うので...)
本エントリで使用しているソースはこちらにあります.適宜記事内でも参照してます.
開発用ディレクトリの作成
とりあえず普通にROS2パッケージを作成するときのように,<ワークスペース名>/src
のディレクトリをWSL上に作ります(ここではワークスペース名をws
とします).
また,ワークスペース以下にdocker
ディレクトリも作っておきます.
ws ├── docker └── src
ROS2開発用Dockerイメージの準備
ROS2実行用イメージを用意し,そこに開発に必要なパッケージを加えて開発用イメージを作ります.
ROS2実行用イメージの用意
ちょっと何故かはよくわからないですが,DockerHubにはROSの公式っぽいレジストリが2つあります.
両方とも,Dockerfileは同じレポジトリのものを使ってるみたいですが,前者にはcoreとbaseがあり,後者はdesktop版しかありません.
まぁとは言え2つのレジストリなんて気にせずにdocker pull
で入れられます.今回は,GUI(rqt, rviz2)も使うのでdesctop版を入れます.
$ docker pull osrf/ros:foxy-desktop
ROS2パッケージ開発用イメージの作成
osrf/ros:foxy-desktopをベースに,開発に必要なものを入れた開発用イメージを作成していきます.
Dockerfile等の細かい説明はここではしません.とりあえず,すでにあるものを使って進めますので,ここにある各ファイル(Dockerfile.dev
,Dockerfile.rel
,build_image.sh
,entrypoint.sh
,run_dev-container.sh
)をros2-study/docker
以下に配置してください.
※ .env
ファイルのDOCKER_IMG
変数が,これから作成するDockerイメージの名前になるので適宜変更してください
ここでws/docker/build_image.sh
を実行すると,$DOCKER_IMG:dev_<ワークスペース名>
という名前で開発用イメージを作成してくれます(本エントリの例だと,mu777/ros:dev_ws
という名前になります)
$ cd ws $ bash docker/build_image.sh
Dockerfile.dev
では,osrf/ros:foxy-desktopをベースに開発に必要なライブラリをインストールしています.未検証ですが,sudo
,gosu
,build-essential
,libpython3-dev
,python3-pip
,python3-colcon-common-extensions
,python3-rosdep
があれば最低限OKかなと思います.
が,他にも必要そうなものは適当に入れています.bash-completion
があると,補完が効いて便利なので入れています.
ちょっとROSのテストまわりはわかっていないので本記事には入れてません.テストに必要なパッケージ等も別途入れる必要があるかもしれません.適宜必要なものを入れるよう,修正ください.
ROS2開発用コンテナ上での開発
上までの手順で作成した開発用イメージのコンテナ上で,ROS2パッケージの開発を行います.
開発用コンテナの起動
何はともあれ,開発用コンテナを起動させましょう~
docker run
実行時に開発のためのもろもろの設定が必要なため,起動処理をスクリプト(run_dev-container.sh
)にまとめております.それを実行してみてください.
<ワークスペース名>_dev
という名前のコンテナが起動すればOKです!
$ cd ws $ bash docker/run_dev-container.sh $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0e9c19de69d5 mu777/ros2:dev_ws "/entrypoint.sh /bin…" 14 seconds ago Up 12 seconds ws-dev
run_dev-container.sh
では,主にユーザ周りの設定やGUIを使う設定などを行っています.
ユーザ周りの設定に関しては,以下の記事を大変参考にさせていただきました🙏
vscodeでの開発設定
ほぼまんま以下の記事の内容を使っています(ありがたい...🙏🙏)
ワークスペース以下に.vscodeフォルダを作成し,そこに上記事内のc_cpp_properties.json
, settings.json
, tasks.json
を作成します..gitignore
も記事通り設定します.
この時点のディレクトリ構成は,以下のようになっているはずです.
ws ├── .gitignore ├── .vscode │ ├── c_cpp_properties.json │ ├── settings.json │ └── tasks.json ├── docker │ ├── .env │ ├── Dockerfile.dev │ ├── Dockerfile.rel │ ├── build_image.sh │ ├── entrypoint.sh │ └── run_dev-container.sh └── src
tasks.json
だけ,rosdepを毎回実施するために以下のように書き換えました.
{ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { "label": "ROS Build Setup", "type": "shell", "command": "source /opt/ros/$ROS_DISTRO/setup.bash; rosdep update; rosdep install -i --from-path ${workspaceRoot}/src --rosdistro $ROS_DISTRO -y;", "options": { "cwd": "${workspaceRoot}" } }, { "label": "ROS Build", "type": "shell", "command": "colcon build", "options": { "cwd": "${workspaceRoot}" } }, { "label": "Build", "group": { "kind": "build", "isDefault": true }, "dependsOrder": "sequence", "dependsOn": [ "ROS Build Setup", "ROS Build" ], "problemMatcher": [] } ] }
開発用コンテナに接続されたvscodeを開く
やっとvscodeの出番が来ました!
Windowsで普通にvscodeを起動させ,vscodeのリモートエクスプローラから「Containers」を選ぶと,起動中の開発用コンテナ(ws-dev)がリストに出ていると思うので,それにAttachしてください.
vscodeのウインドウが開くと思うので,「Open Folder」からワークスペースのパスを選択し,開いてください(ワークスペースはrun_dev-container.sh
でマウントされています)
これで,このvscode上で普通に開発ができます!!
コンテナ上でのROSパッケージの開発とビルド
普通にコンテナ上でいつものようにROSパッケージを開発すればよいだけなのですが,動作確認も兼ねて,以下のチュートリアルを普通にやってみます
vscodeのターミナルがコンテナ内になっているので,そこでコマンドを実行していきます(普通にターミナルからdocker execで開発用コンテナ内に入ってコマンド実行しても大丈夫です)
まずは,ros2 pkg create
でパッケージを作成して,
$ cd ws/src $ ros2 pkg create --build-type ament_cmake cpp_pubsub
チュートリアルに書いているwgetコマンドで,ソースをダウンロードします.
$ cd ws/src/cpp_pubsub/src/ $ wget -O publisher_member_function.cpp https://raw.githubusercontent.com/ros2/examples/foxy/rclcpp/topics/minimal_publisher/member_function.cpp $ wget -O subscriber_member_function.cpp https://raw.githubusercontent.com/ros2/examples/foxy/rclcpp/topics/minimal_subscriber/member_function.cpp
package.xml
へ依存パッケージを記載して,
+ <depend>rclcpp</depend> + <depend>std_msgs</depend>
CMakeLists.txt
を編集します.
+ find_package(rclcpp REQUIRED) + find_package(std_msgs REQUIRED) + add_executable(talker src/publisher_member_function.cpp) + ament_target_dependencies(talker rclcpp std_msgs) + add_executable(listener src/subscriber_member_function.cpp) + ament_target_dependencies(listener rclcpp std_msgs) + install(TARGETS + talker + listener + DESTINATION lib/${PROJECT_NAME})
チュートリアルに従ってビルドコマンドを実行してみると,ビルドできました🎉🎉
$ rosdep install -i --from-path src --rosdistro foxy -y $ colcon build --packages-select cpp_pubsub
ビルドコマンドはtasks.json
に設定済みなので,vscodeからもビルドを実行できます.
ターミナルを2つ出して,talkerとlisternerをそれぞれ実行すると,ちゃんと実行されていることがわかります!👏
$ source install/setup.bash $ ros2 run cpp_pubsub talker
$ source install/setup.bash $ ros2 run cpp_pubsub listener
GUI(rqt, rviz2)の使用
本エントリで採用した方法は,Windowsホスト側にXサーバを立てる方式です.
諸事情により自分の環境がまだWindows10なので採用できませんでしたが,Windows11ではWSLでGUIアプリを動かす方法としてWSLgというものがあります.今後はそちらのほうがよいかもしれません.
以下で簡単に,GUI(rqt, rviz2)をXで使う方法をまとめます.
まず,Windows側でXサーバを立てます.よくあるのはVcXsrvとかXmingでしょうか. 自分の環境ではもともと使っていたMobaXtermに入っているXサーバを使っています.
設定は以下のような感じです.
クライアント側(コンテナ側)では,DISPLAY変数を設定しておきます.
と言っても,run_dev-container.sh
で以下のように設定済みのはずです.
HOST_IP=`ipconfig.exe | grep IPv4 | grep -v 172 | cut -d: -f2 | awk '{ print $1}' | sed 's/\r//g'` DISPLAY=${HOST_IP}:0.0
ので,コンテナ内で確認してみてください.
$ echo $DISPLAY 192.168.0.6:0.0
IPアドレスの部分はWindows側のものを指定する必要があります.
もし設定がうまくできていなければ,コマンドプロンプトでipconfig
コマンドを実行するなどしてIPアドレスを調べ,コンテナ内のDISPLAY
変数を設定してください
※ このコンテナを実行しっぱなしでwifiをつなぎ直したりすると,コンテナ内のDISPLAY
変数はそのままだけど,IPアドレスが変わってしまって,Xサーバと接続できなくなることがあります その場合もDISPLAY
変数を再設定してください
この状態でコンテナ内でrqt, rviz2を実行すると,ホストのWindows側にrqt, rviz2が起動します.
リリース用Dockerイメージの作成と実行
ROS2パッケージ開発を進めていくと,リリース用の必要最低限の環境が入ったdockerイメージを作成したくなってくると思います.
以下では簡単にその方法をまとめます.
リリース用イメージの作成
ROSのDockerHubのページの「Creating a Dockerfile to build ROS packages」を参考にリリース用イメージを作っていきます.
が,これもスクリプト化しているので,WSL上でdocker/build_image.sh
をrel
という引数で実行すれば作ってくれます.
$ cd ws $ bash docker/build_image.sh rel
$DOCKER_IMG:rel_<ワークスペース名>
という名前でイメージができたらOKです(本エントリの例だと,mu777/ros2:rel_ws
という名前になります)
以下に少し少し細かい話を書いておきます.
Dockerのコンテキストですが,リリース用イメージは開発対象のパッケージを含むため,ワークスペース全体としています.一方,開発用イメージは,開発対象のパッケージには依存しないので,コンテキストはdockerフォルダだけにするようにしています.
vcs周りは正直使い方がよくわかっていないので,rosinstallとかには対応できていません.これだけだと依存関係がうまく構築できないかもです(だれか教えて欲しい..)
リリース用イメージの実行
リリース用イメージが作成できたら実行するだけです.
WSLのターミナルを2つ開いて片方でtalker,もう片方でlistenerを実行します
$ docker run --rm -it mu777/ros2:rel_ws ros2 run cpp_pubsub talker
$ docker run --rm -it mu777/ros2:rel_ws ros2 run cpp_pubsub listener
すると,期待通り実行され,ノード間で通信できていることがわかります!🎉🎉
おわりに
ちょっとROS2がまだよくわかってないですが,ROS1を使っていたけどしばらく離れていた自分には,roscoreも実行せずに勝手に各ノードがpub/subできてるのは感動的ですね~
いろいろ遊べるとよいなと思います💪💪