ROS学习--7.写一个发布与订阅节点

1.写一个publisher节点

“节点”是连接到ROS网络的可执行文件的ROS术语。在这里,我们将创建一个发布者(“ talker”)节点,该节点将不断广播消息。

1.1 将目录更改为在catkin工作区以前的教程中创建的beginner_tutorials包:

roscd beginner_tutorials

1.2 在beginner_tutorials包目录中创建一个src目录:

mkdir -p src

该目录将包含我们beginner_tutorials包的所有源文件。

1.3 在beginner_tutorials包中创建src / talker.cpp文件,并将以下内容粘贴到其中:

// ros/ros.h是一个方便的工具,其中包括使用ROS系统最常见的公共部分所需的所有标头。
#include "ros/ros.h"

// 这包括std_msgs / String消息,该消息驻留在std_msgs包中。
// 这是从该程序包中的String.msg文件自动生成的标头。有关消息定义的更多信息,请参见msg页面。
#include "std_msgs/String.h"

#include 

/**
* 本教程演示了如何通过ROS系统简单地发送消息。
*/

//        这是下面事情的精简版:
//          初始化ROS系统
//          宣传我们将在chatter主题上向主服务器发布std_msgs / String消息
//          在将消息发布到聊天时每秒循环10次

int main(int argc, char** argv)
{
//    初始化ROS。这使ROS可以通过命令行进行名称重映射-目前尚不重要。
//    这也是我们指定节点名称的地方。节点名称在运行的系统中必须唯一。
    ros::init(argc, argv, "talker");
    
//    创建此进程的节点的句柄。创建的第一个NodeHandle实际上将对节点进行初始化,
//    而最后一个被破坏的节点将清理该节点正在使用的所有资源。
    ros::NodeHandle node_handle;
    
//    告诉管理员,我们将在主题讨论中发布std_msgs / String类型的消息。
//    这样,主服务器就可以告诉所有正在聊天的节点,我们将发布有关该主题的数据。
//    第二个参数是发布队列的大小。在这种情况下,如果我们发布得太快,
//    它将最多缓冲1000条消息,然后再开始丢弃旧消息。

//    NodeHandle :: advertise()返回一个ros :: Publisher对象,
//    该对象有两个作用:
//    1)它包含一个publish()方法,可用于将消息发布到其创建的主题上;
//    2)当它超出范围时,它将自动取消广告。
    ros::Publisher chatter_pub = node_handle.advertise("chatter", 100);

//    ros :: Rate对象允许您指定要循环播放的频率。
//    它将跟踪自上次调用Rate::sleep()以来已等待了多长时间,并睡眠了正确的时间。
//    在这种情况下,我们告诉我们要以10Hz运行。
    ros::Rate loop_rate(10);

    int count = 0;
    
//    默认情况下,roscpp将安装SIGINT处理程序,
//    该处理程序提供Ctrl-C处理,如果发生这种情况,
//    将导致ros :: ok()返回false。

//    ros :: ok()将在以下情况下返回false:
//      收到SIGINT(Ctrl-C)
//      我们已经被另一个同名节点踢出网络
//      ros :: shutdown()已由应用程序的另一部分调用。
//      所有ros :: NodeHandles已被销毁
//    一旦ros :: ok()返回false,所有ROS调用都会失败。
    while (ros::ok())
    {
//        我们使用消息自适应类在ROS上广播消息,该类通常是从msg文件生成的。
//        可能有更复杂的数据类型,但是现在我们将使用标准的String消息,
//        该消息具有一个成员:“ data”。
        std_msgs::String msg;
        std::stringstream ss;

        ss << "hello world" << count;
        msg.data = ss.str();

//        ROS_INFO可以代替printf / cout。有关更多信息,请参见rosconsole文档。
        ROS_INFO("%s", msg.data.c_str());

//        现在,我们实际上将消息广播给了已连接的任何人。
        chatter_pub.publish(msg);

//        对于这个简单的程序,不需要在此处调用ros :: spinOnce(),
//        因为我们没有收到任何回调。但是,如果您要向此应用程序添加订阅,
//        并且在此处没有ros :: spinOnce(),则将永远不会调用您的回调。
//        因此,请将其添加为良好的度量。
        ros::spinOnce();

//        现在,我们使用ros :: Rate对象休眠剩余时间,使我们达到10Hz的发布速率。
        loop_rate.sleep();
        ++count;
    }
    return 0;
}

2.写一个subscriber节点

  • 在beginner_tutorials包中创建src / listener.cpp文件,并将以下内容粘贴到其中:
// ros/ros.h是一个方便的工具,其中包括使用ROS系统最常见的公共部分所需的所有标头。
#include "ros/ros.h"

// 这包括std_msgs / String消息,该消息驻留在std_msgs包中。
// 这是从该程序包中的String.msg文件自动生成的标头。有关消息定义的更多信息,请参见msg页面。
#include "std_msgs/String.h"

/**
本教程演示了通过ROS系统简单接收消息的过程。
*/

//当在chatter主题上收到新消息时,将调用此回调函数。
// 该消息在boost shared_ptr中传递,
// 这意味着您可以根据需要将其存储起来,
// 而不必担心它下面的内容被删除,也无需复制基础数据。
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
    ROS_INFO("I heard: [%s]", msg->data.c_str());
}

