ROS2探索总结(三)——小试牛刀

  • 内容
  • 评论
  • 相关

        看了之前ROS2的框架设计,是不是对ROS2产生了很多好奇。相比ROS1,ROS2中融入了很多新的东西,但是很多核心的概念并没有改变。
 
一、ROS中的Graph

        还记不记得ROS1中Graph的几个概念?(可以出门左转复习《ROS探索总结(二)——ROS总体框架》)节点、消息、主题、服务,在ROS2里边又新加入了一个发现(Discovery)的概念。节点、消息、主题、服务这几个概念这里就不赘述了,在ROS2和ROS1里是相同的,我们来看一下什么叫Discovery。

        我们从前边的框架中已经看到了,ROS2里是没有master的,那么节点之间是怎么知道彼此存在的呢?这就全靠一种自动发现的机制——Discovery。什么意思呢?简单来说,当一个节点启动后,首先在网络中发条广播,大声告诉这个世界我来了(忽然想到三体里人类向宇宙发送广播,招来了外星人。。。),其他节点听到之后,也纷纷反馈各自的信息,这样一来二去也就联系上了。当然,万一哪个节点掉线了怎们办?没关系,每个节点都会周期性的发布广播,告诉其他节点他还在线,就算要下线,他也会广播告诉其他节点他要走了,下次再聊。
 
二、小试牛刀

        看了这么多概念,一时不一定消化得了,让我们小试牛刀,加强一下印象。从哪里下手呢?还记不记得ROS wiki上最初的talker and listener,ROS2还是继续从这里出发。

        1. 安装ROS2

        说了这么多,我们好像还没有安装ROS2吧,那就看一下怎么安装。

        目前ROS2还处于开发阶段,提供两种安装方法:二进制包和源码编译。我们还是偷偷懒,直接使用编译好的二进制包。打开网站https://github.com/ros2/ros2/releases,找到最新发布的ROS版本,目前最新版是Beta1,看看下载列表,是不是很激动的可以看到linux、osx、windows三个版本的二进制包,支持的平台确实比ROS1多了吧。不过我们还是从熟悉的Linux环境开始,需要Ubuntu16.04,从列表中下载ros2-beta1-package-linux-fastrtps.tar.bz2

Image[8]

          然后我们回到系统的终端,先来安装一些依赖包:

  1. sudo apt-get update && sudo apt-get install -q -y \
  2.     libopencv-core2.4v5 \
  3.     libhighgui2.4 \
  4.     libopencv-imgproc2.4v5 \
  5.     wget

         接着,解压刚才下载的ros2-beta1-package-linux-fastrtps.tar.bz2到你需要的目录下。进入文件夹,你应该可以看到如下图所示的一些文件。

Image(1)[8]

        有没有点熟悉,没错,和ROS1的目录结构几乎一致。

          2. 设置环境变量

        由于我们下载的是已经编译好的二进制包,不需要编译安装的过程(包括里边的示例代码,talker和listener都已经是编译好的),直接就可以使用了。当然运行前还是要设置一下环境变量(每个终端都需要,或者直接在.bashrc文件里添加):

  1. source setup.bash

3. 执行程序

         好啦,终于到最激动人心的运行程序啦,在两个终端中分别执行talkerlistener命令(也许会出现某些错误,不用担心,使用apt-get install统统可以解决),一切顺利的话,你就可以看到如下的界面了:

Image[8]
         久违的感觉了,有没有!两个节点成功连接上,而且并没有master的参与,这就是“神奇”的Discovery机制。
 
