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中,執行該函式後,程式不會返回。