C++でROS2のプログラミングをしよう

## はじめに
　初めて記事を書きます。オガネソンです。ただいま情報通信工学科のB3です。C++をプログラミングしたいけど、何を目標にしていいか分からないそこのあなた！ROS2のプログラミングを通してC++を練習しましょう！
　想定されるレベルは次の通りです。

- C++は入門書である程度んだけど特に作りたいものも無いという方
- ROS2をC++でプログラミングしてみたい方

また、使用するPCは以下の水準以上のものをおすすめします。
| 使用OS | Ubuntu 22.04 LTS |
|:-----------|------------:|
| ROS distribution  | ROS2 humble   |
|CPU性能|11th Gen Intel® Core™ i7-1165G7|
## ROS2とは？
ROS2を説明するにはここのページは余白が狭すぎる...と言いたいところですが、簡単にROS2について説明したいと思います。

ROS2とは、ROS(Robot Operating System)の進化版である、ロボット開発に必要なライブラリ群、ツール群、通信規格などを含んだオープンソースミドルウェアです。ROSには経路計画や地図生成のアプリケーションが用意されていて、ロボット開発にはなくてはならない存在です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3573929/17fcb2d4-faf5-ab06-9f7f-ec36d376172a.png)
出典：(https://www.fsi.co.jp/ros/)

そのROSには問題点が多くあり、例えば、ROSは主に研究開発用に作られており、一般に使用されることは難しいところがありました。また、ROSを使用できるプラットホームがUbuntuのみで、一般的に売られているパソコンにはWindows OSか、Mac OSが搭載されているので、OSを複数入れなければならず、参入する障壁が高いです。

しかし、ROS2では、そのようなROSの不便な点が数多く解消されているので、一般の人や企業でも導入しやすくなりました。対応OSもWisndowsやMacにも対応しましたし、通信方式や基盤になっているシステムが大幅に変わりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3573929/e213ba06-45e8-6f47-2ccf-71dda0312616.png)
出典：(https://www.slideshare.net/takasehideki/fpgaros-240272923)

このように使いやすくなったROS2を使ってロボットのプログラミングをやってみようという訳ですが、ROS2のセットアップは最初はかなり大変です。
## Ubuntuをインストール
今まで散々Ubuntu以外でも使えるよと言ってきたのになんでと思われるかもしれませんが、Ubuntu OSでセットアップするのがプログラミングをする上で一番簡単に終わるのです。インストールには[こちら](https://eng-entrance.com/ubuntu-install)のサイトが分かりやすいです。

:::note warn
ROS2 humbleを当記事では扱うので、それに合うバージョンは**Ubuntu 22.04 LTS**となっています。20.04以前のUbuntuではROS2 humbleはインストールできないのでご注意ください。
:::

## ROS2をインストール
UbuntuをインストールしたらいよいよROS2のインストールです。ディストリビューション（バージョン）はhumbleが2027年までサポートしているので、おすすめです。サイトは[こちら](https://qiita.com/NeK/items/4ce04a2aa2b5eae3488b)がとても分かりやすいです。

https://qiita.com/NeK/items/4ce04a2aa2b5eae3488b

以下のコマンドを１行ずつコピーしてターミナルで実行しましょう。
```bash:ターミナル
$ sudo apt update && sudo apt install curl software-properties-common python3-rosdep
$ sudo add-apt-repository universe
$ sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
$ sudo apt update && sudo apt upgrade -y
$ sudo apt install ros-humble-desktop
$ echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
$ source ~/.bashrc
$ sudo rosdep init && rosdep update
```
以上を実行したらROS2 humbleがインストールされます。インストールされたか確認するには、ターミナルを開いて
```bash
$ ros2 run demo_nodes_cpp talker
```
もうひとつ新たなターミナルを開き、そこに以下のコマンドを実行します。
```bash
$ ros2 run demo_nodes_py listener
```
お互いに通信ができていればインストールは完了となります。
## C++の基礎知識
いよいよプログラミングに入ります。ROS2のプログラミングをするのに最低限必要なC++の知識を上げておきます。

:::note info
- 基本的なプログラミング（条件分岐、繰り返し、変数の型など）
- オブジェクト指向（クラス、インスタンス、コンストラクタetc...）
- ポインター（アロー演算子とドット演算子の使い分け、スマートポインタなど）
:::
これらの知識が身についていればすぐにでもROS2のプログラミングを始めましょう！

:::note warn
上に挙げたC++の例が十分身についていなくても、ポインターとクラスの継承の仕方、コンストラクタの意味などが分かっていれば十分です。
:::
## ROS2のパッケージを作る
ROS2のプログラミングを始める前に、プログラムを保管しておくフォルダを作って置かなければなりません。そのフォルダをROSの用語では<font color="Red">パッケージ</font>といいます。パッケージは用途に合わせて幾つも作ることができ、そのパッケージをまとめるフォルダを<font color="Red">ワークスペース</font>といいます。これからそのパッケージとワークスペースを一緒に作りましょう。

### 1.ワークスペースを作る
ここではワークスペース名は`colcon_ws`とします。srcディレクトリを作っておくと自動でパッケージを作ってくれるので、以下のようにコマンドを実行します。
```bash
$ mkdir -p ~/colcon_ws/src
```
### 2.パッケージを作る
パッケージはsrcディレクトリで作ります。ここではC++で開発をしたいので、ビルドシステムを`ament_cmake`にします。以下のようにしてください。
```bash
$ cd ~/colcon_ws/src
$ ros2 pkg create --build-type ament-cmake <パッケージ名>
```
### 3.パッケージのビルド
ビルドシステムは`ament_cmake`ですが、ROS2でのパッケージのビルド方法は`colcon build`です。
```bash
$ cd ~/colcon_ws && colcon build
```
:::note warn
後ほどC++のプログラムのビルドを行いますが、そちらとは意味合いが異なり、パッケージのビルドになります。まあ深いことは気にしないで大丈夫です。
:::
以下のようになれば成功です。
![colcon buildの成功](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3573929/94e79a17-e4dd-5d35-02b6-66780578be6a.png)
出典：(https://zenn.dev/uchidaryo/articles/ros2-programming-2)

## ROS2のプログラム
ここからはようやくROS2のプログラムを書いていきます。基本的なプログラムしか記事の都合上ご紹介することができませんが、そちらは今後の記事をお待ちください。

**Happy world！とターミナル上に表示させるプログラム**

これからソースコードを書いていくわけですが、書けるようになるためにはソースコードの流れ（フロー）をしっかり理解した上で**自分で**手を動かして書くことが大事です。
```cpp:happy_node.cpp
#include"rclcpp/rclcpp.hpp"

////happy worldと画面に表示するノード
class HappyNode : public rclcpp::Node{ //rclcppからNodeクラスを継承
    public :
        HappyNode() : Node("happy_node"){ //スーパークラスのNodeコンストラクタ呼び出し。ノードの定義をする。
            RCLCPP_INFO(this->get_logger(),"Happy world!"); //ターミナルに表示したい文字を出力できる
        }
};

int main(int argc, char **argv){
    rclcpp::init(argc,argv); ////ROS2通信を初期化
    auto node = std::make_shared<HappyNode>(); //ノードを生成
    rclcpp::shutdown(); //ROS２通信をシャットダウン
    return 0;
}
```
長ったらしいプログラムに見えますが、構造は単純です。クラスでROSのノードを定義して、メイン関数内で実行しているだけです。
このプログラムのポイントを一つずつ解説していきます。

1行目　**インポート**　ROS2ではrclという基礎部分の上にC++やpythonでコーディングするのでrclcppをインポートしてきます。

4行目　**クラスを作成**　先程インポートしてきたrclcppライブラリからNodeクラスを継承しています。

5行目　**ノードを定義**　クラスのコンストラクタを呼び出してインスタンス化された時にノードが定義されるようになっています。

6行目 **ログを表示** 　`RCLCPP_INFO()`メソッドでログとして文章を表示することができます。引数の方で`get_logger()`メソッドを置いておく必要があります。

11行目〜 **メイン文で、プログラムがここから順に実行される。**

12行目　**ROS2の通信を初期化**

13行目　**クラスをインスタンス化してノードを生成**　先程の5行目のコンストラクタが呼び出されることでノードが定義されます。

14行目 **ROS2通信をシャットダウン**

このような流れでROS2のプログラムを書きます。

:::note warn
**演習１** このソースコードの流れを理解したら、なるべく何も見ないでもう一度同じようなプログラムを作ってみてください。
:::
## プログラムを実行する
C++で書いたプログラムは事前にコンパイル（機械語に翻訳）しておかなければなりません。コンパイルするにはCMakelists.txtをちょっと書かなくてはいけません。
### CMakelists.txt
コンパイルするときの手順書のようなものです。以下のように書きます。
```bash
cmake_minimum_required(VERSION 3.8)
project(ros_practice)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(happy_node src/happy_node.cpp)
ament_target_dependencies(happy_node rclcpp)

install(TARGETS
  happy_node
DESTINATION lib/${PROJECT_NAME})

ament_package()
```
実際はパッケージを作る時に大半は出来上がっていて、新しく書くべきは
```bash
add_executable(happy_node src/happy_node.cpp)
ament_target_dependencies(happy_node rclcpp)
```
これと`install(TARGETS`の下に`happy_node`を
```bash
install(TARGETS
  happy_node
DESTINATION lib/${PROJECT_NAME})
```
と書きましょう。

書いたら保存してターミナルに戻って
```bash
$ cd ~/colcon_ws && colcon build --symlink-install
```
と打ち込みましょう。`--symlink-install`は便利なオプションらしいです。成功したら
```bash
$ ros2 run ros_practice happy_node
```
を実行すれば、
```bash
[INFO] [1698247301.829961920] [happy_node]: hello world!
```
と表示されるはずです。
## さいごに
お疲れ様でした！

これでROS2のノードをC++で書くことができました。次はパブリッシャーとサブスクライバーを書いてみましょう。

## 参考文献
[出村公成,ROS2とpythonで作って学ぶAIロボット入門,講談社,2022](https://www.amazon.co.jp/ROS2%E3%81%A8Python%E3%81%A7%E4%BD%9C%E3%81%A3%E3%81%A6%E5%AD%A6%E3%81%B6AI%E3%83%AD%E3%83%9C%E3%83%83%E3%83%88%E5%85%A5%E9%96%80-KS%E7%90%86%E5%B7%A5%E5%AD%A6%E5%B0%82%E9%96%80%E6%9B%B8-%E5%87%BA%E6%9D%91-%E5%85%AC%E6%88%90/dp/4065289564/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=3I66L40WVHAWG&keywords=ROS2&qid=1698287450&sprefix=ros2%2Caps%2C1066&sr=8-2)