三、源码剖析

        运行完程序了,是不是有点想看源码,还是老规矩,我们来解析一下ROS2中的talker和listener到底有什么不同。talker和listener的源码在:https://github.com/ros2/tutorials

        1. talker

  1. #include <iostream>
  2. #include <memory>
  3.  
  4. #include "rclcpp/rclcpp.hpp"
  5. #include "std_msgs/msg/string.hpp"
  6.  
  7. int main(int argc, char * argv[])
  8. {
  9.   //ros::init(argc, argv, "talker");
  10.   rclcpp::init(argc, argv);
  11.  
  12.   //ros::NodeHandle n;
  13.   auto node = rclcpp::node::Node::make_shared("talker");
  14.  
  15.   rmw_qos_profile_t custom_qos_profile = rmw_qos_profile_default;
  16.   custom_qos_profile.depth = 7;
  17.  
  18.   //ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
  19.   auto chatter_pub = node->create_publisher<std_msgs::msg::String>("chatter", custom_qos_profile);
  20.  
  21.   //ros::Rate loop_rate(10);
  22.   rclcpp::WallRate loop_rate(2);
  23.  
  24.   auto msg = std::make_shared<std_msgs::msg::String>();
  25.   auto i = 1;
  26.  
  27.   //while (ros::ok())
  28.   while (rclcpp::ok()) {
  29.     msg->data = "Hello World: " + std::to_string(i++);
  30.     std::cout << "Publishing: '" << msg->data << "'" << std::endl;
  31.  
  32.     //chatter_pub.publish(msg);
  33.     chatter_pub->publish(msg);
  34.  
  35.     //ros::spinOnce();
  36.     rclcpp::spin_some(node);
  37.  
  38.     //loop_rate.sleep();
  39.     loop_rate.sleep();
  40.   }
  41.  
  42.   return 0;
  43. }
 

        2. listener

  1. #include <iostream>
  2. #include <memory>
  3.  
  4. #include "rclcpp/rclcpp.hpp"
  5. #include "std_msgs/msg/string.hpp"
  6.  
  7. //void chatterCallback(const std_msgs::String::ConstPtr& msg)
  8. void chatterCallback(const std_msgs::msg::String::SharedPtr msg)
  9. {
  10.   std::cout << "I heard: [" << msg->data << "]" << std::endl;
  11. }
  12.  
  13. int main(int argc, char * argv[])
  14. {
  15.   //ros::init(argc, argv, "listener");
  16.   rclcpp::init(argc, argv);
  17.  
  18.   //ros::NodeHandle n;
  19.   auto node = rclcpp::Node::make_shared("listener");
  20.  
  21.   //ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
  22.   auto sub = node->create_subscription<std_msgs::msg::String>(
  23.     "chatter", chatterCallback, rmw_qos_profile_default);
  24.  
  25.   //ros::spin();
  26.   rclcpp::spin(node);
  27.  
  28.   return 0;
  29. }

       我在每句的代码上用注释标注了对应于ROS1中的代码,便于大家比较。仔细阅读上边的代码,我们可以从以下几点做出对比分析:

1. ROS2中的API相比ROS1中发生了较大的变化,这和ROS2设计文档中描述的一致,ROS2并不是在ROS1的基础上查漏补缺,而是完全从新设计。关于ROS2的API说明,可以参考API文档:http://docs.ros2.org/beta1/api/rclcpp/index.html

2. 使用了更多C++的特性,比如auto、make_shared等。

3. 加入了QoS配置,从上边的代码中,我们可以看到QoS有默认的配置rmw_qos_profile_default ,而且talker将QoS的depth配置设置为7

4. 代码的总体架构还是与ROS1极为相似的。

参考资料:

Overview of ROS 2 concepts : https://github.com/ros2/ros2/wiki/Overview-of-ROS-2-concepts

C++ ROS Client Library API:http://docs.ros2.org/beta1/api/rclcpp/index.html


原创文章,转载请注明: 转载自古月居

本文链接地址: ROS2探索总结(三)——小试牛刀

微信 OR 支付宝 扫描二维码
为本文作者 打个赏
pay_weixinpay_weixin

评论

2条评论
  1. Gravatar 头像

    liufanghua 回复

    这里下载的ROS2安装包带了DDS么?运行的例程是否需要DDS的支持?

发表评论

电子邮件地址不会被公开。 必填项已用*标注