ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

Client doesn't return when declared inside c++ class in ROS 2

asked 2019-12-19 20:05:30 -0500

JGramsch gravatar image

updated 2019-12-24 17:00:30 -0500

Hi, I need to declare a client inside my class so I can access various services within this class' execution, but everytime I use the client I'm stuck waiting for a response(specifically waiting for "resp.wait()" function) . I've use this exact same methods but outside a class declaration in another node to call services and it has worked. My code is as follows:

#include "rclcpp/rclcpp.hpp"
#include "cstm_msg/srv/mov_loc.hpp"
class ModuloCentral: public rclcpp::Node
{
public:
  ModuloCentral() : Node("modulo_central")
  {
      mov_loc_client = this->create_client<cstm_msg::srv::MovLoc>("mov_localiz");
      while (!mov_loc_client->wait_for_service(1s)) {
          if (!rclcpp::ok()) {
              RCLCPP_ERROR(rclcpp::get_logger("modulo_central"), "Interrupted while waiting .");
              exit(0);
       }
          RCLCPP_INFO(rclcpp::get_logger("modulo_central"), "service not available, waiting again...");
      }
  }

  cstm_msg::srv::MovLoc::Response::SharedPtr move_robot(RobPos pos)
  {
      auto request = std::make_shared<cstm_msg::srv::MovLoc::Request>();
      for (size_t i = 0; i < 8; i++)
      {
           request->pose[i] = pos[i];
      }
      auto resp = mov_loc_client->async_send_request(request);
      printf("esperando respuesta de mov\n");
      resp.wait();
      printf("results are in! \n");
      return resp.get();
  }
private:
  void start()
  {
      auto r = move_robot(posQR1);
  }
   rclcpp::Client<cstm_msg::srv::MovLoc>::SharedPtr mov_loc_client;

};
int main(int argc, char * argv[])
{
   rclcpp::init(argc, argv);
   rclcpp::spin(std::make_shared<ModuloCentral>());
   rclcpp::shutdown();
   return 0;
}

I know my server works as I've tested them it with other clients (not written inside a class) and with "ros2 service call" in the terminal getting a proper response each time. I know the request is processed by the server when I call it like this but after that the response still doesn't reach this node. Finally to call the function start I've tried putting a timer in the constructor with the function as a callback, call it in the at the end of the constructor method, and calling it with a subscription. It doesn't seem to change the outcome. I haven't been able to find any examples of a client defined within a class has anyone else here tried it? please help :(

ps. my code isn't exactly like this but this are the parts regarding clients

update 1: I've tried using other clients on other classes (nodes) and the reaction is exactly the same (service is being executed but no answer comes back)

update 2: I've tried calling start like this:

from within the constructor:

  ModuloCentral() : Node("modulo_central")
  {
    /.../ 
    start()
  }

As a callback to a ROS timer:

  ModuloCentral() : Node("modulo_central")
  {
      /.../ 
      timer_ = create_wall_timer(
      500ms, std::bind(&ModuloCentral::start, this));
  }
 /.../
 private:
    rclcpp::TimerBase::SharedPtr timer_;

And as a callback to a subscriber:

  ModuloCentral() : Node("modulo_central")
  {
      subscription_ = this->create_subscription<std_msgs::msg::Bool>(
      "start_central", 10, std::bind(&ModuloCentral::start_callback, this, _1));
  }
  void start_callback(const std_msgs::msg::String::SharedPtr msg)
  {
     start();
  }

update 3: Acording to the answer my client and start callback where in the same mutually exclusive callback group. So to solve this I declared a new mutually exclusive callback group where I added all my clients (I only want to call one service at a time) then I added the node to a multi threaded executor and spin the executor. The final code ended up ... (more)

edit retag flag offensive close merge delete

Comments

Can you also share how you are spinning the node? The problem looks to me that there's no executor spinning the node while you wait on the future and therefore the response callback has no opportunity to run.

jdlangs gravatar image jdlangs  ( 2019-12-20 23:17:30 -0500 )edit

Hey thanks for the answer. I've added my main function in which I spin the node. doing it this way still allows me to receive subscription messages without problem

JGramsch gravatar image JGramsch  ( 2019-12-21 19:37:08 -0500 )edit

How is start() being run?

jdlangs gravatar image jdlangs  ( 2019-12-22 00:04:05 -0500 )edit

I added the three ways I've tried to run start, on all of them I get to the same point.

JGramsch gravatar image JGramsch  ( 2019-12-22 10:51:48 -0500 )edit

1 Answer

Sort by ยป oldest newest most voted
1

answered 2019-12-22 21:53:07 -0500

jdlangs gravatar image

So the problem is in all three methods there's no executor spinning while move_robot is running and you're waiting on the future value. Spinning is required because the service response is just another message coming in on a topic and so a subscription callback (internal to the service client) must be run to receive it.

In the first method, you're still in the node constructor so the spin function hasn't been called yet. In the second and third ones you're running move_robot from inside another callback and the executor won't return to spinning until that callback returns.

It is possible to have multiple callbacks run simultaneously (so the service response can arrive while you wait in another callback) but it's a bit complicated. You have to manually create a MultiThreadedExecutor and use it for spinning. You also have to either create separate callback groups or create a reentrant callback group since the default callback group setting is to be mutually exclusive and only allow one callback to run at a time.

edit flag offensive delete link more

Comments

Is there a different way to run a start() method? I'll try what you said.

JGramsch gravatar image JGramsch  ( 2019-12-22 22:39:01 -0500 )edit

Hey so I tired what you said and it worked! I updated the question to reflect this

JGramsch gravatar image JGramsch  ( 2019-12-24 06:32:14 -0500 )edit

Question Tools

1 follower

Stats

Asked: 2019-12-19 19:58:01 -0500

Seen: 1,074 times

Last updated: Dec 24 '19