1. 程式人生 > >話題的釋出與訂閱

話題的釋出與訂閱

用RoboWare Studio建立好工作區和package後,在src下新建兩個cpp檔案,一個做話題的釋出者,另一個做話題的訂閱者,然後編譯下就可以測試運行了,不過RoboWare只能除錯執行一個節點,另一個可以用自帶的整合終端(ctrl+`)或者新開一個終端執行,當然也可以寫一個launch啟動檔案。

釋出者:

//ros/ros.h是一個實用的標頭檔案,它引用了ROS系統中大部分常用的標頭檔案
#include "ros/ros.h"
//std_msgs/String存放在std_msgs package裡,由String.msg檔案自動生成的標頭檔案
#include "std_msgs/String.h"
#include <sstream>


int main(int argc, char **argv)
{
    //初始化ROS,注意:名稱必須唯一
    ros::init(argc,argv,"example1_a");

    //設定節點程序控制代碼
    ros::NodeHandle n;

    //告訴master我們將要在message topic上釋出一個std_msgs/String的訊息
    //引數一為釋出的話題的名稱;
    //引數二為緩衝區大小,如果我們釋出的訊息太快,緩衝區中的訊息在大於1000個的時候就會開始丟棄先前釋出的訊息
    //NodeHandle::advertise() 返回一個 ros::Publisher物件,它有兩個作用: 
    //1) 它有一個publish()成員函式可以讓你在topic上釋出訊息; 2) 如果訊息型別不對,它會拒絕釋出
    ros::Publisher chatter_pub = n.advertise<std_msgs::String>("message",1000);

    //設定傳送頻率10Hz
    //ros::Rate物件可以允許你指定自迴圈的頻率,自上一次呼叫Rate::sleep()後時間的流逝,並休眠直到一個頻率週期的時間
    ros::Rate loop_rate(10);

    //ros::ok()返回false,如果下列條件之一發生:
    //1、SIGINT接收到(Ctrl-C)
    //2、被另一同名節點踢出ROS網路
    //3、ros::shutdown()被程式的另一部分呼叫
    //4、所有的ros::NodeHandles都已經被銷燬 
    while(ros::ok())
    {
        //建立訊息變數
        std_msgs::String msg;
        std::stringstream ss;
        ss << "Talker node sending message!";
        msg.data=ss.str();
        //ROS_INFO("%s",msg.data.c_str());  類似printf,輸出檢驗

        //釋出訊息
        chatter_pub.publish(msg);

        //如果出現一個訂閱者,ROS就會更新並讀取所有主題
        //ROS訊息回撥處理函式ros::spin() 和 ros::spinOnce(),兩者區別在於
        //前者呼叫後不會再返回,也就是你的主程式到這兒就不往下執行了,而後者在呼叫後還可以繼續執行之後的程式
        ros::spinOnce();
        
        //休眠
        loop_rate.sleep();
    }
    return 0;
}

訂閱者:

#include "ros/ros.h"
//ros/ros.h是一個實用的標頭檔案,它引用了ROS系統中大部分常用的標頭檔案
#include "std_msgs/String.h"
//std_msgs/String存放在std_msgs package裡,由String.msg檔案自動生成的標頭檔案

//回撥函式,當message topic訊息到達後會呼叫此函式
void sub_callback(const std_msgs::String::ConstPtr& msg)
{
    ROS_INFO("I hear: [%s]",msg->data.c_str());
}


int main(int argc, char **argv)
{
    //初始化ROS,注意:名稱必須唯一
    ros::init(argc, argv, "example1_b");

    //設定節點程序控制代碼
    ros::NodeHandle n;

    //引數一為訂閱的話題名稱(message);
    //引數二是訊息快取佇列,這裡設定為1000,即快取了1000個訊息後,如果由新的訊息到達,則開始丟棄先前接收的訊息;
    //引數三為當收到訊息後呼叫的函式名稱(sub_callback)
    ros::Subscriber sub = n.subscribe("message", 1000, sub_callback);
    
    //ros::spin()進入自迴圈,可以儘可能快的呼叫訊息回撥函式
    ros::spin();  
    return 0;
}

launch啟動檔案

<?xml version="1.0"?>
<launch>
 <node name = "example1_a" pkg = "chapter2_tutorials" type = "example1_a"/>
 <node name = "example1_b" pkg = "chapter2_tutorials" type = "example1_b"/>
</launch>
節點名、package包名字對應自己建立的進行更改,我的工作區東西比較多就不用tree列出來了。

將兩個節點跑起來後,可以在終端輸入rostopic echo /message 來檢視話題釋出的內容(message是我的話題名,可以根據自己的程式碼修改)。

圖1、釋出者

圖2、訂閱者

圖3、工作區結構