//  同样,这是正在发生的事情的精简版:
//      初始化ROS系统
//      订阅聊天主题
//      旋转,等待消息到达
//      消息到达时,将调用chatterCallback()函数

int main(int argc, char** argv)
{
//    初始化ROS。这使ROS可以通过命令行进行名称重映射-目前尚不重要。
//    这也是我们指定节点名称的地方。节点名称在运行的系统中必须唯一。
    ros::init(argc, argv, "listener");
    
//    创建此进程的节点的句柄。创建的第一个NodeHandle实际上将对节点进行初始化,
//    而最后一个被破坏的节点将清理该节点正在使用的所有资源。
    ros::NodeHandle node_handle;
    
//    订阅与主机的聊天主题。每当有新消息到达时,ROS就会调用chatterCallback()函数。
//    第二个参数是队列大小,以防万一我们不能足够快地处理消息。
//    在这种情况下,如果队列达到1000条消息,我们将在新消息到达时开始丢弃旧消息。

//    NodeHandle :: subscribe()返回ros :: Subscriber对象,
//    您必须保留该对象直到要取消订阅为止。破坏Subscriber对象后,
//    它将自动取消订阅chatter主题。

//    NodeHandle :: subscribe()函数有多种版本,
//    可让您指定类成员函数,甚至可以指定Boost.Function对象可以调用的任何函数。
    ros::Subscriber sub = node_handle.subscribe("chatter", 100, chatterCallback);

//    ros :: spin()进入循环,并尽可能快地调用消息回调。
//    不过,请不要担心,如果没有什么可做的,则不会占用太多CPU。
//    一旦ros :: ok()返回false,ros :: spin()将退出,
//    这意味着ros :: shutdown()已被默认Ctrl-C处理程序,
//    主程序告诉我们关闭或被调用了手动。
    ros::spin();
    
    return 0;
}

3.编译节点

您在上一教程中使用过catkin_create_pkg,该教程为您创建了package.xml和CMakeLists.txt文件。 生成的CMakeLists.txt应该如下所示(对“创建Msgs和Srvs”教程进行了修改,并删除了未使用的注释和示例):

   1 cmake_minimum_required(VERSION 2.8.3)
   2 project(beginner_tutorials)
   3 
   4 ## Find catkin and any catkin packages
   5 find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)
   6 
   7 ## Declare ROS messages and services
   8 add_message_files(DIRECTORY msg FILES Num.msg)
   9 add_service_files(DIRECTORY srv FILES AddTwoInts.srv)
  10 
  11 ## Generate added messages and services
  12 generate_messages(DEPENDENCIES std_msgs)
  13 
  14 ## Declare a catkin package
  15 catkin_package()

不必担心修改注释的(#)示例,只需将以下几行添加到CMakeLists.txt的底部:

add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker beginner_tutorials_generate_messages_cpp)

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener beginner_tutorials_generate_messages_cpp)
  • 生成的CMakeLists.txt文件应如下所示:
   1 cmake_minimum_required(VERSION 2.8.3)
   2 project(beginner_tutorials)
   3 
   4 ## Find catkin and any catkin packages
   5 find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)
   6 
   7 ## Declare ROS messages and services
   8 add_message_files(FILES Num.msg)
   9 add_service_files(FILES AddTwoInts.srv)
  10 
  11 ## Generate added messages and services
  12 generate_messages(DEPENDENCIES std_msgs)
  13 
  14 ## Declare a catkin package
  15 catkin_package()
  16 
  17 ## Build talker and listener
  18 include_directories(include ${catkin_INCLUDE_DIRS})
  19 
  20 add_executable(talker src/talker.cpp)
  21 target_link_libraries(talker ${catkin_LIBRARIES})
  22 add_dependencies(talker beginner_tutorials_generate_messages_cpp)
  23 
  24 add_executable(listener src/listener.cpp)
  25 target_link_libraries(listener ${catkin_LIBRARIES})
  26 add_dependencies(listener beginner_tutorials_generate_messages_cpp)

这将创建两个可执行文件,talker和listener,默认情况下它们将进入开发空间的package目录,默认情况下位于〜/ catkin_ws / devel / lib /

  • 请注意,您必须将可执行目标的依赖项添加到消息生成目标:
target_link_libraries(talker ${catkin_LIBRARIES})

您可以直接调用可执行文件,也可以使用rosrun调用它们。它们没有放在' / bin'中,因为在将软件包安装到系统时,这会污染PATH。

  • 现在运行catkin_make编译:
# In your catkin workspace
cd ~/catkin_ws
catkin_make  

4.测试你的节点(两种方式)

  1. 打开三个终端分别运行:
roscore
source ~/catkin_ws/devel/setup.bash
rosrun beginer_tutorials talker
source ~/catkin_ws/devel/setup.bash
rosrun beginer_tutorials listener
  1. 打开三个终端分别运行:
roscore
~/catkin_ws/devel/lib/beginer_tutorials/talker
~/catkin_ws/devel/lib/beginer_tutorials/listener

最后结果:

你可能感兴趣的:(ROS学习--7.写一个发布与订阅节点)