机器人编程趣味实践08-任务请求回复(服务)ROS 2服务-services-

举报
zhangrelay 发表于 2021/07/15 00:11:55 2021/07/15
【摘要】 上一节的主题,适用于机器人的传感器数据传输,通信一般为单项,定义某个节点发送或者接受。 日常还有一类常见的应用比如,A:今天天气怎么样,B:今天温度20度,有小雨。 有求有答,节点分为服务器端和客户端,基础补充参考如下链接: ROS 2服务-services- 背景知识 服务是ROS图中节点通信的另一种方法。 服务基于调用响应模型,而不是主题的发布者-订阅者模型...

上一节的主题,适用于机器人的传感器数据传输,通信一般为单项,定义某个节点发送或者接受。

日常还有一类常见的应用比如,A:今天天气怎么样,B:今天温度20度,有小雨。

有求有答,节点分为服务器端和客户端,基础补充参考如下链接:

背景知识

服务是ROS图中节点通信的另一种方法。

  1. 服务基于调用响应模型,而不是主题的发布者-订阅者模型。
  2. 主题允许节点订阅数据流并获得连续更新,但是服务仅在客户端专门调用它们时才提供数据。

上述是主题和服务的典型区别。引用ROS2Wiki的图示如下:

一对一模式-一个服务端和一个客户端

一对多模式-一个服务器端和多个客户端

预备知识

在此之前,要掌握前七讲的内容哦,当然还是以二维机器人为例吧。

掌握代码编写和机器人编程,不推荐安装功能包方式,推荐源代码编译方式。

实践任务

1 开启

开启机器人节点,之前轨迹不全,修改如下代码:

path_image_(888, 666, QImage::Format_ARGB32)
 

分别在两个终端运行:

  1. ros2 run turtlesim turtlesim_node
       
  2. ros2 run turtlesim turtle_teleop_key
       

2 服务列表

再新开第三个窗口,输入 ros2 service list ,将会出现如下内容:

  1. /teleop_turtle
  2. /turtle1
  3. /turtlesim

这里,本文重点看如下这些个服务。

/clear, /kill, /reset, /spawn, /turtle1/set_pen, /turtle1/teleport_absolute, 和 /turtle1/teleport_relative

3 服务消息类型

主题用主题消息通信,服务用服务消息通信。

  • .msg
  • .srv

主题位置案例Pose.msg


      float32 x
      float32 y
      float32 theta
      float32 linear_velocity
      float32 angular_velocity
  
 

服务添加机器人案例Spawn.srv


      float32 x
      float32 y
      float32 theta
      string name
      ---
      string name
  
 

典型使用方式如下:

  • ros2 service type <service_name>
       

  • ros2 service type /clear
       
  • std_srvs/srv/Empty
    
       

响应服务,但不会返回消息。

列表详情

ros2 service list -t

4 服务查找

ros2 service find <type_name>

 

如std_srvs/srv/Empty

ros2 service find std_srvs/srv/Empty
 

5 服务接口类型显示

命令如下:

  • ros2 interface show <type_name>.srv
    
       

这里以spawn.srv为例:

  • ros2 interface show turtlesim/srv/Spawn
       

等到如下显示:

使用---区分调用和应答的消息类型。

6 服务调用

通用命令格式:

  • ros2 service call <service_name> <service_type> <arguments>
       

机器人遍历一周:

调用如下服务,清除轨迹:

  • ros2 service call /clear std_srvs/srv/Empty
       

那些往事,转眼成空……

然后,再用扩展机器人,向环境中添加机器人:

  • ros2 service call /spawn turtlesim/srv/Spawn "{x: 2, y: 2, theta: 0.2, name: 'robot1'}"
  • ros2 service call /spawn turtlesim/srv/Spawn "{x: 4, y: 2, theta: 0.4, name: 'robot2'}"
  • ros2 service call /spawn turtlesim/srv/Spawn "{x: 6, y: 2, theta: 0.6, name: 'robot3'}"
  • ros2 service call /spawn turtlesim/srv/Spawn "{x: 8, y: 2, theta: 0.8, name: 'robot4'}"
  • ros2 service call /spawn turtlesim/srv/Spawn "{x: 10, y: 2, theta: 1.0, name: 'robot5'}"

