ROS講座09 ROSメッセージ(とarray型の使い方)

# 環境
この記事は以下の環境で動いています。

| 項目 | 値 |
|:-:|:-:|
| CPU | Core i5-8250U |
| Ubuntu | 16.04 |
| ROS | Kinetic |

インストールについては[ROS講座02 インストール](https://qiita.com/srs/items/e0e0a9dc3f94c2d3348e)を参照してください。
またこの記事のプログラムはgithubにアップロードされています。[ROS講座11 gitリポジトリ](https://qiita.com/srs/items/25a56a6abda41dcf396e)を参照してください。

# 概要
ROSのpub sub通信ではROSで定義されている型で通信を行います。Float32やInt32などの基本的な型が標準で組み込まれています。これらの使い方について説明します。

# 基本的な使い方
「ROS講座03 Pub & Sub」で説明した例を見てみましょう。

```C++:baic_lecture/basic_simple_talker.cpp（再掲）
#include <ros/ros.h>
#include <std_msgs/String.h>

int main(int argc, char** argv)
{
  ros::init(argc, argv, "basic_simple_talker");
  ros::NodeHandle nh;
  ros::Publisher chatter_pub = nh.advertise<std_msgs::String>("chatter", 10);
  ros::Rate loop_rate(10);

  while (ros::ok())
  {
    std_msgs::String msg;
    msg.data = "hello world!";
    ROS_INFO("publish: %s", msg.data.c_str());
    chatter_pub.publish(msg);

    ros::spinOnce();
    loop_rate.sleep();
  }
  return 0;
}
```

msgが絡むのは2行目と8行目です。2行目の`#include <std_msgs/String.h>`でmsg型をインクルードしています。intやstringという基本型でもすべてincludeが必要です。8行目でもpublisherの設定でincludeした型を使っています。型名は`std_msgs::String`のように(パッケージ名)::(型名)というヘッダファイルを指定します。すべてのROSmsgは何らかのパッケージに属しています。
また`std_msgs::String msg;`と宣言したときに`msg`自体は文字列のデータではなく。その中の要素`msg.data`が文字列のデータになります。

# 配列型の使い方
例えばfloatの配列を送るには`std_msgs/Float32MultiArray`という型を使用します。リストを含む型の使い方を見てみます。

## ソースコード
### publish
```c++:basic_lecture/src/basic_array_talker.cpp
#include <ros/ros.h>
#include <std_msgs/Float32MultiArray.h>

int main(int argc, char** argv)
{
  ros::init(argc, argv, "basic_array_talker");
  ros::NodeHandle nh;
  ros::Publisher pub = nh.advertise<std_msgs::Float32MultiArray>("array", 10);
  
  ros::Rate loop_rate(1);
  while (ros::ok())
  {
    std_msgs::Float32MultiArray array;
    array.data.resize(4);
    array.data[0] = 0.0;
    array.data[1] = 1.0;
    array.data[2] = 2.0;
    array.data[3] = 3.0;
    pub.publish(array);
    ROS_INFO("I published array!");
    ros::spinOnce();
    loop_rate.sleep();
  }
}
```

`#include "std_msgs/Float32MultiArray.h"`でインクルード。Float32以外でもほぼすべての型で`*****MultiArray`という型が定義されています。配列はstd::vectorとして扱えます。初期化時には`array.data`は空の(=sizeが0の)`std::vector`です。そのためにまず配列のサイズを`array.data.resize(4)`で決定します。後は`array.data[0]`のようにインデックスでアクセスします。

### Subscribe
```c++:basic_lecture/src/basic_array_listener.cpp
#include <ros/ros.h>
#include <std_msgs/Float32MultiArray.h>

void chatterCallback(const std_msgs::Float32MultiArray& msg)
{
  int num = msg.data.size();
  ROS_INFO("I susclibed [%i]", num);
  for (int i = 0; i < num; i++)
  {
    ROS_INFO("[%i]:%f", i, msg.data[i]);
  }
}

int main(int argc, char** argv)
{
  ros::init(argc, argv, "basic_array_listener");
  ros::NodeHandle nh;
  ros::Subscriber sub = nh.subscribe("array", 1000, chatterCallback);

  ros::spin();
  return 0;
}
```
`msg.data.size()`で配列のサイズを取得できます。

### CmakeList
以下の4つを付け加えます。

```cmake:basic_lecture/CMakeLists.txt
add_executable(basic_array_talker    src/basic_array_talker.cpp)
add_executable(basic_array_listener  src/basic_array_listener.cpp)

target_link_libraries(basic_array_talker
  ${catkin_LIBRARIES}
)
target_link_libraries(basic_array_listener
  ${catkin_LIBRARIES}
)
```

### launch 
```xml:basic_lecture/launch/pubsub_array.launch
<launch>
  <node name="talker" pkg="basic_lecture" type="basic_array_talker" output="screen"/>
  <node name="listener" pkg="basic_lecture" type="basic_array_listener" output="screen"/>
</launch>
```

## ビルド
```shell
cd catkin_ws
catkin build
```

## 実行
```shell
roslaunch basic_lecture pubsub_array.launch
```

実行すると以下のような表示が流れてサイズが4の配列をpublish、subscribeしている様子がわかります。

```text:launchの結果
[ INFO] [1534072121.442238388]: I susclibed [4]
[ INFO] [1534072121.442407677]: [0]:0.000000
[ INFO] [1534072121.442449432]: [1]:1.000000
[ INFO] [1534072121.442472959]: [2]:2.000000
[ INFO] [1534072121.442494261]: [3]:3.000000
[ INFO] [1534072122.440483018]: I published array!
[ INFO] [1534072122.441309532]: I susclibed [4]
[ INFO] [1534072122.441474609]: [0]:0.000000
[ INFO] [1534072122.441571959]: [1]:1.000000
[ INFO] [1534072122.441607914]: [2]:2.000000
[ INFO] [1534072122.441794112]: [3]:3.000000
```

# 別のパッケージの型を使用
上記の例では`std_msgs::String`を使いました。`std_msgs`はリンクされているので、上記のincludeだけで使えるのですが、ほかのパッケージのmsgを使おうとすると、そのパッケージをリンクする作業が必要です。例えば`geometry_msgs/Twist`という型を使う場合は3つのファイルで記述が必要です。

## ソースファイル
以下のようにc++のソースファイルの初めにインクルードをする必要があります。

```c++:xxx.cppの一部
#include <geometry_msgs/Twist.h>
```

## CmakeList
以下のように`find_package`に使うmsgの属するROS packageを追加します。

```cmake:CMakeList.txtの一部
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  geometry_msgs　#この行を追加
)
```

## packge.xml
以下のように使うmsgの属するROS packageを追加します。これは追加しなくてもビルド&実行はできてしまいますが、作法として必要です。

```xml:package.xmlの一部
<build_depend>std_msgs</build_depend>
<exec_depend>std_msgs</exec_depend>
```

#rosmsgコマンド
メッセージの中身を調べることができます。[05 ROStools](https://qiita.com/srs/items/e6fb075ff57fa7ff8812)を参照

#参考
型対応表：http://wiki.ros.org/msg

# 目次ページへのリンク
[ROS講座の目次へのリンク](https://qiita.com/srs/items/5f44440afea0eb616b4a)