1. 程式人生 > 實用技巧 >ROS之話題的釋出與訂閱

ROS之話題的釋出與訂閱

訊息:

msg檔案就是一個描述ROS中所使用訊息型別的簡單文字。它們會被用來生成不同語言的原始碼。
注意,在構建的時候,我們只需要"message_generation"。然而,在執行的時候,我們只需要"message_runtime"。
檢視package.xml, 確保它包含以下兩條語句:
<build_depend>message_generation</build_depend>
<run_depend>message_runtime</run_depend>
在 CMakeLists.txt檔案中,利用find_packag函式,增加對message_generation的依賴:


catkin_package( … CATKIN_DEPENDS message_runtime … …)
add_message_files( FILES Num.msg)
generate_messages()

1、建立工作空間:

mkdir -p ~/ROS_Learning_ws/src
cd ~/ROS_Learning_ws/src
catkin_init_workspace	#初始化工作空間
cd ~/ROS_Learning_ws
catkin_make	#編譯工作空間
source devel/setup.bash	#將該工作空間加入環境變數

2建立功能包:

建立工作空間後,工作空間可以順利通過編譯,此時工作空間不存在功能包,即還沒有功能實現。需要使用catkin_create_pkg建立功能包。

cd ~/ROS_Leraning/src
catkin_create_pkg learning_communication  std_msgs  roscpp  rospy

catkin_create_pkg命令列格式:catkin_create_pkg [package_name] [depend1] [depend2] [depend3]。因此上述命令列中的std_msgs和roscpp分別為功能包ROS_Test1的依賴項。

std_msgs:包含了常見的訊息型別,表示基本資料型別和其他基本的訊息構造。

roscpp:表示該功能包通過c++實現ROS的各種功能。提供了一個客戶端庫,c++開發者可以呼叫介面迅速完成主題、服務等相關工作。

rospy:表示該功能包通過python實現ROS的各種功能。提供了一個客戶端庫,python開發者可以呼叫介面迅速完成主題、服務等相關工作。

此時執行以下命令可以檢視功能包的依賴項。  

rospack depends learning_communication    #檢視功能包依賴項

3、編譯功能包:

 返回到工作空間根目錄:

cd ~/ROS_Learning
catkin_make

4、建立釋出和訂閱節點

在功能包下的src檔案下,即learning_communication/src建立釋出話題節點檔案:talker.cpp 內容如下:

 //該例程將釋出chatter話題,訊息型別String
 
#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"

int main(int argc, char **argv)
{
    // ROS節點初始化
    ros::init(argc, argv, "talker");

    // 建立節點控制代碼
    ros::NodeHandle n;

    // 建立一個Publisher,釋出名為chatter的topic,訊息型別為std_msgs::String
    ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

    // 設定迴圈的頻率
    ros::Rate loop_rate(10);

    int count = 0;
    while (ros::ok())
    {
        // 初始化std_msgs::String型別的訊息
        std_msgs::String msg;
        std::stringstream ss;
        ss << "hello world " << count;
        msg.data = ss.str();

        // 釋出訊息
        ROS_INFO("%s", msg.data.c_str());
        chatter_pub.publish(msg);

        // 迴圈等待回撥函式
        ros::spinOnce();

        // 按照迴圈頻率延時
        loop_rate.sleep();
        ++count;
    }

    return 0;
}

在功能包下的src檔案下,即learning_communication/src建立訂閱話題節點檔案:listener.cpp 內容如下:  

//該例程將訂閱chatter話題,訊息型別String

 
#include "ros/ros.h"
#include "std_msgs/String.h"

// 接收到訂閱的訊息後,會進入訊息回撥函式
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
    // 將接收到的訊息打印出來
    ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
    // 初始化ROS節點
    ros::init(argc, argv, "listener");

    // 建立節點控制代碼
    ros::NodeHandle n;

    // 建立一個Subscriber,訂閱名為chatter的topic,註冊回撥函式chatterCallback
    ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

    // 迴圈等待回撥函式
    ros::spin();

    return 0;
}

在一個功能包內可以同時釋出可建立多個例項化節點控制代碼,建立多個釋出函式,建立多個訂閱回撥函式。  

5、建立CMake檔案:

learning_communication包根目錄下找到CMakeLists.txt檔案在檔案結尾端新增如下:

add_executable(talker src/talker.cpp)    #將talker.cpp檔案編譯成可執行檔案talker
target_link_libraries(talker ${catkin_LIBRARIES})      #為可執行檔案talker新增連結庫 
add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp) #新增可執行檔案的訊息依賴

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp)

以上內容編輯完成以後,進行節點編譯:

回到工作空間根目錄進行編譯:

cd ~/ROS_Learning
catkin_make

編譯完成後執行

roscore
rosrun learning_communication talker   #需開啟新終端
rosrun learning_communication listener  #需開啟新終端

執行結果如下圖:

補充:

ros::ok()返回false的條件:

1. SIGINT收到(Ctrl-C)訊號
2. 另一個同名節點啟動,會先中止之前的同名節點
3. ros::shutdown()被呼叫
4. 所有的ros::NodeHandles被銷燬

spinOnce()與spin()區別:
spinOnce()與spin()是兄弟函式,學名叫做訊息回撥處理函式。區別如下:

spinOnce()函式呼叫後,會繼續執行後續的程式碼段。例如talker中,執行該函式後會繼續執行loop_rate.sleep()。
spin()呼叫後,程式不會返回,不會執行後續的程式碼段。例如listener中,執行該函式後,程式不會返回。