调用服务生成新机器人。

响应并生成了对应robot1-5。

然后,服务就爆炸了:

小结

节点可以使用ROS 2中的服务进行通信。与主题不同(这种方式是节点发布一个或多个订阅者可以获取信息的一种通信方式),服务则是一种请求/响应方式,其中客户端向节点发出请求。 服务器端提供服务,并且该服务处理请求并生成响应。 通常,不希望将服务用于连续通信(理解为机器人任务获取); 主题甚至行动将更适合连续通信模式。 在本教程中,使用了命令行工具来识别,详细说明和调用服务。

节点-主题-服务示意

服务程序代码示例:

新建


        clear_srv_ = nh_->create_service<std_srvs::srv::Empty>("clear", std::bind(&TurtleFrame::clearCallback, this, std::placeholders::_1, std::placeholders::_2));
        reset_srv_ = nh_->create_service<std_srvs::srv::Empty>("reset", std::bind(&TurtleFrame::resetCallback, this, std::placeholders::_1, std::placeholders::_2));
        spawn_srv_ = nh_->create_service<turtlesim::srv::Spawn>("spawn", std::bind(&TurtleFrame::spawnCallback, this, std::placeholders::_1, std::placeholders::_2));
        kill_srv_ = nh_->create_service<turtlesim::srv::Kill>("kill", std::bind(&TurtleFrame::killCallback, this, std::placeholders::_1, std::placeholders::_2));
  
 

实现


      bool TurtleFrame::spawnCallback(const turtlesim::srv::Spawn::Request::SharedPtr req, turtlesim::srv::Spawn::Response::SharedPtr res)
      {
       std::string name = spawnTurtle(req->name, req->x, req->y, req->theta);
       if (name.empty())
        {
       RCLCPP_ERROR(nh_->get_logger(), "A turtle named [%s] already exists", req->name.c_str());
      return false;
        }
        res->name = name;
       return true;
      }
  
 

      void TurtleFrame::clear()
      {
       // make all pixels fully transparent
        path_image_.fill(qRgba(255, 255, 255, 0));
        update();
      }
  
 

二维界面显示机器人


      bool TurtleFrame::hasTurtle(const std::string& name)
      {
       return turtles_.find(name) != turtles_.end();
      }
      std::string TurtleFrame::spawnTurtle(const std::string& name, float x, float y, float angle)
      {
       return spawnTurtle(name, x, y, angle, rand() % turtle_images_.size());
      }
      std::string TurtleFrame::spawnTurtle(const std::string& name, float x, float y, float angle, size_t index)
      {
       std::string real_name = name;
       if (real_name.empty())
        {
      do
       {
      std::stringstream ss;
       ss << "turtle" << ++id_counter_;
       real_name = ss.str();
       } while (hasTurtle(real_name));
        }
       else
        {
      if (hasTurtle(real_name))
       {
      return "";
       }
        }
        TurtlePtr t = std::make_shared<Turtle>(nh_, real_name, turtle_images_[static_cast<int>(index)], QPointF(x, height_in_meters_ - y), angle);
        turtles_[real_name] = t;
        update();
        RCLCPP_INFO(nh_->get_logger(), "Spawning turtle [%s] at x=[%f], y=[%f], theta=[%f]", real_name.c_str(), x, y, angle);
       return real_name;
      }
  
 

-End-


 

文章来源: zhangrelay.blog.csdn.net,作者:zhangrelay,版权归原作者所有,如需转载,请联系作者。

原文链接:zhangrelay.blog.csdn.net/article/details/117064499

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。