学习ROS的过程中,在话题的发布与订阅之间,我一直在思考,我们能不能定义自己的话题名,甚至在编写我们自己的ROS软件包时,定义我们自己的消息类型。
当然可以,在ROS中,消息的传递是通过话题、服务的方式进行的,其中很大一部分都是通过节点发布话题、订阅话题实现的。 在进行话题的订阅和发布时,其实,话题名 就是订阅者和发布者双方约定的一个暗号,(只要记住,发布者和订阅者定义成一样,剩下的事情就交给节点管理器吧)。
所以话题名,你想怎么定义就怎么定义,只要发布者和接收者双方协商好就好。只不过我们常常使用别人的ros功能软件包,所以就只好把我们的节点中的订阅者/发布者定义的话题名写成别人软件包的,不得已呀!, 当然我们要自己搞一个订阅者与我们自己的发布者进行通信,当然可以自己定义啦~
而且在launch文件中还有一个话题重映射的功能,我们可以把别人原本好好的订阅-发布的话题,从中间劈一刀,插入一个我们自己的话题,对它进行修改。
//自定义话题非常简单,想定义什么就在“×××”中写什么就行,
ros::Publisher str_pub = nh.advertise("test_topic", 10); //话题名可以自己定义
//要注意两点:
# 1、订阅和发布要对应
# 2、要想好你的话题要携带什么消息,也就是前面紧跟的消息类型
首先明确在ROS中,消息的载体是 话题,我们要真真想要传递的消息内容实际上是通过话题的发布->订阅,从而进行消息的发送和接收的。话题我们都可以自己定义,我们当然可以自己定义。
当我们使用别人的话题是,当然也要使用它的消息类型,当我们自己定义话题,大多数也是使用别人的消息类型。(因为毕竟要和别人的节点通信吗,仅仅话题一样,消息不一样哪行),所以自定义消息类型的情况比较少,但是也还是能用得到的,所以这个技能还是要会的。
1、首先在软件包目录下 新建一个 msg文件夹,并且新建一个消息类型文件
mkdir ~/roswork_space/src/hello_ros/msg
cd ~/roswork_space/src/hello_ros/msg
touch my_msg.msg
或者直接 vim ~/roswork_space/src/hello_ros/msg/my_msg.msg2、编辑你想要的消息类型
int32 A int32 B int32 C
常见的ros消息中包含的类型有
int8, int16, int32, int64 (plus uint*)
float32, float64
string
time, duration
other msg files
variable-length array[] and fixed-length array[C]
Header(包含一个timestamp和坐标系信息)3、编辑软件包下的CMakeLists.txt文件
find_package(catkin REQUIRED COMPONENTS
message_generation roscpp geometry_msgsadd_message_files(FILES my_msg.msg) //根据自己的消息写
generate_messages(DEPENDENCIES
std_msgs)catkin_package(
CATKIN_DEPENDS
message_runtime
)
4、编辑package.xml文件
message_generation
message_generation
message_runtime
编译 后检查
rosmsg show hello_ros/my_msg
int32 A
int32 B
int32 C
自定义话题的实例 发布&订阅
#include "ros/ros.h"
#include "std_msgs/String.h" // for std_msgs::String message
#include
//for stringstream对象 int main(int argc, char *argv[])
{
ros::init(argc, argv, “pub_string_node”);
ros::NodeHandle nh;
ros::Publisher str_pub = nh.advertise(“string_msg“, 1000); //话题名可以自己定义,
ros::Rate rate_loop(10);
while (ros::ok())
{
std_msgs::String str_msg; //消息不可以随便定义
std::stringstream ss;
ss << “I am s test stream”;
str_msg.data = ss.str();
//ROS_INFO(“I send (%s)”, str_msg.data.c_str());
ROS_INFO(“I send (%s)”, str_msg.data.c_str());
str_pub.publish(str_msg);
ros::spinOnce();
rate_loop.sleep();
}
return 0;
}
#include "ros/ros.h"
#include "std_msgs/String.h"
void messageCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO(“I heard: [%s]”, msg->data.c_str());
}int main(int argc, char **argv)
{
ros::init(argc, argv, “sub_string_node”);
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe(“string_msg“, 10, messageCallback);
ros::spin(); //一直授权订阅
return 0;
}
自定义消息类型,自己发布&订阅
#include "ros/ros.h"
#include "hello_ros/test_msg.h" //虽然是test_msg.msg,这里却是.h
int main(int argc, char *argv[])
{
ros::init(argc, argv, “pub_num_node”);
ros::NodeHandle nh;
ros::Publisher num_pub = nh.advertise(“add_num_msg”, 10); //话题名可以自己定义,hello_ros::test_msg num; //定义消息
ros::Rate rate_loop(10);
while (ros::ok())
{
static int i;
i++;
num.A = i;
num.B = i;
num.C = i;
num_pub.publish(num);
ros::spinOnce();
rate_loop.sleep();
}
return 0;
}
#include "ros/ros.h"
#include "hello_ros/test_msg.h" //虽然是test_msg.msg,这里却是.h
void messageCallback(const hello_ros::test_msg::ConstPtr& msg)
{
ROS_INFO(“I heard: A=%d,B=%d,C=%d sum=[%d]”,msg->A,msg->B,msg->C,msg->A+msg->B+msg->C);
//这里只做求和,表示简单的处理
}int main(int argc, char **argv)
{
ros::init(argc, argv, “sub_num_node”);
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe(“add_num_msg”, 10, messageCallback);
ros::spin(); //一直授权订阅
return 0;
}
注意,自定义消息的时候,要添加test_msg.msg文件,并且修改CMakeLists.txt和package.xml