目录

判断是否需要创建自定义消息

确认需要自定义消息

1 创建新软件包,添加依赖

2 创建消息文件

3 4 5 编辑Cmakelists.txt文件

6 编辑package.xml文件

7 编译软件包生成新定义的消息类型

检查

新消息类型在C++中的使用(发布者——订阅者话题通信)

发布者节点修改

1 引入头文件

2 将话题的消息类型改为新的消息类型

3 按照新消息包的定义,对消息内容进行修改和解析

4 5 编辑发布者所在的软件包A的Cmakelists.txt文件

6 编辑package.xml文件

7 编译使修改的内容生效 

订阅者节点修改

1 引入头文件

2 将回调函数中的消息类型改为新的消息类型

3 编辑订阅者所在的软件包B的Cmakelists.txt文件

4 编辑package.xml文件

5 编译使修改的内容生效 

发布者、订阅者cpp文件修改示例


在上一篇文章中发送的内容是std_msgs的string,但是std_msgs自带的消息格式有时候不能满足我们的需求,这时候需要依据自己的要求创建想发送的消息格式。

(在上一篇文章中有些部分进行了颜色/加粗等显示,这是为了内容对应,或者可以进行自定义内容的修改,但是由于标记的颜色过多,颜色的对应只存在当前所阅读文章中,没有做到全部对应)对于内容的注释使用文字背景颜色进行标注,同时对于修改的地方也是用文字背景颜色注明。

判断是否需要创建自定义消息

首先需要判断std_msgs自带的格式是否能够满足自己的需求

确认需要自定义消息

当确认完ROS的标准消息库无法满足我们的需求后,正式开始生成自定义消息的内容,内容可以分成下图所示。

1 创建新软件包,添加依赖

自定义的消息也是一个包,那我们就创建一个新的软件包,并添加依赖项。

catkin_create_pkg 创建的消息包名 rospy roscpp std_msgs message_generation message_runtime

可以看到除了之前的三个依赖项rospy roscpp std_msgs外,多出了message_generation message_runtime,在自定的消息包时要将这两个依赖添加进去。

2 创建消息文件

创建的消息包名再创建msg目录,在目录中创建新消息.msg文件,可以对新消息的内容进行定义,.msg文件的定义格式为 数据类型 变量名,下面创建自己的消息内容,例:

string grade

int64 star

3 4 5 编辑Cmakelists.txt文件

打开Cmakelists.txt文件确认message_generation  message_runtime已经在find_package里面包含

3 在Cmakelists.txt文件中找到add_message_files(),取消注释并将新消息.msg文件放入该部分,如果定义了多个消息文件,都可以在这块包含

4 在Cmakelists.txt文件中找到generate_messages(),去掉注释,(这一部分是表明新消息.msg文件用到的其他消息包列表),我们创建的新消息.msg文件只用到了std_msgs,所以只需要确保std_msgs在里面,如果用到了其他的消息包,将用到的消息包加进去即可

5 在Cmakelists.txt文件中找到catkin_package这一项,取消CATKIN_DEPENDS这一行的注释,并需要确保message_runtime在其中。(这一句是为了让依赖自己创建的消息包名的其他软件包可以在运行时使用新定义的消息类型)

对于Cmakelists.txt文件的编辑工作就已经结束,最后Ctrl+S保存

6 编辑package.xml文件

翻到下方的依赖项列表,确保两部分bulid_depend和exec_depend

<bulid_depend>message_generation</bulid_depend><bulid_depend>message_runtime</bulid_depend>

<exec_depend>message_generation</exec_depend><exec_depend>message_runtime</exec_depend>

两部分都有message_generation  message_runtime

Ctrl+ S保存

7 编译软件包生成新定义的消息类型

在终端进入自命名的工作空间,使用catkin_make编译,没有出现错误即编译完成

检查

最后编译完成后检查新的消息类型是否进入了ROS的消息列表,在终端执行

rosmsg show 创建的消息包名/新消息

终端输出的结果跟上面定义的新消息内容格式一样,新的消息就自定义完成了。

新消息类型在C++中的使用(发布者——订阅者话题通信)

新消息类型在C++节点的应用分为以下几步,在这里对消息包做出如下命名,方便后续的理解。发布者所在的软件包A订阅者所在的软件包B新消息软件包C


发布者节点修改

我们先对发布者节点的.cpp文件进行编辑,修改前确认新消息软件包C仍在工作空间中

1 引入头文件

#include<创建的消息包名/新消息.h>

