ROS編寫第一個訂閱器(Subscriber)

在上一篇文章中,咱們實現了第一個ROS程序—發佈器(publisher),然而在上一篇文章的最後咱們也注意到,儘管咱們的程序很是小,但佔據的CPU資源卻很是多。node

CPU.png

這是由於在發佈器的while循環裏沒有執行必要的sleep操做,使得發佈器一直以最高速率運行,長時間佔用CPU。c++

本篇文章分爲如下兩部分:bash

  1. 在發佈器中加入sleep調用使發佈器的頻率穩定在1Hz
  2. 實現一個訂閱器(Subscriber)

1. 發佈器加入sleep

事實上,咱們所須要作的只有兩行工做,首先建立一個ros::Rate對象,而後在while循環裏調用該對象的.sleep()函數便可。ide

修改後完整的代碼以下:函數

#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函數可讓程序在這裏
        // 中止一段時間以便達到要求的發佈頻率
        // ++++
    }
}

將修改後的發佈器從新進行編譯,而後按照和上篇文章同樣依次運行:post

roscore

再打開一個終端,運行spa

rosrun my_minimal_node my_minimal_publisher # 啓動發佈器

檢查發佈頻率,運行3d

rostopic hz /topic1

sleep.png

能夠看到此時發佈器的發佈頻率已經基本穩定在1Hz了。而後檢查系統監視器的狀態:code

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編寫第一個訂閱器程序

以上全部過程我錄製了一個視頻,在瀏覽文章過程當中若是遇到問題,您能夠查看視頻來看看我是怎麼作的。

相關文章
相關標籤/搜索