ROS講座78 rosparamを使う2

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

| 項目 | 値 |
|:-:|:-:|
| CPU | Core i5-8250U |
| Ubuntu | 20.04 |
| ROS | Noetic |

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

# 概要
前回は基本的なint型のparameterを読み込みましたが、rosparamでは辞書型やリスト型も使えます。これらの型のrosparamをROSノードで使う方法を解説します。

# ソースコード

## yamlファイル
今回読み込むパラメーターを記述したファイルです。以下の様にリスト型があり、そのアイテムが辞書型になっています。

```yaml:adv_lecture/config/param2_config
member_list:
  - name: aaa
    id: 1
  - name: bbb
    id: 2
  - name: ccc
    id: 3
```

## launch

```xml:adv_lecture/launch/rosparam2.launch
<launch>
  <node name="adv_param2_display" pkg="adv_lecture" type="adv_param2_display" output="screen">
    <rosparam command="load" file="$(find adv_lecture)/config/param2_config.yaml"/>
  </node>
</launch>
```

先ほどのyamlファイルをロードしています。

## ソースコード(rosノード)

```c++:adv_lecture/src/adv_param2_display.cpp
#include <ros/ros.h>

int main(int argc, char** argv)
{
  ros::init(argc, argv, "param_sample");
  ros::NodeHandle nh;
  ros::NodeHandle pnh("~");

  XmlRpc::XmlRpcValue member_list;
  pnh.getParam("member_list", member_list);
  ROS_ASSERT(member_list.getType() == XmlRpc::XmlRpcValue::TypeArray);
  ROS_INFO("member size: %i", (int)member_list.size());
  for (int32_t i = 0; i < member_list.size(); ++i)
  {
    ROS_INFO("read [%i]", i);
    int id = 0;
    std::string name = "";
    if (!member_list[i]["id"].valid() || !member_list[i]["name"].valid())
    {
      ROS_WARN("No id or name");
      continue;
    }
    if (member_list[i]["id"].getType() == XmlRpc::XmlRpcValue::TypeInt)
      id = static_cast<int>(member_list[i]["id"]);
    if (member_list[i]["name"].getType() == XmlRpc::XmlRpcValue::TypeString)
      name = static_cast<std::string>(member_list[i]["name"]);
    ROS_INFO("[%i] id: %i, name: %s", i, id, name.c_str());
  }
  return 0;
}
```

* `XmlRpc::XmlRpcValue member_list; pnh.getParam("member_list", member_list);`でxmlrpc形式で読み込みます。
* 辞書やリストには`member_list[i]["id"]`のように添え字でアクセスします。
* `getType()`でその値の型を判別します。`TypeInvalid`, `TypeBoolean`, `TypeInt`, `TypeDouble`, `TypeString`, `TypeArray`などがあります。
* リスト型なら`.size()`でサイズを取得できます。
* `辞書型なら.valid()`でそのキーがあるかどうかを判定します。
* 値を読むときは`static_cast<int>()`のようにキャストします。

# ビルド
```shell
cd ~/catkin_ws
catkin_make
```

# 実行
各ターミナルごとに実行前に`source ~/catkin_ws/devel/setup.bash`を実行する必要があります。

```shell
roslaunch adv_lecture rosparam2.launch 
```

以下のように表示されるはずです。

```txt:結果
[ INFO] [1588423525.235388960]: member size: 3
[ INFO] [1588423525.235467370]: read [0]
[ WARN] [1588423525.235506030]: No id or name
[ INFO] [1588423525.235519417]: read [1]
[ INFO] [1588423525.235534347]: [1] id: 1, name: bbb
[ INFO] [1588423525.235543629]: read [2]
[ INFO] [1588423525.235553543]: [2] id: 2, name: ccc
```

# 補足
* XmlRpc::XmlRpcValue::getType()で判定できる値として以下があります（本当はもう少しありますが、ROSで出てくるのはこれぐらい）。
    * TypeBoolean
    * TypeInt
    * TypeDouble
    * TypeString
    * TypeArray
    * TypeStruct
* TypeArrayやTypeStructは範囲for文が使えます

# 参考
[rosparamタグ](http://wiki.ros.org/roslaunch/XML/rosparam)
[parameter_server](http://wiki.ros.org/roscpp/Overview/Parameter%20Server)

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