LoginSignup
3
0

More than 1 year has passed since last update.

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

Last updated at Posted at 2019-07-17

ROS2関係トップページへ
ROS2レクチャー:初級 -ROS1 style-

【前:ROS2のpublisher/subscriber概要
【次:ROS2における時間管理・Rate系とTimer系

ROS風nodeによるsubscriberプログラムを作成する.
ここで作成するプログラムは以下の2種類.

  • ROS風nodeによるsubscriber.callback関数を使用.
  • ROS風nodeによるsubscriber.lambda関数を使用.

また,ここではpublisherは作成せず,コマンドでメッセージを送信してsubscriberが受信する様子を観察する.

準備

terminal
$ cd ~/ros2_studies_ws/
$ ros2 pkg create minimal_subscriber_ros1_like --dependencies rclcpp example_interfaces

callback関数を使用したsubscriber

作成物:

  • src/callback_main.cpp

プログラム

callback_main.cpp
#include <rclcpp/rclcpp.hpp>
#include <rclcpp/qos.hpp>
#include <example_interfaces/msg/string.hpp>

rclcpp::Node::SharedPtr node = nullptr;

void topic_callback(const example_interfaces::msg::String::SharedPtr msg){
  RCLCPP_INFO(node->get_logger(), "I heard: %s", msg->data.c_str());
}

int main(int argc, char * argv[]){
  rclcpp::init(argc, argv);

  node=rclcpp::Node::make_shared("ros1_like_subscriber_test");
  auto subscription = node->create_subscription<example_interfaces::msg::String>(
    "topic_test",
    rclcpp::QoS(10),
    std::bind(topic_callback, std::placeholders::_1)
  );
  rclcpp::spin(node);
  rclcpp::shutdown();

  subscription = nullptr;
  node=nullptr;
  return 0;
}

概要

メッセージを受信したらcallback関数(topic_callback)を呼んで処理を任せる.
メッセージの種類はとりあえずぱっと使えるexample_interfaceで,その中のstring型(example_interfacesのmsgのstring)を使用.
subscriberのcallback関数はメッセージのポインタを受け取る.

説明

main関数とcallback関数(topic_callback)の両方でnodeを使用するので5行目のようにglobal変数にしてヌルポインタを代入しておく.
7~9行目がcallback関数.今回はメッセージを出力するだけのもの.
11行目からmain関数で,14行目でnodeを作成し15行目でそのnodeをsubscriberとして使用するための設定を行っている.

  • create_subscription関数で「subscriberとして設定」
  • subscriberとして(publisherから)受け取るメッセージの種類は<>内で設定
    • example_interfaces::msg::String
  • 関数の第一引数(16行目)がトピック名の指定
    • topic_test
      • subscriberがトピックを作るのではなく,publisherが作るトピックの名前を指定
  • 関数の第二引数(17行目)はQuality of Serviceの設定
    • rclcpp::QoS(n)で「historyをnほど持つ」という意味になるので,適当にnを設定
    • rclcpp::QoSの設定自体は様々あるみたいだが,ここではhistoryに関するもののみで「とりあえず」いい?
  • 関数の第三引数(18行目)がメッセージを受け取った時の処理・callback関数を指定
  • 設定をポインタ変数subscriptionで保存
    • subscriptionはautoで型類推しているが,本来はSubscription型のスマートポインタ

<rclcpp/qos.hpp>について公式APIのQOSの項目では<qos.hpp>となっているが,/opt/ros/foxy/include以下を見ると<rclcpp/qos.hpp>が正しそうに見える.APIの記述が変わるか,プログラムの記述を変えなくてはいけなくなるか分からないのでメモ

20行目で,設定の終わったnodeを実行.

string型について

  • 3行目のようにexample_interfaces/msg/string.hppをインクルード.
    • string.hppはファイル名
  • 使用する場合には,7行目や15行目のようにexample_interfaces::msg::Stringと指定
    • Stringはクラス名
  • メッセージはSharedPtr,UniquePtr,WeakPtrの使用が可
  • ros2/example_interfacesを見るとわかるが,example_interfacesのStringクラスはstring型の変数dataのみを持つ.文字列として出力するために8行目のようにc_str()でC言語の文字列に変換している.


global変数,ホントウはだめ絶対C言語の場合にはstaticを使用してファイルスコープにすべき.C++では無名名前空間(namespace{})を使用すべきである.

