Updated on: 2018-01-11
ROS 1とROS 2の通信プロトコルは全く違うので、直接繋がることはできません。 しかしROS 1にあってROS 2にないフィーチャーはまだたくさんあります。 おかげでROS 1とROS 2は一緒に利用することが望ましいです。
この問題を解決するためにROS 2がros1_bridgeというプロトコル通訳用(「ブリッジ」)のパッケージを提供します。
本セクションでros1_bridgeを利用してROS 1のノードとROS 2のノードの一緒に利用する方法を説明します。
注意:ros1_bridgeを利用するためにROS 1もROS 2も同時インストールすることが必要です。
注意:下記の説明通りに実習するために、端末は自動的にROS 1もROS 2も有効にしないようにしてください。(source /opt/ros/melodic/setup.bash等を実行しません。)端末によってどちらを利用するか変わります。
ROS 1とROS 2に含まれているデモノードを利用してブリッジの起動方法を説明します。
まずは4つの端末を起動します。
端末1にROS 1の環境を有効にして、roscoreを起動します。
1
2
$ source /opt/ros/melodic/setup.bash
$ roscore
端末2にROS 1とROS 2の環境を有効にして、ros1_bridgeパッケージ内のdynamic_bridgeノードを起動します。
1
2
3
$ source /opt/ros/melodic/setup.bash
$ source /opt/ros/crystal/setup.bash
$ ros2 run ros1_bridge dynamic_bridge
dynamic_bridgeは定期的にROS 1側とROS 2側に利用中のトピッkうを探します。
トピックがあったら、そのトピックで流れているデータを反対側で送信します。
利用するために同じメッセージ名がROS 1にもROS 2にも存在することが必要です。
端末3にROS 1のtalkerサンプルノードを起動します。
1
2
3
4
5
6
7
$ source /opt/ros/melodic/setup.bash
$ rosrun rospy_tutorials talker
[INFO] [1515642714.321480]: hello world 1515642714.32
[INFO] [1515642714.421406]: hello world 1515642714.42
[INFO] [1515642714.521378]: hello world 1515642714.52
[INFO] [1515642714.621575]: hello world 1515642714.62
...
最後に、端末4でROS 2のlistenerサンプルノードを起動します。
1
2
3
4
5
6
7
$ source /opt/ros/crystal/setup.bash
$ ros2 run demo_nodes_cpp listener
[INFO] [listener]: I heard: [hello world 1515642733.42]
[INFO] [listener]: I heard: [hello world 1515642733.52]
[INFO] [listener]: I heard: [hello world 1515642733.62]
[INFO] [listener]: I heard: [hello world 1515642733.72]
...
ROS 1側で送信されているメッセージがROS 2側で受信されています。
もちろん、逆方向も可能です。
端末3でROS 1のlistenerノードを起動して、端末4でROS 2のtalkerノードを起動するとメッセージはブリッジを通じて逆方向に流れます。
1
2
3
4
5
$ ros2 run demo_nodes_cpp talker
[INFO] [talker]: Publishing: 'Hello World: 1'
[INFO] [talker]: Publishing: 'Hello World: 2'
[INFO] [talker]: Publishing: 'Hello World: 3'
[INFO] [talker]: Publishing: 'Hello World: 4'
1
2
3
4
5
$ rosrun rospy_tutorials listener
[INFO] [1515647471.965369]: /listener_7925_1515647462461I heard Hello World: 1
[INFO] [1515647472.965250]: /listener_7925_1515647462461I heard Hello World: 2
[INFO] [1515647473.964986]: /listener_7925_1515647462461I heard Hello World: 3
[INFO] [1515647474.965300]: /listener_7925_1515647462461I heard Hello World: 4
ros1_bridgeはサービスも通訳できます。
使い方はメッセージと同様です。
上記のセクションの4つの端末をまた利用します。
端末3にROS 1のadd_two_ints_serverサンプルノードを起動したから、 端末4にROS 2のadd_two_ints_clientサンプルノードを起動します。
1
2
3
$ rosrun roscpp_tutorials add_two_ints_server
[ INFO] [1515648143.985914494]: request: x=2, y=3
[ INFO] [1515648143.985952552]: sending back response: [5]
1
2
$ ros2 run demo_nodes_cpp add_two_ints_client
[INFO] [add_two_ints_client]: Result of add_two_ints: 5
リソースを無駄に利用しないように、dynamic_bridgeは動的にトピックが利用されているかどうかを判断して、利用されていないトピックを向こう側で送信しません。
「トピックが利用されている」という条件は、どこかにデータが送信されていて、そしてブリッジの反対側でそのトピックにサブスクライブするノードがあるということです。
おかげで、dynamic_bridgeを起動することだけの状態でrostopic list等は反対側のトピックを表示しません。
例えば、ROS 1側でtfのトピックがパブリッシュされていても、ROS 2側でtfにサブスクライブするノードがなければブリッジはROS 2側にトピックを作成しません。
トピックをリストすることやrosbagでデータを保存することには全トピックの見えることが必要です。
dynamic_bridgeを起動するときに--bridge-all-topicsオプションを渡すと、トピックが利用されていなくても反対側で見えるようにします。
端末2でdynamic_bridgeをオプションなしで起動します。
1
$ ros2 run ros1_bridge dynamic_bridge
端末4でROS 2のtalkerサンプルノードを起動します。
1
2
3
$ ros2 run demo_nodes_cpp talker
[INFO] [talker]: Publishing: 'Hello World: 1'
[INFO] [talker]: Publishing: 'Hello World: 2'
端末2でなにも出力されていないことは確認できます。
端末3でrostopic listを実行すると/chatterトピックは表示されていないと確認できます。
1
2
3
$ rostopic list
/rosout
/rosout_agg
端末4のtalkerノードを終了します。
それから端末2でdynamic_bridgeを終了して、そして--bridge-all-topicsオプションを渡してもう一度起動します。
1
$ ros2 run ros1_bridge dynamic_bridge --bridge-all-topics
端末4でまたROS 2のtalkerサンプルノードを起動します。
端末2で下記のような出力が表示されます。ノードがトピックを作成することだけでブリッジが通訳し始めました。
1
2
created 2to1 bridge for topic '/chatter' with ROS 2 type 'std_msgs/String' and ROS 1 type 'std_msgs/String'
[INFO] [ros1_bridge]: Passing message from ROS 2 std_msgs/String to ROS 1 std_msgs/String (showing msg only once per type)
そしてrostopic listのアウトプットに/chatterトピックが見えます。
1
2
3
4
$ rostopic list
/chatter
/rosout
/rosout_agg