|
Package Summary
Tags | No category tags. |
Version | 0.20.5 |
License | Apache License 2.0 |
Build type | AMENT_CMAKE |
Use | RECOMMENDED |
Repository Summary
Checkout URI | https://github.com/ros2/demos.git |
VCS Type | git |
VCS Version | humble |
Last Updated | 2024-07-26 |
Dev Status | DEVELOPED |
CI status | No Continuous Integration |
Released | RELEASED |
Tags | No category tags. |
Contributing |
Help Wanted (0)
Good First Issues (0) Pull Requests to Review (0) |
Package Description
Additional Links
Maintainers
- Audrow Nash
- Michael Jeronimo
Authors
- Karsten Knese
- Mabel Zhang
Introduction
ROS 2 introduces the concept of managed nodes, also called
LifecycleNode
s. In the following tutorial, we explain the purpose of
these nodes, what makes them different from regular nodes and how they
comply to a lifecycle management. Managed nodes contain a state machine
with a set of predefined states. These states can be changed by invoking
a transition id which indicates the succeeding consecutive state. The
state machine is implemented as described at the ROS 2 design
page.
Our implementation differentiates between Primary States
and
Transition States
. Primary States are supposed to be steady states in
which any node can do the respected task. On the other hand, Transition
States are meant as temporary intermediate states attached to a
transition. The result of these intermediate states are used to indicate
whether a transition between two primary states is considered successful
or not. Thus, any managed node can be in one of the following states:
Primary States (steady states):
- unconfigured
- inactive
- active
- shutdown
Transition States (intermediate states):
- configuring
- activating
- deactivating
- cleaningup
- shuttingdown
The possible transitions to invoke are:
- configure
- activate
- deactivate
- cleanup
- shutdown
For a more verbose explanation on the applied state machine, we refer to the design page which provides an in-detail explanation about each state and transition.
The demo
What's happening
The demo is split into 3 separate applications:
- lifecycle_talker
- lifecycle_listener
- lifecycle_service_client
The lifecycle_talker
represents a managed node and publishes according
to which state the node is in. We split the tasks of the talker node
into separate pieces and execute them as follows:
- configuring: We initialize our publisher and timer
- activate: We activate the publisher and timer in order to enable a publishing
- deactivate: We stop the publisher and timer
- cleanup: We destroy the publisher and timer
This demo shows a typical talker/listener pair of nodes. However, imagine a real scenario with attached hardware which may have a rather long booting phase, i.e. a laser or camera. One could imagine bringing up the device driver in the configuring state, start and stop only the publishing of the device's data in active/deactive state, and only in the cleanup/shutdown state actually shutdown the device.
The lifecycle_listener
is a simple listener which shows the
characteristics of the lifecycle talker. The talker enables message
publishing only in the active state and thus the listener only receives
messages when the talker is in an active state.
The lifecycle_service_client
is a script calling different transitions
on the lifecycle_talker
. This is meant as the external user
controlling the lifecycle of nodes.
Run the demo
In order to run this demo, we open three terminals and source our ROS 2 environment variables either from the binary distributions or the workspace we compiled from source.
lifecycle_talker lifecycle_listener lifecycle_service_client
———————————————————————————— ———————————————————————————— ————————————————————————————
$ ros2 run lifecycle lifecycle_talker
$ ros2 run lifecycle lifecycle_listener
$ ros2 run lifecycle lifecycle_service_client
Alternatively, these three programs can be run together in the same terminal using the launch file:
``` {.sourceCode .bash} ros2 launch lifecycle lifecycle_demo.launch.py
If we look at the output of the `lifecycle_talker`, we notice that
nothing seems to happen. This makes sense, since every node starts as
`unconfigured`. The lifecycle\_talker is not configured yet and in our
example, no publishers and timers are created yet. The same behavior can
be seen for the `lifecycle_listener`, which is less surprising given
that no publishers are available at this moment. The interesting part
starts with the third terminal. In there we launch our
`lifecycle_service_client` which is responsible for changing the states
of the `lifecycle_talker`.
Triggering transition 1 (configure)
-----------------------------------
``` {.sourceCode .bash}
[lc_client] Transition 1 successfully triggered.
[lc_client] Node lc_talker has current state inactive.
Makes the lifecycle talker change its state to inactive. Inactive means that all publishers and timers are created and configured. However, the node is still not active. Therefore no messages are getting published.
``` {.sourceCode .bash} [lc_talker] on_configure() is called. Lifecycle publisher is currently inactive. Messages are not published. …
At the same time the lifecycle listener receives a notification as it
listens to every state change notification of the lifecycle talker. In
fact, the listener receives two consecutive notifications. One for
changing from the primary state \"unconfigured\" to \"configuring\", and
a second notification changing the state from \"configuring\" to
\"inactive\" (since the configuring step was successful in the talker).
``` {.sourceCode .bash}
[lc_listener] notify callback: Transition from state unconfigured to configuring
[lc_listener] notify callback: Transition from state configuring to inactive
Triggering transition 2 (activate)
``` {.sourceCode .bash} [lc_client] Transition 2 successfully triggered. [lc_client] Node lc_talker has current state active.
Makes the lifecycle talker change its state to active. That means all
publishers and timers are now activated and therefore the messages are
now getting published.
``` {.sourceCode .bash}
[lc_talker] on_activate() is called.
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #11]
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #12]
...
The lifecycle listener receives the same set of notifications as before. Lifecycle talker changed its state from inactive to active.
``` {.sourceCode .bash} [lc_listener]: notify callback: Transition from state inactive to activating [lc_listener]: notify callback: Transition from state activating to active
The difference from the earlier transition event is that our listener
now also receives the actual published data.
``` {.sourceCode .bash}
[lc_listener] data_callback: Lifecycle HelloWorld #11
[lc_listener] data_callback: Lifecycle HelloWorld #12
...
Please note that the index of the published message is already at 11.
The purpose of this demo is to show that even though we call publish
at every state of the lifecycle talker, the messages are only actually
published when the state in active.
For the rest of the demo, you will see similar output as we deactivate and activate the lifecycle talker and finally shut it down.
The demo code
lifecycle_talker, lifecycle_listener and lifecycle_service_client
If we have a look at the code, there is one significant change for the
lifecycle talker compared to a regular talker. Our node does not inherit
from the regular rclcpp::node::Node
but from
rclcpp_lifecycle::LifecycleNode
.
``` {.sourceCode .bash} class LifecycleTalker : public rclcpp_lifecycle::LifecycleNode
Every child of LifecycleNodes have a set of callbacks provided. These
callbacks go along with the applied state machine attached to it. These
callbacks are:
``` {.sourceCode .c}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_configure(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_activate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_deactivate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_cleanup(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_shutdown(const rclcpp_lifecycle::State & previous_state)
In the following we assume that we are inside the namespace
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface
to shorten
the name of the return type. All these callbacks have a positive default
return value (return CallbackReturn::SUCCESS
). This allows a lifecycle
node to change its state even though no explicit callback function was
overridden. There is one other callback function for error handling.
Whenever a state transition throws an uncaught exception, we call
on_error
:
CallbackReturn on_error(const rclcpp_lifecycle::State & previous_state)
This gives room for executing custom error handling. Only (!) in the
case that this function returns CallbackReturn::SUCCESS
, the state
machine transitions to the state unconfigured
. By default, the
on_error
returns CallbackReturn::FAILURE
and the state machine
transitions into finalized
.
At the same time, every lifecycle node has by default 5 different communication interfaces.
- Publisher
<node_name>__transition_event
: publishes in case a transition is happening.
This allows users to get notified of transition events within the network.
- Service
<node_name>__get_state
: query about the current state of the node.
Return either a primary or transition state.
- Service
<node_name>__change_state
: triggers a transition for the current node.
This service call takes a transition id. The transition is fulfilled only in the case that this transition ID is a valid transition from the current state. All other cases are ignored.
- Service
<node_name>__get_available_states
: This is meant to be an introspection tool.
It returns a list of all possible states this node can be.
- Service
<node_name>__get_available_transitions
: Same as above, meant to an introspection tool.
It returns a list of all possible transitions this node can execute.
ros2 lifecycle command line interface
The lifecycle_service_client
application is a fixed order script for
demo purposes only. It explains the use and the API calls made for this
lifecycle implementation, but may be inconvenient to use otherwise. For
this reason we implemented a command line tool which lets you
dynamically change states or various nodes.
In the case you want to get the current state of the lc_talker
node,
you would call:
``` {.sourceCode .bash} $ ros2 lifecycle get /lc_talker unconfigured [1]
The next step would be to execute a state change:
``` {.sourceCode .bash}
$ ros2 lifecycle set /lc_talker configure
Transitioning successful
In order to see what states are currently available:
``` {.sourceCode .bash} $ ros2 lifecycle list lc_talker
- configure [1] Start: unconfigured Goal: configuring
- shutdown [5] Start: unconfigured Goal: shuttingdown
In this case we see that currently, the available transitions are
`configure` and `shutdown`. The complete state machine can be viewed
with the following command, which can be helpful for debugging or
visualization purposes:
``` {.sourceCode .bash}
$ ros2 lifecycle list lc_talker -a
- configure [1]
Start: unconfigured
Goal: configuring
- transition_success [10]
Start: configuring
Goal: inactive
- transition_failure [11]
Start: configuring
Goal: unconfigured
- transition_error [12]
Start: configuring
Goal: errorprocessing
[...]
- transition_error [62]
Start: errorprocessing
Goal: finalized
All of the above commands are nothing more than calling the lifecycle node's services. With that being said, we can also call these services directly with the ros2 command line interface:
``` {.sourceCode .bash} $ ros2 service call /lc_talker/get_state lifecycle_msgs/GetState requester: making request: lifecycle_msgs.srv.GetState_Request()
response: lifecycle_msgs.srv.GetState_Response(current_state=lifecycle_msgs.msg.State(id=1, label=’unconfigured’))
In order to trigger a transition, we call the `change_state` service
``` {.sourceCode .bash}
$ ros2 service call /lc_talker/change_state lifecycle_msgs/ChangeState "{transition: {id: 2}}"
requester: making request: lifecycle_msgs.srv.ChangeState_Request(transition=lifecycle_msgs.msg.Transition(id=2, label=''))
response:
lifecycle_msgs.srv.ChangeState_Response(success=True)
It is slightly less convenient, because you have to know the IDs which correspond to each transition. You can find them though in the lifecycle_msgs package.
``` {.sourceCode .bash} $ ros2 interface show lifecycle_msgs/msg/Transition
```
Changelog for package lifecycle
0.20.5 (2024-07-26)
0.20.4 (2024-05-15)
0.20.3 (2023-01-10)
0.20.2 (2022-05-10)
0.20.1 (2022-04-08)
- Make lifecycle demo automatically exit when done (#558)
- Contributors: Shane Loretz
0.20.0 (2022-03-01)
- Use default on_activate()/on_deactivate() implemenetation of Node (#552)
- Contributors: Ivan Santiago Paunovic
0.19.0 (2022-01-14)
0.18.0 (2021-12-17)
- Update maintainers to Audrow Nash and Michael Jeronimo (#543)
- Contributors: Audrow Nash
0.17.0 (2021-10-18)
- Fix use of future in lifecycle demo (#534)
- Fixing deprecated subscriber callback warnings (#532)
- Contributors: Abrar Rahman Protyasha, Christophe Bedard
0.16.0 (2021-08-11)
0.15.0 (2021-05-14)
0.14.2 (2021-04-26)
- Cleanup the README.rst for the lifecycle demo. (#508)
- Contributors: Chris Lalancette
0.14.1 (2021-04-19)
0.14.0 (2021-04-06)
- change ParameterEventHandler to take events as const ref instead of shared pointer (#494)
- Contributors: William Woodall
0.13.0 (2021-03-25)
0.12.1 (2021-03-18)
0.12.0 (2021-01-25)
0.11.0 (2020-12-10)
- Update the package.xml files with the latest Open Robotics maintainers (#466)
- Contributors: Michael Jeronimo
0.10.1 (2020-09-21)
- Add missing required parameter in LifecycleNode launch action (#456)
- Contributors: Ivan Santiago Paunovic
0.10.0 (2020-06-17)
0.9.3 (2020-06-01)
0.9.2 (2020-05-26)
- Fix typo (#445)
- Replace
ros2 msg
command in lifecycle README (#446) - Contributors: Audrow Nash, Shota Aoki
0.9.1 (2020-05-12)
0.9.0 (2020-04-30)
- Replace deprecated launch_ros usage (#437)
- Update launch_ros action usage (#431)
- code style only: wrap after open parenthesis if not in one line (#429)
- Contributors: Dirk Thomas, Jacob Perron
0.8.4 (2019-11-19)
0.8.3 (2019-11-11)
0.8.2 (2019-11-08)
- Remove unnecessary dependency on ros2run (#413)
- Contributors: Michel Hidalgo
0.8.1 (2019-10-23)
- Replace ready_fn with ReadyToTest action (#404)
- Contributors: Peter Baughman
0.8.0 (2019-09-26)
- Fix lifecycle_service_client namespace (#369)
- Contributors: Cameron Evans
0.7.6 (2019-05-30)
0.7.5 (2019-05-29)
- Update asciinema recordings (#360)
- Use rate instead of thread::sleep to react to Ctrl-C (#348)
- Contributors: Dirk Thomas, Karsten Knese
0.7.4 (2019-05-20)
- Add lifecycle rostest (#336)
- Contributors: Michel Hidalgo
0.7.3 (2019-05-10)
0.7.2 (2019-05-08)
- changes to avoid deprecated API's (#332)
- Corrected publish calls with shared_ptr signature (#327)
- Contributors: William Woodall, ivanpauno
0.7.1 (2019-04-26)
0.7.0 (2019-04-14)
- Updated for NodeOptions Node constructor. (#308)
- Contributors: Michael Carroll
0.6.2 (2019-01-15)
- Added readme.rst (#300)
- Contributors: Karsten Knese
0.6.1 (2018-12-13)
0.6.0 (2018-12-07)
- Cleaned up lifecycle demo (#283)
- Updated for refactoring in rclcpp (#276)
- Added semicolons to all RCLCPP and RCUTILS macros. (#278)
- Fixed typo in comment (#270)
- Contributors: Chris Lalancette, Karsten Knese, Yutaka Kondo
0.5.1 (2018-06-28)
0.5.0 (2018-06-27)
- Converted launch files to the new launch style. (#262)
- Updated to support remapping arguments to python nodes by passing unused arguments to rclpy from argparse. (#252)
- Updated to handle change in signature to
get_service_name
. (#245) - Updated launch files to account for the "old launch" getting
renamespaced as
launch
->launch.legacy
. (#239) - Updated service client demos to handle multiple requests. (#228)
- Contributors: Geoffrey Biggs, Kevin Allen, Shane Loretz, William Woodall, dhood
Wiki Tutorials
Package Dependencies
Deps | Name |
---|---|
lifecycle_msgs | |
rclcpp_lifecycle | |
std_msgs | |
ament_cmake | |
ament_lint_auto | |
ament_lint_common | |
ros_testing |
System Dependencies
Dependant Packages
Name | Deps |
---|---|
lifecycle_py | |
test_launch_ros | |
desktop |
Launch files
Messages
Services
Plugins
Recent questions tagged lifecycle at Robotics Stack Exchange
|
Package Summary
Tags | No category tags. |
Version | 0.27.2 |
License | Apache License 2.0 |
Build type | AMENT_CMAKE |
Use | RECOMMENDED |
Repository Summary
Checkout URI | https://github.com/ros2/demos.git |
VCS Type | git |
VCS Version | iron |
Last Updated | 2024-07-11 |
Dev Status | DEVELOPED |
CI status | No Continuous Integration |
Released | RELEASED |
Tags | No category tags. |
Contributing |
Help Wanted (0)
Good First Issues (0) Pull Requests to Review (0) |
Package Description
Additional Links
Maintainers
- Aditya Pande
- Audrow Nash
- Michael Jeronimo
Authors
- Karsten Knese
- Mabel Zhang
Introduction
ROS 2 introduces the concept of managed nodes, also called
LifecycleNode
s. In the following tutorial, we explain the purpose of
these nodes, what makes them different from regular nodes and how they
comply to a lifecycle management. Managed nodes contain a state machine
with a set of predefined states. These states can be changed by invoking
a transition id which indicates the succeeding consecutive state. The
state machine is implemented as described at the ROS 2 design
page.
Our implementation differentiates between Primary States
and
Transition States
. Primary States are supposed to be steady states in
which any node can do the respected task. On the other hand, Transition
States are meant as temporary intermediate states attached to a
transition. The result of these intermediate states are used to indicate
whether a transition between two primary states is considered successful
or not. Thus, any managed node can be in one of the following states:
Primary States (steady states):
- unconfigured
- inactive
- active
- shutdown
Transition States (intermediate states):
- configuring
- activating
- deactivating
- cleaningup
- shuttingdown
The possible transitions to invoke are:
- configure
- activate
- deactivate
- cleanup
- shutdown
For a more verbose explanation on the applied state machine, we refer to the design page which provides an in-detail explanation about each state and transition.
The demo
What's happening
The demo is split into 3 separate applications:
- lifecycle_talker
- lifecycle_listener
- lifecycle_service_client
The lifecycle_talker
represents a managed node and publishes according
to which state the node is in. We split the tasks of the talker node
into separate pieces and execute them as follows:
- configuring: We initialize our publisher and timer
- activate: We activate the publisher and timer in order to enable a publishing
- deactivate: We stop the publisher and timer
- cleanup: We destroy the publisher and timer
This demo shows a typical talker/listener pair of nodes. However, imagine a real scenario with attached hardware which may have a rather long booting phase, i.e. a laser or camera. One could imagine bringing up the device driver in the configuring state, start and stop only the publishing of the device's data in active/deactive state, and only in the cleanup/shutdown state actually shutdown the device.
The lifecycle_listener
is a simple listener which shows the
characteristics of the lifecycle talker. The talker enables message
publishing only in the active state and thus the listener only receives
messages when the talker is in an active state.
The lifecycle_service_client
is a script calling different transitions
on the lifecycle_talker
. This is meant as the external user
controlling the lifecycle of nodes.
Run the demo
In order to run this demo, we open three terminals and source our ROS 2 environment variables either from the binary distributions or the workspace we compiled from source.
lifecycle_talker lifecycle_listener lifecycle_service_client
———————————————————————————— ———————————————————————————— ————————————————————————————
$ ros2 run lifecycle lifecycle_talker
$ ros2 run lifecycle lifecycle_listener
$ ros2 run lifecycle lifecycle_service_client
Alternatively, these three programs can be run together in the same terminal using the launch file:
``` {.sourceCode .bash} ros2 launch lifecycle lifecycle_demo_launch.py
If we look at the output of the `lifecycle_talker`, we notice that
nothing seems to happen. This makes sense, since every node starts as
`unconfigured`. The lifecycle\_talker is not configured yet and in our
example, no publishers and timers are created yet. The same behavior can
be seen for the `lifecycle_listener`, which is less surprising given
that no publishers are available at this moment. The interesting part
starts with the third terminal. In there we launch our
`lifecycle_service_client` which is responsible for changing the states
of the `lifecycle_talker`.
Triggering transition 1 (configure)
-----------------------------------
``` {.sourceCode .bash}
[lc_client] Transition 1 successfully triggered.
[lc_client] Node lc_talker has current state inactive.
Makes the lifecycle talker change its state to inactive. Inactive means that all publishers and timers are created and configured. However, the node is still not active. Therefore no messages are getting published.
``` {.sourceCode .bash} [lc_talker] on_configure() is called. Lifecycle publisher is currently inactive. Messages are not published. …
At the same time the lifecycle listener receives a notification as it
listens to every state change notification of the lifecycle talker. In
fact, the listener receives two consecutive notifications. One for
changing from the primary state \"unconfigured\" to \"configuring\", and
a second notification changing the state from \"configuring\" to
\"inactive\" (since the configuring step was successful in the talker).
``` {.sourceCode .bash}
[lc_listener] notify callback: Transition from state unconfigured to configuring
[lc_listener] notify callback: Transition from state configuring to inactive
Triggering transition 2 (activate)
``` {.sourceCode .bash} [lc_client] Transition 2 successfully triggered. [lc_client] Node lc_talker has current state active.
Makes the lifecycle talker change its state to active. That means all
publishers and timers are now activated and therefore the messages are
now getting published.
``` {.sourceCode .bash}
[lc_talker] on_activate() is called.
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #11]
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #12]
...
The lifecycle listener receives the same set of notifications as before. Lifecycle talker changed its state from inactive to active.
``` {.sourceCode .bash} [lc_listener]: notify callback: Transition from state inactive to activating [lc_listener]: notify callback: Transition from state activating to active
The difference from the earlier transition event is that our listener
now also receives the actual published data.
``` {.sourceCode .bash}
[lc_listener] data_callback: Lifecycle HelloWorld #11
[lc_listener] data_callback: Lifecycle HelloWorld #12
...
Please note that the index of the published message is already at 11.
The purpose of this demo is to show that even though we call publish
at every state of the lifecycle talker, the messages are only actually
published when the state in active.
For the rest of the demo, you will see similar output as we deactivate and activate the lifecycle talker and finally shut it down.
The demo code
lifecycle_talker, lifecycle_listener and lifecycle_service_client
If we have a look at the code, there is one significant change for the
lifecycle talker compared to a regular talker. Our node does not inherit
from the regular rclcpp::node::Node
but from
rclcpp_lifecycle::LifecycleNode
.
``` {.sourceCode .bash} class LifecycleTalker : public rclcpp_lifecycle::LifecycleNode
Every child of LifecycleNodes have a set of callbacks provided. These
callbacks go along with the applied state machine attached to it. These
callbacks are:
``` {.sourceCode .c}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_configure(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_activate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_deactivate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_cleanup(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_shutdown(const rclcpp_lifecycle::State & previous_state)
In the following we assume that we are inside the namespace
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface
to shorten
the name of the return type. All these callbacks have a positive default
return value (return CallbackReturn::SUCCESS
). This allows a lifecycle
node to change its state even though no explicit callback function was
overridden. There is one other callback function for error handling.
Whenever a state transition throws an uncaught exception, we call
on_error
:
CallbackReturn on_error(const rclcpp_lifecycle::State & previous_state)
This gives room for executing custom error handling. Only (!) in the
case that this function returns CallbackReturn::SUCCESS
, the state
machine transitions to the state unconfigured
. By default, the
on_error
returns CallbackReturn::FAILURE
and the state machine
transitions into finalized
.
At the same time, every lifecycle node has by default 5 different communication interfaces.
- Publisher
<node_name>__transition_event
: publishes in case a transition is happening.
This allows users to get notified of transition events within the network.
- Service
<node_name>__get_state
: query about the current state of the node.
Return either a primary or transition state.
- Service
<node_name>__change_state
: triggers a transition for the current node.
This service call takes a transition id. The transition is fulfilled only in the case that this transition ID is a valid transition from the current state. All other cases are ignored.
- Service
<node_name>__get_available_states
: This is meant to be an introspection tool.
It returns a list of all possible states this node can be.
- Service
<node_name>__get_available_transitions
: Same as above, meant to an introspection tool.
It returns a list of all possible transitions this node can execute.
ros2 lifecycle command line interface
The lifecycle_service_client
application is a fixed order script for
demo purposes only. It explains the use and the API calls made for this
lifecycle implementation, but may be inconvenient to use otherwise. For
this reason we implemented a command line tool which lets you
dynamically change states or various nodes.
In the case you want to get the current state of the lc_talker
node,
you would call:
``` {.sourceCode .bash} $ ros2 lifecycle get /lc_talker unconfigured [1]
The next step would be to execute a state change:
``` {.sourceCode .bash}
$ ros2 lifecycle set /lc_talker configure
Transitioning successful
In order to see what states are currently available:
``` {.sourceCode .bash} $ ros2 lifecycle list lc_talker
- configure [1] Start: unconfigured Goal: configuring
- shutdown [5] Start: unconfigured Goal: shuttingdown
In this case we see that currently, the available transitions are
`configure` and `shutdown`. The complete state machine can be viewed
with the following command, which can be helpful for debugging or
visualization purposes:
``` {.sourceCode .bash}
$ ros2 lifecycle list lc_talker -a
- configure [1]
Start: unconfigured
Goal: configuring
- transition_success [10]
Start: configuring
Goal: inactive
- transition_failure [11]
Start: configuring
Goal: unconfigured
- transition_error [12]
Start: configuring
Goal: errorprocessing
[...]
- transition_error [62]
Start: errorprocessing
Goal: finalized
All of the above commands are nothing more than calling the lifecycle node's services. With that being said, we can also call these services directly with the ros2 command line interface:
``` {.sourceCode .bash} $ ros2 service call /lc_talker/get_state lifecycle_msgs/GetState requester: making request: lifecycle_msgs.srv.GetState_Request()
response: lifecycle_msgs.srv.GetState_Response(current_state=lifecycle_msgs.msg.State(id=1, label=’unconfigured’))
In order to trigger a transition, we call the `change_state` service
``` {.sourceCode .bash}
$ ros2 service call /lc_talker/change_state lifecycle_msgs/ChangeState "{transition: {id: 2}}"
requester: making request: lifecycle_msgs.srv.ChangeState_Request(transition=lifecycle_msgs.msg.Transition(id=2, label=''))
response:
lifecycle_msgs.srv.ChangeState_Response(success=True)
It is slightly less convenient, because you have to know the IDs which correspond to each transition. You can find them though in the lifecycle_msgs package.
``` {.sourceCode .bash} $ ros2 interface show lifecycle_msgs/msg/Transition
```
Changelog for package lifecycle
0.27.2 (2024-07-10)
0.27.1 (2023-05-11)
0.27.0 (2023-04-13)
0.26.0 (2023-04-11)
- update launch file name format to match documentation (#588)
- Contributors: Patrick Wspanialy
0.25.0 (2023-03-01)
0.24.1 (2023-02-24)
0.24.0 (2023-02-14)
- Update the demos to C++17. (#594)
- [rolling] Update maintainers - 2022-11-07 (#589)
- Contributors: Audrow Nash, Chris Lalancette
0.23.0 (2022-11-02)
0.22.0 (2022-09-13)
0.21.0 (2022-04-29)
0.20.1 (2022-04-08)
- Make lifecycle demo automatically exit when done (#558)
- Contributors: Shane Loretz
0.20.0 (2022-03-01)
- Use default on_activate()/on_deactivate() implemenetation of Node (#552)
- Contributors: Ivan Santiago Paunovic
0.19.0 (2022-01-14)
0.18.0 (2021-12-17)
- Update maintainers to Audrow Nash and Michael Jeronimo (#543)
- Contributors: Audrow Nash
0.17.0 (2021-10-18)
- Fix use of future in lifecycle demo (#534)
- Fixing deprecated subscriber callback warnings (#532)
- Contributors: Abrar Rahman Protyasha, Christophe Bedard
0.16.0 (2021-08-11)
0.15.0 (2021-05-14)
0.14.2 (2021-04-26)
- Cleanup the README.rst for the lifecycle demo. (#508)
- Contributors: Chris Lalancette
0.14.1 (2021-04-19)
0.14.0 (2021-04-06)
- change ParameterEventHandler to take events as const ref instead of shared pointer (#494)
- Contributors: William Woodall
0.13.0 (2021-03-25)
0.12.1 (2021-03-18)
0.12.0 (2021-01-25)
0.11.0 (2020-12-10)
- Update the package.xml files with the latest Open Robotics maintainers (#466)
- Contributors: Michael Jeronimo
0.10.1 (2020-09-21)
- Add missing required parameter in LifecycleNode launch action (#456)
- Contributors: Ivan Santiago Paunovic
0.10.0 (2020-06-17)
0.9.3 (2020-06-01)
0.9.2 (2020-05-26)
- Fix typo (#445)
- Replace
ros2 msg
command in lifecycle README (#446) - Contributors: Audrow Nash, Shota Aoki
0.9.1 (2020-05-12)
0.9.0 (2020-04-30)
- Replace deprecated launch_ros usage (#437)
- Update launch_ros action usage (#431)
- code style only: wrap after open parenthesis if not in one line (#429)
- Contributors: Dirk Thomas, Jacob Perron
0.8.4 (2019-11-19)
0.8.3 (2019-11-11)
0.8.2 (2019-11-08)
- Remove unnecessary dependency on ros2run (#413)
- Contributors: Michel Hidalgo
0.8.1 (2019-10-23)
- Replace ready_fn with ReadyToTest action (#404)
- Contributors: Peter Baughman
0.8.0 (2019-09-26)
- Fix lifecycle_service_client namespace (#369)
- Contributors: Cameron Evans
0.7.6 (2019-05-30)
0.7.5 (2019-05-29)
- Update asciinema recordings (#360)
- Use rate instead of thread::sleep to react to Ctrl-C (#348)
- Contributors: Dirk Thomas, Karsten Knese
0.7.4 (2019-05-20)
- Add lifecycle rostest (#336)
- Contributors: Michel Hidalgo
0.7.3 (2019-05-10)
0.7.2 (2019-05-08)
- changes to avoid deprecated API's (#332)
- Corrected publish calls with shared_ptr signature (#327)
- Contributors: William Woodall, ivanpauno
0.7.1 (2019-04-26)
0.7.0 (2019-04-14)
- Updated for NodeOptions Node constructor. (#308)
- Contributors: Michael Carroll
0.6.2 (2019-01-15)
- Added readme.rst (#300)
- Contributors: Karsten Knese
0.6.1 (2018-12-13)
0.6.0 (2018-12-07)
- Cleaned up lifecycle demo (#283)
- Updated for refactoring in rclcpp (#276)
- Added semicolons to all RCLCPP and RCUTILS macros. (#278)
- Fixed typo in comment (#270)
- Contributors: Chris Lalancette, Karsten Knese, Yutaka Kondo
0.5.1 (2018-06-28)
0.5.0 (2018-06-27)
- Converted launch files to the new launch style. (#262)
- Updated to support remapping arguments to python nodes by passing unused arguments to rclpy from argparse. (#252)
- Updated to handle change in signature to
get_service_name
. (#245) - Updated launch files to account for the "old launch" getting
renamespaced as
launch
->launch.legacy
. (#239) - Updated service client demos to handle multiple requests. (#228)
- Contributors: Geoffrey Biggs, Kevin Allen, Shane Loretz, William Woodall, dhood
Wiki Tutorials
Package Dependencies
Deps | Name |
---|---|
lifecycle_msgs | |
rclcpp_lifecycle | |
std_msgs | |
ament_cmake | |
ament_lint_auto | |
ament_lint_common | |
ros_testing |
System Dependencies
Dependant Packages
Name | Deps |
---|---|
lifecycle_py | |
test_launch_ros | |
desktop |
Launch files
Messages
Services
Plugins
Recent questions tagged lifecycle at Robotics Stack Exchange
|
Package Summary
Tags | No category tags. |
Version | 0.33.5 |
License | Apache License 2.0 |
Build type | AMENT_CMAKE |
Use | RECOMMENDED |
Repository Summary
Checkout URI | https://github.com/ros2/demos.git |
VCS Type | git |
VCS Version | jazzy |
Last Updated | 2024-09-06 |
Dev Status | DEVELOPED |
CI status | No Continuous Integration |
Released | RELEASED |
Tags | No category tags. |
Contributing |
Help Wanted (0)
Good First Issues (0) Pull Requests to Review (0) |
Package Description
Additional Links
Maintainers
- Aditya Pande
- Audrow Nash
Authors
- Karsten Knese
- Mabel Zhang
Introduction
ROS 2 introduces the concept of managed nodes, also called
LifecycleNode
s. In the following tutorial, we explain the purpose of
these nodes, what makes them different from regular nodes and how they
comply to a lifecycle management. Managed nodes contain a state machine
with a set of predefined states. These states can be changed by invoking
a transition id which indicates the succeeding consecutive state. The
state machine is implemented as described at the ROS 2 design
page.
Our implementation differentiates between Primary States
and
Transition States
. Primary States are supposed to be steady states in
which any node can do the respected task. On the other hand, Transition
States are meant as temporary intermediate states attached to a
transition. The result of these intermediate states are used to indicate
whether a transition between two primary states is considered successful
or not. Thus, any managed node can be in one of the following states:
Primary States (steady states):
- unconfigured
- inactive
- active
- shutdown
Transition States (intermediate states):
- configuring
- activating
- deactivating
- cleaningup
- shuttingdown
The possible transitions to invoke are:
- configure
- activate
- deactivate
- cleanup
- shutdown
For a more verbose explanation on the applied state machine, we refer to the design page which provides an in-detail explanation about each state and transition.
The demo
What's happening
The demo is split into 3 separate applications:
- lifecycle_talker
- lifecycle_listener
- lifecycle_service_client
The lifecycle_talker
represents a managed node and publishes according
to which state the node is in. We split the tasks of the talker node
into separate pieces and execute them as follows:
- configuring: We initialize our publisher and timer
- activate: We activate the publisher and timer in order to enable a publishing
- deactivate: We stop the publisher and timer
- cleanup: We destroy the publisher and timer
This demo shows a typical talker/listener pair of nodes. However, imagine a real scenario with attached hardware which may have a rather long booting phase, i.e. a laser or camera. One could imagine bringing up the device driver in the configuring state, start and stop only the publishing of the device's data in active/deactive state, and only in the cleanup/shutdown state actually shutdown the device.
The lifecycle_listener
is a simple listener which shows the
characteristics of the lifecycle talker. The talker enables message
publishing only in the active state and thus the listener only receives
messages when the talker is in an active state.
The lifecycle_service_client
is a script calling different transitions
on the lifecycle_talker
. This is meant as the external user
controlling the lifecycle of nodes.
Run the demo
In order to run this demo, we open three terminals and source our ROS 2 environment variables either from the binary distributions or the workspace we compiled from source.
lifecycle_talker lifecycle_listener lifecycle_service_client
———————————————————————————— ———————————————————————————— ————————————————————————————
$ ros2 run lifecycle lifecycle_talker
$ ros2 run lifecycle lifecycle_listener
$ ros2 run lifecycle lifecycle_service_client
Alternatively, these three programs can be run together in the same terminal using the launch file:
``` {.sourceCode .bash} ros2 launch lifecycle lifecycle_demo_launch.py
If we look at the output of the `lifecycle_talker`, we notice that
nothing seems to happen. This makes sense, since every node starts as
`unconfigured`. The lifecycle\_talker is not configured yet and in our
example, no publishers and timers are created yet. The same behavior can
be seen for the `lifecycle_listener`, which is less surprising given
that no publishers are available at this moment. The interesting part
starts with the third terminal. In there we launch our
`lifecycle_service_client` which is responsible for changing the states
of the `lifecycle_talker`.
Triggering transition 1 (configure)
-----------------------------------
``` {.sourceCode .bash}
[lc_client] Transition 1 successfully triggered.
[lc_client] Node lc_talker has current state inactive.
Makes the lifecycle talker change its state to inactive. Inactive means that all publishers and timers are created and configured. However, the node is still not active. Therefore no messages are getting published.
``` {.sourceCode .bash} [lc_talker] on_configure() is called. Lifecycle publisher is currently inactive. Messages are not published. …
At the same time the lifecycle listener receives a notification as it
listens to every state change notification of the lifecycle talker. In
fact, the listener receives two consecutive notifications. One for
changing from the primary state \"unconfigured\" to \"configuring\", and
a second notification changing the state from \"configuring\" to
\"inactive\" (since the configuring step was successful in the talker).
``` {.sourceCode .bash}
[lc_listener] notify callback: Transition from state unconfigured to configuring
[lc_listener] notify callback: Transition from state configuring to inactive
Triggering transition 2 (activate)
``` {.sourceCode .bash} [lc_client] Transition 2 successfully triggered. [lc_client] Node lc_talker has current state active.
Makes the lifecycle talker change its state to active. That means all
publishers and timers are now activated and therefore the messages are
now getting published.
``` {.sourceCode .bash}
[lc_talker] on_activate() is called.
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #11]
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #12]
...
The lifecycle listener receives the same set of notifications as before. Lifecycle talker changed its state from inactive to active.
``` {.sourceCode .bash} [lc_listener]: notify callback: Transition from state inactive to activating [lc_listener]: notify callback: Transition from state activating to active
The difference from the earlier transition event is that our listener
now also receives the actual published data.
``` {.sourceCode .bash}
[lc_listener] data_callback: Lifecycle HelloWorld #11
[lc_listener] data_callback: Lifecycle HelloWorld #12
...
Please note that the index of the published message is already at 11.
The purpose of this demo is to show that even though we call publish
at every state of the lifecycle talker, the messages are only actually
published when the state in active.
For the rest of the demo, you will see similar output as we deactivate and activate the lifecycle talker and finally shut it down.
The demo code
lifecycle_talker, lifecycle_listener and lifecycle_service_client
If we have a look at the code, there is one significant change for the
lifecycle talker compared to a regular talker. Our node does not inherit
from the regular rclcpp::node::Node
but from
rclcpp_lifecycle::LifecycleNode
.
``` {.sourceCode .bash} class LifecycleTalker : public rclcpp_lifecycle::LifecycleNode
Every child of LifecycleNodes have a set of callbacks provided. These
callbacks go along with the applied state machine attached to it. These
callbacks are:
``` {.sourceCode .c}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_configure(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_activate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_deactivate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_cleanup(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_shutdown(const rclcpp_lifecycle::State & previous_state)
In the following we assume that we are inside the namespace
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface
to shorten
the name of the return type. All these callbacks have a positive default
return value (return CallbackReturn::SUCCESS
). This allows a lifecycle
node to change its state even though no explicit callback function was
overridden. There is one other callback function for error handling.
Whenever a state transition throws an uncaught exception, we call
on_error
:
CallbackReturn on_error(const rclcpp_lifecycle::State & previous_state)
This gives room for executing custom error handling. Only (!) in the
case that this function returns CallbackReturn::SUCCESS
, the state
machine transitions to the state unconfigured
. By default, the
on_error
returns CallbackReturn::FAILURE
and the state machine
transitions into finalized
.
At the same time, every lifecycle node has by default 5 different communication interfaces.
- Publisher
<node_name>__transition_event
: publishes in case a transition is happening.
This allows users to get notified of transition events within the network.
- Service
<node_name>__get_state
: query about the current state of the node.
Return either a primary or transition state.
- Service
<node_name>__change_state
: triggers a transition for the current node.
This service call takes a transition id. The transition is fulfilled only in the case that this transition ID is a valid transition from the current state. All other cases are ignored.
- Service
<node_name>__get_available_states
: This is meant to be an introspection tool.
It returns a list of all possible states this node can be.
- Service
<node_name>__get_available_transitions
: Same as above, meant to an introspection tool.
It returns a list of all possible transitions this node can execute.
ros2 lifecycle command line interface
The lifecycle_service_client
application is a fixed order script for
demo purposes only. It explains the use and the API calls made for this
lifecycle implementation, but may be inconvenient to use otherwise. For
this reason we implemented a command line tool which lets you
dynamically change states or various nodes.
In the case you want to get the current state of the lc_talker
node,
you would call:
``` {.sourceCode .bash} $ ros2 lifecycle get /lc_talker unconfigured [1]
The next step would be to execute a state change:
``` {.sourceCode .bash}
$ ros2 lifecycle set /lc_talker configure
Transitioning successful
In order to see what states are currently available:
``` {.sourceCode .bash} $ ros2 lifecycle list lc_talker
- configure [1] Start: unconfigured Goal: configuring
- shutdown [5] Start: unconfigured Goal: shuttingdown
In this case we see that currently, the available transitions are
`configure` and `shutdown`. The complete state machine can be viewed
with the following command, which can be helpful for debugging or
visualization purposes:
``` {.sourceCode .bash}
$ ros2 lifecycle list lc_talker -a
- configure [1]
Start: unconfigured
Goal: configuring
- transition_success [10]
Start: configuring
Goal: inactive
- transition_failure [11]
Start: configuring
Goal: unconfigured
- transition_error [12]
Start: configuring
Goal: errorprocessing
[...]
- transition_error [62]
Start: errorprocessing
Goal: finalized
All of the above commands are nothing more than calling the lifecycle node's services. With that being said, we can also call these services directly with the ros2 command line interface:
``` {.sourceCode .bash} $ ros2 service call /lc_talker/get_state lifecycle_msgs/GetState requester: making request: lifecycle_msgs.srv.GetState_Request()
response: lifecycle_msgs.srv.GetState_Response(current_state=lifecycle_msgs.msg.State(id=1, label=’unconfigured’))
In order to trigger a transition, we call the `change_state` service
``` {.sourceCode .bash}
$ ros2 service call /lc_talker/change_state lifecycle_msgs/ChangeState "{transition: {id: 2}}"
requester: making request: lifecycle_msgs.srv.ChangeState_Request(transition=lifecycle_msgs.msg.Transition(id=2, label=''))
response:
lifecycle_msgs.srv.ChangeState_Response(success=True)
It is slightly less convenient, because you have to know the IDs which correspond to each transition. You can find them though in the lifecycle_msgs package.
``` {.sourceCode .bash} $ ros2 interface show lifecycle_msgs/msg/Transition
```
Changelog for package lifecycle
0.33.5 (2024-09-06)
0.33.4 (2024-06-27)
0.33.3 (2024-05-13)
0.33.2 (2024-03-28)
- A few uncrustify fixes for 0.78. (#667)
- Update maintainer list in package.xml files (#665)
- Contributors: Chris Lalancette, Michael Jeronimo
0.33.1 (2024-02-07)
0.33.0 (2024-01-24)
- Migrate std::bind calls to lambda expressions (#659)
- Contributors: Felipe Gomes de Melo
0.32.1 (2023-12-26)
0.32.0 (2023-11-06)
0.31.1 (2023-09-07)
0.31.0 (2023-08-21)
- Switch to using RCLCPP logging macros in the lifecycle package. (#644)
- Contributors: Chris Lalancette
0.30.1 (2023-07-11)
0.30.0 (2023-06-12)
0.29.0 (2023-06-07)
0.28.1 (2023-05-11)
0.28.0 (2023-04-27)
0.27.0 (2023-04-13)
0.26.0 (2023-04-11)
- update launch file name format to match documentation (#588)
- Contributors: Patrick Wspanialy
0.25.0 (2023-03-01)
0.24.1 (2023-02-24)
0.24.0 (2023-02-14)
- Update the demos to C++17. (#594)
- [rolling] Update maintainers - 2022-11-07 (#589)
- Contributors: Audrow Nash, Chris Lalancette
0.23.0 (2022-11-02)
0.22.0 (2022-09-13)
0.21.0 (2022-04-29)
0.20.1 (2022-04-08)
- Make lifecycle demo automatically exit when done (#558)
- Contributors: Shane Loretz
0.20.0 (2022-03-01)
- Use default on_activate()/on_deactivate() implemenetation of Node (#552)
- Contributors: Ivan Santiago Paunovic
0.19.0 (2022-01-14)
0.18.0 (2021-12-17)
- Update maintainers to Audrow Nash and Michael Jeronimo (#543)
- Contributors: Audrow Nash
0.17.0 (2021-10-18)
- Fix use of future in lifecycle demo (#534)
- Fixing deprecated subscriber callback warnings (#532)
- Contributors: Abrar Rahman Protyasha, Christophe Bedard
0.16.0 (2021-08-11)
0.15.0 (2021-05-14)
0.14.2 (2021-04-26)
- Cleanup the README.rst for the lifecycle demo. (#508)
- Contributors: Chris Lalancette
0.14.1 (2021-04-19)
0.14.0 (2021-04-06)
- change ParameterEventHandler to take events as const ref instead of shared pointer (#494)
- Contributors: William Woodall
0.13.0 (2021-03-25)
0.12.1 (2021-03-18)
0.12.0 (2021-01-25)
0.11.0 (2020-12-10)
- Update the package.xml files with the latest Open Robotics maintainers (#466)
- Contributors: Michael Jeronimo
0.10.1 (2020-09-21)
- Add missing required parameter in LifecycleNode launch action (#456)
- Contributors: Ivan Santiago Paunovic
0.10.0 (2020-06-17)
0.9.3 (2020-06-01)
0.9.2 (2020-05-26)
- Fix typo (#445)
- Replace
ros2 msg
command in lifecycle README (#446) - Contributors: Audrow Nash, Shota Aoki
0.9.1 (2020-05-12)
0.9.0 (2020-04-30)
- Replace deprecated launch_ros usage (#437)
- Update launch_ros action usage (#431)
- code style only: wrap after open parenthesis if not in one line (#429)
- Contributors: Dirk Thomas, Jacob Perron
0.8.4 (2019-11-19)
0.8.3 (2019-11-11)
0.8.2 (2019-11-08)
- Remove unnecessary dependency on ros2run (#413)
- Contributors: Michel Hidalgo
0.8.1 (2019-10-23)
- Replace ready_fn with ReadyToTest action (#404)
- Contributors: Peter Baughman
0.8.0 (2019-09-26)
- Fix lifecycle_service_client namespace (#369)
- Contributors: Cameron Evans
0.7.6 (2019-05-30)
0.7.5 (2019-05-29)
- Update asciinema recordings (#360)
- Use rate instead of thread::sleep to react to Ctrl-C (#348)
- Contributors: Dirk Thomas, Karsten Knese
0.7.4 (2019-05-20)
- Add lifecycle rostest (#336)
- Contributors: Michel Hidalgo
0.7.3 (2019-05-10)
0.7.2 (2019-05-08)
- changes to avoid deprecated API's (#332)
- Corrected publish calls with shared_ptr signature (#327)
- Contributors: William Woodall, ivanpauno
0.7.1 (2019-04-26)
0.7.0 (2019-04-14)
- Updated for NodeOptions Node constructor. (#308)
- Contributors: Michael Carroll
0.6.2 (2019-01-15)
- Added readme.rst (#300)
- Contributors: Karsten Knese
0.6.1 (2018-12-13)
0.6.0 (2018-12-07)
- Cleaned up lifecycle demo (#283)
- Updated for refactoring in rclcpp (#276)
- Added semicolons to all RCLCPP and RCUTILS macros. (#278)
- Fixed typo in comment (#270)
- Contributors: Chris Lalancette, Karsten Knese, Yutaka Kondo
0.5.1 (2018-06-28)
0.5.0 (2018-06-27)
- Converted launch files to the new launch style. (#262)
- Updated to support remapping arguments to python nodes by passing unused arguments to rclpy from argparse. (#252)
- Updated to handle change in signature to
get_service_name
. (#245) - Updated launch files to account for the "old launch" getting
renamespaced as
launch
->launch.legacy
. (#239) - Updated service client demos to handle multiple requests. (#228)
- Contributors: Geoffrey Biggs, Kevin Allen, Shane Loretz, William Woodall, dhood
Wiki Tutorials
Package Dependencies
Deps | Name |
---|---|
ament_cmake | |
ament_lint_auto | |
ament_lint_common | |
ros_testing | |
lifecycle_msgs | |
rclcpp | |
rclcpp_lifecycle | |
std_msgs |
System Dependencies
Dependant Packages
Name | Deps |
---|---|
lifecycle_py | |
test_launch_ros | |
desktop |
Launch files
Messages
Services
Plugins
Recent questions tagged lifecycle at Robotics Stack Exchange
|
Package Summary
Tags | No category tags. |
Version | 0.35.0 |
License | Apache License 2.0 |
Build type | AMENT_CMAKE |
Use | RECOMMENDED |
Repository Summary
Checkout URI | https://github.com/ros2/demos.git |
VCS Type | git |
VCS Version | rolling |
Last Updated | 2024-11-01 |
Dev Status | DEVELOPED |
CI status | No Continuous Integration |
Released | RELEASED |
Tags | No category tags. |
Contributing |
Help Wanted (0)
Good First Issues (0) Pull Requests to Review (0) |
Package Description
Additional Links
Maintainers
- Aditya Pande
- Audrow Nash
Authors
- Karsten Knese
- Mabel Zhang
Introduction
ROS 2 introduces the concept of managed nodes, also called
LifecycleNode
s. In the following tutorial, we explain the purpose of
these nodes, what makes them different from regular nodes and how they
comply to a lifecycle management. Managed nodes contain a state machine
with a set of predefined states. These states can be changed by invoking
a transition id which indicates the succeeding consecutive state. The
state machine is implemented as described at the ROS 2 design
page.
Our implementation differentiates between Primary States
and
Transition States
. Primary States are supposed to be steady states in
which any node can do the respected task. On the other hand, Transition
States are meant as temporary intermediate states attached to a
transition. The result of these intermediate states are used to indicate
whether a transition between two primary states is considered successful
or not. Thus, any managed node can be in one of the following states:
Primary States (steady states):
- unconfigured
- inactive
- active
- shutdown
Transition States (intermediate states):
- configuring
- activating
- deactivating
- cleaningup
- shuttingdown
The possible transitions to invoke are:
- configure
- activate
- deactivate
- cleanup
- shutdown
For a more verbose explanation on the applied state machine, we refer to the design page which provides an in-detail explanation about each state and transition.
The demo
What's happening
The demo is split into 3 separate applications:
- lifecycle_talker
- lifecycle_listener
- lifecycle_service_client
The lifecycle_talker
represents a managed node and publishes according
to which state the node is in. We split the tasks of the talker node
into separate pieces and execute them as follows:
- configuring: We initialize our publisher and timer
- activate: We activate the publisher and timer in order to enable a publishing
- deactivate: We stop the publisher and timer
- cleanup: We destroy the publisher and timer
This demo shows a typical talker/listener pair of nodes. However, imagine a real scenario with attached hardware which may have a rather long booting phase, i.e. a laser or camera. One could imagine bringing up the device driver in the configuring state, start and stop only the publishing of the device's data in active/deactive state, and only in the cleanup/shutdown state actually shutdown the device.
The lifecycle_listener
is a simple listener which shows the
characteristics of the lifecycle talker. The talker enables message
publishing only in the active state and thus the listener only receives
messages when the talker is in an active state.
The lifecycle_service_client
is a script calling different transitions
on the lifecycle_talker
. This is meant as the external user
controlling the lifecycle of nodes.
Run the demo
In order to run this demo, we open three terminals and source our ROS 2 environment variables either from the binary distributions or the workspace we compiled from source.
lifecycle_talker lifecycle_listener lifecycle_service_client
———————————————————————————— ———————————————————————————— ————————————————————————————
$ ros2 run lifecycle lifecycle_talker
$ ros2 run lifecycle lifecycle_listener
$ ros2 run lifecycle lifecycle_service_client
Alternatively, these three programs can be run together in the same terminal using the launch file:
``` {.sourceCode .bash} ros2 launch lifecycle lifecycle_demo_launch.py
If we look at the output of the `lifecycle_talker`, we notice that
nothing seems to happen. This makes sense, since every node starts as
`unconfigured`. The lifecycle\_talker is not configured yet and in our
example, no publishers and timers are created yet. The same behavior can
be seen for the `lifecycle_listener`, which is less surprising given
that no publishers are available at this moment. The interesting part
starts with the third terminal. In there we launch our
`lifecycle_service_client` which is responsible for changing the states
of the `lifecycle_talker`.
Triggering transition 1 (configure)
-----------------------------------
``` {.sourceCode .bash}
[lc_client] Transition 1 successfully triggered.
[lc_client] Node lc_talker has current state inactive.
Makes the lifecycle talker change its state to inactive. Inactive means that all publishers and timers are created and configured. However, the node is still not active. Therefore no messages are getting published.
``` {.sourceCode .bash} [lc_talker] on_configure() is called. Lifecycle publisher is currently inactive. Messages are not published. …
At the same time the lifecycle listener receives a notification as it
listens to every state change notification of the lifecycle talker. In
fact, the listener receives two consecutive notifications. One for
changing from the primary state \"unconfigured\" to \"configuring\", and
a second notification changing the state from \"configuring\" to
\"inactive\" (since the configuring step was successful in the talker).
``` {.sourceCode .bash}
[lc_listener] notify callback: Transition from state unconfigured to configuring
[lc_listener] notify callback: Transition from state configuring to inactive
Triggering transition 2 (activate)
``` {.sourceCode .bash} [lc_client] Transition 2 successfully triggered. [lc_client] Node lc_talker has current state active.
Makes the lifecycle talker change its state to active. That means all
publishers and timers are now activated and therefore the messages are
now getting published.
``` {.sourceCode .bash}
[lc_talker] on_activate() is called.
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #11]
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #12]
...
The lifecycle listener receives the same set of notifications as before. Lifecycle talker changed its state from inactive to active.
``` {.sourceCode .bash} [lc_listener]: notify callback: Transition from state inactive to activating [lc_listener]: notify callback: Transition from state activating to active
The difference from the earlier transition event is that our listener
now also receives the actual published data.
``` {.sourceCode .bash}
[lc_listener] data_callback: Lifecycle HelloWorld #11
[lc_listener] data_callback: Lifecycle HelloWorld #12
...
Please note that the index of the published message is already at 11.
The purpose of this demo is to show that even though we call publish
at every state of the lifecycle talker, the messages are only actually
published when the state in active.
For the rest of the demo, you will see similar output as we deactivate and activate the lifecycle talker and finally shut it down.
The demo code
lifecycle_talker, lifecycle_listener and lifecycle_service_client
If we have a look at the code, there is one significant change for the
lifecycle talker compared to a regular talker. Our node does not inherit
from the regular rclcpp::node::Node
but from
rclcpp_lifecycle::LifecycleNode
.
``` {.sourceCode .bash} class LifecycleTalker : public rclcpp_lifecycle::LifecycleNode
Every child of LifecycleNodes have a set of callbacks provided. These
callbacks go along with the applied state machine attached to it. These
callbacks are:
``` {.sourceCode .c}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_configure(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_activate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_deactivate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_cleanup(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_shutdown(const rclcpp_lifecycle::State & previous_state)
In the following we assume that we are inside the namespace
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface
to shorten
the name of the return type. All these callbacks have a positive default
return value (return CallbackReturn::SUCCESS
). This allows a lifecycle
node to change its state even though no explicit callback function was
overridden. There is one other callback function for error handling.
Whenever a state transition throws an uncaught exception, we call
on_error
:
CallbackReturn on_error(const rclcpp_lifecycle::State & previous_state)
This gives room for executing custom error handling. Only (!) in the
case that this function returns CallbackReturn::SUCCESS
, the state
machine transitions to the state unconfigured
. By default, the
on_error
returns CallbackReturn::FAILURE
and the state machine
transitions into finalized
.
At the same time, every lifecycle node has by default 5 different communication interfaces.
- Publisher
<node_name>__transition_event
: publishes in case a transition is happening.
This allows users to get notified of transition events within the network.
- Service
<node_name>__get_state
: query about the current state of the node.
Return either a primary or transition state.
- Service
<node_name>__change_state
: triggers a transition for the current node.
This service call takes a transition id. The transition is fulfilled only in the case that this transition ID is a valid transition from the current state. All other cases are ignored.
- Service
<node_name>__get_available_states
: This is meant to be an introspection tool.
It returns a list of all possible states this node can be.
- Service
<node_name>__get_available_transitions
: Same as above, meant to an introspection tool.
It returns a list of all possible transitions this node can execute.
ros2 lifecycle command line interface
The lifecycle_service_client
application is a fixed order script for
demo purposes only. It explains the use and the API calls made for this
lifecycle implementation, but may be inconvenient to use otherwise. For
this reason we implemented a command line tool which lets you
dynamically change states or various nodes.
In the case you want to get the current state of the lc_talker
node,
you would call:
``` {.sourceCode .bash} $ ros2 lifecycle get /lc_talker unconfigured [1]
The next step would be to execute a state change:
``` {.sourceCode .bash}
$ ros2 lifecycle set /lc_talker configure
Transitioning successful
In order to see what states are currently available:
``` {.sourceCode .bash} $ ros2 lifecycle list lc_talker
- configure [1] Start: unconfigured Goal: configuring
- shutdown [5] Start: unconfigured Goal: shuttingdown
In this case we see that currently, the available transitions are
`configure` and `shutdown`. The complete state machine can be viewed
with the following command, which can be helpful for debugging or
visualization purposes:
``` {.sourceCode .bash}
$ ros2 lifecycle list lc_talker -a
- configure [1]
Start: unconfigured
Goal: configuring
- transition_success [10]
Start: configuring
Goal: inactive
- transition_failure [11]
Start: configuring
Goal: unconfigured
- transition_error [12]
Start: configuring
Goal: errorprocessing
[...]
- transition_error [62]
Start: errorprocessing
Goal: finalized
All of the above commands are nothing more than calling the lifecycle node's services. With that being said, we can also call these services directly with the ros2 command line interface:
``` {.sourceCode .bash} $ ros2 service call /lc_talker/get_state lifecycle_msgs/GetState requester: making request: lifecycle_msgs.srv.GetState_Request()
response: lifecycle_msgs.srv.GetState_Response(current_state=lifecycle_msgs.msg.State(id=1, label=’unconfigured’))
In order to trigger a transition, we call the `change_state` service
``` {.sourceCode .bash}
$ ros2 service call /lc_talker/change_state lifecycle_msgs/ChangeState "{transition: {id: 2}}"
requester: making request: lifecycle_msgs.srv.ChangeState_Request(transition=lifecycle_msgs.msg.Transition(id=2, label=''))
response:
lifecycle_msgs.srv.ChangeState_Response(success=True)
It is slightly less convenient, because you have to know the IDs which correspond to each transition. You can find them though in the lifecycle_msgs package.
``` {.sourceCode .bash} $ ros2 interface show lifecycle_msgs/msg/Transition
```
Changelog for package lifecycle
0.35.0 (2024-10-03)
0.34.2 (2024-07-29)
0.34.1 (2024-06-17)
0.34.0 (2024-04-26)
0.33.2 (2024-03-28)
- A few uncrustify fixes for 0.78. (#667)
- Update maintainer list in package.xml files (#665)
- Contributors: Chris Lalancette, Michael Jeronimo
0.33.1 (2024-02-07)
0.33.0 (2024-01-24)
- Migrate std::bind calls to lambda expressions (#659)
- Contributors: Felipe Gomes de Melo
0.32.1 (2023-12-26)
0.32.0 (2023-11-06)
0.31.1 (2023-09-07)
0.31.0 (2023-08-21)
- Switch to using RCLCPP logging macros in the lifecycle package. (#644)
- Contributors: Chris Lalancette
0.30.1 (2023-07-11)
0.30.0 (2023-06-12)
0.29.0 (2023-06-07)
0.28.1 (2023-05-11)
0.28.0 (2023-04-27)
0.27.0 (2023-04-13)
0.26.0 (2023-04-11)
- update launch file name format to match documentation (#588)
- Contributors: Patrick Wspanialy
0.25.0 (2023-03-01)
0.24.1 (2023-02-24)
0.24.0 (2023-02-14)
- Update the demos to C++17. (#594)
- [rolling] Update maintainers - 2022-11-07 (#589)
- Contributors: Audrow Nash, Chris Lalancette
0.23.0 (2022-11-02)
0.22.0 (2022-09-13)
0.21.0 (2022-04-29)
0.20.1 (2022-04-08)
- Make lifecycle demo automatically exit when done (#558)
- Contributors: Shane Loretz
0.20.0 (2022-03-01)
- Use default on_activate()/on_deactivate() implemenetation of Node (#552)
- Contributors: Ivan Santiago Paunovic
0.19.0 (2022-01-14)
0.18.0 (2021-12-17)
- Update maintainers to Audrow Nash and Michael Jeronimo (#543)
- Contributors: Audrow Nash
0.17.0 (2021-10-18)
- Fix use of future in lifecycle demo (#534)
- Fixing deprecated subscriber callback warnings (#532)
- Contributors: Abrar Rahman Protyasha, Christophe Bedard
0.16.0 (2021-08-11)
0.15.0 (2021-05-14)
0.14.2 (2021-04-26)
- Cleanup the README.rst for the lifecycle demo. (#508)
- Contributors: Chris Lalancette
0.14.1 (2021-04-19)
0.14.0 (2021-04-06)
- change ParameterEventHandler to take events as const ref instead of shared pointer (#494)
- Contributors: William Woodall
0.13.0 (2021-03-25)
0.12.1 (2021-03-18)
0.12.0 (2021-01-25)
0.11.0 (2020-12-10)
- Update the package.xml files with the latest Open Robotics maintainers (#466)
- Contributors: Michael Jeronimo
0.10.1 (2020-09-21)
- Add missing required parameter in LifecycleNode launch action (#456)
- Contributors: Ivan Santiago Paunovic
0.10.0 (2020-06-17)
0.9.3 (2020-06-01)
0.9.2 (2020-05-26)
- Fix typo (#445)
- Replace
ros2 msg
command in lifecycle README (#446) - Contributors: Audrow Nash, Shota Aoki
0.9.1 (2020-05-12)
0.9.0 (2020-04-30)
- Replace deprecated launch_ros usage (#437)
- Update launch_ros action usage (#431)
- code style only: wrap after open parenthesis if not in one line (#429)
- Contributors: Dirk Thomas, Jacob Perron
0.8.4 (2019-11-19)
0.8.3 (2019-11-11)
0.8.2 (2019-11-08)
- Remove unnecessary dependency on ros2run (#413)
- Contributors: Michel Hidalgo
0.8.1 (2019-10-23)
- Replace ready_fn with ReadyToTest action (#404)
- Contributors: Peter Baughman
0.8.0 (2019-09-26)
- Fix lifecycle_service_client namespace (#369)
- Contributors: Cameron Evans
0.7.6 (2019-05-30)
0.7.5 (2019-05-29)
- Update asciinema recordings (#360)
- Use rate instead of thread::sleep to react to Ctrl-C (#348)
- Contributors: Dirk Thomas, Karsten Knese
0.7.4 (2019-05-20)
- Add lifecycle rostest (#336)
- Contributors: Michel Hidalgo
0.7.3 (2019-05-10)
0.7.2 (2019-05-08)
- changes to avoid deprecated API's (#332)
- Corrected publish calls with shared_ptr signature (#327)
- Contributors: William Woodall, ivanpauno
0.7.1 (2019-04-26)
0.7.0 (2019-04-14)
- Updated for NodeOptions Node constructor. (#308)
- Contributors: Michael Carroll
0.6.2 (2019-01-15)
- Added readme.rst (#300)
- Contributors: Karsten Knese
0.6.1 (2018-12-13)
0.6.0 (2018-12-07)
- Cleaned up lifecycle demo (#283)
- Updated for refactoring in rclcpp (#276)
- Added semicolons to all RCLCPP and RCUTILS macros. (#278)
- Fixed typo in comment (#270)
- Contributors: Chris Lalancette, Karsten Knese, Yutaka Kondo
0.5.1 (2018-06-28)
0.5.0 (2018-06-27)
- Converted launch files to the new launch style. (#262)
- Updated to support remapping arguments to python nodes by passing unused arguments to rclpy from argparse. (#252)
- Updated to handle change in signature to
get_service_name
. (#245) - Updated launch files to account for the "old launch" getting
renamespaced as
launch
->launch.legacy
. (#239) - Updated service client demos to handle multiple requests. (#228)
- Contributors: Geoffrey Biggs, Kevin Allen, Shane Loretz, William Woodall, dhood
Wiki Tutorials
Package Dependencies
Deps | Name |
---|---|
ament_cmake | |
ament_lint_auto | |
ament_lint_common | |
ros_testing | |
lifecycle_msgs | |
rclcpp | |
rclcpp_lifecycle | |
std_msgs |
System Dependencies
Dependant Packages
Name | Deps |
---|---|
lifecycle_py | |
test_launch_ros | |
desktop |
Launch files
Messages
Services
Plugins
Recent questions tagged lifecycle at Robotics Stack Exchange
|
Package Summary
Tags | No category tags. |
Version | 0.4.0 |
License | Apache License 2.0 |
Build type | AMENT_CMAKE |
Use | RECOMMENDED |
Repository Summary
Checkout URI | https://github.com/ros2/demos.git |
VCS Type | git |
VCS Version | ardent |
Last Updated | 2017-12-09 |
Dev Status | DEVELOPED |
CI status | No Continuous Integration |
Released | RELEASED |
Tags | No category tags. |
Contributing |
Help Wanted (0)
Good First Issues (0) Pull Requests to Review (0) |
Package Description
Additional Links
Maintainers
- Karsten Knese
Authors
Wiki Tutorials
Package Dependencies
Deps | Name |
---|---|
lifecycle_msgs | |
rclcpp_lifecycle | |
std_msgs | |
ament_cmake | |
ros2run | |
ament_lint_auto | |
ament_lint_common |
System Dependencies
Dependant Packages
Name | Deps |
---|---|
desktop |
Launch files
Messages
Services
Plugins
Recent questions tagged lifecycle at Robotics Stack Exchange
|
Package Summary
Tags | No category tags. |
Version | 0.5.1 |
License | Apache License 2.0 |
Build type | AMENT_CMAKE |
Use | RECOMMENDED |
Repository Summary
Checkout URI | https://github.com/ros2/demos.git |
VCS Type | git |
VCS Version | bouncy |
Last Updated | 2018-10-30 |
Dev Status | DEVELOPED |
CI status | No Continuous Integration |
Released | RELEASED |
Tags | No category tags. |
Contributing |
Help Wanted (0)
Good First Issues (0) Pull Requests to Review (0) |
Package Description
Additional Links
Maintainers
- Karsten Knese
Authors
Introduction
ROS2 introduces the concept of managed nodes, also called
LifecycleNode
s. In the following tutorial, we explain the purpose of
these nodes, what makes them different from regular nodes and how they
comply to a lifecycle management. Managed nodes are scoped within a
state machine of a finite amount of states. These states can be changed
by invoking a transition id which indicates the succeeding consecutive
state. The state machine is implemented as described at the ROS2 design
page.
Our implementation differentiates between Primary States
and
Transition States
. Primary States are supposed to be steady states in
which any node can do the respected task. On the other hand, Transition
States are meant as temporary intermediate states attached to a
transition. The result of these intermediate states are used to indicate
whether a transition between two primary states is considered successful
or not. Thus, any managed node can be in one of the following states:
Primary States (steady states):
- unconfigured
- inactive
- active
- shutdown
Transition States (intermediate states):
- configuring
- activating
- deactivating
- cleaningup
- shuttingdown
The possible transitions to invoke are:
- configure
- activate
- deactivate
- cleanup
- shutdown
For a more verbose explanation on the applied state machine, we refer to the design page which provides an in-detail explanation about each state and transition.
The demo
What's happening
The demo is split into 3 different separate applications.
- lifecycle_talker
- lifecycle_listener
- lifecycle_service_client
The lifecycle_talker
represents a managed node and publishes according
to which state the node is in. We split the tasks of the talker node
into separate pieces and execute them as followed.
- configuring: We initialize our publisher and timer
- activate: We activate the publisher and timer in order to enable a publishing
- deactivate: We stop the publisher and timer
- cleanup: We destroy the publisher and timer
The principle is implemented in this demo as the typical talker/listener demo. However, imaging a real scenario with attached hardware which may have a rather long booting phase, i.e. a laser or camera. One could image bringing up the device driver in the configuring state, start and stop only the publishing of the device's data and only in the cleanup/shutdown phase actually shutdown the device.
The lifecycle_listener
is a simple listener which shows the
characteristics of the lifecycle talker. The talker enables the message
publishing only in the active state and thus making the listener
receiving only messages when the talker is in an active state.
The lifecycle_service_client
is a script calling different transitions
on the lifecycle_talker
. This is meant as the external user
controlling the lifecycle of nodes.
Run the demo
In order to run this demo, we open three terminals and source our ROS2 environment variables either from the binary distributions or the workspace we compiled from source.
lifecycle_talker lifecycle_listener lifecycle_service_client
————————————————————————————————————————– ————————————————————————————————————————– ————————————————————————————————————————–
$ ros2 run lifecycle lifecycle_talker
$ ros2 run lifecycle lifecycle_listener
$ ros2 run lifecycle lifecycle_service_client
Alternatively, these three programs can be run together in the same terminal using the launch file (as of ROS 2 Bouncy):
``` {.sourceCode .bash} ros2 launch lifecycle lifecycle_demo.launch.py
If we look at the output of the `lifecycle_talker`, we notice that
nothing seems to happen. And this does make sense, since every node
starts as `unconfigured`. The lifecycle\_talker is not configured yet
and in our example, no publishers and timers are created yet. The same
behavior can be seen for the `lifecycle_listener`, which is less
surprising given that no publishers are available at this moment. The
interesting part starts with the third terminal. In there we launch our
`lifecycle_service_client` which is responsible for changing the states
of the `lifecycle_talker`.
Triggering transition 1 (configure)
-----------------------------------
``` {.sourceCode .bash}
[lc_client] Transition 1 successfully triggered.
[lc_client] Node lc_talker has current state inactive.
makes the lifecycle talker change its state to inactive. Inactive means that all publishers and timers are created and configured. However, the node is still not active. Therefore no messages are getting published.
``` {.sourceCode .bash} [lc_talker] on_configure() is called. Lifecycle publisher is currently inactive. Messages are not published. …
The lifecycle listener on the same time receives a notification as it
listens to every state change notification of the lifecycle talker. In
fact, the listener receives two consecutive notifications. One for
changing from the primary state \"unconfigured\" to \"configuring\".
Because the configuring step was successful within the lifecycle talker,
a second notification from \"configuring\" to \"inactive\".
``` {.sourceCode .bash}
[lc_listener] notify callback: Transition from state unconfigured to configuring
[lc_listener] notify callback: Transition from state configuring to inactive
Triggering transition 2 (activate)
``` {.sourceCode .bash} [lc_client] Transition 2 successfully triggered. [lc_client] Node lc_talker has current state active.
makes the lifecycle talker change its state to active. Active means that
all publishers and timers are now activated. Therefore the messages are
now getting published.
``` {.sourceCode .bash}
[lc_talker] on_activate() is called.
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #11]
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #12]
...
The lifecycle listener receives the same set of notifications as before. Lifecycle talker changed its state from inactive to active.
``` {.sourceCode .bash} [lc_listener] notify callback: Transition from state unconfigured to configuring [lc_listener] notify callback: Transition from state configuring to inactive
The difference to the transition event before is that our listener now
also receives the actual published data.
``` {.sourceCode .bash}
[lc_listener] data_callback: Lifecycle HelloWorld #11
[lc_listener] data_callback: Lifecycle HelloWorld #12
...
Please note that the index of the published message is already at 11.
The purpose of this demo is to show that even though we call publish
at every state of the lifecycle talker, only when the state in active,
the messages are actually published. As for the beta1, all other
messages are getting ignored. This behavior may change in future
versions in order to provide better error handling.
For the rest of the demo, you will see similar output as we deactivate and activate the lifecycle talker and finally shut it down.
The demo code
lifecycle_talker, lifecycle_listener and lifecycle_service_client
If we have a look at the code, there is one significant change for the
lifecycle talker compared to a regular talker. Our node does not inherit
from the regular rclcpp::node::Node
but from
rclcpp_lifecycle::LifecycleNode
.
``` {.sourceCode .bash} class LifecycleTalker : public rclcpp_lifecycle::LifecycleNode
Every child of LifecycleNodes have a set of callbacks provided. These
callbacks go along with the applied state machine attached to it. These
callbacks are:
- `rcl_lifecycle_ret_t on_configure(const rclcpp_lifecycle::State & previous_state)`
- `rcl_lifecycle_ret_t on_activate(const rclcpp_lifecycle::State & previous_state)`
- `rcl_lifecycle_ret_t on_deactivate(const rclcpp_lifecycle::State & previous_state)`
- `rcl_lifecycle_ret_t on_cleanup(const rclcpp_lifecycle::State & previous_state)`
- `rcl_lifecycle_ret_t on_shutdown(const rclcpp_lifecycle::State & previous_state)`
All these callbacks have a positive default return value
(`return RCL_LIFECYCLE_RET_OK`). This allows a lifecycle node to change
its state even though no explicit callback function was overwritten.
There is one other callback function for error handling. Whenever a
state transition throws an uncaught exception, we call `on_error`.
- `rcl_lifecycle_ret_t on_error(const rclcpp_lifecycle::State & previous_state)`
This gives room for executing a custom error handling. Only (!) in the
case that this function returns `RCL_LIFECYCLE_RET_OK`, the state
machine transitions to the state `unconfigured`. By default, the
`on_error` returns `RCL_LIFECYCLE_RET_ERROR` and the state machine
transitions into `finalized`.
At the same time, every lifecycle node has by default 5 different
communication interfaces.
\* Publisher `<node_name>__transition_event`: publishes in case a
transition is happening. This allows users to get notified of transition
events within the network.
\* Service `<node_name>__get_state`: query about the current state of
the node. Return either a primary or transition state.
\* Service `<node_name>__change_state`: triggers a transition for the
current node. This service call takes a transition id. Only in the case,
that this transition ID is a valid transition of the current state, the
transition is fulfilled. All other cases are getting ignored.
\* Service `<node_name>__get_available_states`: This is meant to be an
introspection tool. It returns a list of all possible states this node
can be.
\* Service `<node_name>__get_available_transitions`: Same as above,
meant to an introspection tool. It returns a list of all possible
transitions this node can execute.
lifecycle\_service\_client\_py.py
---------------------------------
The `lifecycle_service_client` application is a fixed order script for
this demo purpose only. It explains the use and the API calls made for
this lifecycle implementation, but may be inconvenient to use otherwise.
For this reason, we implemented a separate python script, which lets you
dynamically change states or various nodes.
``` {.sourceCode .bash}
$ ros2 run lifecycle lifecycle_service_client_py.py
usage: lifecycle_service_client_py.py [-h]
[--change-state-args {configure,cleanup,shutdown,activate,deactivate}]
{change_state,get_state,get_available_states,get_available_transitions}
node
In the case you want to get the current state of the lc_talker
node,
you'd call:
``` {.sourceCode .bash} $ ros2 run lifecycle lifecycle_service_client_py.py get_state lc_talker lc_talker is in state unconfigured(1)
The next step would be to execute a state change:
``` {.sourceCode .bash}
$ ros2 run lifecycle lifecycle_service_client_py.py change_state --change-state-args configure lc_talker
All of the above commands are nothing else than calling the lifecycle node's services. With that being said, we can also call these services directly with the ros2 command line interface:
``` {.sourceCode .bash} $ ros2 service call /lc_talker/get_state lifecycle_msgs/GetState “{node_name: lc_talker}” requester: making request: lifecycle_msgs.srv.GetState_Request(node_name=’lc_talker’)
response: lifecycle_msgs.srv.GetState_Response(current_state=lifecycle_msgs.msg.State(id=1, label=’unconfigured’))
In order to trigger a transition, we call the `change_state` service
``` {.sourceCode .bash}
$ ros2 service call /lc_talker/change_state lifecycle_msgs/ChangeState "{node_name: lc_talker, transition: {id: 2}}"
requester: making request: lifecycle_msgs.srv.ChangeState_Request(node_name='lc_talker', transition=lifecycle_msgs.msg.Transition(id=2, label=''))
response:
lifecycle_msgs.srv.ChangeState_Response(success=True)
It is slightly less convenient, because you have to know the IDs which correspond to each transition. You can find them though in the lifecycle_msgs package.
Outlook
The above description points to the current state of the development as for beta1. The future todo list for this topic comprises:
- Python lifecycle nodes
- Lifecycle manager: A global node, handling and dispatching trigger requests for multiple nodes.
- LifeyclceSubscriber/LifecycleWalltimer/... add more lifecycle controlled entities.
Changelog for package lifecycle
0.5.1 (2018-06-28)
0.5.0 (2018-06-27)
- Converted launch files to the new launch style. (#262)
- Updated to support remapping arguments to python nodes by passing unused arguments to rclpy from argparse. (#252)
- Updated to handle change in signature to
get_service_name
. (#245) - Updated launch files to account for the "old launch" getting
renamespaced as
launch
->launch.legacy
. (#239) - Updated service client demos to handle multiple requests. (#228)
- Contributors: Geoffrey Biggs, Kevin Allen, Shane Loretz, William Woodall, dhood
Wiki Tutorials
Package Dependencies
Deps | Name |
---|---|
lifecycle_msgs | |
rclcpp_lifecycle | |
std_msgs | |
ament_cmake | |
ros2run | |
ament_lint_auto | |
ament_lint_common |
System Dependencies
Dependant Packages
Name | Deps |
---|---|
desktop |
Launch files
Messages
Services
Plugins
Recent questions tagged lifecycle at Robotics Stack Exchange
|
Package Summary
Tags | No category tags. |
Version | 0.6.2 |
License | Apache License 2.0 |
Build type | AMENT_CMAKE |
Use | RECOMMENDED |
Repository Summary
Checkout URI | https://github.com/ros2/demos.git |
VCS Type | git |
VCS Version | crystal |
Last Updated | 2019-01-15 |
Dev Status | DEVELOPED |
CI status | No Continuous Integration |
Released | RELEASED |
Tags | No category tags. |
Contributing |
Help Wanted (0)
Good First Issues (0) Pull Requests to Review (0) |
Package Description
Additional Links
Maintainers
- Karsten Knese
Authors
Introduction
ROS2 introduces the concept of managed nodes, also called
LifecycleNode
s. In the following tutorial, we explain the purpose of
these nodes, what makes them different from regular nodes and how they
comply to a lifecycle management. Managed nodes are scoped within a
state machine of a finite amount of states. These states can be changed
by invoking a transition id which indicates the succeeding consecutive
state. The state machine is implemented as described at the ROS2 design
page.
Our implementation differentiates between Primary States
and
Transition States
. Primary States are supposed to be steady states in
which any node can do the respected task. On the other hand, Transition
States are meant as temporary intermediate states attached to a
transition. The result of these intermediate states are used to indicate
whether a transition between two primary states is considered successful
or not. Thus, any managed node can be in one of the following states:
Primary States (steady states):
- unconfigured
- inactive
- active
- shutdown
Transition States (intermediate states):
- configuring
- activating
- deactivating
- cleaningup
- shuttingdown
The possible transitions to invoke are:
- configure
- activate
- deactivate
- cleanup
- shutdown
For a more verbose explanation on the applied state machine, we refer to the design page which provides an in-detail explanation about each state and transition.
The demo
What's happening
The demo is split into 3 different separate applications.
- lifecycle_talker
- lifecycle_listener
- lifecycle_service_client
The lifecycle_talker
represents a managed node and publishes according
to which state the node is in. We split the tasks of the talker node
into separate pieces and execute them as followed.
- configuring: We initialize our publisher and timer
- activate: We activate the publisher and timer in order to enable a publishing
- deactivate: We stop the publisher and timer
- cleanup: We destroy the publisher and timer
The principle is implemented in this demo as the typical talker/listener demo. However, imaging a real scenario with attached hardware which may have a rather long booting phase, i.e. a laser or camera. One could image bringing up the device driver in the configuring state, start and stop only the publishing of the device's data and only in the cleanup/shutdown phase actually shutdown the device.
The lifecycle_listener
is a simple listener which shows the
characteristics of the lifecycle talker. The talker enables the message
publishing only in the active state and thus making the listener
receiving only messages when the talker is in an active state.
The lifecycle_service_client
is a script calling different transitions
on the lifecycle_talker
. This is meant as the external user
controlling the lifecycle of nodes.
Run the demo
In order to run this demo, we open three terminals and source our ROS2 environment variables either from the binary distributions or the workspace we compiled from source.
lifecycle_talker lifecycle_listener lifecycle_service_client
————————————————————————————————————————– ————————————————————————————————————————– ————————————————————————————————————————–
$ ros2 run lifecycle lifecycle_talker
$ ros2 run lifecycle lifecycle_listener
$ ros2 run lifecycle lifecycle_service_client
Alternatively, these three programs can be run together in the same terminal using the launch file (as of ROS 2 Bouncy):
``` {.sourceCode .bash} ros2 launch lifecycle lifecycle_demo.launch.py
If we look at the output of the `lifecycle_talker`, we notice that
nothing seems to happen. And this does make sense, since every node
starts as `unconfigured`. The lifecycle\_talker is not configured yet
and in our example, no publishers and timers are created yet. The same
behavior can be seen for the `lifecycle_listener`, which is less
surprising given that no publishers are available at this moment. The
interesting part starts with the third terminal. In there we launch our
`lifecycle_service_client` which is responsible for changing the states
of the `lifecycle_talker`.
Triggering transition 1 (configure)
-----------------------------------
``` {.sourceCode .bash}
[lc_client] Transition 1 successfully triggered.
[lc_client] Node lc_talker has current state inactive.
makes the lifecycle talker change its state to inactive. Inactive means that all publishers and timers are created and configured. However, the node is still not active. Therefore no messages are getting published.
``` {.sourceCode .bash} [lc_talker] on_configure() is called. Lifecycle publisher is currently inactive. Messages are not published. …
The lifecycle listener on the same time receives a notification as it
listens to every state change notification of the lifecycle talker. In
fact, the listener receives two consecutive notifications. One for
changing from the primary state \"unconfigured\" to \"configuring\".
Because the configuring step was successful within the lifecycle talker,
a second notification from \"configuring\" to \"inactive\".
``` {.sourceCode .bash}
[lc_listener] notify callback: Transition from state unconfigured to configuring
[lc_listener] notify callback: Transition from state configuring to inactive
Triggering transition 2 (activate)
``` {.sourceCode .bash} [lc_client] Transition 2 successfully triggered. [lc_client] Node lc_talker has current state active.
makes the lifecycle talker change its state to active. That means all
publishers and timers are now activated and herefore the messages are
now getting published.
``` {.sourceCode .bash}
[lc_talker] on_activate() is called.
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #11]
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #12]
...
The lifecycle listener receives the same set of notifications as before. Lifecycle talker changed its state from inactive to active.
``` {.sourceCode .bash} [lc_listener]: notify callback: Transition from state inactive to activating [lc_listener]: notify callback: Transition from state activating to active
The difference to the transition event before is that our listener now
also receives the actual published data.
``` {.sourceCode .bash}
[lc_listener] data_callback: Lifecycle HelloWorld #11
[lc_listener] data_callback: Lifecycle HelloWorld #12
...
Please note that the index of the published message is already at 11.
The purpose of this demo is to show that even though we call publish
at every state of the lifecycle talker, only when the state in active,
the messages are actually published. As for the beta1, all other
messages are getting ignored. This behavior may change in future
versions in order to provide better error handling.
For the rest of the demo, you will see similar output as we deactivate and activate the lifecycle talker and finally shut it down.
The demo code
lifecycle_talker, lifecycle_listener and lifecycle_service_client
If we have a look at the code, there is one significant change for the
lifecycle talker compared to a regular talker. Our node does not inherit
from the regular rclcpp::node::Node
but from
rclcpp_lifecycle::LifecycleNode
.
``` {.sourceCode .bash} class LifecycleTalker : public rclcpp_lifecycle::LifecycleNode
Every child of LifecycleNodes have a set of callbacks provided. These
callbacks go along with the applied state machine attached to it. These
callbacks are:
``` {.sourceCode .c}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_configure(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_activate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_deactivate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_cleanup(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_shutdown(const rclcpp_lifecycle::State & previous_state)
In the following we assume that we are inside the namespace
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface
to shorten
the name of the return type. All these callbacks have a positive default
return value (return CallbackReturn::SUCCESS
). This allows a lifecycle
node to change its state even though no explicit callback function was
overwritten. There is one other callback function for error handling.
Whenever a state transition throws an uncaught exception, we call
on_error
.
CallbackReturn on_error(const rclcpp_lifecycle::State & previous_state)
This gives room for executing a custom error handling. Only (!) in the
case that this function returns CallbackReturn::SUCCESS
, the state
machine transitions to the state unconfigured
. By default, the
on_error
returns CallbackReturn::FAILURE
and the state machine
transitions into finalized
.
At the same time, every lifecycle node has by default 5 different communication interfaces.
- Publisher
<node_name>__transition_event
: publishes in case a transition is happening.
This allows users to get notified of transition events within the network.
- Service
<node_name>__get_state
: query about the current state of the node.
Return either a primary or transition state.
- Service
<node_name>__change_state
: triggers a transition for the current node.
This service call takes a transition id. Only in the case, that this transition ID is a valid transition of the current state, the transition is fulfilled. All other cases are getting ignored.
- Service
<node_name>__get_available_states
: This is meant to be an introspection tool.
It returns a list of all possible states this node can be.
- Service
<node_name>__get_available_transitions
: Same as above, meant to an introspection tool.
It returns a list of all possible transitions this node can execute.
ros2 lifecycle command line interface
The lifecycle_service_client
application is a fixed order script for
this demo purpose only. It explains the use and the API calls made for
this lifecycle implementation, but may be inconvenient to use otherwise.
For this reason we implemented a command line tool which lets you
dynamically change states or various nodes.
In the case you want to get the current state of the lc_talker
node,
you would call:
``` {.sourceCode .bash} $ ros2 lifecycle get /lc_talker unconfigured [1]
The next step would be to execute a state change:
``` {.sourceCode .bash}
$ ros2 lifecycle set /lc_talker configure
Transitioning successful
In order to see what states are currently available:
``` {.sourceCode .bash} $ ros2 lifecycle list lc_talker
- configure [1] Start: unconfigured Goal: configuring
- shutdown [5] Start: unconfigured Goal: shuttingdown
In this case we see that currently, the available transitions are
`configure` and `shutdown`. The complete state machine can be viewed
with the following command, which can be helpful for debugging or
visualization purposes:
``` {.sourceCode .bash}
$ ros2 lifecycle list lc_talker -a
- configure [1]
Start: unconfigured
Goal: configuring
- transition_success [10]
Start: configuring
Goal: inactive
- transition_failure [11]
Start: configuring
Goal: unconfigured
- transition_error [12]
Start: configuring
Goal: errorprocessing
[...]
- transition_error [62]
Start: errorprocessing
Goal: finalized
All of the above commands are nothing else than calling the lifecycle node's services. With that being said, we can also call these services directly with the ros2 command line interface:
``` {.sourceCode .bash} $ ros2 service call /lc_talker/get_state lifecycle_msgs/GetState requester: making request: lifecycle_msgs.srv.GetState_Request()
response: lifecycle_msgs.srv.GetState_Response(current_state=lifecycle_msgs.msg.State(id=1, label=’unconfigured’))
In order to trigger a transition, we call the `change_state` service
``` {.sourceCode .bash}
$ ros2 service call /lc_talker/change_state lifecycle_msgs/ChangeState "{transition: {id: 2}}"
requester: making request: lifecycle_msgs.srv.ChangeState_Request(transition=lifecycle_msgs.msg.Transition(id=2, label=''))
response:
lifecycle_msgs.srv.ChangeState_Response(success=True)
It is slightly less convenient, because you have to know the IDs which correspond to each transition. You can find them though in the lifecycle_msgs package.
``` {.sourceCode .bash} $ ros2 msg show lifecycle_msgs/Transition
```
Outlook
The above description points to the current state of the development as for beta1. The future todo list for this topic comprises:
- Python lifecycle nodes
- Lifecycle manager: A global node, handling and dispatching trigger requests for multiple nodes.
- LifeyclceSubscriber/LifecycleWalltimer/... add more lifecycle controlled entities.
Changelog for package lifecycle
0.6.2 (2019-01-15)
- Added readme.rst (#300)
- Contributors: Karsten Knese
0.6.1 (2018-12-13)
0.6.0 (2018-12-07)
- Cleaned up lifecycle demo (#283)
- Updated for refactoring in rclcpp (#276)
- Added semicolons to all RCLCPP and RCUTILS macros. (#278)
- Fixed typo in comment (#270)
- Contributors: Chris Lalancette, Karsten Knese, Yutaka Kondo
0.5.1 (2018-06-28)
0.5.0 (2018-06-27)
- Converted launch files to the new launch style. (#262)
- Updated to support remapping arguments to python nodes by passing unused arguments to rclpy from argparse. (#252)
- Updated to handle change in signature to
get_service_name
. (#245) - Updated launch files to account for the "old launch" getting
renamespaced as
launch
->launch.legacy
. (#239) - Updated service client demos to handle multiple requests. (#228)
- Contributors: Geoffrey Biggs, Kevin Allen, Shane Loretz, William Woodall, dhood
Wiki Tutorials
Package Dependencies
Deps | Name |
---|---|
lifecycle_msgs | |
rclcpp_lifecycle | |
std_msgs | |
ament_cmake | |
ros2run | |
ament_lint_auto | |
ament_lint_common |
System Dependencies
Dependant Packages
Name | Deps |
---|---|
desktop |
Launch files
Messages
Services
Plugins
Recent questions tagged lifecycle at Robotics Stack Exchange
|
Package Summary
Tags | No category tags. |
Version | 0.8.4 |
License | Apache License 2.0 |
Build type | AMENT_CMAKE |
Use | RECOMMENDED |
Repository Summary
Checkout URI | https://github.com/ros2/demos.git |
VCS Type | git |
VCS Version | eloquent |
Last Updated | 2020-11-04 |
Dev Status | DEVELOPED |
CI status | No Continuous Integration |
Released | RELEASED |
Tags | No category tags. |
Contributing |
Help Wanted (0)
Good First Issues (0) Pull Requests to Review (0) |
Package Description
Additional Links
Maintainers
- Mabel Zhang
- Michael Jeronimo
Authors
- Karsten Knese
Introduction
ROS2 introduces the concept of managed nodes, also called
LifecycleNode
s. In the following tutorial, we explain the purpose of
these nodes, what makes them different from regular nodes and how they
comply to a lifecycle management. Managed nodes are scoped within a
state machine of a finite amount of states. These states can be changed
by invoking a transition id which indicates the succeeding consecutive
state. The state machine is implemented as described at the ROS2 design
page.
Our implementation differentiates between Primary States
and
Transition States
. Primary States are supposed to be steady states in
which any node can do the respected task. On the other hand, Transition
States are meant as temporary intermediate states attached to a
transition. The result of these intermediate states are used to indicate
whether a transition between two primary states is considered successful
or not. Thus, any managed node can be in one of the following states:
Primary States (steady states):
- unconfigured
- inactive
- active
- shutdown
Transition States (intermediate states):
- configuring
- activating
- deactivating
- cleaningup
- shuttingdown
The possible transitions to invoke are:
- configure
- activate
- deactivate
- cleanup
- shutdown
For a more verbose explanation on the applied state machine, we refer to the design page which provides an in-detail explanation about each state and transition.
The demo
What's happening
The demo is split into 3 different separate applications.
- lifecycle_talker
- lifecycle_listener
- lifecycle_service_client
The lifecycle_talker
represents a managed node and publishes according
to which state the node is in. We split the tasks of the talker node
into separate pieces and execute them as followed.
- configuring: We initialize our publisher and timer
- activate: We activate the publisher and timer in order to enable a publishing
- deactivate: We stop the publisher and timer
- cleanup: We destroy the publisher and timer
The principle is implemented in this demo as the typical talker/listener demo. However, imaging a real scenario with attached hardware which may have a rather long booting phase, i.e. a laser or camera. One could image bringing up the device driver in the configuring state, start and stop only the publishing of the device's data and only in the cleanup/shutdown phase actually shutdown the device.
The lifecycle_listener
is a simple listener which shows the
characteristics of the lifecycle talker. The talker enables the message
publishing only in the active state and thus making the listener
receiving only messages when the talker is in an active state.
The lifecycle_service_client
is a script calling different transitions
on the lifecycle_talker
. This is meant as the external user
controlling the lifecycle of nodes.
Run the demo
In order to run this demo, we open three terminals and source our ROS2 environment variables either from the binary distributions or the workspace we compiled from source.
lifecycle_talker lifecycle_listener lifecycle_service_client
———————————————————————————— ———————————————————————————— ————————————————————————————
$ ros2 run lifecycle lifecycle_talker
$ ros2 run lifecycle lifecycle_listener
$ ros2 run lifecycle lifecycle_service_client
Alternatively, these three programs can be run together in the same terminal using the launch file (as of ROS 2 Bouncy):
``` {.sourceCode .bash} ros2 launch lifecycle lifecycle_demo.launch.py
If we look at the output of the `lifecycle_talker`, we notice that
nothing seems to happen. And this does make sense, since every node
starts as `unconfigured`. The lifecycle\_talker is not configured yet
and in our example, no publishers and timers are created yet. The same
behavior can be seen for the `lifecycle_listener`, which is less
surprising given that no publishers are available at this moment. The
interesting part starts with the third terminal. In there we launch our
`lifecycle_service_client` which is responsible for changing the states
of the `lifecycle_talker`.
Triggering transition 1 (configure)
-----------------------------------
``` {.sourceCode .bash}
[lc_client] Transition 1 successfully triggered.
[lc_client] Node lc_talker has current state inactive.
makes the lifecycle talker change its state to inactive. Inactive means that all publishers and timers are created and configured. However, the node is still not active. Therefore no messages are getting published.
``` {.sourceCode .bash} [lc_talker] on_configure() is called. Lifecycle publisher is currently inactive. Messages are not published. …
The lifecycle listener on the same time receives a notification as it
listens to every state change notification of the lifecycle talker. In
fact, the listener receives two consecutive notifications. One for
changing from the primary state \"unconfigured\" to \"configuring\".
Because the configuring step was successful within the lifecycle talker,
a second notification from \"configuring\" to \"inactive\".
``` {.sourceCode .bash}
[lc_listener] notify callback: Transition from state unconfigured to configuring
[lc_listener] notify callback: Transition from state configuring to inactive
Triggering transition 2 (activate)
``` {.sourceCode .bash} [lc_client] Transition 2 successfully triggered. [lc_client] Node lc_talker has current state active.
makes the lifecycle talker change its state to active. That means all
publishers and timers are now activated and herefore the messages are
now getting published.
``` {.sourceCode .bash}
[lc_talker] on_activate() is called.
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #11]
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #12]
...
The lifecycle listener receives the same set of notifications as before. Lifecycle talker changed its state from inactive to active.
``` {.sourceCode .bash} [lc_listener]: notify callback: Transition from state inactive to activating [lc_listener]: notify callback: Transition from state activating to active
The difference to the transition event before is that our listener now
also receives the actual published data.
``` {.sourceCode .bash}
[lc_listener] data_callback: Lifecycle HelloWorld #11
[lc_listener] data_callback: Lifecycle HelloWorld #12
...
Please note that the index of the published message is already at 11.
The purpose of this demo is to show that even though we call publish
at every state of the lifecycle talker, only when the state in active,
the messages are actually published. As for the beta1, all other
messages are getting ignored. This behavior may change in future
versions in order to provide better error handling.
For the rest of the demo, you will see similar output as we deactivate and activate the lifecycle talker and finally shut it down.
The demo code
lifecycle_talker, lifecycle_listener and lifecycle_service_client
If we have a look at the code, there is one significant change for the
lifecycle talker compared to a regular talker. Our node does not inherit
from the regular rclcpp::node::Node
but from
rclcpp_lifecycle::LifecycleNode
.
``` {.sourceCode .bash} class LifecycleTalker : public rclcpp_lifecycle::LifecycleNode
Every child of LifecycleNodes have a set of callbacks provided. These
callbacks go along with the applied state machine attached to it. These
callbacks are:
``` {.sourceCode .c}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_configure(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_activate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_deactivate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_cleanup(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_shutdown(const rclcpp_lifecycle::State & previous_state)
In the following we assume that we are inside the namespace
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface
to shorten
the name of the return type. All these callbacks have a positive default
return value (return CallbackReturn::SUCCESS
). This allows a lifecycle
node to change its state even though no explicit callback function was
overwritten. There is one other callback function for error handling.
Whenever a state transition throws an uncaught exception, we call
on_error
.
CallbackReturn on_error(const rclcpp_lifecycle::State & previous_state)
This gives room for executing a custom error handling. Only (!) in the
case that this function returns CallbackReturn::SUCCESS
, the state
machine transitions to the state unconfigured
. By default, the
on_error
returns CallbackReturn::FAILURE
and the state machine
transitions into finalized
.
At the same time, every lifecycle node has by default 5 different communication interfaces.
- Publisher
<node_name>__transition_event
: publishes in case a transition is happening.
This allows users to get notified of transition events within the network.
- Service
<node_name>__get_state
: query about the current state of the node.
Return either a primary or transition state.
- Service
<node_name>__change_state
: triggers a transition for the current node.
This service call takes a transition id. Only in the case, that this transition ID is a valid transition of the current state, the transition is fulfilled. All other cases are getting ignored.
- Service
<node_name>__get_available_states
: This is meant to be an introspection tool.
It returns a list of all possible states this node can be.
- Service
<node_name>__get_available_transitions
: Same as above, meant to an introspection tool.
It returns a list of all possible transitions this node can execute.
ros2 lifecycle command line interface
The lifecycle_service_client
application is a fixed order script for
this demo purpose only. It explains the use and the API calls made for
this lifecycle implementation, but may be inconvenient to use otherwise.
For this reason we implemented a command line tool which lets you
dynamically change states or various nodes.
In the case you want to get the current state of the lc_talker
node,
you would call:
``` {.sourceCode .bash} $ ros2 lifecycle get /lc_talker unconfigured [1]
The next step would be to execute a state change:
``` {.sourceCode .bash}
$ ros2 lifecycle set /lc_talker configure
Transitioning successful
In order to see what states are currently available:
``` {.sourceCode .bash} $ ros2 lifecycle list lc_talker
- configure [1] Start: unconfigured Goal: configuring
- shutdown [5] Start: unconfigured Goal: shuttingdown
In this case we see that currently, the available transitions are
`configure` and `shutdown`. The complete state machine can be viewed
with the following command, which can be helpful for debugging or
visualization purposes:
``` {.sourceCode .bash}
$ ros2 lifecycle list lc_talker -a
- configure [1]
Start: unconfigured
Goal: configuring
- transition_success [10]
Start: configuring
Goal: inactive
- transition_failure [11]
Start: configuring
Goal: unconfigured
- transition_error [12]
Start: configuring
Goal: errorprocessing
[...]
- transition_error [62]
Start: errorprocessing
Goal: finalized
All of the above commands are nothing else than calling the lifecycle node's services. With that being said, we can also call these services directly with the ros2 command line interface:
``` {.sourceCode .bash} $ ros2 service call /lc_talker/get_state lifecycle_msgs/GetState requester: making request: lifecycle_msgs.srv.GetState_Request()
response: lifecycle_msgs.srv.GetState_Response(current_state=lifecycle_msgs.msg.State(id=1, label=’unconfigured’))
In order to trigger a transition, we call the `change_state` service
``` {.sourceCode .bash}
$ ros2 service call /lc_talker/change_state lifecycle_msgs/ChangeState "{transition: {id: 2}}"
requester: making request: lifecycle_msgs.srv.ChangeState_Request(transition=lifecycle_msgs.msg.Transition(id=2, label=''))
response:
lifecycle_msgs.srv.ChangeState_Response(success=True)
It is slightly less convenient, because you have to know the IDs which correspond to each transition. You can find them though in the lifecycle_msgs package.
``` {.sourceCode .bash} $ ros2 msg show lifecycle_msgs/Transition
```
Outlook
The above description points to the current state of the development as for beta1. The future todo list for this topic comprises:
- Python lifecycle nodes
- Lifecycle manager: A global node, handling and dispatching trigger requests for multiple nodes.
- LifeyclceSubscriber/LifecycleWalltimer/... add more lifecycle controlled entities.
Changelog for package lifecycle
0.8.4 (2019-11-19)
0.8.3 (2019-11-11)
0.8.2 (2019-11-08)
- Remove unnecessary dependency on ros2run (#413)
- Contributors: Michel Hidalgo
0.8.1 (2019-10-23)
- Replace ready_fn with ReadyToTest action (#404)
- Contributors: Peter Baughman
0.8.0 (2019-09-26)
- Fix lifecycle_service_client namespace (#369)
- Contributors: Cameron Evans
0.7.6 (2019-05-30)
0.7.5 (2019-05-29)
- Update asciinema recordings (#360)
- Use rate instead of thread::sleep to react to Ctrl-C (#348)
- Contributors: Dirk Thomas, Karsten Knese
0.7.4 (2019-05-20)
- Add lifecycle rostest (#336)
- Contributors: Michel Hidalgo
0.7.3 (2019-05-10)
0.7.2 (2019-05-08)
- changes to avoid deprecated API's (#332)
- Corrected publish calls with shared_ptr signature (#327)
- Contributors: William Woodall, ivanpauno
0.7.1 (2019-04-26)
0.7.0 (2019-04-14)
- Updated for NodeOptions Node constructor. (#308)
- Contributors: Michael Carroll
0.6.2 (2019-01-15)
- Added readme.rst (#300)
- Contributors: Karsten Knese
0.6.1 (2018-12-13)
0.6.0 (2018-12-07)
- Cleaned up lifecycle demo (#283)
- Updated for refactoring in rclcpp (#276)
- Added semicolons to all RCLCPP and RCUTILS macros. (#278)
- Fixed typo in comment (#270)
- Contributors: Chris Lalancette, Karsten Knese, Yutaka Kondo
0.5.1 (2018-06-28)
0.5.0 (2018-06-27)
- Converted launch files to the new launch style. (#262)
- Updated to support remapping arguments to python nodes by passing unused arguments to rclpy from argparse. (#252)
- Updated to handle change in signature to
get_service_name
. (#245) - Updated launch files to account for the "old launch" getting
renamespaced as
launch
->launch.legacy
. (#239) - Updated service client demos to handle multiple requests. (#228)
- Contributors: Geoffrey Biggs, Kevin Allen, Shane Loretz, William Woodall, dhood
Wiki Tutorials
Package Dependencies
Deps | Name |
---|---|
lifecycle_msgs | |
rclcpp_lifecycle | |
std_msgs | |
ament_cmake | |
ament_lint_auto | |
ament_lint_common | |
ros_testing |
System Dependencies
Dependant Packages
Name | Deps |
---|---|
desktop |
Launch files
Messages
Services
Plugins
Recent questions tagged lifecycle at Robotics Stack Exchange
|
Package Summary
Tags | No category tags. |
Version | 0.7.9 |
License | Apache License 2.0 |
Build type | AMENT_CMAKE |
Use | RECOMMENDED |
Repository Summary
Checkout URI | https://github.com/ros2/demos.git |
VCS Type | git |
VCS Version | dashing |
Last Updated | 2020-10-28 |
Dev Status | DEVELOPED |
CI status | No Continuous Integration |
Released | RELEASED |
Tags | No category tags. |
Contributing |
Help Wanted (0)
Good First Issues (0) Pull Requests to Review (0) |
Package Description
Additional Links
Maintainers
- Mabel Zhang
- Michael Jeronimo
Authors
- Karsten Knese
Introduction
ROS2 introduces the concept of managed nodes, also called
LifecycleNode
s. In the following tutorial, we explain the purpose of
these nodes, what makes them different from regular nodes and how they
comply to a lifecycle management. Managed nodes are scoped within a
state machine of a finite amount of states. These states can be changed
by invoking a transition id which indicates the succeeding consecutive
state. The state machine is implemented as described at the ROS2 design
page.
Our implementation differentiates between Primary States
and
Transition States
. Primary States are supposed to be steady states in
which any node can do the respected task. On the other hand, Transition
States are meant as temporary intermediate states attached to a
transition. The result of these intermediate states are used to indicate
whether a transition between two primary states is considered successful
or not. Thus, any managed node can be in one of the following states:
Primary States (steady states):
- unconfigured
- inactive
- active
- shutdown
Transition States (intermediate states):
- configuring
- activating
- deactivating
- cleaningup
- shuttingdown
The possible transitions to invoke are:
- configure
- activate
- deactivate
- cleanup
- shutdown
For a more verbose explanation on the applied state machine, we refer to the design page which provides an in-detail explanation about each state and transition.
The demo
What's happening
The demo is split into 3 different separate applications.
- lifecycle_talker
- lifecycle_listener
- lifecycle_service_client
The lifecycle_talker
represents a managed node and publishes according
to which state the node is in. We split the tasks of the talker node
into separate pieces and execute them as followed.
- configuring: We initialize our publisher and timer
- activate: We activate the publisher and timer in order to enable a publishing
- deactivate: We stop the publisher and timer
- cleanup: We destroy the publisher and timer
The principle is implemented in this demo as the typical talker/listener demo. However, imaging a real scenario with attached hardware which may have a rather long booting phase, i.e. a laser or camera. One could image bringing up the device driver in the configuring state, start and stop only the publishing of the device's data and only in the cleanup/shutdown phase actually shutdown the device.
The lifecycle_listener
is a simple listener which shows the
characteristics of the lifecycle talker. The talker enables the message
publishing only in the active state and thus making the listener
receiving only messages when the talker is in an active state.
The lifecycle_service_client
is a script calling different transitions
on the lifecycle_talker
. This is meant as the external user
controlling the lifecycle of nodes.
Run the demo
In order to run this demo, we open three terminals and source our ROS2 environment variables either from the binary distributions or the workspace we compiled from source.
lifecycle_talker lifecycle_listener lifecycle_service_client
———————————————————————————— ———————————————————————————— ————————————————————————————
$ ros2 run lifecycle lifecycle_talker
$ ros2 run lifecycle lifecycle_listener
$ ros2 run lifecycle lifecycle_service_client
Alternatively, these three programs can be run together in the same terminal using the launch file (as of ROS 2 Bouncy):
``` {.sourceCode .bash} ros2 launch lifecycle lifecycle_demo.launch.py
If we look at the output of the `lifecycle_talker`, we notice that
nothing seems to happen. And this does make sense, since every node
starts as `unconfigured`. The lifecycle\_talker is not configured yet
and in our example, no publishers and timers are created yet. The same
behavior can be seen for the `lifecycle_listener`, which is less
surprising given that no publishers are available at this moment. The
interesting part starts with the third terminal. In there we launch our
`lifecycle_service_client` which is responsible for changing the states
of the `lifecycle_talker`.
Triggering transition 1 (configure)
-----------------------------------
``` {.sourceCode .bash}
[lc_client] Transition 1 successfully triggered.
[lc_client] Node lc_talker has current state inactive.
makes the lifecycle talker change its state to inactive. Inactive means that all publishers and timers are created and configured. However, the node is still not active. Therefore no messages are getting published.
``` {.sourceCode .bash} [lc_talker] on_configure() is called. Lifecycle publisher is currently inactive. Messages are not published. …
The lifecycle listener on the same time receives a notification as it
listens to every state change notification of the lifecycle talker. In
fact, the listener receives two consecutive notifications. One for
changing from the primary state \"unconfigured\" to \"configuring\".
Because the configuring step was successful within the lifecycle talker,
a second notification from \"configuring\" to \"inactive\".
``` {.sourceCode .bash}
[lc_listener] notify callback: Transition from state unconfigured to configuring
[lc_listener] notify callback: Transition from state configuring to inactive
Triggering transition 2 (activate)
``` {.sourceCode .bash} [lc_client] Transition 2 successfully triggered. [lc_client] Node lc_talker has current state active.
makes the lifecycle talker change its state to active. That means all
publishers and timers are now activated and herefore the messages are
now getting published.
``` {.sourceCode .bash}
[lc_talker] on_activate() is called.
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #11]
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #12]
...
The lifecycle listener receives the same set of notifications as before. Lifecycle talker changed its state from inactive to active.
``` {.sourceCode .bash} [lc_listener]: notify callback: Transition from state inactive to activating [lc_listener]: notify callback: Transition from state activating to active
The difference to the transition event before is that our listener now
also receives the actual published data.
``` {.sourceCode .bash}
[lc_listener] data_callback: Lifecycle HelloWorld #11
[lc_listener] data_callback: Lifecycle HelloWorld #12
...
Please note that the index of the published message is already at 11.
The purpose of this demo is to show that even though we call publish
at every state of the lifecycle talker, only when the state in active,
the messages are actually published. As for the beta1, all other
messages are getting ignored. This behavior may change in future
versions in order to provide better error handling.
For the rest of the demo, you will see similar output as we deactivate and activate the lifecycle talker and finally shut it down.
The demo code
lifecycle_talker, lifecycle_listener and lifecycle_service_client
If we have a look at the code, there is one significant change for the
lifecycle talker compared to a regular talker. Our node does not inherit
from the regular rclcpp::node::Node
but from
rclcpp_lifecycle::LifecycleNode
.
``` {.sourceCode .bash} class LifecycleTalker : public rclcpp_lifecycle::LifecycleNode
Every child of LifecycleNodes have a set of callbacks provided. These
callbacks go along with the applied state machine attached to it. These
callbacks are:
``` {.sourceCode .c}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_configure(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_activate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_deactivate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_cleanup(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_shutdown(const rclcpp_lifecycle::State & previous_state)
In the following we assume that we are inside the namespace
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface
to shorten
the name of the return type. All these callbacks have a positive default
return value (return CallbackReturn::SUCCESS
). This allows a lifecycle
node to change its state even though no explicit callback function was
overwritten. There is one other callback function for error handling.
Whenever a state transition throws an uncaught exception, we call
on_error
.
CallbackReturn on_error(const rclcpp_lifecycle::State & previous_state)
This gives room for executing a custom error handling. Only (!) in the
case that this function returns CallbackReturn::SUCCESS
, the state
machine transitions to the state unconfigured
. By default, the
on_error
returns CallbackReturn::FAILURE
and the state machine
transitions into finalized
.
At the same time, every lifecycle node has by default 5 different communication interfaces.
- Publisher
<node_name>__transition_event
: publishes in case a transition is happening.
This allows users to get notified of transition events within the network.
- Service
<node_name>__get_state
: query about the current state of the node.
Return either a primary or transition state.
- Service
<node_name>__change_state
: triggers a transition for the current node.
This service call takes a transition id. Only in the case, that this transition ID is a valid transition of the current state, the transition is fulfilled. All other cases are getting ignored.
- Service
<node_name>__get_available_states
: This is meant to be an introspection tool.
It returns a list of all possible states this node can be.
- Service
<node_name>__get_available_transitions
: Same as above, meant to an introspection tool.
It returns a list of all possible transitions this node can execute.
ros2 lifecycle command line interface
The lifecycle_service_client
application is a fixed order script for
this demo purpose only. It explains the use and the API calls made for
this lifecycle implementation, but may be inconvenient to use otherwise.
For this reason we implemented a command line tool which lets you
dynamically change states or various nodes.
In the case you want to get the current state of the lc_talker
node,
you would call:
``` {.sourceCode .bash} $ ros2 lifecycle get /lc_talker unconfigured [1]
The next step would be to execute a state change:
``` {.sourceCode .bash}
$ ros2 lifecycle set /lc_talker configure
Transitioning successful
In order to see what states are currently available:
``` {.sourceCode .bash} $ ros2 lifecycle list lc_talker
- configure [1] Start: unconfigured Goal: configuring
- shutdown [5] Start: unconfigured Goal: shuttingdown
In this case we see that currently, the available transitions are
`configure` and `shutdown`. The complete state machine can be viewed
with the following command, which can be helpful for debugging or
visualization purposes:
``` {.sourceCode .bash}
$ ros2 lifecycle list lc_talker -a
- configure [1]
Start: unconfigured
Goal: configuring
- transition_success [10]
Start: configuring
Goal: inactive
- transition_failure [11]
Start: configuring
Goal: unconfigured
- transition_error [12]
Start: configuring
Goal: errorprocessing
[...]
- transition_error [62]
Start: errorprocessing
Goal: finalized
All of the above commands are nothing else than calling the lifecycle node's services. With that being said, we can also call these services directly with the ros2 command line interface:
``` {.sourceCode .bash} $ ros2 service call /lc_talker/get_state lifecycle_msgs/GetState requester: making request: lifecycle_msgs.srv.GetState_Request()
response: lifecycle_msgs.srv.GetState_Response(current_state=lifecycle_msgs.msg.State(id=1, label=’unconfigured’))
In order to trigger a transition, we call the `change_state` service
``` {.sourceCode .bash}
$ ros2 service call /lc_talker/change_state lifecycle_msgs/ChangeState "{transition: {id: 2}}"
requester: making request: lifecycle_msgs.srv.ChangeState_Request(transition=lifecycle_msgs.msg.Transition(id=2, label=''))
response:
lifecycle_msgs.srv.ChangeState_Response(success=True)
It is slightly less convenient, because you have to know the IDs which correspond to each transition. You can find them though in the lifecycle_msgs package.
``` {.sourceCode .bash} $ ros2 msg show lifecycle_msgs/Transition
```
Outlook
The above description points to the current state of the development as for beta1. The future todo list for this topic comprises:
- Python lifecycle nodes
- Lifecycle manager: A global node, handling and dispatching trigger requests for multiple nodes.
- LifeyclceSubscriber/LifecycleWalltimer/... add more lifecycle controlled entities.
Changelog for package lifecycle
0.7.6 (2019-05-30)
0.7.5 (2019-05-29)
- Update asciinema recordings (#360)
- Use rate instead of thread::sleep to react to Ctrl-C (#348)
- Contributors: Dirk Thomas, Karsten Knese
0.7.4 (2019-05-20)
- Add lifecycle rostest (#336)
- Contributors: Michel Hidalgo
0.7.3 (2019-05-10)
0.7.2 (2019-05-08)
- changes to avoid deprecated API's (#332)
- Corrected publish calls with shared_ptr signature (#327)
- Contributors: William Woodall, ivanpauno
0.7.1 (2019-04-26)
0.7.0 (2019-04-14)
- Updated for NodeOptions Node constructor. (#308)
- Contributors: Michael Carroll
0.6.2 (2019-01-15)
- Added readme.rst (#300)
- Contributors: Karsten Knese
0.6.1 (2018-12-13)
0.6.0 (2018-12-07)
- Cleaned up lifecycle demo (#283)
- Updated for refactoring in rclcpp (#276)
- Added semicolons to all RCLCPP and RCUTILS macros. (#278)
- Fixed typo in comment (#270)
- Contributors: Chris Lalancette, Karsten Knese, Yutaka Kondo
0.5.1 (2018-06-28)
0.5.0 (2018-06-27)
- Converted launch files to the new launch style. (#262)
- Updated to support remapping arguments to python nodes by passing unused arguments to rclpy from argparse. (#252)
- Updated to handle change in signature to
get_service_name
. (#245) - Updated launch files to account for the "old launch" getting
renamespaced as
launch
->launch.legacy
. (#239) - Updated service client demos to handle multiple requests. (#228)
- Contributors: Geoffrey Biggs, Kevin Allen, Shane Loretz, William Woodall, dhood
Wiki Tutorials
Package Dependencies
Deps | Name |
---|---|
lifecycle_msgs | |
rclcpp_lifecycle | |
std_msgs | |
ament_cmake | |
ros2run | |
ament_lint_auto | |
ament_lint_common | |
ros_testing |
System Dependencies
Dependant Packages
Name | Deps |
---|---|
desktop |
Launch files
Messages
Services
Plugins
Recent questions tagged lifecycle at Robotics Stack Exchange
|
Package Summary
Tags | No category tags. |
Version | 0.14.4 |
License | Apache License 2.0 |
Build type | AMENT_CMAKE |
Use | RECOMMENDED |
Repository Summary
Checkout URI | https://github.com/ros2/demos.git |
VCS Type | git |
VCS Version | galactic |
Last Updated | 2022-12-07 |
Dev Status | DEVELOPED |
CI status | No Continuous Integration |
Released | RELEASED |
Tags | No category tags. |
Contributing |
Help Wanted (0)
Good First Issues (0) Pull Requests to Review (0) |
Package Description
Additional Links
Maintainers
- Mabel Zhang
- Michael Jeronimo
Authors
- Karsten Knese
Introduction
ROS 2 introduces the concept of managed nodes, also called
LifecycleNode
s. In the following tutorial, we explain the purpose of
these nodes, what makes them different from regular nodes and how they
comply to a lifecycle management. Managed nodes contain a state machine
with a set of predefined states. These states can be changed by invoking
a transition id which indicates the succeeding consecutive state. The
state machine is implemented as described at the ROS 2 design
page.
Our implementation differentiates between Primary States
and
Transition States
. Primary States are supposed to be steady states in
which any node can do the respected task. On the other hand, Transition
States are meant as temporary intermediate states attached to a
transition. The result of these intermediate states are used to indicate
whether a transition between two primary states is considered successful
or not. Thus, any managed node can be in one of the following states:
Primary States (steady states):
- unconfigured
- inactive
- active
- shutdown
Transition States (intermediate states):
- configuring
- activating
- deactivating
- cleaningup
- shuttingdown
The possible transitions to invoke are:
- configure
- activate
- deactivate
- cleanup
- shutdown
For a more verbose explanation on the applied state machine, we refer to the design page which provides an in-detail explanation about each state and transition.
The demo
What's happening
The demo is split into 3 separate applications:
- lifecycle_talker
- lifecycle_listener
- lifecycle_service_client
The lifecycle_talker
represents a managed node and publishes according
to which state the node is in. We split the tasks of the talker node
into separate pieces and execute them as follows:
- configuring: We initialize our publisher and timer
- activate: We activate the publisher and timer in order to enable a publishing
- deactivate: We stop the publisher and timer
- cleanup: We destroy the publisher and timer
This demo shows a typical talker/listener pair of nodes. However, imagine a real scenario with attached hardware which may have a rather long booting phase, i.e. a laser or camera. One could imagine bringing up the device driver in the configuring state, start and stop only the publishing of the device's data in active/deactive state, and only in the cleanup/shutdown state actually shutdown the device.
The lifecycle_listener
is a simple listener which shows the
characteristics of the lifecycle talker. The talker enables message
publishing only in the active state and thus the listener only receives
messages when the talker is in an active state.
The lifecycle_service_client
is a script calling different transitions
on the lifecycle_talker
. This is meant as the external user
controlling the lifecycle of nodes.
Run the demo
In order to run this demo, we open three terminals and source our ROS 2 environment variables either from the binary distributions or the workspace we compiled from source.
lifecycle_talker lifecycle_listener lifecycle_service_client
———————————————————————————— ———————————————————————————— ————————————————————————————
$ ros2 run lifecycle lifecycle_talker
$ ros2 run lifecycle lifecycle_listener
$ ros2 run lifecycle lifecycle_service_client
Alternatively, these three programs can be run together in the same terminal using the launch file:
``` {.sourceCode .bash} ros2 launch lifecycle lifecycle_demo.launch.py
If we look at the output of the `lifecycle_talker`, we notice that
nothing seems to happen. This makes sense, since every node starts as
`unconfigured`. The lifecycle\_talker is not configured yet and in our
example, no publishers and timers are created yet. The same behavior can
be seen for the `lifecycle_listener`, which is less surprising given
that no publishers are available at this moment. The interesting part
starts with the third terminal. In there we launch our
`lifecycle_service_client` which is responsible for changing the states
of the `lifecycle_talker`.
Triggering transition 1 (configure)
-----------------------------------
``` {.sourceCode .bash}
[lc_client] Transition 1 successfully triggered.
[lc_client] Node lc_talker has current state inactive.
Makes the lifecycle talker change its state to inactive. Inactive means that all publishers and timers are created and configured. However, the node is still not active. Therefore no messages are getting published.
``` {.sourceCode .bash} [lc_talker] on_configure() is called. Lifecycle publisher is currently inactive. Messages are not published. …
At the same time the lifecycle listener receives a notification as it
listens to every state change notification of the lifecycle talker. In
fact, the listener receives two consecutive notifications. One for
changing from the primary state \"unconfigured\" to \"configuring\", and
a second notification changing the state from \"configuring\" to
\"inactive\" (since the configuring step was successful in the talker).
``` {.sourceCode .bash}
[lc_listener] notify callback: Transition from state unconfigured to configuring
[lc_listener] notify callback: Transition from state configuring to inactive
Triggering transition 2 (activate)
``` {.sourceCode .bash} [lc_client] Transition 2 successfully triggered. [lc_client] Node lc_talker has current state active.
Makes the lifecycle talker change its state to active. That means all
publishers and timers are now activated and therefore the messages are
now getting published.
``` {.sourceCode .bash}
[lc_talker] on_activate() is called.
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #11]
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #12]
...
The lifecycle listener receives the same set of notifications as before. Lifecycle talker changed its state from inactive to active.
``` {.sourceCode .bash} [lc_listener]: notify callback: Transition from state inactive to activating [lc_listener]: notify callback: Transition from state activating to active
The difference from the earlier transition event is that our listener
now also receives the actual published data.
``` {.sourceCode .bash}
[lc_listener] data_callback: Lifecycle HelloWorld #11
[lc_listener] data_callback: Lifecycle HelloWorld #12
...
Please note that the index of the published message is already at 11.
The purpose of this demo is to show that even though we call publish
at every state of the lifecycle talker, the messages are only actually
published when the state in active.
For the rest of the demo, you will see similar output as we deactivate and activate the lifecycle talker and finally shut it down.
The demo code
lifecycle_talker, lifecycle_listener and lifecycle_service_client
If we have a look at the code, there is one significant change for the
lifecycle talker compared to a regular talker. Our node does not inherit
from the regular rclcpp::node::Node
but from
rclcpp_lifecycle::LifecycleNode
.
``` {.sourceCode .bash} class LifecycleTalker : public rclcpp_lifecycle::LifecycleNode
Every child of LifecycleNodes have a set of callbacks provided. These
callbacks go along with the applied state machine attached to it. These
callbacks are:
``` {.sourceCode .c}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_configure(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_activate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_deactivate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_cleanup(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_shutdown(const rclcpp_lifecycle::State & previous_state)
In the following we assume that we are inside the namespace
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface
to shorten
the name of the return type. All these callbacks have a positive default
return value (return CallbackReturn::SUCCESS
). This allows a lifecycle
node to change its state even though no explicit callback function was
overridden. There is one other callback function for error handling.
Whenever a state transition throws an uncaught exception, we call
on_error
:
CallbackReturn on_error(const rclcpp_lifecycle::State & previous_state)
This gives room for executing custom error handling. Only (!) in the
case that this function returns CallbackReturn::SUCCESS
, the state
machine transitions to the state unconfigured
. By default, the
on_error
returns CallbackReturn::FAILURE
and the state machine
transitions into finalized
.
At the same time, every lifecycle node has by default 5 different communication interfaces.
- Publisher
<node_name>__transition_event
: publishes in case a transition is happening.
This allows users to get notified of transition events within the network.
- Service
<node_name>__get_state
: query about the current state of the node.
Return either a primary or transition state.
- Service
<node_name>__change_state
: triggers a transition for the current node.
This service call takes a transition id. The transition is fulfilled only in the case that this transition ID is a valid transition from the current state. All other cases are ignored.
- Service
<node_name>__get_available_states
: This is meant to be an introspection tool.
It returns a list of all possible states this node can be.
- Service
<node_name>__get_available_transitions
: Same as above, meant to an introspection tool.
It returns a list of all possible transitions this node can execute.
ros2 lifecycle command line interface
The lifecycle_service_client
application is a fixed order script for
demo purposes only. It explains the use and the API calls made for this
lifecycle implementation, but may be inconvenient to use otherwise. For
this reason we implemented a command line tool which lets you
dynamically change states or various nodes.
In the case you want to get the current state of the lc_talker
node,
you would call:
``` {.sourceCode .bash} $ ros2 lifecycle get /lc_talker unconfigured [1]
The next step would be to execute a state change:
``` {.sourceCode .bash}
$ ros2 lifecycle set /lc_talker configure
Transitioning successful
In order to see what states are currently available:
``` {.sourceCode .bash} $ ros2 lifecycle list lc_talker
- configure [1] Start: unconfigured Goal: configuring
- shutdown [5] Start: unconfigured Goal: shuttingdown
In this case we see that currently, the available transitions are
`configure` and `shutdown`. The complete state machine can be viewed
with the following command, which can be helpful for debugging or
visualization purposes:
``` {.sourceCode .bash}
$ ros2 lifecycle list lc_talker -a
- configure [1]
Start: unconfigured
Goal: configuring
- transition_success [10]
Start: configuring
Goal: inactive
- transition_failure [11]
Start: configuring
Goal: unconfigured
- transition_error [12]
Start: configuring
Goal: errorprocessing
[...]
- transition_error [62]
Start: errorprocessing
Goal: finalized
All of the above commands are nothing more than calling the lifecycle node's services. With that being said, we can also call these services directly with the ros2 command line interface:
``` {.sourceCode .bash} $ ros2 service call /lc_talker/get_state lifecycle_msgs/GetState requester: making request: lifecycle_msgs.srv.GetState_Request()
response: lifecycle_msgs.srv.GetState_Response(current_state=lifecycle_msgs.msg.State(id=1, label=’unconfigured’))
In order to trigger a transition, we call the `change_state` service
``` {.sourceCode .bash}
$ ros2 service call /lc_talker/change_state lifecycle_msgs/ChangeState "{transition: {id: 2}}"
requester: making request: lifecycle_msgs.srv.ChangeState_Request(transition=lifecycle_msgs.msg.Transition(id=2, label=''))
response:
lifecycle_msgs.srv.ChangeState_Response(success=True)
It is slightly less convenient, because you have to know the IDs which correspond to each transition. You can find them though in the lifecycle_msgs package.
``` {.sourceCode .bash} $ ros2 interface show lifecycle_msgs/msg/Transition
```
Changelog for package lifecycle
0.14.4 (2022-12-06)
0.14.3 (2021-05-10)
0.14.2 (2021-04-26)
- Cleanup the README.rst for the lifecycle demo. (#508)
- Contributors: Chris Lalancette
0.14.1 (2021-04-19)
0.14.0 (2021-04-06)
- change ParameterEventHandler to take events as const ref instead of shared pointer (#494)
- Contributors: William Woodall
0.13.0 (2021-03-25)
0.12.1 (2021-03-18)
0.12.0 (2021-01-25)
0.11.0 (2020-12-10)
- Update the package.xml files with the latest Open Robotics maintainers (#466)
- Contributors: Michael Jeronimo
0.10.1 (2020-09-21)
- Add missing required parameter in LifecycleNode launch action (#456)
- Contributors: Ivan Santiago Paunovic
0.10.0 (2020-06-17)
0.9.3 (2020-06-01)
0.9.2 (2020-05-26)
- Fix typo (#445)
- Replace
ros2 msg
command in lifecycle README (#446) - Contributors: Audrow Nash, Shota Aoki
0.9.1 (2020-05-12)
0.9.0 (2020-04-30)
- Replace deprecated launch_ros usage (#437)
- Update launch_ros action usage (#431)
- code style only: wrap after open parenthesis if not in one line (#429)
- Contributors: Dirk Thomas, Jacob Perron
0.8.4 (2019-11-19)
0.8.3 (2019-11-11)
0.8.2 (2019-11-08)
- Remove unnecessary dependency on ros2run (#413)
- Contributors: Michel Hidalgo
0.8.1 (2019-10-23)
- Replace ready_fn with ReadyToTest action (#404)
- Contributors: Peter Baughman
0.8.0 (2019-09-26)
- Fix lifecycle_service_client namespace (#369)
- Contributors: Cameron Evans
0.7.6 (2019-05-30)
0.7.5 (2019-05-29)
- Update asciinema recordings (#360)
- Use rate instead of thread::sleep to react to Ctrl-C (#348)
- Contributors: Dirk Thomas, Karsten Knese
0.7.4 (2019-05-20)
- Add lifecycle rostest (#336)
- Contributors: Michel Hidalgo
0.7.3 (2019-05-10)
0.7.2 (2019-05-08)
- changes to avoid deprecated API's (#332)
- Corrected publish calls with shared_ptr signature (#327)
- Contributors: William Woodall, ivanpauno
0.7.1 (2019-04-26)
0.7.0 (2019-04-14)
- Updated for NodeOptions Node constructor. (#308)
- Contributors: Michael Carroll
0.6.2 (2019-01-15)
- Added readme.rst (#300)
- Contributors: Karsten Knese
0.6.1 (2018-12-13)
0.6.0 (2018-12-07)
- Cleaned up lifecycle demo (#283)
- Updated for refactoring in rclcpp (#276)
- Added semicolons to all RCLCPP and RCUTILS macros. (#278)
- Fixed typo in comment (#270)
- Contributors: Chris Lalancette, Karsten Knese, Yutaka Kondo
0.5.1 (2018-06-28)
0.5.0 (2018-06-27)
- Converted launch files to the new launch style. (#262)
- Updated to support remapping arguments to python nodes by passing unused arguments to rclpy from argparse. (#252)
- Updated to handle change in signature to
get_service_name
. (#245) - Updated launch files to account for the "old launch" getting
renamespaced as
launch
->launch.legacy
. (#239) - Updated service client demos to handle multiple requests. (#228)
- Contributors: Geoffrey Biggs, Kevin Allen, Shane Loretz, William Woodall, dhood
Wiki Tutorials
Package Dependencies
Deps | Name |
---|---|
lifecycle_msgs | |
rclcpp_lifecycle | |
std_msgs | |
ament_cmake | |
ament_lint_auto | |
ament_lint_common | |
ros_testing |
System Dependencies
Dependant Packages
Name | Deps |
---|---|
test_launch_ros | |
desktop |
Launch files
Messages
Services
Plugins
Recent questions tagged lifecycle at Robotics Stack Exchange
|
Package Summary
Tags | No category tags. |
Version | 0.9.4 |
License | Apache License 2.0 |
Build type | AMENT_CMAKE |
Use | RECOMMENDED |
Repository Summary
Checkout URI | https://github.com/ros2/demos.git |
VCS Type | git |
VCS Version | foxy |
Last Updated | 2022-07-25 |
Dev Status | DEVELOPED |
CI status | No Continuous Integration |
Released | RELEASED |
Tags | No category tags. |
Contributing |
Help Wanted (0)
Good First Issues (0) Pull Requests to Review (0) |
Package Description
Additional Links
Maintainers
- Mabel Zhang
- Michael Jeronimo
Authors
- Karsten Knese
Introduction
ROS2 introduces the concept of managed nodes, also called
LifecycleNode
s. In the following tutorial, we explain the purpose of
these nodes, what makes them different from regular nodes and how they
comply to a lifecycle management. Managed nodes are scoped within a
state machine of a finite amount of states. These states can be changed
by invoking a transition id which indicates the succeeding consecutive
state. The state machine is implemented as described at the ROS2 design
page.
Our implementation differentiates between Primary States
and
Transition States
. Primary States are supposed to be steady states in
which any node can do the respected task. On the other hand, Transition
States are meant as temporary intermediate states attached to a
transition. The result of these intermediate states are used to indicate
whether a transition between two primary states is considered successful
or not. Thus, any managed node can be in one of the following states:
Primary States (steady states):
- unconfigured
- inactive
- active
- shutdown
Transition States (intermediate states):
- configuring
- activating
- deactivating
- cleaningup
- shuttingdown
The possible transitions to invoke are:
- configure
- activate
- deactivate
- cleanup
- shutdown
For a more verbose explanation on the applied state machine, we refer to the design page which provides an in-detail explanation about each state and transition.
The demo
What's happening
The demo is split into 3 different separate applications.
- lifecycle_talker
- lifecycle_listener
- lifecycle_service_client
The lifecycle_talker
represents a managed node and publishes according
to which state the node is in. We split the tasks of the talker node
into separate pieces and execute them as followed.
- configuring: We initialize our publisher and timer
- activate: We activate the publisher and timer in order to enable a publishing
- deactivate: We stop the publisher and timer
- cleanup: We destroy the publisher and timer
The principle is implemented in this demo as the typical talker/listener demo. However, imaging a real scenario with attached hardware which may have a rather long booting phase, i.e. a laser or camera. One could image bringing up the device driver in the configuring state, start and stop only the publishing of the device's data and only in the cleanup/shutdown phase actually shutdown the device.
The lifecycle_listener
is a simple listener which shows the
characteristics of the lifecycle talker. The talker enables the message
publishing only in the active state and thus making the listener
receiving only messages when the talker is in an active state.
The lifecycle_service_client
is a script calling different transitions
on the lifecycle_talker
. This is meant as the external user
controlling the lifecycle of nodes.
Run the demo
In order to run this demo, we open three terminals and source our ROS2 environment variables either from the binary distributions or the workspace we compiled from source.
lifecycle_talker lifecycle_listener lifecycle_service_client
———————————————————————————— ———————————————————————————— ————————————————————————————
$ ros2 run lifecycle lifecycle_talker
$ ros2 run lifecycle lifecycle_listener
$ ros2 run lifecycle lifecycle_service_client
Alternatively, these three programs can be run together in the same terminal using the launch file (as of ROS 2 Bouncy):
``` {.sourceCode .bash} ros2 launch lifecycle lifecycle_demo.launch.py
If we look at the output of the `lifecycle_talker`, we notice that
nothing seems to happen. And this does make sense, since every node
starts as `unconfigured`. The lifecycle\_talker is not configured yet
and in our example, no publishers and timers are created yet. The same
behavior can be seen for the `lifecycle_listener`, which is less
surprising given that no publishers are available at this moment. The
interesting part starts with the third terminal. In there we launch our
`lifecycle_service_client` which is responsible for changing the states
of the `lifecycle_talker`.
Triggering transition 1 (configure)
-----------------------------------
``` {.sourceCode .bash}
[lc_client] Transition 1 successfully triggered.
[lc_client] Node lc_talker has current state inactive.
makes the lifecycle talker change its state to inactive. Inactive means that all publishers and timers are created and configured. However, the node is still not active. Therefore no messages are getting published.
``` {.sourceCode .bash} [lc_talker] on_configure() is called. Lifecycle publisher is currently inactive. Messages are not published. …
The lifecycle listener on the same time receives a notification as it
listens to every state change notification of the lifecycle talker. In
fact, the listener receives two consecutive notifications. One for
changing from the primary state \"unconfigured\" to \"configuring\".
Because the configuring step was successful within the lifecycle talker,
a second notification from \"configuring\" to \"inactive\".
``` {.sourceCode .bash}
[lc_listener] notify callback: Transition from state unconfigured to configuring
[lc_listener] notify callback: Transition from state configuring to inactive
Triggering transition 2 (activate)
``` {.sourceCode .bash} [lc_client] Transition 2 successfully triggered. [lc_client] Node lc_talker has current state active.
makes the lifecycle talker change its state to active. That means all
publishers and timers are now activated and herefore the messages are
now getting published.
``` {.sourceCode .bash}
[lc_talker] on_activate() is called.
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #11]
[lc_talker] Lifecycle publisher is active. Publishing: [Lifecycle HelloWorld #12]
...
The lifecycle listener receives the same set of notifications as before. Lifecycle talker changed its state from inactive to active.
``` {.sourceCode .bash} [lc_listener]: notify callback: Transition from state inactive to activating [lc_listener]: notify callback: Transition from state activating to active
The difference to the transition event before is that our listener now
also receives the actual published data.
``` {.sourceCode .bash}
[lc_listener] data_callback: Lifecycle HelloWorld #11
[lc_listener] data_callback: Lifecycle HelloWorld #12
...
Please note that the index of the published message is already at 11.
The purpose of this demo is to show that even though we call publish
at every state of the lifecycle talker, only when the state in active,
the messages are actually published. As for the beta1, all other
messages are getting ignored. This behavior may change in future
versions in order to provide better error handling.
For the rest of the demo, you will see similar output as we deactivate and activate the lifecycle talker and finally shut it down.
The demo code
lifecycle_talker, lifecycle_listener and lifecycle_service_client
If we have a look at the code, there is one significant change for the
lifecycle talker compared to a regular talker. Our node does not inherit
from the regular rclcpp::node::Node
but from
rclcpp_lifecycle::LifecycleNode
.
``` {.sourceCode .bash} class LifecycleTalker : public rclcpp_lifecycle::LifecycleNode
Every child of LifecycleNodes have a set of callbacks provided. These
callbacks go along with the applied state machine attached to it. These
callbacks are:
``` {.sourceCode .c}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_configure(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_activate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_deactivate(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_cleanup(const rclcpp_lifecycle::State & previous_state)
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_shutdown(const rclcpp_lifecycle::State & previous_state)
In the following we assume that we are inside the namespace
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface
to shorten
the name of the return type. All these callbacks have a positive default
return value (return CallbackReturn::SUCCESS
). This allows a lifecycle
node to change its state even though no explicit callback function was
overwritten. There is one other callback function for error handling.
Whenever a state transition throws an uncaught exception, we call
on_error
.
CallbackReturn on_error(const rclcpp_lifecycle::State & previous_state)
This gives room for executing a custom error handling. Only (!) in the
case that this function returns CallbackReturn::SUCCESS
, the state
machine transitions to the state unconfigured
. By default, the
on_error
returns CallbackReturn::FAILURE
and the state machine
transitions into finalized
.
At the same time, every lifecycle node has by default 5 different communication interfaces.
- Publisher
<node_name>__transition_event
: publishes in case a transition is happening.
This allows users to get notified of transition events within the network.
- Service
<node_name>__get_state
: query about the current state of the node.
Return either a primary or transition state.
- Service
<node_name>__change_state
: triggers a transition for the current node.
This service call takes a transition id. Only in the case, that this transition ID is a valid transition of the current state, the transition is fulfilled. All other cases are getting ignored.
- Service
<node_name>__get_available_states
: This is meant to be an introspection tool.
It returns a list of all possible states this node can be.
- Service
<node_name>__get_available_transitions
: Same as above, meant to an introspection tool.
It returns a list of all possible transitions this node can execute.
ros2 lifecycle command line interface
The lifecycle_service_client
application is a fixed order script for
this demo purpose only. It explains the use and the API calls made for
this lifecycle implementation, but may be inconvenient to use otherwise.
For this reason we implemented a command line tool which lets you
dynamically change states or various nodes.
In the case you want to get the current state of the lc_talker
node,
you would call:
``` {.sourceCode .bash} $ ros2 lifecycle get /lc_talker unconfigured [1]
The next step would be to execute a state change:
``` {.sourceCode .bash}
$ ros2 lifecycle set /lc_talker configure
Transitioning successful
In order to see what states are currently available:
``` {.sourceCode .bash} $ ros2 lifecycle list lc_talker
- configure [1] Start: unconfigured Goal: configuring
- shutdown [5] Start: unconfigured Goal: shuttingdown
In this case we see that currently, the available transitions are
`configure` and `shutdown`. The complete state machine can be viewed
with the following command, which can be helpful for debugging or
visualization purposes:
``` {.sourceCode .bash}
$ ros2 lifecycle list lc_talker -a
- configure [1]
Start: unconfigured
Goal: configuring
- transition_success [10]
Start: configuring
Goal: inactive
- transition_failure [11]
Start: configuring
Goal: unconfigured
- transition_error [12]
Start: configuring
Goal: errorprocessing
[...]
- transition_error [62]
Start: errorprocessing
Goal: finalized
All of the above commands are nothing else than calling the lifecycle node's services. With that being said, we can also call these services directly with the ros2 command line interface:
``` {.sourceCode .bash} $ ros2 service call /lc_talker/get_state lifecycle_msgs/GetState requester: making request: lifecycle_msgs.srv.GetState_Request()
response: lifecycle_msgs.srv.GetState_Response(current_state=lifecycle_msgs.msg.State(id=1, label=’unconfigured’))
In order to trigger a transition, we call the `change_state` service
``` {.sourceCode .bash}
$ ros2 service call /lc_talker/change_state lifecycle_msgs/ChangeState "{transition: {id: 2}}"
requester: making request: lifecycle_msgs.srv.ChangeState_Request(transition=lifecycle_msgs.msg.Transition(id=2, label=''))
response:
lifecycle_msgs.srv.ChangeState_Response(success=True)
It is slightly less convenient, because you have to know the IDs which correspond to each transition. You can find them though in the lifecycle_msgs package.
``` {.sourceCode .bash} $ ros2 interface show lifecycle_msgs/msg/Transition
```
Outlook
The above description points to the current state of the development as for beta1. The future todo list for this topic comprises:
- Python lifecycle nodes
- Lifecycle manager: A global node, handling and dispatching trigger requests for multiple nodes.
- LifeyclceSubscriber/LifecycleWalltimer/... add more lifecycle controlled entities.
Changelog for package lifecycle
0.9.4 (2022-07-25)
- Update maintainer list for Foxy (#471)
- Contributors: Michael Jeronimo
0.9.3 (2020-06-01)
0.9.2 (2020-05-26)
- Fix typo (#445)
- Replace
ros2 msg
command in lifecycle README (#446) - Contributors: Audrow Nash, Shota Aoki
0.9.1 (2020-05-12)
0.9.0 (2020-04-30)
- Replace deprecated launch_ros usage (#437)
- Update launch_ros action usage (#431)
- code style only: wrap after open parenthesis if not in one line (#429)
- Contributors: Dirk Thomas, Jacob Perron
0.8.4 (2019-11-19)
0.8.3 (2019-11-11)
0.8.2 (2019-11-08)
- Remove unnecessary dependency on ros2run (#413)
- Contributors: Michel Hidalgo
0.8.1 (2019-10-23)
- Replace ready_fn with ReadyToTest action (#404)
- Contributors: Peter Baughman
0.8.0 (2019-09-26)
- Fix lifecycle_service_client namespace (#369)
- Contributors: Cameron Evans
0.7.6 (2019-05-30)
0.7.5 (2019-05-29)
- Update asciinema recordings (#360)
- Use rate instead of thread::sleep to react to Ctrl-C (#348)
- Contributors: Dirk Thomas, Karsten Knese
0.7.4 (2019-05-20)
- Add lifecycle rostest (#336)
- Contributors: Michel Hidalgo
0.7.3 (2019-05-10)
0.7.2 (2019-05-08)
- changes to avoid deprecated API's (#332)
- Corrected publish calls with shared_ptr signature (#327)
- Contributors: William Woodall, ivanpauno
0.7.1 (2019-04-26)
0.7.0 (2019-04-14)
- Updated for NodeOptions Node constructor. (#308)
- Contributors: Michael Carroll
0.6.2 (2019-01-15)
- Added readme.rst (#300)
- Contributors: Karsten Knese
0.6.1 (2018-12-13)
0.6.0 (2018-12-07)
- Cleaned up lifecycle demo (#283)
- Updated for refactoring in rclcpp (#276)
- Added semicolons to all RCLCPP and RCUTILS macros. (#278)
- Fixed typo in comment (#270)
- Contributors: Chris Lalancette, Karsten Knese, Yutaka Kondo
0.5.1 (2018-06-28)
0.5.0 (2018-06-27)
- Converted launch files to the new launch style. (#262)
- Updated to support remapping arguments to python nodes by passing unused arguments to rclpy from argparse. (#252)
- Updated to handle change in signature to
get_service_name
. (#245) - Updated launch files to account for the "old launch" getting
renamespaced as
launch
->launch.legacy
. (#239) - Updated service client demos to handle multiple requests. (#228)
- Contributors: Geoffrey Biggs, Kevin Allen, Shane Loretz, William Woodall, dhood
Wiki Tutorials
Package Dependencies
Deps | Name |
---|---|
lifecycle_msgs | |
rclcpp_lifecycle | |
std_msgs | |
ament_cmake | |
ament_lint_auto | |
ament_lint_common | |
ros_testing |
System Dependencies
Dependant Packages
Name | Deps |
---|---|
test_launch_ros | |
desktop |