wiki链接: http://wiki.ros.org/roscpp/Overview/Services
1、服务的定义,请求消息和响应消息
ROS服务被srv文件定义,包含一个request消息和一个response消息.这与ros话题的消息的使用相同.roscpp将这些srv文件转化为c++代码,并且创建三个类分别是:服务类,请求类,响应类.
这些类的名字直接由srv文件名得来.
m_package/srv/Foo.srv ->
m_package::Foo
m_package::Foo::Request
m_package::Foo::Response
生成的结构:
namespace my_package
{
struct Foo //服务结构体
{
class Request //请求类
{
...
};
class Response //响应类
{
...
};
Request request;
Response response;
};
}
Request类提供了服务的输入,Response类返回给客户端服务的输出.
由两种方式调用服务
A.使用整体结构,将一个服务看作一个整体.
my_package::Foo foo;
foo.request.<var> = <value>;
...
<call>(foo);
B.使用分别的请求和响应对象
my_package::Foo::Request req;
my_package::Foo::Response res;
req.<var> = <value>;
...
<call>(req, res);
2.调用服务,主要使用ServiceClient类
相关链接:ros::service::call() API 调用服务 : http://docs.ros.org/api/roscpp/html/namespaceros_1_1service.html
ros::NodeHandle::serviceCLient() API 返回一个服务客户端: http://docs.ros.org/api/roscpp/html/classros_1_1NodeHandle.html
ros::ServiceClient API ServiceClient类: http://docs.ros.org/api/roscpp/html/classros_1_1ServiceClient.html
有两种方式调用一个服务:
A.直接使用命名空间sevice的call函数
ros::service命名空间提供了一个call方法.不需要创建一个NodeHandle;ros::service命名空间也提供了其它方法.
/remember that ros::init(...) must have been called
my_package::Foo foo;
...
if (ros::service::call("my_service_name", foo))
{
...
}
B.句柄方式
使用NodeHandle类对象创建一个ServiceClient类对象,然后调用该类对象的call方法
ros::ServiceClient client = nh.serviceClient<my_package::Foo>("my_service_name");
my_package::Foo foo;
...
if (client.call(foo))
{
...
}
持久的连接
ROS支持对一个service的持久连接,通过持久连接,一个客户端保持对服务的连接.
否则,一个客户端通常是每次对一个服务搜寻并重复连接.这允许客户端每次调用服务时,连接不同的节点.
持久连接的使用要小心,这显著提高了反复请求的性能,但同时也使得客户端对于服务失败更加脆弱.
使用持久连接的客户端自己要实现重连接的逻辑,以防持久连接的失败.
对ros::NodeHandle::serviceClient()方法的第二个参数设置为true将创建一个持久连接.
使用if(client){}来测试连接是否失败,使用ros::ServiceClient::shutdown()方法关闭连接.
3.提供服务,主要使用ServiceServer类
相关链接:
ros::NodeHandle::advertiseService() API返回一个ServiceServer对象: http://docs.ros.org/api/roscpp/html/classros_1_1NodeHandle.html
ros::ServiceServer API: http://docs.ros.org/api/roscpp/html/classros_1_1ServiceServer.html
在roscpp客户端库下,使用NodeHandle的advertiseService()方法创建一个ServiceServer对象来提供服务.
advertiseService()方法和subscribe()消息订阅方法类似,需要提供一个服务名,以及服务处理回调函数.
1)可选项
advertiseService()方法有不同的重载版本,基本原型如下:
template<class MReq, class MRes>
ros::ServiceServer nh.advertiseService(const std::string& service, <callback>);
参数说明:
MReq[可选],请求消息类型模版参数
MRes[可选],响应消息的类型模版参数
service ,服务名
<callback>,请求到达时的回调函数
2)回调函数原型
bool callback(MReq& request, MRes& response);
参数表明了请求消息的类型和响应消息的类型,函数返回true表示服务成功,reponse对象的相应数据项会被填充.
函数返回false表明服务调用失败,响应消息的对象将不会被送到服务调用者.
3)回调函数的类型
a.一般函数
bool callback(std_srvs::Empty::Request& request, std_srvs::Empty::Response& response)
{
//处理服务
return true;
}
ros::ServiceServer service = nh.advertiseService("my_service", callback);
b.类成员方法
bool Foo::callback(std_srvs::Empty::Request& request, std_srvs::Empty::Response& response)
{
//处理服务
return true;
}
Foo foo_object;
ros::ServiceServer service = nh.advertiseService("my_service", &Foo::callback, &foo_object);
c.仿函数对象
同消息回调函数相似,对于服务来说,其回调函数也可以使用仿函数.
class Foo
{
public:
bool operator()(std_srvs::Empty::Request& request, std_srvs::Empty::Response& response)
{
//处理服务
return true;
}
};
ros::ServiceServer srv = nh.advertiseService<std_srvs::Empty::Request, std_srvs::Empty::Response>("my_service", Foo());
4.服务连接头
当两个节点之间通过话题或服务连接时,服务连接头允许发送额外的元数据信息.
ROS使用这些headers来传递如连接的客户端callerid这样的基本信息.