Ask Your Question
0

Can a Node be a service and client

asked 2018-04-17 14:55:52 -0500

Priyanka gravatar image

Hello everyone,

I am new to ROS. I am trying to communicate service and client in the single Node. Is it even possible.

Code:

 bool add(beginner_tutorials::AddTwoInts::Request &req, beginner_tutorials::AddTwoInts::Response &res) 
 {
 res.sum = req.a + req.b;


 ROS_INFO("\n request: a=%ld, b=%ld", (long int)req.a, (long int)req.b);
 ROS_INFO("\n sending back response: [%ld]", (long int)res.sum);


   return true;
 }


 int main(int argc, char *argv[])
 {

ros::init(argc, argv, "serclntrtest");

ros::NodeHandle n;
beginner_tutorials::AddTwoInts srv;
srv.request.a = 3;
srv.request.b = 6;


ros::ServiceServer service = n.advertiseService("test", add);


std::cout<< "\n \n After the service \n" << std::endl;

ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("test");


if(client.call(srv))
{
    ROS_INFO("Sum: %ld", (long int)srv.response.sum);   

}
else
{
   ROS_ERROR("Failed to call service add_two_ints");
   return 1;
}

ros::spinOnce();

   return 0; 

 }

I have tried it with two different nodes, but with single node it is getting stuck at client.call() function. Could anyone please explain me how it would be done, if there a way.

Thanks in advance

edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
0

answered 2018-04-17 18:11:55 -0500

updated 2018-04-18 04:00:44 -0500

Based on your code, the request to service is processed at ros::spinOnce(), and client.call() is waiting the response from service. Then a deadlock happens and your program gets stuck at client.call() as you found.

Using two different nodes, or two processes, is the best way to implement this example because the purpose of ServiceServer is to provide service to any clients. If you still require to implement this example in a node, I would suggest you create a thread to handle either ros::spinOnce() or client.call.

#include<thread>
void spin_wrapper()
{
  ros::spin();
}
...
int main(int argc, char *argv[])
{
  ...
  //create and start a thread
  std::thread spin_thread(spin_wrapper);
  //send request
  if(client.call(srv))
  {
    ROS_INFO("Sum: %ld", (long int)srv.response.sum);   

  }
  else
  {
    ROS_ERROR("Failed to call service add_two_ints");
    return 1;
  }
  //ros::spinOnce();
}

Note that thread works since C++11 so your CMakeLists.txt file should add add_compile_options(-std=c++11) to enable the function.

Update

Thank @gvdhoorn for better solutions of multi-threaded spinners. I update the solution using ros::AsyncSpinner.

int main(int argc, char *argv[])
{
  ...
  //create and start a thread
  ros::AsyncSpinner spinner(1); // Use 1 thread
  spinner.start();
  //send request
  if(client.call(srv))
  {
    ROS_INFO("Sum: %ld", (long int)srv.response.sum);   

  }
  else
  {
    ROS_ERROR("Failed to call service add_two_ints");
    return 1;
  }
  //ros::spinOnce();
}
edit flag offensive delete link more

Comments

Thank you so much @chung for the simple solution. It is working perfectly now.

Priyanka gravatar image Priyanka  ( 2018-04-18 01:40:47 -0500 )edit
2

Using a separate thread is an option, but I believe @Priyanka could use one of the by-default supported multi-threaded spinners, such as AsyncSpinner or MultiThreadedSpinner. See wiki/roscpp/Callbacks and Spinning.

gvdhoorn gravatar image gvdhoorn  ( 2018-04-18 02:55:21 -0500 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 2018-04-17 14:55:52 -0500

Seen: 109 times

Last updated: Apr 18 '18