-
Notifications
You must be signed in to change notification settings - Fork 430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prevent API gaps between Node and LifecycleNode #898
Comments
just idea, i think rclcpp_lifecycle::LifercycleNode is built on top of rclcpp::Node. so rclcpp_lifecycle::LifecycleNode Class inherits based on rclcpp::Node and featured with lifecycle interfaces. what i really care if for code maintenance. and also i cannot think of anything that is required for rclcpp::Node but not for rclcpp_lifecycle::LifercycleNode. if i am not understanding correctly, could you enlighten me what discussion should be done here? |
Currently, the
I agree, the |
I'm going to add a second issue to track just adding the currently missing APIs, and we can continue discussion on how to prevent this in the future on this issue. |
@bpwilcox @fujitatomoya @mjcarroll @Karsten1987 About the relationship of node and lifecycleNode, I think the design has been discussed in #318. So the decision tends to move lifecycle into node class. I think Lifecycle can be as feature(component) of node and enabled by node option. BTW, in order to avoid growing gap of API between libcycleNode and Node, moving should be done ASAP. |
decision's been made before, but not sure we still get along with this. @wjwwood could you share your thoughts if possible?
agree. |
I'm not sure that would be a good idea. Perhaps it could be the right approach, but part of the interface of a lifecycle node is that you do not create normal publishers but lifecycle publishers instead. Doing what you suggest doesn't remove the normal So, maybe something like this could work, but not without more thought and details as to how it would work. I don't have time to pursue that right now. |
i do not have concrete design right now, not sure which way is suitable/reasonable at this time. I would come back on this, since i do not have resource either. or somebody else takes over the consideration. |
This may be far out but....what about deriving Node from LifecycleNode? IMO LifecycleNode is a beautiful implementation and should be defacto and pushed as best-practice. Node can just provide a default transition impl for on_configure|activate|deactivate|etc and also transition itself (unless a "self_manage" parameter is explicitly false or something). I think this fits the c++ best practices of "derived classes shouldnt modify behavior much" and in fact to the external observer there is no behavior change - only internal. Benefits:
|
I came across this problem when I tried to create a library that does provide both a LifecycleNode and rclcpp::Node. I have a class (lets call it DriverInterface) that should take LifecycleNode or rclcpp::Node in the constructor and add a bunch of services, subscriptions and publishers. In this class I would like to use the normal node functions such as create publisher, create client, create_timer, ... (not node_interface provided functions, as they are not well documented and require much reimplementation and maintenance if upstream changes). This seems to be impossible right now, even templating does not really work you, just end up reimplmenting most things seperately for both node types. The current situation just makes handling Node and LifecycleNode instances with the same code a huge pain. I would be willing to create and add node_user_interface.hpp and make LifecycleNode and Node inherit from it. |
To be clear; it was an explicit design goal to not require inheritance between the two of them, to avoid the myriad problems with inheritance. Whether that is the right call is not totally clear, but we would definitely want to make sure we change/update the design if we were to go this route. That said...
This should be possible today, either by using templating (like what is done in https://github.com/ros2/message_filters/blob/rolling/include/message_filters/subscriber.h), or by using the Node interfaces instead of the node directly (like what is done in https://github.com/ros2/geometry2/blob/rolling/tf2_ros/include/tf2_ros/transform_listener.h#L119-L133). |
If the approach is to use the node interfaces, it would be super nice, if they would expose the standard functions of the node i.e. create_service, create_client, create_wall_timer etc. Which they partially do, but not completely. |
I think the difficulty in some of those (e.g. You'd call rclcpp::create_service(), passing in the node base interface and node services interfaces, I think. |
Just an update, There is now a third option aside from passing individual interfaces or templating on NodeT. (Though this only unifies any functionality that is defined within an interface, but not any of the node->XXX methods that aren't) An aggregate class that implicitly converts node-likes into a collection of aggregated interfaces has been implemented in: And can be used as such: create_service(
NodeInterfaces<NodeBaseInterface, NodeServicesInterface> node_handle,
// ...
// User calls with (or can just pass in the (non pointer) object for implicit conversion))
auto service = create_service(
NodeInterfaces<NodeBaseInterface, NodeServicesInterface>(*my_node_or_lifecycle_node_class_ptr),
// ... |
I was working on a feature using
rclcpp_lifecycle::LifecycleNode
to declare a parameter when I noticed that thedeclare_parameter
API on the lifecycle node interface does not include theignore_overrides
flag as does the version inrclcpp::Node
. It seems that in addition to this, there are a handful of functions that have yet to be implemented in the lifecycle node. From a brief comparison (I didn't check all the signatures so there could be other differences), I found these functions that are missing:get_fully_qualified_name()
declare_parameter
(missingignore_overrides
argument)add_on_set_parameters_callback(OnParametersSetCallbackType callback);
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler);
get_sub_namespace()
get_effective_namespace()
create_sub_node()
assert_liveliness()
I think some PRs to implement the above functions and close the gap on the common node API is a solution, but I also would propose a discussion on a common interface by which these nodes must abide. Apparently these APIs can go out of sync with new changes, so I'd like to hear thoughts on how to better synchronize these Node classes.
The text was updated successfully, but these errors were encountered: