自定义消息一般存储在功能包的msg文件夹下的.msg文件中,这些定义可告诉ROS这些数据的类型和名称,以便于在ROS 节点中使用。添加完这些自定义消息后,ROS会将其转为等效的C++节点,从而可在其他节点中使用。
1、编写msg文件
自定义消息必须在.msg文件中编写且保存在功能包的msg文件夹中。在上一节<ROS-4 : ROS节点和主题>创建的功能包ros_demo_pkg下创建文件夹msg,并在其中添加文件demo_msg.msg,该文件内容为:
string greeting
int32 number
2、修改package.xml文件
由于自定义消息需要依赖于其他功能包,所以在功能包ros_demo_pkg的package.xml文件中添加或uncomment以下行:
<build_depend>message_generation</build_depend> <exec_depend>message_runtime</exec_depend>
3、修改CMakeList.txt文件
编辑该功能包的CMakeList.txt文件,添加message_generation:
find_package(catkin REQUIRED COMPONENTS)
roscpp
rospy
std_msgs
actionlib
actionlib_msgs
message_generation
)
添加自定义的message文件:
add_message_files(
FILES
demo_msg.msg
)
## Generate added messages and services with any dependencies listed here
generate_messages(
DEPENDENCIES
std_msgs
actionlib_msgs
)
4、编译并构建该功能包
$ cd ~/catkin_ws
$ catkin_ws
5、验证自定义消息
使用以下命令验证是否成功构建自定义消息:
$ rosmsg show ros_demo_pkg/demo_msg
6、使用自定义消息
在功能包ros_demo_pkg中,创建使用该自定义消息的publisher和subscriber节点,分别为msg_pubsher.cpp和msg_subscriber.cpp,保存在该功能包的src文件夹中。其中msg_publisher.cpp的代码如下:
#include "ros/ros.h" #include "std_msgs/Int32.h" #include "ros_demo_pkg/demo_msg.h" #include <iostream> using namespace std; int main(int argc, char **argv) { //Initializing ROS node with a name of demo_topic_publisher ros::init(argc, argv,"msg_publisher"); //Created a nodehandle object ros::NodeHandle node_obj;
//Create a publisher object ros::Publisher number_publisher = node_obj.advertise<ros_demo_pkg::demo_msg>("/msg_topic",10); ros::Rate loop_rate(10); int number_count = 0; //While loop for incrementing number and publishing to topic /numbers while (ros::ok())
{ //Created a Int32 message ros_demo_pkg::demo_msg msg; //Inserted data to message header string ss="hello world "; msg.greeting = ss; msg.number = number_count;
//Printing message data ROS_INFO("%d",msg.number); ROS_INFO("%s",msg.greeting.c_str()); //Publishing the message number_publisher.publish(msg); //Spining once for doing the all operation once ros::spinOnce(); //Setting the loop rate loop_rate.sleep(); //Increamenting the count ++number_count;
} return 0; }
而msg_subscriber.cpp的代码如下:
#include "ros/ros.h" #include "ros_demo_pkg/demo_msg.h" #include <iostream> void number_callback(const ros_demo_pkg::demo_msg::ConstPtr& msg) { ROS_INFO("Recieved greeting [%s]",msg->greeting.c_str()); ROS_INFO("Recieved [%d]",msg->number); } int main(int argc, char **argv) { //Initializing ROS node with a name of demo_topic_subscriber ros::init(argc, argv,"msg_subscriber"); //Created a nodehandle object ros::NodeHandle node_obj; ros::Subscriber number_subscriber = node_obj.subscribe("/msg_topic",10,number_callback); //Spinning the node ros::spin(); return 0; }
接下来修改该功能包的CMakeList.txt文件,添加以下行:
add_executable(msg_publisher src/msg_publisher.cpp)
add_executable(msg_subscriber src/demo_msg_subscriber.cpp)
add_dependencies(msg_publisher ros_demo_pkg_generate_messages_cpp)
add_dependencies(msg_subscriber ros_demo_pkg_generate_messages_cpp)
target_link_libraries(msg_publisher ${catkin_LIBRARIES})
target_link_libraries(msg_subscriber ${catkin_LIBRARIES})
然后编译并构建该功能包,在终端分别启动roscore、自定义消息发布节点和自定义消息订阅节点:
$ roscore
$ rosrun ros_demo_pkg msg_publisher
$ rosrun ros_demo_pkg msg_subscriber
可看到发布者发布一个字符串和一个整数,订阅者节点订阅该topic并打印信息。
使用rqt_graph可查看主题msg_topic的连接关系:
7、总结
在ROS nodes中使用自定义节点包括以下几个步骤:
1. 在功能包的msg文件夹下定义消息的.msg文件;
2. 修改功能包的package.xml和CMakeList.txt文件,添加依赖项和构建信息;
3. 编译并构建功能包,生成自定义消息节点;
4. 在需要使用该自定义消息的节点代码中添加该消息头文件,如 #include “ros_demo_pkg/demo_msg.h”。