-
Notifications
You must be signed in to change notification settings - Fork 79
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
Autostarting lifecycle nodes and example launch file demo #430
base: rolling
Are you sure you want to change the base?
Conversation
@mjcarroll can I get a review on this now that we're back from the holidays? :-) |
That would be amazing to have this part of the standard launch! |
@mjcarroll can I request a review? ❤️ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few questions, but looking pretty good. Thanks for the contribution!
@wjwwood I addressed all of your comments and made a fix by your review requests |
I sent a few responses, resolved a few others. Sorry it took so long to reply, I'll try to be quicker on the next iteration. Thanks again! |
I appreciate it, I know this isn't the most active project in the ROS core ecosystem, so I appreciate the attention here :-) I think I've completed all of the tasks that need to be addressed |
Sorry, one more iteration on the matchers. |
See updated comment :-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks really close
I continued our conversation on the other thread, and pointed out a potential issue with how autostart is being typed and documented. Other than that, it's mostly cleanup requests after your most recent set of changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, after re-reviewing the new class you recently added I found some more things that should be looked into.
launch_ros/launch_ros/descriptions/composable_lifecycle_node.py
Outdated
Show resolved
Hide resolved
launch_ros/launch_ros/descriptions/composable_lifecycle_node.py
Outdated
Show resolved
Hide resolved
launch_ros/launch_ros/descriptions/composable_lifecycle_node.py
Outdated
Show resolved
Hide resolved
launch_ros/launch_ros/descriptions/composable_lifecycle_node.py
Outdated
Show resolved
Hide resolved
@wjwwood all of your comments have been addressed, I believe fully now. I see I must have missed a DCO sign off on my commits, but I really don't want to mess with the git commit history bc I know that'll cause you more trouble re-reviewing not knowing what exactly I just changed. As the CEO of my own company, I trust that I can just say I give myself permissions to do this. I can also fix DCO after you review and approve if you like. I just don't want to make your life hard. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Had a few non-blocking questions, but I think this is good to go with passing CI.
@@ -51,8 +50,19 @@ def __init__( | |||
|
|||
If matcher is given, the other conditions are not considered. | |||
""" | |||
if not isinstance(target_lifecycle_node, (LifecycleNode, type(None))): | |||
raise RuntimeError("OnStateTransition requires a 'LifecycleNode' action as the target") | |||
lifecycle_property = type(target_lifecycle_node).__dict__.get('is_lifecycle_node', None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious, but is getattr(target_lifecycle_node, 'is_lifecycle_node', None)
not sufficient? https://docs.python.org/3/library/functions.html#getattr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The __dict__
method checks the class definition if it has that attribute rather than the individual instance passed into the function. I thought this was a more strict type-checking method of handling it since someone could make an instance with that property instead.
if not isinstance(target_lifecycle_node, (LifecycleNode, type(None))): | ||
raise RuntimeError("OnStateTransition requires a 'LifecycleNode' action as the target") | ||
lifecycle_property = type(target_lifecycle_node).__dict__.get('is_lifecycle_node', None) | ||
if not isinstance(lifecycle_property, (property, type(None))): | ||
raise RuntimeError('OnStateTransition requires a "LifecycleNode" action as the target,' | ||
' target_lifecycle_node is not a node type.') | ||
|
||
if ( | ||
target_lifecycle_node and | ||
hasattr(target_lifecycle_node, 'is_lifecycle_node') and | ||
not target_lifecycle_node.is_lifecycle_node | ||
): | ||
raise RuntimeError('OnStateTransition requires a "LifecycleNode" action as the target,' | ||
' target_lifecycle_node is not a lifecycle-enabled node.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This diff is still a bit confusing to me, why is the original check not sufficient? Is it so we can support non-LifecycleNode based classes?
Also the why do we need the first new condition? It seems like it being either None
or a property
isn't important, but the second check definitely makes sense with hasattr
and checking the value of is_lifecycle_node
. Plus the two possible errors seem to be more or less the same (at least based on the error message).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OnStateTransition is now used within the lifecycle node for the LifecycleTransition class, so we can't import LifecycleNode
into the class or it creates circular dependencies.
I'm going to fix these up to be more semantically meaningful. The first if is checking if we have the property at all in the class definition and the second is checking if its true. The second hasattr(target_lifecycle_node, 'is_lifecycle_node')
is my defensive programming to make sure its there before calling it target_lifecycle_node.is_lifecycle_node
, but I suppose at this point it shouldn't necessarily be needed.
I think its nice to have 2 different error logging for either if the property doesn't exist (i.e. not a lifecycle node at all) and also if the value present is non-true.
Rpr looks like it is failing due to a few small linter issues. After you fix that I'll run full CI with Windows and everything on ci.ros2.org unless someone else beats me to it. |
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
Signed-off-by: Steve Macenski <[email protected]>
07c6627
to
e03c8b2
Compare
Should be good to go. I also resolved the DCO sign off |
This resolves #418 which implements autostarting lifecycle nodes. This is complete and ready for a review
You'll notice a couple of key changes worth explaining:
There is a new
is_lifecycle_node
attribute of the node and lifecycle nodes which is needed to remove a circular dependency on the LifecycleNode within theLifecycleTransition
class which only is type checking. I replace this type check with checking if a non-None object (1) has the attribute at all and (2) has a lifecycle attribute with appropriate logging between the difference of a non-lifecycle node being attempted vs a non-node. This has been tested as well to function using the demos.You will also notice that I refactored lifecycle node to have a separate util
LifecycleEventManager
, who handles the event emitting, handling, and topic listening for lifecycle nodes. This way, this can be used in lifecycle-components as well! No changes were made here except removing theself.__current_state
variable which was completely unused. TheLifecycleEventManager
is only created if the node requests autostart at Launch time and otherwise has no overhead nor exposes the interfaces/event handler/emitter if its a non-lifecycle node.The component nodes don't add a
/
before the node names with the namespaces. This messes with the node event matcher. I add in a leading/
so that theaction.node_name == node_name
which has the/
forcably applied in the node event matcherI tested
LifecycleNode
,ComposableNodeContainer
,LoadCompoableNodes
for all cases:autostart=True
autostart=False
, andautostart
field not supplied. You can also run any experiments you like using the 2 extra launch files I provide in the examples directory which shows all the features at work/