ROS学习之 cpp服务


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这样的基本信息.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值