ROS2に関する基本情報

[ROS2関係トップページへ](https://qiita.com/NeK/items/7ac0f4ec10d51dbca084)

# 更新履歴
2023/01/07:workspace/package/というディレクトリ構造をworkspace/src/packageに変更(公式に合わせた)
2023/01/07:図の改善


# ROS2の構造
## 用語

<dl>
<dt>ノード:node</dt>
<dd>ROS2における機能単位．ROS2では通信を通して他のnodeと情報交換を行い，なんらかの仕事を行う．そのためnodeは通信を伴うpublisher/subscriberやservice/client，parameterになる．通信を伴わないスタンドアロンのものもありだが，それならROS系でない方が実装が簡単．</dd>
<dt>ターゲット:target</dt>
<dd>実行単位．ROSではtarget=nodeだったが，ROS2ではtarget≠nodeである．ROS風にも実装できるが推奨されない．nodeをクラス化しtargetで実体化するか，クラス化したnodeを共有ライブラリとしてtargetで使用する．これによりnodeの再利用性を高めるとともにnodeの制御を柔軟に行えるようになる．</dd>
<dt>ライブラリ:library</dt>
<dd>nodeを共有ライブラリ化したもの．nodeの再利用性を高めるため共有ライブラリにすることが推奨されているが，その手順は少々煩雑である．ちなみにlibraryはROSでのnodeletに相当するらしい．</dd>
<dt>パッケージ:package，プロジェクト:project</dt>
<dd>関係の深いターゲット，ライブラリを集めたもの．関係の深いターゲット，ライブラリを集めたもの．ROS2としての呼び名はpackage．ただROS2では様々な言語を使用でき，projectという呼び名を使っているものもあるので併記．ros2のコマンド(ros2 pkg create)で作成する．</dd>
<dt>ワークスペース:workspace</dt>
<dd>使用するパッケージを集めたトップディレクトリ．使用状況に応じてパッケージをまとめて実行する単位となる．コンパイル・ビルドはパッケージのディレクトリでなくてもよい．そのため普通はワークスペースにてサブディレクトリとなるパッケージ群を一度に or 選択してコンパイル・ビルドする．ros2のコマンドで作成するのではなく普通にmkdirなどで作成する．</dd>
<dt>アンダーレイ:underlayとオーバーレイ:overlay</dt>
<dd>ROS2が管理する領域．特に管理する全体の領域を<font color="Red">アンダーレイ:underlay</font>と呼び，source /opt/ros/&lt;distro&gt;/setup.bashで設定される．その中にworkspaceやpackageがある．
workspaceやpackageなど，切り替えて使用するもの/できるものを，アンダーレイに対して<font color="red">オーバーレイ:overlay</font>と呼ぶ．
</dd>
</dl>

### イメージ
全体的な階層構造は下記図の通り．一番下のunderlayがros2管理領域全体を表し，`source /opt/ros/<distro>/setup.bash`により設定される．`source ...`コマンドを実行したターミナル上の環境がoverlayとなっている，というイメージ．

![overlay_underlay.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284261/2fcae89a-85a8-608c-14e5-6eb3f5807610.png)

バージョン・distroを切り替えない場合，単一のoverlayとなるので以下のようなイメージとなる．この場合，`source ...`コマンドを`~/.bashrc`に書いておくと楽(ターミナル起動時にoverlayが設定されるので)．

![underlay.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284261/05139b34-1f4d-4f8d-e29d-bde4c2d42917.png)

手動で`source ...`コマンドを実行し，ターミナル毎にバージョン・distroを変更する場合，以下のようなイメージとなる．

![change_distro.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284261/b7ea020a-6c85-bbc9-9740-8fa29d10f4bd.png)

workspaceは製作物の目的に応じて作成し，コンパイルして実行するときの一塊で，一般に複数のパッケージからなる．
`src/`以下にパッケージ群を配置する．workspaceのトップディレクトリでビルドすることで，`install/`,`build/`,`log/`ディレクトリが作成される．`. install/setup.bash`を実行することでoverlayを構築・実行している．
workspaceおよびその下部ディレクトリ`src/`は手動で作成する．

![workspaces.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284261/541af6c1-1f92-7ec5-84be-02bd0226e4dc.png)

ちなみにworkspaceは概念的なものとも捉えられる一方，overlayは`. install/setup.bash`を実行することで構築する環境といえる．そのため，packageの中でビルドしてoveralyの環境を構築することも可能．

![overlay_for_pacakge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284261/d51dd974-7686-c680-cbe6-37d030142963.png)

また以下を設定することで`colcon_cd <パッケージ名>`コマンドで`~/<workspace名>/`以下にある<パッケージ名>のパッケージのあるディレクトリに移動できる．

```shell
export _colcon_cd_root=~/<workspace名>
```

これも個々のworkspaceに対して設定するのではなく，「ros2の全てのworkspace，package，プログラムは~/ros2_install/以下に作る．」とするなら，以下のようにして`.bashrc`に書き込むと楽．というか，こちらが普通．

```shell
echo "export _colcon_cd_root=~/ros2_install" >> ~/.bashrc
```



## 全体設定と個別設定について
ROS2では全体設定(underlay)と個別設定(overlay)がある．
全体設定は/opt以下のsetup.bashである([個人設定](https://qiita.com/NeK/items/64196305ba9dc90c26e4)参照)．
個別設定は，ビルドごとの設定である．個別設定により，ビルドごとの独立したROS2実行環境を持てる．個別設定の行い方は以下のとおり．

```Bash:terminal
$ cd ビルドしたディレクトリ
$ . install/setup.bash
```

`. install/setup.bash`は`source install/setup.bash`と同じ．
[ドットコマンドと直接スクリプトを実行した時の違い](http://d.hatena.ne.jp/moroto1122/20110517/1305595513)が分かりやすい．

# ROS2における実装方法
ROS2での実装スタイルを大別すると以下となる．

- ROS風node
    - 従来のROS風の書き方．非推奨だがものによってはROS風になる．
- クラス化したnode
    - ROS2風への第一歩．一番はnodeを共有ライブラリとして実装する方法だが，そこに至るまでの入り口となる．
- 共有ライブラリ化したnode
    - ROS2で推奨している実装方法．
- コンポーネント化したnode
    - 共有ライブラリと近しいが，これ単体で使用できるもの？
    - 実行ファイル形式ではない
    - [ROS2 diff between node and component](https://answers.ros.org/question/313001/ros2-diff-between-node-and-component/)

## ROS風node
ROS風の実装方法だと，main関数の頭から，

1. ROS2システムのための初期化
1. nodeに関する設定．初期化やnodeの実行に必要な処理などを行う部分．
1. nodeを実行．下図ではwhileをつかって「ループして実行してます！」と表現しているけど，ROS/ROS2の通常ではspin()を使う．
1. 終了処理．nodeの実行が正しく終わったらちゃんと終了させないとね．

という流れとなる．

![ROS風PG.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284261/360ce933-edff-701e-38bd-4e73a69b967a.png)


## クラス化したnode
ROS2ではターゲットとnodeを分離することが推奨されている．これによりnodeの再利用を高めるとともに，一つのターゲットで複数のnodeを使用できるようになる(それにより実行順番など細かな制御も可能になる)．
nodeの実行はROS2システムのspin関数により制御されるので，クラスとしてはnodeの準備・設定についてのコードを書くことになる．おそらく標準的なプログラムでは，コンストラクタの中にすべての準備・設定を書くことになる．これによりターゲットの中では，nodeを宣言するのみでよくなり，下記のようなコード一行となる．

```C++:node(クラス名"My")の実行に関する部分の例
rclcpp::spin(std::make_shared<My>());
```

<details>
<summary>spin関数とnodeの実行・制御・管理について</summary><div>nodeには様々な機能があるが，主にはcallback関数の形で実現されており，これにより定期的な処理やイベントに対する処理が行われる．そのためプログラムの基本な流れは，callback関数を使用するための準備・設定を行い，ROSシステムによってcallback関数の実行・制御管理が行われる．spin関数はnodeの様々なcallback関数を実行・制御・管理するもので，基本的にはctrl-cなどで終了されるまで実行・制御・管理を行い続ける．[rclcppのAPI](http://docs.ros2.org/crystal/api/rclcpp/index.html)にあるとおり，spin関数は3種類あり状況に応じて使用する．普通はspinで大丈夫．その他のexecutorsは，多数のnodeを個別に実行・制御・管理したり非同期処理のための便利道具を提供するときに使うものだと思われる．要調査．</div>
</details>


![ROS2クラス化PG.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284261/eafb4a29-3ac0-d54a-f06e-e85121e5a7aa.png)

## 共有ライブラリ化したnode
最も推奨されている実装方法は，クラス化したnodeを共有ライブラリとして作成し，他のパッケージからの利用を簡単にするやり方である．
実現の手順は少々煩雑であるが，考え方としては「クラスをライブラリにしようよ」だけ．

![ROS2ライブラリ化PG.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284261/e0f4cca6-140e-f741-e2d2-771193dd6ce2.png)

## nodeの「設定」と「実行」
上記では，nodeを宣言し「設定」を行ってspin関数により「実行」する，と書いた．厳密にはspin関数で「実行」されるまでnodeが動いていないかというと違う．nodeがクラスであればメンバ関数を使えるし，ROSパラメータの設定なども行える．「設定」と「実行」とは以下の通り(2019/7/13書きかけ)

- 設定
    - ROSの特徴的な機能を使うための設定を行う．
        - 特徴的な機能とは，publisher/subscriber, service/client, parameterなどとなる．
        - 特徴的な機能はメッセージやトピックに関する<font color=red>callback関数</font>により実現されている．
            - つまり<font color=red>callback関数</font>に関する設定が主となる．
- 実行
    - メッセージやトピックに関する待ち受けを行い，必要に応じて<font color="red">callback関数</font>を呼び出すことを「実行」と呼んでいる．
    - つまりそれ以外のnodeに関する処理は随時実行される．
        - spin関数がなくても実行される．