Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
72c3ff6
wip
ivanpauno Dec 10, 2021
d72dc29
wip 2
ivanpauno Dec 13, 2021
fb17060
Fix possible ownership issue
ivanpauno Dec 13, 2021
b0bf636
make basic example work
ivanpauno Dec 14, 2021
19d5234
Make all the services work, checked by doing manual testing
ivanpauno Dec 15, 2021
c01fe6f
More consistent style
ivanpauno Dec 15, 2021
0c3b02b
Add some docs, add ManagedEntity concept
ivanpauno Dec 15, 2021
8efe11c
Make all linters happy
ivanpauno Dec 15, 2021
581d030
Quick lifecycle publisher implementation
ivanpauno Dec 15, 2021
d8451be
Minor style change
ivanpauno Dec 15, 2021
f5967cf
Fix issues introduced when implementing LifecyclePublisher, automatic…
ivanpauno Dec 15, 2021
ed57e05
Fixes to make it work again
ivanpauno Dec 15, 2021
30cb7a0
Modularize the implementation
ivanpauno Dec 16, 2021
b53bb36
Improve SimpleManagedEntity.when_enabled
ivanpauno Dec 16, 2021
d1ff708
Add some docs to lifecycle publisher
ivanpauno Dec 16, 2021
2ac7da1
Register all necessary callbacks, add State abstraction, other minor …
ivanpauno Dec 16, 2021
33157f1
Minor style changes, add local API to trigger transitions
ivanpauno Dec 17, 2021
ebd1d9a
Test LifecycleNode constructor, fix when enable_communication_interfa…
ivanpauno Dec 17, 2021
c6c4d73
test transitions + fixes
ivanpauno Dec 17, 2021
7517641
Add tests for lifecycle publisher
ivanpauno Dec 17, 2021
ce0d256
Please flake8
ivanpauno Dec 17, 2021
bd253ac
Minor style change after writting the demos
ivanpauno Dec 20, 2021
324d4ef
Fix misspelled word
ivanpauno Dec 20, 2021
2616315
Make some attributes in Node "protected" instead of private for easie…
ivanpauno Dec 20, 2021
b57a779
Remove TODO, add better docs
ivanpauno Dec 20, 2021
041ea6d
Remove TODO in __register_callback
ivanpauno Dec 20, 2021
a72645b
Remove TODO
ivanpauno Dec 20, 2021
bc98247
Check transition callbacks return code type. Check type of added mana…
ivanpauno Dec 20, 2021
6c20f80
Check that state is 'unconfigured' also before transition
ivanpauno Dec 22, 2021
928ee79
Test lifecycle services
ivanpauno Dec 22, 2021
59fcc4c
Delete early debugging code
ivanpauno Dec 22, 2021
c31b4f6
Please linters
ivanpauno Dec 22, 2021
4ca2a36
Test the two remaining shutdown transitions. Correct error handling w…
ivanpauno Dec 22, 2021
c693398
Address peer review comments
ivanpauno Dec 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion rclpy/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ endif()

