更新履歴
2023/01/07:workspace/package/というディレクトリ構造をworkspace/src/packageに変更(公式に合わせた)
2023/01/07:図の改善
ROS2の構造
用語
- ノード:node
- ROS2における機能単位.ROS2では通信を通して他のnodeと情報交換を行い,なんらかの仕事を行う.そのためnodeは通信を伴うpublisher/subscriberやservice/client,parameterになる.通信を伴わないスタンドアロンのものもありだが,それならROS系でない方が実装が簡単.
- ターゲット:target
- 実行単位.ROSではtarget=nodeだったが,ROS2ではtarget≠nodeである.ROS風にも実装できるが推奨されない.nodeをクラス化しtargetで実体化するか,クラス化したnodeを共有ライブラリとしてtargetで使用する.これによりnodeの再利用性を高めるとともにnodeの制御を柔軟に行えるようになる.
- ライブラリ:library
- nodeを共有ライブラリ化したもの.nodeの再利用性を高めるため共有ライブラリにすることが推奨されているが,その手順は少々煩雑である.ちなみにlibraryはROSでのnodeletに相当するらしい.
- パッケージ:package,プロジェクト:project
- 関係の深いターゲット,ライブラリを集めたもの.関係の深いターゲット,ライブラリを集めたもの.ROS2としての呼び名はpackage.ただROS2では様々な言語を使用でき,projectという呼び名を使っているものもあるので併記.ros2のコマンド(ros2 pkg create)で作成する.
- ワークスペース:workspace
- 使用するパッケージを集めたトップディレクトリ.使用状況に応じてパッケージをまとめて実行する単位となる.コンパイル・ビルドはパッケージのディレクトリでなくてもよい.そのため普通はワークスペースにてサブディレクトリとなるパッケージ群を一度に or 選択してコンパイル・ビルドする.ros2のコマンドで作成するのではなく普通にmkdirなどで作成する.
- アンダーレイ:underlayとオーバーレイ:overlay
- ROS2が管理する領域.特に管理する全体の領域をアンダーレイ:underlayと呼び,source /opt/ros/<distro>/setup.bashで設定される.その中にworkspaceやpackageがある. workspaceやpackageなど,切り替えて使用するもの/できるものを,アンダーレイに対してオーバーレイ:overlayと呼ぶ.
イメージ
全体的な階層構造は下記図の通り.一番下のunderlayがros2管理領域全体を表し,source /opt/ros/<distro>/setup.bash
により設定される.source ...
コマンドを実行したターミナル上の環境がoverlayとなっている,というイメージ.
バージョン・distroを切り替えない場合,単一のoverlayとなるので以下のようなイメージとなる.この場合,source ...
コマンドを~/.bashrc
に書いておくと楽(ターミナル起動時にoverlayが設定されるので).
手動でsource ...
コマンドを実行し,ターミナル毎にバージョン・distroを変更する場合,以下のようなイメージとなる.
workspaceは製作物の目的に応じて作成し,コンパイルして実行するときの一塊で,一般に複数のパッケージからなる.
src/
以下にパッケージ群を配置する.workspaceのトップディレクトリでビルドすることで,install/
,build/
,log/
ディレクトリが作成される.. install/setup.bash
を実行することでoverlayを構築・実行している.
workspaceおよびその下部ディレクトリsrc/
は手動で作成する.
ちなみにworkspaceは概念的なものとも捉えられる一方,overlayは. install/setup.bash
を実行することで構築する環境といえる.そのため,packageの中でビルドしてoveralyの環境を構築することも可能.
また以下を設定することでcolcon_cd <パッケージ名>
コマンドで~/<workspace名>/
以下にある<パッケージ名>のパッケージのあるディレクトリに移動できる.
export _colcon_cd_root=~/<workspace名>
これも個々のworkspaceに対して設定するのではなく,「ros2の全てのworkspace,package,プログラムは~/ros2_install/以下に作る.」とするなら,以下のようにして.bashrc
に書き込むと楽.というか,こちらが普通.
echo "export _colcon_cd_root=~/ros2_install" >> ~/.bashrc
全体設定と個別設定について
ROS2では全体設定(underlay)と個別設定(overlay)がある.
全体設定は/opt以下のsetup.bashである(個人設定参照).
個別設定は,ビルドごとの設定である.個別設定により,ビルドごとの独立したROS2実行環境を持てる.個別設定の行い方は以下のとおり.
$ cd ビルドしたディレクトリ
$ . install/setup.bash
. install/setup.bash
はsource install/setup.bash
と同じ.
ドットコマンドと直接スクリプトを実行した時の違いが分かりやすい.
ROS2における実装方法
ROS2での実装スタイルを大別すると以下となる.
- ROS風node
- 従来のROS風の書き方.非推奨だがものによってはROS風になる.
- クラス化したnode
- ROS2風への第一歩.一番はnodeを共有ライブラリとして実装する方法だが,そこに至るまでの入り口となる.
- 共有ライブラリ化したnode
- ROS2で推奨している実装方法.
- コンポーネント化したnode
- 共有ライブラリと近しいが,これ単体で使用できるもの?
- 実行ファイル形式ではない
- ROS2 diff between node and component
ROS風node
ROS風の実装方法だと,main関数の頭から,
- ROS2システムのための初期化
- nodeに関する設定.初期化やnodeの実行に必要な処理などを行う部分.
- nodeを実行.下図ではwhileをつかって「ループして実行してます!」と表現しているけど,ROS/ROS2の通常ではspin()を使う.
- 終了処理.nodeの実行が正しく終わったらちゃんと終了させないとね.
という流れとなる.
クラス化したnode
ROS2ではターゲットとnodeを分離することが推奨されている.これによりnodeの再利用を高めるとともに,一つのターゲットで複数のnodeを使用できるようになる(それにより実行順番など細かな制御も可能になる).
nodeの実行はROS2システムのspin関数により制御されるので,クラスとしてはnodeの準備・設定についてのコードを書くことになる.おそらく標準的なプログラムでは,コンストラクタの中にすべての準備・設定を書くことになる.これによりターゲットの中では,nodeを宣言するのみでよくなり,下記のようなコード一行となる.
rclcpp::spin(std::make_shared<My>());
spin関数とnodeの実行・制御・管理について
共有ライブラリ化したnode
最も推奨されている実装方法は,クラス化したnodeを共有ライブラリとして作成し,他のパッケージからの利用を簡単にするやり方である.
実現の手順は少々煩雑であるが,考え方としては「クラスをライブラリにしようよ」だけ.
nodeの「設定」と「実行」
上記では,nodeを宣言し「設定」を行ってspin関数により「実行」する,と書いた.厳密にはspin関数で「実行」されるまでnodeが動いていないかというと違う.nodeがクラスであればメンバ関数を使えるし,ROSパラメータの設定なども行える.「設定」と「実行」とは以下の通り(2019/7/13書きかけ)
- 設定
- ROSの特徴的な機能を使うための設定を行う.
- 特徴的な機能とは,publisher/subscriber, service/client, parameterなどとなる.
- 特徴的な機能はメッセージやトピックに関するcallback関数により実現されている.
- つまりcallback関数に関する設定が主となる.
- ROSの特徴的な機能を使うための設定を行う.
- 実行
- メッセージやトピックに関する待ち受けを行い,必要に応じてcallback関数を呼び出すことを「実行」と呼んでいる.
- つまりそれ以外のnodeに関する処理は随時実行される.
- spin関数がなくても実行される.