Robot Programming Fun practice 08 - task request reply (service)

Posted by cmason22 on Fri, 11 Feb 2022 22:07:08 +0100

The topic in the previous section is applicable to the sensor data transmission of robots. The communication is generally a single item, which defines the sending or receiving of a node.

For example, A: what's the weather like today, B: today's temperature is 20 degrees and there is light rain.

The nodes are divided into server-side and client-side. The basic supplementary reference is as follows:

background knowledge

Service is another method of node communication in ROS diagram.

  1. The service is based on the invocation response model, not the publisher subscriber model of the topic.
  2. Topics allow nodes to subscribe to data streams and get continuous updates, but services provide data only when clients specifically call them.

The above are typical differences between themes and services. The illustration of referencing ROS2Wiki is as follows:

One to one mode the first mock exam server and one client.

One to many mode - one server and multiple clients

Preparatory knowledge

Before that, you should master the contents of the first seven lectures. Of course, take the two-dimensional robot as an example.

Master code writing and robot programming. It is not recommended to install the function package, but to compile the source code.

Practical tasks

1 on

When the robot node is started, the previous track is incomplete, and the following code is modified:

path_image_(888, 666, QImage::Format_ARGB32)

Run on two terminals respectively:

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

2 service list

Open the third window and enter ros2 service list. The following contents will appear:

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

Here, this article focuses on the following services.

/clear, /kill, /reset, /spawn, /turtle1/set_pen, /turtle1/teleport_absolute, and / turnle1 / Report_ relative

3 service message type

Topics communicate with topic messages, and services communicate with service messages.

  • .msg
  • .srv

Subject location case pose msg

float32 x
float32 y
float32 theta

float32 linear_velocity
float32 angular_velocity

Add a robot case to the service: spawn srv

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

Typical usage is as follows:

  • ros2 service type <service_name>

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

Responds to the service, but does not return a message.

List details

ros2 service list -t

4 service search

ros2 service find <type_name>

Such as std_srvs/srv/Empty

ros2 service find std_srvs/srv/Empty

5 service interface type display

The command is as follows:

  • ros2 interface show <type_name>.srv
    

Here with spawn SRV as an example:

  • ros2 interface show turtlesim/srv/Spawn

Wait until the following appears:

Use --- to distinguish the message types of call and reply.

6 service call

General command format:

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

Robot traverses a week:

Call the following services to clear the track:

  • ros2 service call /clear std_srvs/srv/Empty

Those past events are empty in the twinkling of an eye

Then, use the extended robot to add robots to the environment:

  • 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'}"

Call the service to generate a new robot.

Response and generate corresponding robots 1-5.

Then the service exploded:

Summary

Nodes can communicate using the services in ROS 2. Different from the topic (this mode is a communication mode in which the node publishes one or more subscribers to obtain information), the service is a request / response mode, in which the client sends a request to the node. The server provides a service, and the service processes the request and generates a response. Generally, it is not desirable to use services for continuous communication (understood as robot task acquisition); Topics and even actions will be more suitable for continuous communication mode. In this tutorial, command line tools are used to identify, specify and invoke services.

Node topic service diagram

Service program code example:

newly build

  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));

realization

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();
}

Two dimensional interface display robot

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-