首先,如果我们需要传输自定义消息的话,需要建立一系列的准备文件。我是直接修改的经典教程中的beginner_tutorials中的talker.cpp和listen.cpp文件,因此,均是在beginner_tutorials这个package的文件夹下进行的。
建立msg文件夹
cd catkin_ws/src/beginner_tutorials/
mkdir msg
在msg文件夹中新建一个t_d_m.msg文件,这个文件就是用来传输消息的。官方一点说,msg文件是ROS中定义消息类型的文件,一般放置在功能包根目录下的msg文件夹中,在功能包编译的过程中,可以使用msg文件生成不同编程语言使用的代码文件。
直接打开t_d_m.msg文件,复制粘贴
std_msgs/Header header
string name
int32 sex
int32 age
这些就是我们自定义的消息类型了。其中的std_msgs/Header header是一个标准格式的头信息(也可以不加),具体含义比较简单,可以自行百度。
修改这两个东西,是为了我们能够顺利地编译,比如要传递消息的话,就应该把消息的包包括进去,还有说明一下你的消息文件是什么等。
具体而言,对于package.xml,添加
message_generation
message_generation
message_runtime
对于CMakeList.txt需要修改的地方较多,分别为:
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
## Generate messages in the 'msg' folder
add_message_files(
FILES
t_d_m.msg
)
generate_messages(
DEPENDENCIES
std_msgs
)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES beginner_tutorials
# CATKIN_DEPENDS roscpp rospy std_msgs
# DEPENDS system_lib
CATKIN_DEPENDS message_runtime
)
talker.cpp
#include"ros/ros.h"
#include"std_msgs/String.h"
#include"beginner_tutorials/t_d_m.h"
#include
#include
int main(int argc, char** argv)
{
ros::init(argc, argv, "talker"); // 节点名称
ros::NodeHandle n;
// 话题topic的名称
ros::Publisher chatter_pub = n.advertise("chatter", 1000);
ros::Rate loop_rate(10);
int count = 0;
std::string name("Allison");
int age = 12;
int sex = 1;
while( ros::ok() )
{
beginner_tutorials::t_d_m msg;
msg.header.seq = count;
msg.header.stamp = ros::Time::now();
msg.header.frame_id = "t_d_m";
msg.sex = sex;
msg.age = age;
msg.name = name;
ROS_INFO("Publish/\n");
ROS_INFO("Header/\n");
ROS_INFO(" seq [%d]\n", msg.header.seq);
ROS_INFO(" frame_id [%s]\n", msg.header.frame_id.c_str() );
ROS_INFO(" name [%s]\n", msg.name.c_str() );
ROS_INFO(" sex [%d]\n", msg.sex);
ROS_INFO(" age [%d]\n", msg.age);
chatter_pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
++count;
}
return 0;
}
listener.cpp
#include "ros/ros.h"
#include "std_msgs/String.h"
void chatterCalllback(const beginner_tutorials::t_d_m msg)
{
ROS_INFO("Header/\n");
ROS_INFO(" seq [%d]\n", msg.header.seq);
ROS_INFO(" frame_id [%s]\n", msg.header.frame_id.c_str() );
ROS_INFO(" name [%s]\n", msg.name.c_str() );
ROS_INFO(" sex [%d]\n", msg.sex);
ROS_INFO(" age [%d]\n", msg.age);
}
int main(int argc, char** argv)
{
ros::init(argc, argv, "listener");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe( "chatter", 1000, chatterCalllback );
ros::spin();
return 0;
}
解释一下,
1: 我们并没有建立beginner_tutorials/t_d_m.h文件,却仍然可以将它包含进来,这个文件是在编译过程中由CMakeList自行生成的,不包含会报错的。
2:对于下面这句话
ros::Publisher chatter_pub = n.advertise("chatter", 1000);
两个<>中间填写的就是我们的自定义消息类型了,即为beginner_tutorials::t_d_m,简单理解为一个自己定义的结构体
3:在编写程序的过程中,可能会出现莫名其妙的红线报错,但是最终可以编译通过,我也搞不懂,程序写的有没有问题,至少还是编译一下看看吧
cd catkin_ws/
catkin_make
roscore
rosrun beginner_tutorials talker
可以看到在发布消息
在talker运行的同时,再打开一个终端,运行
rosrun beginner_tutorials listener
可以看到程序收到了我们发布的自定义消息
注意一定要同时打开,否则接受者是接受不到消息的,因为没有人发布消息,我在这里卡了好久,还是自己太笨了。
1:ROS 发布和订阅自定义消息数组
2:ROS消息传递——自定义消息
3:package文件夹的解读
4:ROS中订阅(Subscribe)最新消息以及对消息队列的浅谈