ROS2の最小構成publisher:初級 -ROS1 style-

【[ROS2関係トップページへ](https://qiita.com/NeK/items/7ac0f4ec10d51dbca084)】
【[ROS2レクチャー:初級 -ROS1 style-](https://qiita.com/NeK/items/74e4bb9d1530e22a63fc)】

【前:[ROS2における時間管理・Rate系とTimer系]】
【次:[ROS2独自メッセージの作成]】

[ROS2における時間管理・Rate系とTimer系]:https://qiita.com/NeK/items/bcf518f6dd79f970bb8e
[ROS2独自メッセージの作成]:https://qiita.com/NeK/items/26751b8ed12976ff977d

publisherプログラムを作成する．
メッセージ受信者は[ここで作成](https://qiita.com/NeK/items/2e4e1f78e76594891fc7)したsubscriberプログラムを使用する．

# 更新:2020/07/15
Foxy Fitzroy用に更新．主に以下の点について加筆・修正．

* std_msgsの廃止に伴うexample_interfacesの利用
* create_subscriptionの引数の変更への対応

# 準備

```Bash:terminal
$ cd ~/ros2_studies_ws/
$ ros2 pkg create minimal_publisher_ros1_like --dependencies rclcpp example_interfaces
```

# ROS風publisher
作成物:

- src/ros1_like_main.cpp

## プログラム

```c++:src/ros1_like_main.cpp
#include <rclcpp/rclcpp.hpp>
#include <rclcpp/qos.hpp>
#include <example_interfaces/msg/string.hpp>
#include <chrono>

int main(int argc, char * argv[]){
  using namespace std::chrono_literals;

  rclcpp::init(argc, argv);

  auto node = rclcpp::Node::make_shared("minimal_publisher");
  auto publisher = node->create_publisher<example_interfaces::msg::String>("topic_test",rclcpp::QoS(10));
  auto message = std::make_shared<example_interfaces::msg::String>();
  auto pub_counter=0;

  rclcpp::WallRate loop_rate(1s);

  while(rclcpp::ok()){
    message->data = "hello " + std::to_string(pub_counter++);
    RCLCPP_INFO(node->get_logger(),"Pub:%s",message->data.c_str());
    publisher->publish(*message);
    loop_rate.sleep();
  }
  rclcpp::shutdown();
  return 0;
}
```

### 概要
publisherはメッセージ発信者である．代表的な使用シーンは「定期的にセンサ値を取得して処理をする他のnodeに発信」などである．そのため，例としてRate系を使用した定期的なメッセージ発信を行う．ここでは単なる文字列の発信を行っている．Timer系でも同様の実装は可．
spin系関数を用いていないが，publish関数は即時メッセージを発信するもので，callback関数によって実行されるものではない．よってspin系関数は不必要．詳しくは[こちら](https://qiita.com/NeK/items/18ff9e9c443295d5d805#node%E3%81%AE%E8%A8%AD%E5%AE%9A%E3%81%A8%E5%AE%9F%E8%A1%8C)

### 説明

11,12行目でnodeを作成し，そのnodeがpublisherとして動くように設定．メッセージを発信先の識別名・トピック名を12行目の引数で指定(topic_test)．第二引数はメッセージキューの数．何個までメッセージ数を保持しておくか．
13,14行目で発信するメッセージの変数を宣言．メッセージはROSのStringクラスなので，make_sharedでsharedポインタとして実体化している．

今回はTimer系ではなくRate系を使用していてsleep関数で制御しているため，18行目から始まるwhileで定期的にメッセージ発信を行っている．ただ，ROS2のコーディングとしては非推奨(定期実行をROSではなくC++が制御しているので)．

19行目で発信するメッセージに値を代入しており，21行目で発信している．

細かい話として19行目のstd::to_string関数がある．message->dataはString型で，+演算子で文字列の結合をしようとしている．ここでpub_counterは整数値なので文字列に変換するためにstd::to_string関数を使っている．

# package.xmlとCMakeLists
以下は重要な部分のみを抜粋．

## package.xml

```xml:package.xml
<package format="3">
  <depend>rclcpp</depend>
  <depend>example_interfaces</depend>
```

## CMakeLists.txt

```CmakeLists.txt
find_package(rclcpp REQUIRED)
find_package(example_interfaces REQUIRED)

add_executable(ros1_like_publisher_test
  src/ros1_like_main.cpp
)
ament_target_dependencies(ros1_like_publisher_test
  rclcpp
  example_interfaces
)

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

```

# ビルド・実行
publisherはここで作成したもの，subscriberは[ここで作成](https://qiita.com/NeK/items/2e4e1f78e76594891fc7)したものを使用．

## ビルド

```Bash:terminal
$ cd ~/ros2_studies_ws/
$ colcon build --symlink-install --packages-up-to minimal_publisher_ros1_like
$ . install/local_setup.bash
```

## 実行
publisher用のterminalとsubscriber用のterminalを起動．

```Bash:terminal1
$ cd ~/ros2_studies_ws/
$ . install/local_setup.bash
$ ros2 run minimal_publisher_ros1_like ros1_like_publisher_test
```

```Bash:terminal1
$ cd ~/ros2_studies_ws/
$ . install/local_setup.bash
$ ros2 run minimal_subscriber_ros1_like callback_subscriber_test
```

<details>
<summary>バグ?(2019/4/23現在:dashing)</summary>ros1_like_publisherを実行するとわかるが，最初の一回目のメッセージ発信(publish)が行われない．仕様？バグ？
</details>

【前:[ROS2における時間管理・Rate系とTimer系]】
【次:[ROS2独自メッセージの作成]】