注意最后是以.h结尾,并没有以.msg结尾

2 将话题的消息类型改为新的消息类型

将发布者/订阅者的消息类型一项改为 创建的消息包名::新消息

循环中的消息类型也要对应修改

3 按照新消息包的定义,对消息内容进行修改和解析

 

4 5 编辑发布者所在的软件包A的Cmakelists.txt文件

4 找到find_package这一块(这是编译这个软件包所要用到的依赖项),将创建的消息包名添加到这一块,这块的意思是先编译所用到的依赖项,在编译发布者节点。

5 在Cmakelists.txt文件的末尾添加依赖项add_dependencies(发布者节点名 创建的消息包名_generate_message_cpp)这块的意思为新的消息包先创建好新的消息类型,再来编译发布者节点

Ctrl+S保存

6 编辑package.xml文件

将添加到创建的消息包名添加到build和exec两部分

<bulid_depend>创建的消息包名</bulid_depend>

<exec_depend>创建的消息包名</exec_depend>

Ctrl+S保存

7 编译使修改的内容生效 

在终端进入自命名的工作空间,使用catkin_make编译,没有报错则发布者节点的修改完成。


订阅者节点修改

我们先对发布者节点的.cpp文件进行编辑,修改前确认新消息软件包C仍在工作空间中

1 引入头文件

#include<创建的消息包名/新消息.h>

注意最后是以.h结尾,并没有以.msg结尾

2 将回调函数中的消息类型改为新的消息类型

 

3 编辑订阅者所在的软件包B的Cmakelists.txt文件

 找到find_package这一块(这是编译这个软件包所要用到的依赖项),将创建的消息包名添加到这一块,这块的意思是先编译所用到的依赖项,在编译发布者节点。

5 在Cmakelists.txt文件的末尾添加依赖项add_dependencies(发布者节点名 创建的消息包名_generate_message_cpp)这块的意思为新的消息包先创建好新的消息类型,再来编译发布者节点

Ctrl+S保存

4 编辑package.xml文件

将添加到创建的消息包名添加到build和exec两部分

<bulid_depend>创建的消息包名</bulid_depend>

<exec_depend>创建的消息包名</exec_depend>

Ctrl+S保存

5 编译使修改的内容生效 

在终端进入自命名的工作空间,使用catkin_make编译,没有报错则发布者节点的修改完成。


发布者、订阅者cpp文件修改示例

下方是以上一篇文章为基础所做的修改

#include<ros/ros.h>

#include<创建的消息包名/新消息.h>

int main(int argc, char *argv[])

{

        ros::init(argc,argv,"节点1");

        //实例化句柄

        ros::NodeHandle nh;

        /*用上面实例的句柄实现发布者操作,<>内部的参数是消息类型,()里面两个参数,

        第一个是发布的话题名称,第二个是最大缓存的消息数目*/

        ros::Publisher pub = nh.advertise<创建的消息包名::新消息>("话题名",10);

        ros::Rate loop_rate(10);        //一秒发送10条消息,固定发送频率

        while(ros::ok())

        {

                创建的消息包名::新消息 msg;

                msg.name = "1";

                msg.age = 2;

                msg.height = 3;

                pub.publish(msg);

                loop_rate.sleep();       //调用sleep形成短暂堵塞,保持设置的频率输出

        }

        return 0;

}

订阅者节点的操作类似,按照上文流程逐步完成相关操作,直接给出订阅者代码示例

#include<ros/ros.h>

#include<创建的消息包名/新消息.h>

//发布者的消息类型

void hui(创建的消息包名::新消息 msg;)

{

//msg的data内容,输出需要转化为字符串类型输出

print(msg.name.c_str());

print(msg.age.c_str());

print(msg.height.c_str());

}

int main(int argc, char *argv[])

{

        ros::init(argc,argv,"节点1");

        //实例化句柄

        ros::NodeHandle nh;

        /*用上面实例的句柄实现订阅操作,()里面三个参数, 第一个是订阅的话题名称,

        第二个是最大缓存的消息数目,第三个是回调函数名,订阅操作没有指定话题类型,

        无需修改*/

        ros::Publisher sub = nh.advertise("话题名",10,回调函数名);

        //保持节点运行

        while(ros::ok())

        {

                //新来的消息包内容能够被回调函数接收

                 ros::spinOnce();

        }

        return 0;

}

之后可以在终端运行这几个节点来验证新消息发布的情况。

roscore

rosrun 包名 节点名

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