ROS: dynamic_reconfigureのチュートリアルでの問題点＋解決法



#はじめに
個人的なプロジェクトでROSを使用している中で初期化で定義されたパラメターを再設定する必要があり動的再設定可能なノードが必要されROSチュートリアルに頼りました。

最終的には解決できましたが、ただの理解不足なのかチュートリアルで何度か躓き、混乱する場面は多く、なかなか前に進まず大変でした。　もし辿り着いた解決法がほかのユーザーの為になるのであれば嬉しいです。

[dynamic_reconfigure](http://wiki.ros.org/dynamic_reconfigure/Tutorials)のチュートリアルは英語では完成しておりますが、なぜかの和訳のほうは未完成だそうです。　紹介された内容は以下どうり：

[和訳ーdynamic_reconfigure](http://wiki.ros.org/ja/dynamic_reconfigure/Tutorials)
1. はじめてのcfgファイルを書く
2. nodeのためのDynamic Reconfigureを設定する (python)
3. nodeのためのDynamic Reconfigureを設定する(cpp)
4. Dynamic Reconfigure Pythonクライアントを使う。

私の環境： Main PCからRaspberry-Pi-2へsshで接続。


```
Raspiの環境
----------
Distributor ID:	Ubuntu
Description:	Ubuntu 14.04.4 LTS
Release:        14.04
Codename:       trusty

ROS:            indigo
```


#問題点とその解決法
（個人的の誤解もありますので注意。　もし指定した問題点は誤解でありましたら丁寧に指導をお願い致します。）


###1. server.pyとclient.pyの間のコミュニケーション問題
 server.pyとclient.pyを実装し、server.pyを機動。　何とかうまく機動したよう。　

```
ubuntu@ubuntu:~/ros/src/dynamic_tutorials/nodes$ python server.py 
[INFO] [WallTime: 1472044041.924919] Reconfigure Request: 50, 0.5,\ 
                    Hello World, True, 1
```

次にclient.pyを機動。

```
ubuntu@ubuntu:~/ros/src/dynamic_tutorials/nodes$ python client.py 
Traceback (most recent call last):
  File "client.py", line 15, in <module>
    client = dynamic_reconfigure.client.Client("dynamic_tutorials", timeout=30, config_callback=callback)
  File "/opt/ros/indigo/lib/python2.7/dist-packages/dynamic_reconfigure/client.py", line 84, in __init__
    self._set_service      = self._get_service_proxy('set_parameters', timeout)       
  File "/opt/ros/indigo/lib/python2.7/dist-packages/dynamic_reconfigure/client.py", line 305, in _get_service_proxy
    rospy.wait_for_service(service_name, timeout)
  File "/opt/ros/indigo/lib/python2.7/dist-packages/rospy/impl/tcpros_service.py", line 143, in wait_for_service
    raise ROSException("timeout exceeded while waiting for service %s"%resolved_name)
rospy.exceptions.ROSException: timeout exceeded while waiting for service /dynamic_tutorials/set_parameters
```
client.pyはうまく機動せずtimeoutしたようです。　ここは色々ためした結果、anonymous=Trueとチュートリアルで書かれた一部をanonymous=Falseへ書き換えることで解決。

具体的に

```py
   1 if __name__ == "__main__":
   2     rospy.init_node("dynamic_tutorials", anonymous = True)
   3 
   4     srv = Server(TutorialsConfig, callback)
   5     rospy.spin()
```
のライン２を

```py
   2     rospy.init_node("dynamic_tutorials", anonymous = False)
```
と訂正。



###2. リターンバリューがdouble型を期待、そのアウトプット問題


次に[.cfgのチュートリアル](http://wiki.ros.org/ja/dynamic_reconfigure/Tutorials/HowToWriteYourFirstCfgFile)どうりでソースを組むとdoubleの計算が正確にアウトプットせず初期化はOKでありその後のdoubleのアウトプットは0.0のみです。


```
[INFO] [WallTime: 1472040398.581536] Config set to 50, double 0.5, Hello World, True, 1
[INFO] [WallTime: 1472040398.643655] Config set to 1, double 0.0, 1472040398510832071, True, 1
[INFO] [WallTime: 1472040399.597584] Config set to 2, double 0.0, 1472040399512236118, False, 1
[INFO] [WallTime: 1472040400.831513] Config set to 3, double 0.0, 1472040400512252092, True, 1
[INFO] [WallTime: 1472040401.598809] Config set to 4, double 0.0, 1472040401512007951, False, 1
[INFO] [WallTime: 1472040402.596398] Config set to 5, double 0.0, 1472040402512295007, True, 1
[INFO] [WallTime: 1472040403.604270] Config set to 6, double 0.0, 1472040403512253046, False, 1
[INFO] [WallTime: 1472040404.598363] Config set to 7, double 0.0, 1472040404512221097, True, 1
[INFO] [WallTime: 1472040405.597173] Config set to 8, double 0.0, 1472040405512233018, False, 1
[INFO] [WallTime: 1472040406.597760] Config set to 9, double 0.0, 1472040406512245893, True, 1
[INFO] [WallTime: 1472040407.593346] Config set to 10, double 0.0, 1472040407512260913, False, 1

＊注意点：　上記のアウトプットではdoubleと書かれてますが、分かり易くするために入力したものです。
```

問題はclient.pyのライン25にあり方程式は(1/(x+1))と書かれておりintegerの１からdoubleの1.0へ訂正したことで解決。

```py
  25         client.update_configuration({"int_param":x, "double_param":(1.0/(x+1.0)), "str_param":str(rospy.get_rostime()), "bool_param":b, "size":1})
```

ちなみに訂正後のアウトプット：

```
[INFO] [WallTime: 1472039708.633182] Config set to 50, double 0.5, Hello World, True, 1
[INFO] [WallTime: 1472039708.695360] Config set to 1, double 0.5, 1472039708561244010, True, 1
[INFO] [WallTime: 1472039709.650566] Config set to 2, double 0.333333333333, 1472039709562589883, False, 1
[INFO] [WallTime: 1472039710.652019] Config set to 3, double 0.25, 1472039710562690973, True, 1
[INFO] [WallTime: 1472039711.649892] Config set to 4, double 0.2, 1472039711562654972, False, 1
[INFO] [WallTime: 1472039712.648016] Config set to 5, double 0.166666666667, 1472039712562711000, True, 1
[INFO] [WallTime: 1472039713.644379] Config set to 6, double 0.142857142857, 1472039713563271999, False, 1
[INFO] [WallTime: 1472039714.647212] Config set to 7, double 0.125, 1472039714562716007, True, 1
[INFO] [WallTime: 1472039715.647052] Config set to 8, double 0.111111111111, 1472039715562674999, False, 1
[INFO] [WallTime: 1472039716.656906] Config set to 9, double 0.1, 1472039716562674999, True, 1
[INFO] [WallTime: 1472039717.648899] Config set to 10, double 0.0909090909091, 1472039717562360048, False, 1
```

###3. .cfgファイルでのMin,MaxはOptionalではない？？？　初期化の問題とその解決法


チュートリアルではminとmaxはオプショナルと指定されている。

```
min - specifies the min value (optional and does not apply to strings and bools)
max - specifies the max value (optional and does not apply to strings and bools)
```

チュートリアルで紹介されるパラメター設定：

```py
   8 gen.add("int_param", int_t, 0, "An Integer parameter", 50, 0, 100)
   9 gen.add("double_param", double_t, 0, "A double parameter", .5, 0, 1)
  10 gen.add("str_param", str_t, 0, "A string parameter", "Hello World")
  11 gen.add("bool_param", bool_t, 0, "A Boolean parameter", True)
```

min,maxを外し実際に下記どうり書き換えると

```py
   9 gen.add("double_param", double_t, 0, "A double parameter", .5)
```
うまく初期化はせず問題になり、今回は個人のプロジェクトではここで一番困りました。　本当にオプショナルなのでしょうか？　私の誤解もしくは読み間違いだったのでしょうか？　解決法としてmin,maxをちゃんと定義したことで問題解決。

換えた結果：

```
[INFO] [WallTime: 1472040178.827491] Config set to 50, double -std::numeric_limits<double>::infinity(), Hello World, True, 1
[INFO] [WallTime: 1472040178.908985] Config set to 1, double -std::numeric_limits<double>::infinity(), 1472040178757894992, True, 1
[INFO] [WallTime: 1472040179.842081] Config set to 2, double -std::numeric_limits<double>::infinity(), 1472040179759325027, False, 1
[INFO] [WallTime: 1472040180.854467] Config set to 3, double -std::numeric_limits<double>::infinity(), 1472040180759330034, True, 1
[INFO] [WallTime: 1472040181.839698] Config set to 4, double -std::numeric_limits<double>::infinity(), 1472040181759291887, False, 1
[INFO] [WallTime: 1472040182.841897] Config set to 5, double -std::numeric_limits<double>::infinity(), 1472040182759303092, True, 1
[INFO] [WallTime: 1472040183.842247] Config set to 6, double -std::numeric_limits<double>::infinity(), 1472040183759357929, False, 1
[INFO] [WallTime: 1472040184.843146] Config set to 7, double -std::numeric_limits<double>::infinity(), 1472040184759290933, True, 1
[INFO] [WallTime: 1472040185.844840] Config set to 8, double -std::numeric_limits<double>::infinity(), 1472040185759314060, False, 1
[INFO] [WallTime: 1472040186.843429] Config set to 9, double -std::numeric_limits<double>::infinity(), 1472040186759322881, True, 1
[INFO] [WallTime: 1472040187.844200] Config set to 10, double -std::numeric_limits<double>::infinity(), 1472040187759318113, False, 1
```


#感想

紹介した問題は個人的の設定、使用環境などの原因もあり、もしそうであれば教えてもらえば大変助かります。　初期化問題には大変苦しみましたが最終的に解決方に辿り着いた事には完成度を感じます。　解決方を目指す中でdynamic_reconfigureの使い方には結構力がついた気がしROSにも新たな面からアプローチできたことで勉強になりました。