【ROS入门】使用 ROS 话题(Topic)机制实现消息发布与订阅及launch文件的封装

文章结构

  • 任务要求
  • 话题模型
  • 实现步骤
    • 创建工作空间并初始化
    • 创建功能包并添加依赖
    • 创建发布者代码(C++)
    • 创建订阅方代码(C++)
    • 配置CMakeLists.txt
    • 执行
      • 启动roscore
      • 编译
      • 启动发布和订阅节点
    • launch封装
    • 执行

任务要求

使用 ROS 话题(Topic)机制实现消息发布与订阅:

  • 创建一个发布者,每隔 100ms 依次发送斐波拉契数列的数字到话题/fibonacci 中;
  • 创建一个订阅者,订阅该话题,输出订阅结果。如,订阅者依次输出: 1 1 2 3 5 8…
  • 将发布者和订阅者分别封装成launch文件,并能成功实现上述功能

话题模型

【ROS入门】使用 ROS 话题(Topic)机制实现消息发布与订阅及launch文件的封装_第1张图片

实现步骤

创建工作空间并初始化

$ mkdir -p ROS_Topic_Demo/src
$ cd ROS_Topic_Demo
$ catkin_make

上述命令,首先会创建一个工作空间以及一个 src 子目录,然后再进入工作空间调用 catkin_make命令编译。

创建功能包并添加依赖

在工作空间的src文件夹的目录下打开终端并创建功能包

$ catkin_create_pkg ROS_Topic_Demo roscpp rospy std_msgs

创建发布者代码(C++)

如何实现一个发布者:

  • 初始化ROS节点
  • 向 ROS Master注册节点信息,包括发布的话题名和话题中的消息类型
  • 创建消息数据
  • 按照一定频率循环发布消息

在ROS_Topic_Demo下的src文件夹中创建一个cpp文件:

$ touch topic_demo_pub_c.app
/*创建一个发布者,每隔 100ms 依次发送斐波拉契数列的数字到话题/fibonacci 中*/

//1.头文件
#include "ros/ros.h"    //万能头
// #include "iostream"
#include "std_msgs/String.h"    //普通文本类型的消息

int main(int argc, char *argv[])
{
    //设置编码(其实这行在这个任务里头没啥用,只不过拿来凑行数而已,应要说的话就是能在打印的时候看的更加清楚而已)。
    setlocale(LC_ALL,"");

    //2.初始化ROS节点
    //ros::init()函数需要查看 argc 和 argv,以便执行命令行提供的任何 ROS 参数和名称重映射。
    //参数1和参数2用于传参,参数3为节点名称,需要保持名称唯一
    ros::init(argc,argv,"Publisher");   

    //3.实例化ROS节点句柄
    //节点句柄用来管理ROS相关的api资源。调用api时,经常需要使用节点句柄进行调用。
    ros::NodeHandle n;  

    //4.实例化发布者对象
    //advertise()函数用于告诉ROS需要发布的主题名称。这将调用ROS Master节点,该节点将会记录谁在发布,谁在订阅。
    //调用 advertise() 后,Master节点会通知任何试图订阅该主题名称的节点,并进行配对。
    //advertise() 返回一个发布者对象,它允许您使用该对象通过调用 publish() 在该主题上发布消息。 
    //一旦返回的 Publisher 对象的所有副本都被销毁后,该主题将自动销毁。
    //第一个参数为话题名称,第二个参数为发布消息队列缓冲区的大小。
    ros::Publisher fibonacci_pub = n.advertise<std_msgs::String>("/fibonacci",100);

    //5.组织被发布的数据,并编写逻辑发布数据
    //数据(动态组织)
    std_msgs::String msg;

    int num = 1;
    int temp = 0;

    //设置循环频率
    ros::Rate time(10);
    ros::Rate time1(1);

    time1.sleep();	//确保发布的代码比订阅的代码晚运行,保证订阅者可以完整的订阅到发布者的信息,防止漏掉一开始的信息。

    while(ros::ok())
    {
        //发布消息
        std::stringstream ss;
        ss<<num;
        msg.data = ss.str();
        fibonacci_pub.publish(msg);
        //打印发送的消息
        ROS_INFO("发送数据:%s",msg.data.c_str());
        int former = num;
        num+=temp;
        temp=former;
        //设置休眠时间
        time.sleep();
    }

    return 0;
}


创建订阅方代码(C++)

在ROS_Topic_Demo下的src文件夹中创建一个cpp文件:

$ touch topic_demo_sub_c.app
//1.头文件
#include "ros/ros.h"    
#include "std_msgs/String.h" 

//5.利用回调函数读取数据
void callBack(const std_msgs::String::ConstPtr &msg)
{
    //通过msg获取并操作订阅到的数据
    ROS_INFO("订阅到的数:%s",msg->data.c_str());
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");

    //2.初始化ROS节点
    ros::init(argc,argv,"Subscriber");

    //3.实例化ROS节点句柄
    ros::NodeHandle n;

    //4.实例化发布者对象
    ros::Subscriber fibonacci_sub = n.subscribe<std_msgs::String>("/fibonacci",100,callBack);

    //6.设置循环调用回调函数
    ros::spin();    //循环读取接收的数据,并调用回调函数处理

    return 0;
}

配置CMakeLists.txt

add_executable(topic_demo_pub_c src/topic_demo_pub_c.cpp)
add_executable(topic_demo_sub_c src/topic_demo_sub_c.cpp)

target_link_libraries(topic_demo_pub_c
  ${catkin_LIBRARIES}
)

target_link_libraries(topic_demo_sub_c
  ${catkin_LIBRARIES}
)

位置如图所示:

【ROS入门】使用 ROS 话题(Topic)机制实现消息发布与订阅及launch文件的封装_第2张图片

执行

启动roscore

$ roscore

【ROS入门】使用 ROS 话题(Topic)机制实现消息发布与订阅及launch文件的封装_第3张图片

编译

$ catkin_make

【ROS入门】使用 ROS 话题(Topic)机制实现消息发布与订阅及launch文件的封装_第4张图片

启动发布和订阅节点

$ source ./devel/setup.bash
$ rosrun rosrun topic_demo topic_demo_sub_c

再开一个终端

$ source ./devel/setup.bash
$ rosrun rosrun topic_demo topic_demo_pub_c

效果如下:

【ROS入门】使用 ROS 话题(Topic)机制实现消息发布与订阅及launch文件的封装_第5张图片

launch封装

在功能包添加 launch 文件夹,并添加 launch 文件

【ROS入门】使用 ROS 话题(Topic)机制实现消息发布与订阅及launch文件的封装_第6张图片

<launch>
    <node pkg="topic_demo" type="topic_demo_pub_c" name="Subscriber" output="screen"/>
    <node pkg="topic_demo" type="topic_demo_sub_c" name="Publisher" output="screen"/>
launch>
  • node: 包含的某个节点
  • pkg: 功能包
  • type: 被运行的节点文件
  • name: 为节点命名
  • output: 设置日志的输出目标

执行

$ roslaunch topic_demo topic_demo_launch.launch

【ROS入门】使用 ROS 话题(Topic)机制实现消息发布与订阅及launch文件的封装_第7张图片

你可能感兴趣的:(ROS,机器人)