消息:
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中,執行該函數后,程序不會返回。