ROS学习(基于Ubuntu 15.04 和ROS Jade)第三章 ROS核心教程 之 11 编写简单的消息发布器和订阅器 (C++)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jrc_january/article/details/76473764

http://blog.csdn.net/shiyue0010/article/details/51925295

这里介绍了学习ROS的一些方法和资料。


http://blog.csdn.net/wengge987/article/details/50826217 单个master
http://www.cnblogs.com/shhu1993/p/6021396.html 多个master


引言

本节将使用C++编写两个ROS节点,它们分别是发布器和订阅器。

1. 发布器节点

节点(node)是指ROS网络中的可执行文件。下面我们创建一个名为“talker”的发布器节点,用来广播消息。
切换到beginner_tutorials package的路径下:

$ roscd beginner_titorials

在src目录下创建talker.cpp的文件:

$ cd src/
$ vi talker.cpp

1.1 源代码

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>

int main(int argc, char **argv)
{
  ros::init(argc, argv, "talker");
  ros::NodeHandle n;
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
  ros::Rate loop_rate(10);
  int count = 0;

  while (ros::ok())
  {
    std_msgs::String msg;

    ss << "hello world " << count;

    ROS_INFO("%s", msg.data.c_str());

    chatter_pub.publish(msg);

    loop_rate.sleep();

    ++count;
  }
  return 0;
}

1.2 代码解释

这个教程演示了简单地通过ROS系统发送消息。

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>

ros.h 引用了大部分ROS系统中常用的头文件。std_msgs/string.h是由std_msgs package中的String.msg消息文件自动生成的头文件。


 ros::init(argc, argv, "talker");

ros::init()函数必须在任何ROS函数之前执行,因为它要检查由命令行提供的argc和argv参数。
它的第三个参数是节点的名称在一个ROS网络中,这个名称是唯一的


  ros::NodeHandle n;

句柄(handle)是资源编号,任何可以唯一标识一个对象的东西都可以说是句柄。
nodehandle是与ROS系统通信的主要接入点。第一个创建的nodehandle将完全初始化该节点,最后一个销毁的nodehandle将销毁该节点占用的资源。


  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

advertise()成员的作用是通知ROS Master(roscore启动的主节点)本节点将向哪一个主题发布消息,ROS Master保存了正在发布和正在订阅消息的节点注册信息。在该调用完成后,主节点将通知任何订阅该主题的节点。
该成员函数返回一个publisher对象,该对象用于在注册的主题上发布消息。
advertise()成员的第二个参数指定了消息缓冲大小,一旦发布的消息过快,前面的消息将被丢弃。

扫描二维码关注公众号,回复: 3055888 查看本文章

  ros::Rate loop_rate(10);

ros::Rate 对象可以允许你指定自循环的频率。它会追踪记录自上一次调用 Rate::sleep() 后时间的流逝,并休眠直到一个频率周期的时间。


  int count = 0;

count是一个计数器,用于记录一共发送了多少条消息。这个值将用于创建唯一的消息字符串。


  while (ros::ok())

roscpp 会默认生成一个 SIGINT 句柄(这里指信号处理函数),它负责处理 Ctrl-C 键盘操作——使得 ros::ok() 返回 false。一旦 ros::ok() 返回 false, 所有的 ROS 调用都会失效。

如果下列条件之一发生,ros::ok() 返回false:

  • SIGINT 被触发 (Ctrl-C)
  • 被另一同名节点踢出 ROS 网络
  • ros::shutdown() 被程序的另一部分调用
  • 节点中的所有 ros::NodeHandles 都已经被销毁

std_msgs::String msg;           //创建消息
std::stringstream ss;           //创建stringstream对象。
ss << "hello world " << count;      //合成消息。
msg.data = ss.str();            //填充消息的数据成员。stringstream::str()成员函数返回一个string对象。

创建消息对象,并填充消息。std_msgs::String 消息只有一个数据成员data类型是string。


ROS_INFO("%s", msg.data.c_str());

ROS_INFO()提供了在terminal中显示消息的功能,它类似printf函数,第二个参数接收char *.
ROS_DEBUG()提供了在rqt_consloe中显示消息的功能,需要在rqt_console中选择level等级为DEBUG及以上的级别。


chatter_pub.publish(msg);

ROS::publisher::publish()用于发送消息,它的参数是一个消息对象。消息对象的类型必须与advertise<>中的类型一致。


ros::spinOnce();

这里可以不用调用spinOnce().因为我们不接受回调。如果使用回调函数,则必须加上这一句,使得自循环一次,不然回调函数永远都不会执行。


loop_rate.sleep();

休眠,这里是配合ROS::Rate对象实现发布频率为10Hz的。

2. 编写订阅器节点

同样的在beginner_tutorials/src目录下创建listener.cpp文件。

2.1 源代码

#include "ros/ros.h"
#include "std_msgs/String.h"

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");

  ros::NodeHandle n;

  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

  ros::spin();

  return 0;
}

2.2 代码说明

下面我们逐条解释,在发布器节点代码中重复的就不。

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}

这是一个回调函数,当接收到chatter话题的时候就会被调用。消息以boost shared_ptr指针的形式传输,这意味着你可以存储它而又不需要复制数据。


ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

通过nodehandle::subscribe成员函数来告知master我们要订阅chatter话题上的消息。当消息发布到这个话题上时,ROS就会调用chatterCallback()函数。其第一个参数是订阅的topic,第二个参数是缓存数量。


ros::spin();

ros::spin()进入自循环,可以尽可能快的调用消息回调函数。如果没有消息到达,他不会占用很多CPU,所以不用担心。
一旦 ros::ok() 返回 false,ros::spin() 就会立刻跳出自循环。这有可能是 ros::shutdown() 被调用,或者是用户按下了 Ctrl-C,使得 master 告诉节点要终止运行。也有可能是节点被人为关闭的。

3. 编译节点

3.1 修改CMakeLists.txt文件

之前通过catkin_create_pkg创建了package.xml和CMakeLists.txt文件。现在我们要修改CMakeLists.txt文件,添加以下内容:

 ## Build talker and listener
include_directories(include ${catkin_INCLUDE_DIRS})

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)

add_dependencies()可以确保自定义消息的头文件在被使用之前已经被生成。因为 catkin 把所有的 package 并行的编译,所以如果你要使用其他 catkin 工作空间中其他 package 的消息,你同样也需要添加对他们各自生成的消息文件的依赖。

3.2 编译

# In your catkin workspace
$ catkin_make  

这样,会生成两个可执行文件,talker和listener,默认存储到devel space目录下,具体在~/catkin_ws/devel/lib/package_name中.

3.3 运行

可以直接调用可执行文件,也可以使用rosrun来调用它们。

猜你喜欢

转载自blog.csdn.net/jrc_january/article/details/76473764