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

Posted zhangrelay

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了机器人编程趣味实践08-任务请求回复(服务)相关的知识,希望对你有一定的参考价值。

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

日常还有一类常见的应用比如,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-


 

以上是关于机器人编程趣味实践08-任务请求回复(服务)的主要内容,如果未能解决你的问题,请参考以下文章

机器人编程趣味实践05-二维图形化仿真(turtlesim)

机器人编程趣味实践04-逻辑判断(if)

机器人编程趣味实践03-运算(+ - × ÷)

机器人编程趣味实践19-武林秘籍(文档)

机器人编程趣味实践18-他山之石(功能包)

机器人编程趣味实践07-信息交互(主题)