ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange |
1 | initial version |
We need a node that can subscribe to a topic and call a service request from another node at any given time. I couldn't find any solutions (probably because it is a relatively simple concept)... but I think there should be some documentation for other people stuck with the same problem.
The problem we were having: Most of the service request examples have the service request being called from inside the main function. When we tried to do this, we were only able to request a service once and then the node would be caught in a spin loop. To avoid this error, we decided to move the service request into the subscriber callback function. This way it would be called whenever the subscriber heard a message.
The basic idea: The client is instantiated in the main function, but it needs to be used in the callback function. I made a ros::ServiceClient pointer at a global level (w.r.t. the node) and then gave it the address of the client. In the callback function I dereference the client pointer and use it to request a service.
void SUBSCRIBE_CALLBACK_FUNCTION (const PACKAGE_NAME::MESSAGE_NAME::ConstPtr& msg);
ros::ServiceClient *clientPtr; //pointer for a client
int main (int argc, char **argv)
{
ros::init(argc, argv, "MY_NODE");
ros::NodeHandle n;
ros::ServiceClient client = n.serviceClient<PACKAGE_NAME::SERVICE_NAME>("SERVICE_NAME"); //create the client
clientPtr = &client; //give the address of the client to the clientPtr
ros::Subscriber sub = n.subscribe<PACKAGE_NAME::MESSAGE_NAME>("TOPIC_NAME",1000,SUBSCRIBE_CALLBACK_FUNCTION); //subscribing
ros::spin();
return 0;
}
void SUBSCRIBE_CALLBACK_FUNCTION (const PACKAGE_NAME::MESSAGE_NAME::ConstPtr& msg)
{
PACKAGE_NAME::SERVICE_NAME srv;
srv.request.someBool= false; //just some variables to give the service some structure.
srv.request.someFloat = 4;
srv.request.someFloat = 30;
ros::ServiceClient client = (ros::ServiceClient)*clientPtr; //dereference the clientPtr
if(client.call(srv)) //request service from the client
{
ROS_INFO("Success = %d", srv.response.success);
}
else
{
ROS_ERROR("Failed to call service from motor_control_node");
}
}
2 | No.2 Revision |
Short answer: Yes. A node can be a subscriber and a client at the same time.
We need needed a node that can could subscribe to a topic and call a service request from another node at any given time. I couldn't find any solutions (probably because it is a relatively simple concept)... but I think there should be some documentation for other people stuck with the same problem.
The problem we were having: Most of the service request examples have the service request being called from inside the main function. When we tried to do this, we were only able to request a service once and then the node would be caught in a spin loop. To avoid this error, we decided to move the service request into the subscriber callback function. This way it would be called whenever the subscriber heard a message.
The basic idea: The client is instantiated in the main function, but it needs to be used in the callback function. I made a ros::ServiceClient pointer at a global level (w.r.t. the node) and then gave it the address of the client. In the callback function I dereference the client pointer and use it to request a service.
void SUBSCRIBE_CALLBACK_FUNCTION (const PACKAGE_NAME::MESSAGE_NAME::ConstPtr& msg);
ros::ServiceClient *clientPtr; //pointer for a client
int main (int argc, char **argv)
{
ros::init(argc, argv, "MY_NODE");
ros::NodeHandle n;
ros::ServiceClient client = n.serviceClient<PACKAGE_NAME::SERVICE_NAME>("SERVICE_NAME"); //create the client
clientPtr = &client; //give the address of the client to the clientPtr
ros::Subscriber sub = n.subscribe<PACKAGE_NAME::MESSAGE_NAME>("TOPIC_NAME",1000,SUBSCRIBE_CALLBACK_FUNCTION); //subscribing
ros::spin();
return 0;
}
void SUBSCRIBE_CALLBACK_FUNCTION (const PACKAGE_NAME::MESSAGE_NAME::ConstPtr& msg)
{
PACKAGE_NAME::SERVICE_NAME srv;
srv.request.someBool= false; //just some variables to give the service some structure.
srv.request.someFloat = 4;
srv.request.someFloat = 30;
ros::ServiceClient client = (ros::ServiceClient)*clientPtr; //dereference the clientPtr
if(client.call(srv)) //request service from the client
{
ROS_INFO("Success = %d", srv.response.success);
}
else
{
ROS_ERROR("Failed to call service from motor_control_node");
}
}
3 | No.3 Revision |
Short answer: Yes. A node can be a subscriber and a client at the same time.
We needed a node that could subscribe to a topic and call a service request from another node at any given time. I couldn't find any solutions (probably because it is a relatively simple concept)... but I think there should be some documentation for other people stuck with the same problem.
The problem we were having: Most of the service request examples have the service request being called from inside the main function. When we tried to do this, we were only able to request a service once and then the node would be caught in a spin loop. To avoid this error, we decided to move the service request into the subscriber callback function. This way it would be called whenever the subscriber heard a message.
The basic idea: The client is instantiated in the main function, but it needs to be used in the callback function. I made a ros::ServiceClient pointer at a global level (w.r.t. the node) and then gave it the address of the client. In the callback function I dereference the client pointer and use it to request a service.
void SUBSCRIBE_CALLBACK_FUNCTION (const PACKAGE_NAME::MESSAGE_NAME::ConstPtr& msg);
ros::ServiceClient *clientPtr; //pointer for a client
int main (int argc, char **argv)
{
ros::init(argc, argv, "MY_NODE");
ros::NodeHandle n;
ros::ServiceClient client = n.serviceClient<PACKAGE_NAME::SERVICE_NAME>("SERVICE_NAME"); //create the client
clientPtr = &client; //give the address of the client to the clientPtr
ros::Subscriber sub = n.subscribe<PACKAGE_NAME::MESSAGE_NAME>("TOPIC_NAME",1000,SUBSCRIBE_CALLBACK_FUNCTION); //subscribing
ros::spin();
return 0;
}
void SUBSCRIBE_CALLBACK_FUNCTION (const PACKAGE_NAME::MESSAGE_NAME::ConstPtr& msg)
{
PACKAGE_NAME::SERVICE_NAME srv;
srv.request.someBool= false; //just some variables to give the service some structure.
srv.request.someFloat = 4;
srv.request.someFloat = 30;
ros::ServiceClient client = (ros::ServiceClient)*clientPtr; //dereference the clientPtr
if(client.call(srv)) //request service from the client
{
ROS_INFO("Success = %d", srv.response.success);
}
else
{
ROS_ERROR("Failed to call service from motor_control_node");
}
}