• ROS编写第一个订阅器


    在上一篇文章中,我们实现了第一个ROS程序—发布器(publisher),然而在上一篇文章的最后我们也注意到,尽管我们的程序非常小,但占据的CPU资源却非常多。

    CPU.png

    这是因为在发布器的while循环里没有执行必要的sleep操作,使得发布器一直以最高速率运行,长时间占用CPU。

    本篇文章分为以下两部分:

    1. 在发布器中加入sleep调用使发布器的频率稳定在1Hz
    2. 实现一个订阅器(Subscriber)

    1. 发布器加入sleep

    事实上,我们所需要做的只有两行工作,首先创建一个ros::Rate对象,然后在while循环里调用该对象的.sleep()函数即可。

    修改后完整的代码如下:

    #include <ros/ros.h>
    #include <std_msgs/Float64.h>
    
    int main(int argc, char **argv) {
        ros::init(argc, argv, "minimal_publisher"); // 初始化节点名
        ros::NodeHandle n; //
        
        // ++++
        ros::Rate s_timer(1.0); // 参数1.0代表发布频率即1.0Hz
        // ++++
        
        ros::Publisher my_publisher_object = n.advertise<std_msgs::Float64>("topic1", 1); // 创建一个发布器,调用advertise通知ROS Master话题名称以及话题类型
        //"topic1" 是话题名
        // 参数 "1" 是queue_size,表示缓冲区大小
        
        std_msgs::Float64 input_float; // 创建一个发布器将要使用的消息变量
        // 该消息定义在: /opt/ros/indigo/share/std_msgs
        // 在ROS中发布的消息都应该提前定义,以便订阅者接收到消息后该如何解读
    	// Float64消息的定义如下,其中包含一个数据字段data:
    	// float64 data
    	
        input_float.data = 0.0; // 设置数据字段
        
        
        // 程序所要做的工作将在下面的循环里完成
        while (ros::ok()) 
        {
            // 该循环没有sleep,因此将一直处于运行状态,不断消耗CPU资源
            input_float.data = input_float.data + 0.001; //每循环一次+0.01
            my_publisher_object.publish(input_float); // 发布消息到对应的话题
            // ++++
            s_timer.sleep(); // 在这里调用sleep函数可以让程序在这里
            // 停止一段时间以便达到要求的发布频率
            // ++++
        }
    }
    

    将修改后的发布器重新进行编译,然后按照和上篇文章一样依次运行:

    roscore
    

    再打开一个终端,运行

    rosrun my_minimal_node my_minimal_publisher # 启动发布器
    

    检查发布频率,运行

    rostopic hz /topic1
    

    sleep.png

    可以看到此时发布器的发布频率已经基本稳定在1Hz了。然后检查系统监视器的状态:

    CPU.png

    也同样可以看到此时CPU的占用率已经降下来了。

    2. 实现一个订阅器

    首先将我们提前修改好的订阅器代码复制到src目录下,代码如下:

    #include<ros/ros.h> 
    #include<std_msgs/Float64.h> 
    void myCallback(const std_msgs::Float64& message_holder) 
    { 
      // 打印出我们接收到的值
      ROS_INFO("received value is: %f",message_holder.data); 
    } 
    
    int main(int argc, char **argv) 
    { 
      ros::init(argc,argv,"minimal_subscriber"); //初始化节点
      // 节点名定义为 minimal_subscriber
      ros::NodeHandle n; // 节点句柄,用来创建订阅器
      // 订阅话题'topic1'
      // subscribe中的mycallback是回调函数,每当有新数据到来时,该函数
      // 便会被调用
      // 实际的工作是在回调函数中完成的
      
      ros::Subscriber my_subscriber_object=
          n.subscribe("topic1",1,myCallback); 
    
      ros::spin(); // 类似于 `while(1)`语句,但是当有新消息到来时,会调用回调函数
    
      return 0; 
    } 
    

    然后和上篇文章一样,为了编译我们刚写的订阅器,我们还需要修改CMakeLists.txt文件,以便让编译器知道应该编译我们新增的文件。类比上篇文章的发布器,我们在CMakeLists.txt文件中加入如下两行:

    add_executable(my_minimal_subscriber src/minimal_subscriber .cpp) # 第一个参数是生成后的可执行文件名 第二个参数
    # 是源文件路径名
    target_link_libraries(my_minimal_subscriber  ${catkin_LIBRARIES}) # 链接库
    

    打开终端,导航到工作区目录下~/catkin_ws,然后执行命令

    catkin_make
    

    等待编译完成后,依次执行命令(这些命令都是在不同的终端下输入)

    roscore
    rosrun my_minimal_node my_minimal_publisher
    rosrun my_minimal_node my_minimal_subscriber
    

    然后在订阅器的终端下就可以看出输出

    image.png

    运行命令rosnode list检查节点

    rosnode-list.png

    最后,可以运行命令

    rqt_graph
    

    来显示一个图形化的节点-话题连接图:

    rqt-graph.png

    由上面的直观展示可以看出,消息由发布器流出到话题topic1然后再流向订阅器。

    视频

    ROS编写第一个订阅器程序

    以上所有过程我录制了一个视频,在浏览文章过程中如果遇到问题,您可以查看视频来看看我是怎么做的。

  • 相关阅读:
    WebEssentials 在vs2013 update5安装报错的解决方法.
    提高代码质量系列之三:我是怎么设计函数的?
    ValueInjecter----最好用的OOM(以微信消息转对象举例)
    我的第一个python程序--给2.x的print代码加上括号
    提高代码质量系列之二:重构小技巧——if篇
    提高代码质量系列之一:尽可能少写注释.
    Two-machine debugging
    12306个人敏感信息泄露
    纯手工秒杀VM,SE等虚拟机Handle
    2014版QQ个性显IP(源码+Bin)
  • 原文地址:https://www.cnblogs.com/cporoske/p/11621423.html
Copyright © 2020-2023  润新知