ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question

Revision history [back]

Hi,

I recently came across this issue. In ROS 1, services are clearly different from action as they are synchronous. Porting code from ROS 1 to 2 usually requires service calls to keep synchronous, or induces a change in the architecture.

Here is a simple wrapper to handle this:

template <class ServiceT>
class ServiceNodeSync
{
    typedef typename ServiceT::Request RequestT;
    typedef typename ServiceT::Response ResponseT;
public:
    ServiceNodeSync(std::string name): node(std::make_shared<rclcpp::Node>(name))
    {    }

    void init(std::string service)
    {
    client = node->create_client<ServiceT>(service);
    client->wait_for_service();
    }

    ResponseT sendRequest(const RequestT &req)
    {
    return sendRequest(std::make_shared<RequestT>(req));
    }

    ResponseT sendRequest(const std::shared_ptr<RequestT> &req_ptr)
    {
    auto result = client->async_send_request(req_ptr);
    rclcpp::spin_until_future_complete(node, result);
    return *result.get();
    }

protected:
    rclcpp::Node::SharedPtr node;
    typename rclcpp::Client<ServiceT>::SharedPtr client;
};

It can be used as a member variable (say service_node_sync) of your base node Then the synchronous service call boils down to:

auto response = service_node_sync.sendRequest(request);

I guess this can be adapted for particular uses, but for now that is basically how I can teach/introduce ROS 2 services as being more or less the same as in ROS 1.