Examples¶
This page is the runtime view of the library. Use it once the lifecycle vocabulary is familiar and you want to see how the contract feels in actual nodes and components.
Each example shows where ROS resources are created and what stays dormant until activation.
Activation opens message flow, callbacks, or service handling depending on the component type.
Observe the steady-state behavior you actually care about: publish, subscribe, tick, call, relay.
Deactivate and cleanup reveal what remains allocated, what is gated, and what disappears from the graph.
The final comparison point is always explicit teardown, never implicit destruction.
Read these examples before the API reference when you want the lifecycle model in one pass. They are ordered from the smallest hook surface to full component composition.
If you are new to the repository, run minimal_node.py first. It shows the native ROS 2
transition flow without adding topic resources or runtime behavior.
Across all examples, the same lifecycle contract holds: configure creates long-lived ROS
resources, activate starts behavior, deactivate stops or gates behavior, and cleanup
releases resources.
The companion repository also ships a scenario-driven comparison:
lifecore_ros2_examples sensor watchdog comparison.
Use it when you want the same watchdog behavior shown as plain ROS 2, classic lifecycle, and lifecore_ros2. That README includes the shared sensor publisher command, the commands to run each variant, and the expected /sensor/status and log signals.
Example map¶
Example |
What it demonstrates |
When to read it |
Command to run |
|---|---|---|---|
Smallest |
Start here if you want the base transition flow without topic resources. |
|
|
Lifecycle-managed state with no ROS resource ownership. |
Read after the node example to see lifecycle management applied to owned state rather than ROS resources. |
|
|
Standalone |
Read before the publisher example to understand timer gating in isolation. |
|
|
Library-owned publisher and timer composing in one node without overrides. |
Read after the timer example to see two library components wiring together. |
|
|
Activation-gated delivery with a managed subscription. |
Read when you want to see inactive message drops and subscriber ownership. |
|
|
|
Read when you want to see how inactive requests are answered with a default response. |
|
|
|
Read when you want to see how inactive |
|
|
Full |
Read when you need a concrete pattern for long-lived handles plus runtime behavior. |
|
|
Three sibling components transitioning together inside one node without any ordering. |
Read after the timer example to see three library components composing in one node. |
|
|
Three sibling components with explicit internal dependencies declared at registration time inside one node. |
Read after |
|
After launching an example, drive it with ros2 lifecycle set /<node_name> configure, then
activate, deactivate, and cleanup. Each module docstring includes the expected output
for those transitions, so you can compare logs and graph changes without reading the code first.
Suggested reading path¶
Start with
minimal_node.pyfor the smallest ownership boundary.Continue with
minimal_state_component.pyto see lifecycle management applied to owned state with no ROS resources.Move to timer, publisher, and subscriber examples to see activation gating on long-lived ROS resources.
Continue with service server and client examples to compare inbound versus outbound gating behavior.
Finish with
telemetry_publisher.py,composed_pipeline.py, andcomposed_ordered_pipeline.pyfor full lifecycle separation across multiple responsibilities.Read
composed_ordered_pipeline.pyaftertelemetry_publisher.pyto see howdependenciesdeclared atadd_component(...)impose a guaranteed transition order across independently managed components.
Companion Comparison¶
After the bundled examples, use the sensor watchdog comparison in lifecore_ros2_examples
when you want one applied walkthrough that compares plain ROS 2, classic lifecycle, and lifecore_ros2 on the same watchdog node.
That companion README is the source of truth for its run commands, lifecycle transition commands, and expected /sensor/status and log signals.
Minimal Node¶
Source: examples/minimal_node.py
What it demonstrates¶
The smallest managed setup: one LifecycleComponentNode owns one LifecycleComponent with only
_on_configure overridden.
What to look for¶
configureruns the component hook explicitly and nothing else.The node owns the component; the component does not manage node lifetime.
activateanddeactivatesucceed with the native silent base behavior.No topics or ROS resources are created, retained, or released in this example.
Minimal State Component¶
Source: examples/minimal_state_component.py
What it demonstrates¶
A LifecycleComponent that owns lifecycle-managed state with no ROS resource ownership.
The node calls update() on the component after each activation to demonstrate external mutation.
What to look for¶
configureresets the counter to0; cleanup, shutdown, and error also reset it.deactivatepreserves the counter so accumulated state survives a deactivate / re-activate cycle.The component owns its state; the node calls
update()— the component does not push state outward.No publishers, subscriptions, or timers are created; the lifecycle contract is purely about state.
Minimal Timer¶
Source: examples/minimal_timer.py
What it demonstrates¶
A standalone LifecycleTimerComponent where the library owns the ROS timer and ticks are
routed to on_tick only while the component is active.
What to look for¶
configurecreates the ROS timer with the configured period; ticks fire but are silently dropped.activateopens the gate so each tick reacheson_tick;deactivatecloses it again without destroying the timer.cleanuplets the library cancel and destroy the timer through_release_resources.The component never owns a publisher or subscription, so the example isolates the timer contract on its own.
Minimal Publisher¶
Source: examples/minimal_publisher.py
What it demonstrates¶
A LifecyclePublisherComponent and a LifecycleTimerComponent composing in one node.
The library owns both the ROS publisher and the ROS timer; activation gating is handled
entirely without overrides.
What to look for¶
configurecreates both the publisher on/chatterand the timer.PublisherTimerreceivesPeriodicPublisherat construction and callsemit_next()inon_tick— no overrides needed.activateenables ticks and publication;deactivategates both without any_on_deactivateoverride.cleanupreleases the publisher and timer automatically through the library.
Minimal Subscriber¶
Source: examples/minimal_subscriber.py
What it demonstrates¶
A LifecycleSubscriberComponent where delivery is gated by lifecycle state instead of being
embedded directly in the node.
What to look for¶
configurecreates the subscription on/chatter.The node owns one subscriber component;
on_messageis the component contract.activateallows delivery;deactivatesilently drops messages by design.cleanupreleases the subscription and removes the topic from the subscriber graph.
Minimal Service Server¶
Source: examples/minimal_service_server.py
What it demonstrates¶
A LifecycleServiceServerComponent where the library owns the ROS service and request
handling is gated by lifecycle state through on_service_request.
What to look for¶
configurecreates the ROS service on/trigger; the service appears inros2 service list.activateopens the gate so each request reacheson_service_request.deactivatedoes not destroy the service: incoming requests get a default-constructed response withsuccess=Falseandmessage="component inactive", and a warning is logged.cleanupdestroys the service through_release_resources.
Minimal Service Client¶
Source: examples/minimal_service_client.py
What it demonstrates¶
A LifecycleServiceClientComponent where the library owns the ROS client and outbound
call() / call_async() are gated by lifecycle state.
What to look for¶
configurecreates the ROS client for/trigger; no calls are issued yet.activatemakescall(),call_async(), andwait_for_service()safe to invoke.call(..., timeout_service=...)waits for the service to become available and raisesTimeoutErrorif it does not appear in time.deactivatemakes new calls raiseRuntimeError; futures already returned bycall_async()are not cancelled and remain owned by the application.cleanupdestroys the client through_release_resources.
Telemetry Publisher¶
Source: examples/telemetry_publisher.py
What it demonstrates¶
A publisher component with all four hooks overridden to separate ROS resources, runtime behavior, and non-ROS handles.
What to look for¶
configureacquires both the ROS publisher and the simulated sensor handle.One component owns the publisher, timer, and sensor handle as a single lifecycle unit.
activatestarts sampling;deactivatepauses it without releasing the sensor handle.cleanupreleases the sensor handle and then lets the library release the publisher.
Composed Pipeline¶
Source: examples/composed_pipeline.py
What it demonstrates¶
Three library components — a timer, a publisher, and a subscriber — inside one
LifecycleComponentNode. All three configure, activate, deactivate, and clean up
together through the native ROS 2 lifecycle. No activation overrides needed.
What to look for¶
configurecreates the publisher and subscription, and starts the timer in a ready (not firing) state.The node wires
SineTimertoSinePublisherby passing the publisher at construction — noget_componentcall needed.activateenables end-to-end flow;deactivategates all three components without any manual_on_deactivateoverride.cleanupreleases the publisher, timer, and subscription automatically through the library.
Composed Ordered Pipeline¶
Source: examples/composed_ordered_pipeline.py
What it demonstrates¶
A timer, publisher, and subscriber component wired with explicit dependencies
declared at add_component(...) so the library resolves transition order
from those declarations, not from registration order. No _on_activate or
_on_deactivate overrides are needed — the library gates each component
automatically.
What to look for¶
Components are registered in a deliberately scrambled order (sink first, timer second, publisher last). Dependencies are declared at the registration site, so ordering intent is visible where the node is assembled. Publisher is configured first because both timer and sink depend on it.
SineTimerholds a direct reference toSinePublisherand callsemit_next()inon_tick— no rawcreate_timerorcreate_publishercall appears anywhere in the example.SineTimerandLoggingSinkdo not expose pass-through ordering kwargs in their constructors;dependenciesstay on the node side of the composition boundary.deactivateandcleanuppropagate in reverse dependency order: timer and sink before publisher.