RobotecAI / ros2cs

A C# (.Net) implementation of ros2 client library (rcl), enabling communication between ros2 ecosystem and C#/.Net applications such as Unity3D
Apache License 2.0
91 stars 22 forks source link

Implement ROS2 actions #60

Open RobertoRoos opened 11 months ago

RobertoRoos commented 11 months ago

Title says it all: it would be cool to support ROS2 actions.

Potentially duplicates https://github.com/RobotecAI/ros2-for-unity/issues/48

I'm currently trying to write this, PR will hopefully follow.

An overview on how the different APIs look so far:

Langague Publisher Service Action
Python ```python from std_msgs.msg import String self.create_publisher(String, 'topic', 10) ``` ```python from example_interfaces.srv import AddTwoInts self.create_service(AddTwoInts, 'add_two_ints', self.add_two_ints_callback) ``` ```python from action_tutorials_interfaces.action import Fibonacci ActionServer( self, Fibonacci, 'fibonacci', self.execute_callback) ```
C++ ```cpp #include "std_msgs/msg/string.hpp" this->create_publisher("topic", 10); ``` ```cpp #include "example_interfaces/srv/add_two_ints.hpp" this->create_service("add_two_ints", &add); ``` ```cpp #include "action_tutorials_interfaces/action/fibonacci.hpp" rclcpp_action::create_server( this, "fibonacci", std::bind(&FibonacciActionServer::handle_goal, this, _1, _2), std::bind(&FibonacciActionServer::handle_cancel, this, _1), std::bind(&FibonacciActionServer::handle_accepted, this, _1)); ```
C# ```C# using std_msgs.msg; node.CreatePublisher("chatter"); ``` ```C# using example_interfaces.srv; node.CreateService("add_two_ints", recv_callback); ``` Missing
RobertoRoos commented 11 months ago

I'm first looking at building the interface generator for actions.

Is there some way to quickly test the generator? I am currently running colcon build --packages-select rosidl_generator_cs example_interfaces ... all the time to test the generated code, but it's quite slow.

RobertoRoos commented 11 months ago

Since actions are really two Services and a Publisher (link), another big question is where to 'split'' it. We could define an action from the ground up, or try to define it through Services etc. as soon as possible.

Thoughts?

EDIT: See the table in the original comment - the templating is not entirely consistent. Python and C++ use the main Service type as a single template, whereas our C# version splits the request and the response. For the new action, should be stick to a single template (like Python and C++) or split each message (like C# so far)?

Deric-W commented 11 months ago

Since I contributed to the service implementation I can share some thoughts: I think the splitting into multiple messages is necessary since the different pieces of information like goal, feedback and result each require a class to represent them.

The splitting of Services (but not Actions since they just use normal subscriptions and services) into independent messages is probably a little bit dangerous since it allows using the messages with publishers and subscriptions which I am not sure the rcl C library likes. I tried refactoring it but failed to find detailed documentation on how the ROS type support system and the C type support (which is used by the C# one) work, if you found some I would be thankful if you could send me a link. My plan was to generate type support classes alongside the messages which would be required for creating publishers, subscriptions and so on, preventing them from being used for different purposes since there would be no matching type support available.

RobertoRoos commented 11 months ago

I think the splitting into multiple messages is necessary since the different pieces of information like goal, feedback and result each require a class to represent them.

Right. Python for example does rely on a single Service and Action object, which includes (references to) the request/response and goal/feedback/result messages. Couldn't we also easily create containers for the underlying objects? The gain would be some convenience for application code.

I tried refactoring it but failed to find detailed documentation on how the ROS type support system and the C type support (which is used by the C# one) work, if you found some I would be thankful if you could send me a link. My plan was to generate type support classes alongside the messages which would be required for creating publishers, subscriptions and so on, preventing them from being used for different purposes since there would be no matching type support available.

Myeah, for sure I haven't found out more than you. All of this feels rather undocumented indeed.

Are we using the C/C++ code generation that already exists in ROS2 literally?

Deric-W commented 11 months ago

Yes, to prevent having to implement a type support for every supported DDS implementation the C# type support is more or less just a wrapper around the C type support (the Python type support does this too I think).

RobertoRoos commented 11 months ago

Right. Do you know why there are also {msg,srv,idl}_c.em templates then? I was wandering if I'd also need for the Actions.

Deric-W commented 11 months ago

They are used to provide convenient getter, setter and memory management code which we can call from C# to prevent having to redefine every generated C struct in C#.