ROS与C++入门教程-服务
ROS与C++入门教程-服务
说明:
- 介绍服务及使用
服务定义、请求消息和响应消息
- 查阅消息定义
- ROS服务由SRV文件中定义,其中包含一个请求消息和响应消息。
- 这些都是用与ROS的话题信息相同
- roscpp将这些SRV文件转化为C++源代码和创建三个类,你需要熟悉:服务的定义,请求消息和响应消息。
- 这些类别的名称直接来自SRV文件名:
my_package/srv/Foo.srv →
my_package::Foo
my_package::Foo::Request
my_package::Foo::Response
生成的结构:
- roscpp服务生成器生成结构类似:
namespace my_package
{
struct Foo
{
class Request
{
...
};
class Response
{
...
};
Request request;
Response response;
};
}
- Request类提供作为输入到服务,Response类提供作为服务的输出
创建服务的请求/反馈
- 任何服务调用的方法两个版本:
- 一个Foo struct:
my_package::Foo foo;
foo.request.<var> = <value>;
...
<call>(foo);
- 一个独立对象:
my_package::Foo::Request req;
my_package::Foo::Response res;
req.<var> = <value>;
...
<call>(req, res);
调用服务
查阅API:
两种方法调用服务:handle方法或bare方法
Bare 方法:
- 为了方便,ros::service命名空间提供call函数,不需要创建NodeHandle来使用
- 示例代码:
//remember that ros::init(...) must have been called
my_package::Foo foo;
...
if (ros::service::call("my_service_name", foo))
{
...
}
- ros::service命名空间同样提供一些便利的函数如:exists() 和waitForService()
- 查阅ros::service namespace API docs获取更多信息。
- Handle 方法:
- Handle方法返回ros::ServiceClient对象,用于调用服务
- 示例代码:
ros::ServiceClient client = nh.serviceClient<my_package::Foo>("my_service_name");
my_package::Foo foo;
...
if (client.call(foo))
{
...
}
- ros::ServiceClient同样提供便利的函数,如: exists() 和waitForExistence().
- 查阅ros::ServiceClient API docs
持久连接
- ROS也支持服务的持久连接,在这种模式下,客户端能长期连接到服务端。
- 否则客户端会每次执行查找和重连到服务端。
- 这可能允许客户端每次访问服务调用时连接到一个不同的节点,假设查找返回一个不同的节点。
- 持久连接应小心使用。它们大大提高了重复请求的性能,但也使您的客户对服务故障更加脆弱。
- 如果持久连接失败,使用持久连接的客户端应该实现自己的重新连接逻辑。
- 可以使用可选的第二个参数创建持久连接
- ros::NodeHandle::serviceClient():
ros::ServiceClient client = nh.serviceClient<my_package::Foo>("my_service_name", true);
- 注意:使用持久性服务,您可以通过测试句柄来判断连接是否失败:
if (client)
{
...
}
- ros::ServiceClient句柄引用内部的计数,他们可以被复制,一旦最后的副本销毁,持久连接也会结束。
- 也可以通过ros::ServiceClient::shutdown()手工关闭。
提供服务
查阅API:
在roscpp,通过ros::NodeHandle::advertiseService()来创建ros::ServiceServer。 advertiseService() 工作方式类似 subscribe() 函数,提供一个服务名和回调函数。
(1)可选项
- 针对不同回调函数,有不同版本的advertiseService(),一般形式为:
template<class MReq, class MRes>
ros::ServiceServer nh.advertiseService(const std::string& service, <callback>);
- 函数说明:
- MReq [通常不需要] ,模板参数,指定请求类型。多数不需要定义。
- MRes [通常不需要] ,模板参数,指定反馈类型。多数不需要定义。
- service,服务名称,
,回调函数,当请求收到,调用处理请求的函数。
(2)回调函数的返回值:
- 示例:
bool callback(MReq& request, MRes& response);
- Req和MRes匹配提供给advertiseService()的request/response类型
- 返回值为True代表服务成功,response会有相应的数据。
- 返回值为false代表调用失败,response不会返回。
(3)回调函数类型
- roscpp 使用任何支持boost::function的回调函数类型:
- functions(函数)
- class methods(类方法)
- functor objects (包括boost::bind)
(4)函数作为回调函数
- 示例:
bool callback(std_srvs::Empty::Request& request, std_srvs::Empty::Response& response)
{
return true;
}
ros::ServiceServer service = nh.advertiseService("my_service", callback);
类方法作为回调函数
- 示例:
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);
函数对象作为回调函数
- 函数对象是一个类,用operator()来声明的。
- 示例:
class Foo
{
public:
bool operator()(std_srvs::Empty::Request& request, std_srvs::Empty::Response& response)
{
return true;
}
};
- functor 传递给advertiseService()必需是复制的。
- Foo可用于advertiseService() 例如:
ros::ServiceServer srv = nh.advertiseService<std_srvs::Empty::Request, std_srvs::Empty::Response>("my_service", Foo());
- 注意:当使用函数对象必须显式指定请求和响应类型作为模板参数,因为在这种情况下,编译器无法推断出他们。
服务连接的头信息
- 连接头是ROS主题和ROS服务的一个特性,它可以在两个节点之间进行初始连接时发送额外的元数据。
- ROS使用头信息来传递基本信息,例如连接上的客户端的callerid
- 在服务端,这个功能可以定制,实现先进的功能,如“session”(即cookie)。
- 服务客户端可以发送自己的附加元数据,例如与请求关联的标识符。
- 在客户端,你能传递std::map<std::string, std::string>到ros::NodeHandle::serviceClient()作为第三个参数
std::map<std::string, std::string> header;
header["val1"] = "val";
header["val2"] = "val";
ros::ServiceClient client = nh.serviceClient<my_package::Foo>("my_service_name", false, header);
获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号