ROS 学习笔记(5)—— 话题消息的定义与使用

话题消息的定义与使用

  • 1、前言
  • 2、模型
  • 3、开始自定义消息
    • 步骤一:定义 msg 文件
    • 步骤二:在 package.xml 中添加功能包依赖
    • 步骤三:在 CMakeLists.txt 添加编译选项
    • 步骤四:编写 cpp 程序
    • 步骤五:编译、运行
  • 4、小知识

1、前言

在前面两篇文章中《发布者 publisher 的编程实现》、《订阅者 subscriber 的编程实现》学习到了 publisher 与 subscriber 是如何发布和订阅消息的。但不管是 publisher 发布的 Twist 消息还是 subscriber 订阅的海龟位置 post 信息,都是在 ROS 里面已经定义好了的,我们可以直接使用。那我们在自己的开发过程当中这些 ROS 已经定义好的消息没有办法满足我们的需求时,我们就可以自己来定义消息类型。以下就是要完成消息的自定义。

2、模型

ROS 学习笔记(5)—— 话题消息的定义与使用_第1张图片

3、开始自定义消息

步骤一:定义 msg 文件

learning_topic目录下新建msg文件夹,用来存放后续的消息类文件。
ROS 学习笔记(5)—— 话题消息的定义与使用_第2张图片
进入该文件夹下并在该文件夹下打开命令行,使用touch Person.msg指令新建Person.msg文件。
ROS 学习笔记(5)—— 话题消息的定义与使用_第3张图片

打开该文件,输入以下内容并保存:

string name
uint8 sex
uint8 age

uint8 unknown = 0
uint8 male = 1
uint8 female = 2

这里写的并不是cpp,也不是python。但他在编译过程中会由ros自动编译成cpp或python。

步骤二:在 package.xml 中添加功能包依赖

打开learning_topic文件夹下的package.xml文件。

如果你的电脑安装了浏览器,xml文件可能会由浏览器默认打开,不能编辑。可以在这个目录下打开命令行,输入gedit package.xml指令打开文件。

在最下方如图所示的地方添加以下语句,并保存:

message_generation</build_depend>
message_runtime</exec_depend>

ROS 学习笔记(5)—— 话题消息的定义与使用_第4张图片

用于添加编译依赖,这里添加message_generation功能包
message_runtime功能包

步骤三:在 CMakeLists.txt 添加编译选项

打开learning_topic文件夹下的CMakeLists.txt

  1. 在最上方的find_package中添加message_generation:这一步是为了添加功能包依赖。
    ROS 学习笔记(5)—— 话题消息的定义与使用_第5张图片 -----
    -----
  2. 找到Declare ROS dynamic reconfigure parameters的位置,在上方添加如下语句:
add_message_files(FILES Person.msg)
generate_messages(DEPENDENCIES std_msgs)
  • 第一句话,告诉编译器Person.msg是我们定义的消息接口

  • 第二句话,告诉编译器在编译Person.msg文件的时候,需要依赖哪些库/包。这里我们需要依赖std_msgs,刚刚我们写的如stringuint8,就是在std_msgs中定义的。

