シンプルなPublisherとSubscriber
Simple Wiki Based Contents Management System
関心分野 >> Ros4Winのインストール >> シンプルなPublisherとSubscriber

シンプルなPublisherとSubscriber

このページでは、ROSノードのトッピク通信を行うシンプルなノード(PublisherとSubscriber)を実装していきます。
ここで作成するROSノードは、ROS初心者向けチュートリアルのものと同じです。中身の詳細は、こちらのサイトを参照していただくと良いと思います。

TalkerとListener

では、シンプルなPublisher(talker)とSubscriber(listener)を作成していきます。TalkerとListenerは下記のような機能を実装していきます。
  • Talker: "chatter"という名前のトピック(String型)に ”Hello World!"という文字列を 10Hzの周期で配信し続けるROSノード。
  • Listener: "chatter"という名前のトピック(String型)のを購読し、データを受信すると ”I hard:[<受信文字列>]” を標準出力に出力するROSノード。
ここでは、上記の機能をもつ2つのROSノードをC++とPythonで実装していきます。

C++による実装

では、C++言語で実装していきます。下のように src というディレクトリを作成して移動してください。
 > roscd mytut
 > mkdir src
 > cd src

Talker

では、Talkerノードの実装を行います。
典型的なC++版のPublusher ROSノードのmain関数は、
  1. rosの初期化
  2. トピック通信ポート(Publisher)の生成
  3. 実行周期の定義
  4. 実行ループ
    1. 配信データの生成
    2. 配信(publish)
    3. 周期実行の残り時間のsleep
となります。
talker.cppというフィル名で下のコードを作成しましょう。
 #include "ros/ros.h"
 #include "std_msgs/String.h"
 #include <sstream>

 int main(int argc, char **argv)
 {
    /* initilize ROS Node */
    ros::init(argc, argv, "talker");
    ros::NodeHandle n;

    /* create Publisher interface */
    ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

    /* define the rate of execution loop */
    ros::Rate loop_rate(10);
    int count = 0;

    /* execution loop */
    while (ros::ok())
    {
        /* create a message for publisher */
        std_msgs::String msg;
        std::stringstream ss;
        ss << "hello world " << count;
        msg.data = ss.str();

        ROS_INFO("%s", msg.data.c_str());
        /* Publish the message */
        chatter_pub.publish(msg);

        /* wate for exection loop */
        loop_rate.sleep();
        ++count;
    }
  return 0;
 }

Listener

次に、Listenerを実装します。
典型的なC++版のSubscriber ROSノードのmain関数は、
  1. コールバック関数の定義
  2. rosの初期化
  3. トピック通信(Subscriber)のインターフェースを作成
  4. コールバック関数待ち(実行ループ)
となります。
listener.cppというファイル名で下のコードを作成しましょう。
 #include "ros/ros.h"
 #include "std_msgs/String.h"

 /* define a callback function */
 void chatterCallback(const std_msgs::String::ConstPtr& msg)
 {
    ROS_INFO("I heard: [%s]", msg->data.c_str());
 }

 int main(int argc, char **argv)
 { 
    /* initilize ROS Node */
    ros::init(argc, argv, "listener");
    ros::NodeHandle n;

    /* create a interface for the subscriber */ 
    ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

    /* run execute loop */
    ros::spin();
    return 0;
 }
このコードでは、whereのように明示的な無限ループの記述はありません。ros::spin()関数では、内部で無限ループが回っています。

TalkerとListenerのビルド

takler.cppとlistener.cppの実装が終わったらプログラムをビルドします。
ROSでは、C++のプログラムのビルドにも catkin_makeを使います。
catkin_makeでC++のソースコードをビルドするには、適切にCMakeLists.txtを修正する必要があります。C++のプログラムをビルドするには、
  • include_directories (includeファイルのあるPath設定)
  • add_executabe (ビルドするファイルを設定)
  • target_link_libraries (リンクするライブラリの設定)
を追記します。
以下のコードを追加して下さい。
include_directories(include ${catkin_INCLUDE_DIRS})

add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
CMakeLists.txtの修正が終わったら、最後にワークスペースのトップに移動し、ビルドを行います。
 > roscd
 > catkin_make --use-vc15
以上で、C++版のROSノードの生成は終了です。

Pythonによる実装

次に、PythonでTalkerとListenerの実装を行います。Pythonのコードは、scriptsというディレクトリの下に実装していきます。
 > roscd mytut
 > mkdir scripts
 > cd scripts
Ros4Winでは、Pythonの実行フラグの設定は必要ありません。rosunスクリプトでは、拡張子が.pyであるファイルは、pythonスクリプトとして実行します。

Talker

では、Talkerノードの実装を行います。
典型的なPython版のPublusher ROSノードの実装コードでは、C++言語のmain関数と同様の関数(ここではtalkerとします)を下のように定義します。
  1. トピック通信ポート(Publisher)の生成
  2. rosの初期化
  3. 実行周期の定義
  4. 実行ループ
    1. 配信データの生成
    2. 配信(publish)
    3. 周期実行の残り時間のsleep
この関数は、C++の時のmain関数とほぼ同じです。少し変更しているのは、1と2が逆転していますが、本来この順番は変更可能です。本来は、初期化 ->インターフェースの生成の順の方がよいかと思います。
talker.pyを下のように実装してください。
#
# license removed for brevity
import rospy
from std_msgs.msg import String

def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    r = rospy.Rate(10) # 10hz
    while not rospy.is_shutdown():
        str = "hello world %s"%rospy.get_time()
        rospy.loginfo(str)
        pub.publish(str)
        r.sleep()

if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException: pass

Listener

次に、Listenerを実装していきます。
ここでは、C++版のSubscriber ROSノードのときと同じように、下のように実装します。
  1. コールバック関数の定義
  2. rosの初期化
  3. トピック通信(Subscriber)のインターフェースを作成
  4. コールバック関数待ち(実行ループ)
listener.pyを下のように実装してください。
#
import rospy
from std_msgs.msg import String

def callback(data):
    rospy.loginfo(rospy.get_caller_id()+"I heard %s",data.data)
    
def listener():
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber("chatter", String, callback)
    rospy.spin()
        
if __name__ == '__main__':
    listener()
以上で、典型的なPubliserノードとSubscriberノードの実装は終了です。
次は、これらのコードを実際に動かしてみましょう。