ROS2 C++ Generic Action / Service Client

Hello, I’m trying to make a generic C++ application for controlling ROS robots. The idea is to allow design of GUIs in a higher-level language (QML) without requiring modifying the C++ when integrating new ROS systems.

So far I’ve been using the generic subscription from rosbag2_transport along with introspection via ros2_introspection, which has worked great for topic data.

However, now I’d like to do the same for calling services and actions. From looking at the code, it looks like a writing a “GenericClient” for services would mean creating a new subclass of rclcpp::ClientBase and instantiating it with the relevant typesupport handle. Similarly for actions with rclcpp_action::ClientBase. Or perhaps I am misreading it, and using the ClientBase classes directly would suffice.

Is developing this functionality on any current roadmap, or has anybody attempted this before?

Thanks for your question. However we ask that you please ask questions on http://answers.ros.org following our support guidelines: http://wiki.ros.org/Support

ROS Discourse is for news and general interest discussions. ROS Answers provides a Q&A site which can be filtered by tags to make sure the relevant people can find and/or answer the question, and not overload everyone with hundreds of posts.

I think this doesn’t count as a Q&A, as there is an answer to this yet.
I think there is a lot possible design concepts that could be discussed.

No one is planning to do this as far as I know. It sounds like what you proposed might work, but without digging into it, I’d have a hard time saying one way or the other.

This (interacting with unknown types at runtime) is an area that we need to improve on still in the core API, in my opinion. But it is not on any immediate road map that I’m aware of.

1 Like

I managed to cobble together a generic service client, following in the footsteps of the rosbag2 generic subscription and ros2_introspection.

The principles are the same, just using the service type support instead of the message type support. One oddity I did find is that I had to use an rmw-specific typesupport library (rosidl_typesupport_fastrtps_cpp) to get the service typesupport for a given type, which wasn’t necessary for messages.

Agreed - being a bit of a ROS2 novice I was disappointed to find that I needed to duplicate the(de)serialization method used in the specific rmw implementation I was using in order to get usable data out of a SerializedMessage. It feels like something that should be possible without coupling my application to a specific rmw implementation.

It occurs to me that there is another approach to solve the problem of writing generic C++ applications that work with message / service types not known until runtime. That is to follow the path of SOSS and use generated code which is compiled to plugins that are loaded at runtime. As far as I can tell the key advantage of that route is you don’t have to mess around with the sort of serialisation routines I mentioned above, and should be fully insulated from the rmw. But I don’t know if using using SOSS as a library for an existing application one of its intended uses, rather than as a standalone gateway.

1 Like

Hello,
this is an old topic, but i am currently still looking for a solution for a generic service client (i don’t need a generic server, only client). Apparently @rokel_race created a solution for this, but i am not sure that it is released somewhere. Maybe someone else has solved this in the meantime and published a working implementation of a generic service client for rclcpp?

Some additional context on the problem:
Since the last message in this topic, the Node::create_generic_subscription function was integrated from rosbag2 into the rclcpp library, which is great. However, either i don’t understand how to use it for services, or a generic service is still missing from rclcpp.
I believe that the service message types can be generically converted between YAML and ROS 2 types via the osrf/dynamic_type_introspection library, just like for topic messages. What is explicitly missing though, is the service equivalent to the generic pub/sub, e.g. this part:

        subscription_ = this->node_handle_->create_generic_subscription(
            topic_name_,
            topic_type_,
            qos,
            [this](std::shared_ptr<const rclcpp::SerializedMessage> message)
            {
                this->process_message(message);
            }
        );