ROS 学习笔记(5)—— 话题消息的定义与使用_第6张图片
-----

  1. 找到catkin specific configuration(即## Build ##上方),在图示位置添加以下语句(我这里比较特殊,正上方的注释掉的语句与要添加的语句一模一样,这种情况可以不添加新语句而是直接把那句话的注释解除掉)
CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim

ROS 学习笔记(5)—— 话题消息的定义与使用_第7张图片做完以上三步,保存退出。

回到工作空间的根目录catkin_ws下,打开命令行,输入指令catkin_make进行编译。

编译成功后,可以在/learning_topic/devel/include/learning_topic/路径下,找到刚刚编写的Person.msg文件已经被编译成为Person.h文件。

步骤四:编写 cpp 程序

在图示路径下建立两个cpp文件。代码如下。
ROS 学习笔记(5)—— 话题消息的定义与使用_第8张图片
person_publisher.cpp:

/**
 * 该例程将发布/person_info话题,自定义消息类型learning_topic::Person
 */
 
#include 
//!!!!!关键!!!!!
#include "learning_topic/Person.h"

int main(int argc, char **argv)
{
    // ROS节点初始化
    ros::init(argc, argv, "person_publisher");

    // 创建节点句柄
    ros::NodeHandle n;

    // 创建一个Publisher,发布名为/person_info的topic,消息类型为learning_topic::Person,队列长度10
    //!!!!!关键!!!!!
    ros::Publisher person_info_pub = n.advertise<learning_topic::Person>("/person_info", 10);

    // 设置循环的频率
    ros::Rate loop_rate(1);

    int count = 0;
    while (ros::ok())
    {
        // 初始化learning_topic::Person类型的消息
        learning_topic::Person person_msg;
        person_msg.name = "Tom";
        person_msg.age  = 18;
        person_msg.sex  = learning_topic::Person::male;

        // 发布消息
        person_info_pub.publish(person_msg);

        ROS_INFO("Publish Person Info: name:%s  age:%d  sex:%d", 
                  person_msg.name.c_str(), person_msg.age, person_msg.sex);

        // 按照循环频率延时
        loop_rate.sleep();
    }

    return 0;
}

person_subscriber.cpp:

/**
 * 该例程将订阅/person_info话题,自定义消息类型learning_topic::Person
 */
 
#include 
//!!!!!关键!!!!!
#include "learning_topic/Person.h"

// 接收到订阅的消息后,会进入消息回调函数
void personInfoCallback(const learning_topic::Person::ConstPtr& msg)
{
    // 将接收到的消息打印出来
    ROS_INFO("Subcribe Person Info: name:%s  age:%d  sex:%d", 
             msg->name.c_str(), msg->age, msg->sex);
}

int main(int argc, char **argv)
{
    // 初始化ROS节点
    ros::init(argc, argv, "person_subscriber");

    // 创建节点句柄
    ros::NodeHandle n;

    // 创建一个Subscriber,订阅名为/person_info的topic,注册回调函数personInfoCallback
    //!!!!!关键!!!!!
    ros::Subscriber person_info_sub = n.subscribe("/person_info", 10, personInfoCallback);

    // 循环等待回调函数
    ros::spin();

    return 0;
}

cpp文件编写好后,再次编写刚刚的CMakeLists.txt文件,对刚刚编写cpp内容进行配置。

找到## Install ##位置的上方,添加以下语句,保存。

说明:这里相比之前配置CMakeLists.txt,多了add_dependencies的语句目的是让可执行文件(前两句做的工作)和动态生成的文件产生依赖关系

ROS 学习笔记(5)—— 话题消息的定义与使用_第9张图片

add_executable(person_publisher src/person_publisher.cpp)
target_link_libraries(person_publisher ${catkin_LIBRARIES})
add_dependencies(person_publisher ${PROJECT_NAME}_generate_messages_cpp)

add_executable(person_subscriber src/person_subscriber.cpp)
target_link_libraries(person_subscriber ${catkin_LIBRARIES})
add_dependencies(person_subscriber ${PROJECT_NAME}_generate_messages_cpp)

步骤五:编译、运行

步骤和之前的一模一样。(如果之前修改过.bashrc文件的话就可以把source devel/setup.bash语句省略掉)

cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
rosrun learning_topic person_subscriber
rosrun learning_topic person_publisher

ROS 学习笔记(5)—— 话题消息的定义与使用_第10张图片可以看到,消息发送者 publisher 和消息接收者 subscriber 已经构建联系。

如果已经修改过环境变量,并且可以找到功能包对应的可执行文件,然而执行rosrun命令时也无法自动补全功能包名称,这个时候执行一遍rospack list命令即可。

4、小知识

ROS Master 是帮助节点的创建和链接的。节点一旦创建和链接成功后,就不再受 ROS Master 影响。

此时,如果在执行命令roscore的终端按ctrl+c退出roscore(即退出ROS Master),会发现 subscriber 和 publisher 还在照常收发数据。

除非是需要再访问 ROS Master 介入的参数时,才需要ROS Master 的参与,比如现在有第三个节点想要与这两个中的任意一个节点沟通的话,没有 ROS Master 的帮助,这个沟通是无法进行的。

你可能感兴趣的:(ROS,自动驾驶,人工智能,机器学习,ROS)