lambda関数を使用したROS風subscriber

  • ~/ros2_studies_ws/src/minimal_subscriber_ros1_like/src/lambda_main.cpp

プログラム

lambda_main.cpp
#include <rclcpp/rclcpp.hpp>
#include <rclcpp/qos.hpp>
#include <example_interfaces/msg/string.hpp>

int main(int argc, char * argv[]){
  rclcpp::init(argc, argv);

  node=rclcpp::Node::make_shared("ros1_like_subscriber_test");
  auto subscription = node->create_subscription<example_interfaces::msg::String>(
    "topic_test",
    rclcpp::QoS(10),
    [](const example_interfaces::msg::String::SharedPtr msg) ->void {
      RCLCPP_INFO(node->get_logger(), "I heard: %s", msg->data.c_str());
    }
  );
  rclcpp::spin(node);
  rclcpp::shutdown();

  return 0;
}

概要

ROS1風subscriberのcallback関数の代わりにlambda関数を用いたバージョン.
参考:cpprefjpのラムダ式C++11 ラムダ式、std::function本の虫: lambda 完全解説

説明

12~14行目:返り値がvoidで引数がconst example_interfaces::msg::String::SharedPtr msgのlambda関数.

package.xmlとCMakeLists.txt

package.xml

以下は重要な部分のみを抜粋.

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

説明

rclcppに加え,example_interfacesを使用している.

CMakeLists.txt

以下は重要な部分のみを抜粋.

CMakeLists.txt
find_package(rclcpp REQUIRED)
find_package(example_interfaces REQUIRED)

add_executable(callback_subscriber_test
  src/callback_main.cpp
)
ament_target_dependencies(callback_subscriber_test
  rclcpp
  example_interfaces
)

add_executable(lambda_subscriber_test
  src/lambda_main.cpp
)
ament_target_dependencies(lambda_subscriber_test
  rclcpp
  example_interfaces
)

install(TARGETS
  callback_subscriber_test
  lambda_subscriber_test
  DESTINATION lib/${PROJECT_NAME}
)

rclcppに加え,example_interfacesを使用しているので2行目のように指定.
今回2種類のターゲットを作成する.そのため,add_executableおよびament_target_dependencies2種類ある.
またinstallのところに"ターゲット"も2種類となり,全てをlib/${PROJECT_NAME}にインストールするよう設定してある.

ビルド・実行

ビルド

terminal
$ cd ~/ros2_studies_ws/
$ colcon build --symlink-install --packages-up-to minimal_subscriber_ros1_like
$ . install/local_setup.bash

colcon build --symlink-installのみの場合,ワークスペース以下全てのパッケージをコンパイル・ビルドするので時間がかかる.
--packages-up-to [パッケージ名]とすることで必要なパッケージおよび依存関係のあるパッケージのみコンパイル・ビルドできて楽.複数のパッケージを選択したい場合はスペース区切りで指定.

実行

subscriber(メッセージ受信者)とpublisher(今回はコマンドでメッセージを発信)のため,二つのterminalを起動させる.

terminal1
$ cd ~/ros2_studies_ws/
$ . install/local_setup.bash
$ ros2 run minimal_subscriber_ros1_like [ターゲット名]

CMakeLists.txtにあるとおり,ターゲット名は以下の通り.全部やってみよう.

  • callback_subscriber_test
  • lambda_subscriber_test
termina2
$ cd ~/ros2_studies_ws/
$ . install/local_setup.bash
$ ros2 topic pub /topic_test example_interfaces/String '{data: hello}'

下記のコマンドでデータを発信("pub"lication)している.詳しくはROS2の紹介 by gbiggs

  • ros2 topic pub [トピック名] [データの型] [YAML形式で指定したデータ]

補足

terminal
$ ros2 node list # ノード一覧が表示される
$ ros2 interface list # メッセージ一覧が表示される
$ ros2 interface show example_interfaces/msg/String # example_interfaces/msg/Stringの構造が表示される
$ ros2 topic list # トピック一覧が表示される
$ ros2 topic pub /topic_test std_msgs/String '{data: hello}'

詳しくはIntrospection with command line toolsもしくはROS2コマンド一覧を参照.

【前:ROS2のpublisher/subscriber概要
【次:ROS2における時間管理・Rate系とTimer系

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0