find_package(ament_cmake REQUIRED)
find_package(ament_cmake_python REQUIRED)
find_package(lifecycle_msgs REQUIRED)
find_package(rcl REQUIRED)
find_package(rcl_logging_interface REQUIRED)
find_package(rcl_action REQUIRED)
find_package(rcl_lifecycle REQUIRED)
find_package(rcl_logging_interface REQUIRED)
find_package(rcl_yaml_param_parser REQUIRED)
find_package(rcpputils REQUIRED)
find_package(rcutils REQUIRED)
Expand Down Expand Up @@ -113,6 +115,7 @@ pybind11_add_module(_rclpy_pybind11 SHARED
src/rclpy/exceptions.cpp
src/rclpy/graph.cpp
src/rclpy/guard_condition.cpp
src/rclpy/lifecycle.cpp
src/rclpy/logging.cpp
src/rclpy/names.cpp
src/rclpy/node.cpp
Expand All @@ -133,8 +136,11 @@ target_include_directories(_rclpy_pybind11 PRIVATE
src/rclpy/
)
target_link_libraries(_rclpy_pybind11 PRIVATE
lifecycle_msgs::lifecycle_msgs__rosidl_generator_c
lifecycle_msgs::lifecycle_msgs__rosidl_typesupport_c
rcl::rcl
rcl_action::rcl_action
rcl_lifecycle::rcl_lifecycle
rcl_logging_interface::rcl_logging_interface
rcpputils::rcpputils
rcutils::rcutils
Expand Down
1 change: 1 addition & 0 deletions rclpy/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

<depend>rmw_implementation</depend>
<depend>rcl</depend>
<depend>rcl_lifecycle</depend>
<depend>rcl_logging_interface</depend>
<depend>rcl_action</depend>
<depend>rcl_yaml_param_parser</depend>
Expand Down
44 changes: 44 additions & 0 deletions rclpy/rclpy/lifecycle/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright 2021 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from .managed_entity import ManagedEntity
from .managed_entity import SimpleManagedEntity
from .node import LifecycleNode
from .node import LifecycleNodeMixin
from .node import LifecycleState
from .publisher import LifecyclePublisher

from ..impl.implementation_singleton import rclpy_implementation as _rclpy

# reexport LifecycleNode as Node, so it's possible to write:
# from rclpy.lifecycle import Node
# Do not include that in __all__ to avoid mixing it up with rclpy.node.Node.
Node = LifecycleNode
# same idea here
NodeMixin = LifecycleNodeMixin
State = LifecycleState
Publisher = LifecyclePublisher

# enum defined in pybind11 plugin
TransitionCallbackReturn = _rclpy.TransitionCallbackReturnType


__all__ = [
'LifecycleNodeMixin',
'LifecycleNode',
'LifecycleState',
'LifecyclePublisher',
'ManagedEntity',
'SimpleManagedEntity',
]
81 changes: 81 additions & 0 deletions rclpy/rclpy/lifecycle/managed_entity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Copyright 2021 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from functools import wraps

from ..impl.implementation_singleton import rclpy_implementation as _rclpy


TransitionCallbackReturn = _rclpy.TransitionCallbackReturnType


class ManagedEntity:

def on_configure(self, state) -> TransitionCallbackReturn:
"""Handle configure transition request."""
return TransitionCallbackReturn.SUCCESS

def on_cleanup(self, state) -> TransitionCallbackReturn:
"""Handle cleanup transition request."""
return TransitionCallbackReturn.SUCCESS

def on_shutdown(self, state) -> TransitionCallbackReturn:
"""Handle shutdown transition request."""
return TransitionCallbackReturn.SUCCESS

def on_activate(self, state) -> TransitionCallbackReturn:
"""Handle activate transition request."""
return TransitionCallbackReturn.SUCCESS

def on_deactivate(self, state) -> TransitionCallbackReturn:
"""Handle deactivate transition request."""
return TransitionCallbackReturn.SUCCESS

def on_error(self, state) -> TransitionCallbackReturn:
"""Handle error transition request."""
return TransitionCallbackReturn.SUCCESS


class SimpleManagedEntity(ManagedEntity):
"""A simple managed entity that only sets a flag when activated/deactivated."""

def __init__(self):
self._enabled = False

def on_activate(self, state) -> TransitionCallbackReturn:
self._enabled = True
return TransitionCallbackReturn.SUCCESS

def on_deactivate(self, state) -> TransitionCallbackReturn:
self._enabled = False
return TransitionCallbackReturn.SUCCESS

@property
def enabled(self):
return self._enabled

@staticmethod
def when_enabled(wrapped=None, *, when_not_enabled=None):
def decorator(wrapped):
@wraps(wrapped)
def only_when_enabled_wrapper(self: SimpleManagedEntity, *args, **kwargs):
if not self.enabled:
if when_not_enabled is not None:
when_not_enabled()
return
wrapped(self, *args, **kwargs)
return only_when_enabled_wrapper
if wrapped is None:
return decorator
return decorator(wrapped)
Loading