Lifecycle interface

Core lifecycle for modular robotics systems

Configure · Activate · Run · Transition · Shutdown

Components API

class lifecore_ros2.components.topic_component.TopicComponent(*args, **kwargs)

Bases: LifecycleComponent, ABC, Generic

Intermediate base class for lifecycle-aware topic publisher and subscriber components.

Owns:
  • The topic name, message type, and QoS profile shared by publisher and subscriber subclasses.

Does not own:
  • The ROS publisher or subscription objects — those belong to concrete subclasses.

  • Any lifecycle hook logic — concrete subclasses provide _on_configure, _on_cleanup, and _release_resources implementations.

  • The callback group — it is borrowed from the application and forwarded to the core.

Override points:
  • Not intended to be subclassed directly outside the framework.

  • Subclass LifecyclePublisherComponent or LifecycleSubscriberComponent instead.

Parameters:
  • name (str)

  • topic_name (str)

  • msg_type (type[MsgT] | None)

  • qos_profile (QoSProfile | int)

  • callback_group (CallbackGroup | None)

  • dependencies (Sequence[str])

  • priority (int)

property topic_name: str
property msg_type: type[MsgT]
property qos_profile: QoSProfile | int
class lifecore_ros2.components.lifecycle_publisher_component.LifecyclePublisherComponent(*args, **kwargs)

Bases: TopicComponent, Generic

Publisher component that creates and gates a ROS publisher through the lifecycle.

Owns:
  • The ROS Publisher instance (created on configure, kept across deactivate, released automatically during cleanup, shutdown, or error).

  • publish: the activation-gated publication method.

Does not own:
  • The topic name, message type, or QoS profile (inherited from TopicComponent).

  • The callback group — it is borrowed from the application; lifetime is owned by the caller.

  • The node or lifecycle state transitions.

  • Activation state management (handled by the framework).

Override points:
  • This class is usable directly without subclassing.

  • Override _on_configure for additional setup; call super()._on_configure(state) first.

  • Do not override publish.

Parameters:
  • name (str)

  • topic_name (str)

  • msg_type (type[MsgT] | None)

  • qos_profile (QoSProfile | int)

  • callback_group (CallbackGroup | None)

  • dependencies (Sequence[str])

  • priority (int)

_on_configure(state)

Extension point. Calls super if overridden; creates the ROS publisher.

Override in subclasses for additional setup. Call super()._on_configure(state) first.

Parameters:

state (rclpy.lifecycle.node.LifecycleState)

Return type:

rclpy.lifecycle.node.TransitionCallbackReturn

publish(msg)

Publish a message. Raises RuntimeError if not active.

Parameters:

msg (MsgT)

Return type:

None

_release_resources()

Extension point. Override to release additional resources; call super()._release_resources() last.

Return type:

None

class lifecore_ros2.components.lifecycle_subscriber_component.LifecycleSubscriberComponent(*args, **kwargs)

Bases: TopicComponent, Generic

Subscriber component that creates a ROS subscription and gates message delivery through the lifecycle.

The subscription is created on configure, kept across deactivate, and destroyed automatically during cleanup, shutdown, or error. Incoming messages are silently dropped while the component is inactive, and routed to on_message when active.

Owns:
  • The ROS Subscription instance (created on configure, kept across deactivate, released automatically during cleanup, shutdown, or error).

  • _on_message_wrapper: the @when_active-gated internal callback.

Does not own:
  • The topic name, message type, or QoS profile (inherited from TopicComponent).

  • The callback group — it is borrowed from the application; lifetime is owned by the caller.

  • The node or lifecycle state transitions.

  • Activation state management (handled by the framework).

Override points:
  • on_message: implement to handle incoming messages. Called only while active.

  • Override _on_configure only for additional setup; call super()._on_configure(state) first.

  • Do not override _on_message_wrapper.

Parameters:
  • name (str)

  • topic_name (str)

  • msg_type (type[MsgT] | None)

  • qos_profile (QoSProfile | int)

  • callback_group (CallbackGroup | None)

  • dependencies (Sequence[str])

  • priority (int)

_on_configure(state)

Extension point. Creates the ROS subscription.

Override in subclasses for additional setup. Call super()._on_configure(state) first.

Parameters:

state (rclpy.lifecycle.node.LifecycleState)

Return type:

rclpy.lifecycle.node.TransitionCallbackReturn

abstractmethod on_message(msg)

Extension point. Implement to handle incoming messages while active.

This is the subscriber callback contract. Unlike the _on_* lifecycle hooks, on_message is intentionally public because it defines application behavior, not framework behavior. It is only called while the component is active.

Parameters:

msg (MsgT)

Return type:

None

_release_resources()

Extension point. Override to release additional resources; call super()._release_resources() last.

Return type:

None

class lifecore_ros2.components.lifecycle_timer_component.LifecycleTimerComponent(*args, **kwargs)

Bases: LifecycleComponent

Timer component that creates a periodic ROS timer and gates ticks through the lifecycle.

The timer is created on configure, kept across deactivate, and destroyed automatically during cleanup, shutdown, or error. Ticks are silently dropped while the component is inactive, and routed to on_tick when active.

Owns:
  • The ROS Timer instance (created on configure, kept across deactivate, released automatically during cleanup, shutdown, or error).

  • _on_timer_wrapper: the @when_active-gated internal callback.

  • The autostart flag and the explicit start / stop / reset controls.

Does not own:
  • The clock — uses the node default clock.

  • The callback group — it is borrowed from the application; lifetime is owned by the caller.

  • The node or lifecycle state transitions.

  • Activation state management (handled by the framework).

Override points:
  • on_tick: implement to handle each timer tick. Called only while active.

  • Override _on_configure only for additional setup; call super()._on_configure(state) first.

  • Do not override _on_timer_wrapper.

Parameters:
  • name (str)

  • period (float | Duration)

  • autostart (bool)

  • callback_group (CallbackGroup | None)

  • dependencies (Sequence[str])

  • priority (int)

property period_sec: float

The timer period in seconds.

property autostart: bool

Whether the timer starts firing automatically when created on configure.

property is_running: bool

True iff the underlying timer exists and is currently firing (not canceled).

_on_configure(state)

Extension point. Creates the ROS timer.

Override in subclasses for additional setup. Call super()._on_configure(state) first.

Parameters:

state (rclpy.lifecycle.node.LifecycleState)

Return type:

rclpy.lifecycle.node.TransitionCallbackReturn

abstractmethod on_tick()

Extension point. Implement to handle each timer tick while active.

This is the timer callback contract. Unlike the _on_* lifecycle hooks, on_tick is intentionally public because it defines application behavior, not framework behavior. It is only called while the component is active.

Return type:

None

start()

Resume firing the underlying timer. No-op if already running.

Raises:

ComponentNotConfiguredError – If called before configure or after cleanup.

Return type:

None

stop()

Stop the underlying timer. No-op if already stopped.

Raises:

ComponentNotConfiguredError – If called before configure or after cleanup.

Return type:

None

reset()

Restart the timer period from now. Resumes firing if currently stopped.

Raises:

ComponentNotConfiguredError – If called before configure or after cleanup.

Return type:

None

_release_resources()

Extension point. Override to release additional resources; call super()._release_resources() last.

Return type:

None

class lifecore_ros2.components.service_component.ServiceComponent(*args, **kwargs)

Bases: LifecycleComponent, ABC, Generic

Intermediate base class for lifecycle-aware service server and client components.

Owns:
  • The service name, service type, and QoS profile shared by server and client subclasses.

Does not own:
  • The ROS Service or Client objects — those belong to concrete subclasses.

  • Any lifecycle hook logic — concrete subclasses provide _on_configure, _on_cleanup, and _release_resources implementations.

  • The callback group — it is borrowed from the application and forwarded to the core.

Override points:
  • Not intended to be subclassed directly outside the framework.

  • Subclass LifecycleServiceServerComponent or LifecycleServiceClientComponent instead.

Parameters:
  • name (str)

  • service_name (str)

  • srv_type (type[SrvT] | None)

  • qos_profile (QoSProfile | None)

  • callback_group (CallbackGroup | None)

  • dependencies (Sequence[str])

  • priority (int)

property service_name: str
property srv_type: type[SrvT]
property qos_profile: QoSProfile | None
class lifecore_ros2.components.lifecycle_service_server_component.LifecycleServiceServerComponent(*args, **kwargs)

Bases: ServiceComponent, Generic

Service server component that creates a ROS service and gates request handling through the lifecycle.

The service is created on configure, kept across deactivate, and destroyed automatically during cleanup, shutdown, or error. Incoming requests while the component is inactive are not silently dropped: a warning is logged and a default-constructed response is returned, optionally annotated with diagnostic fields (success=False, message="component inactive").

Owns:
  • The ROS Service instance (created on configure, kept across deactivate, released automatically during cleanup, shutdown, or error).

  • _on_request_wrapper: the framework-internal callback registered with rclpy.

Does not own:
  • The service name, service type, or QoS profile (inherited from ServiceComponent).

  • The callback group — it is borrowed from the application; lifetime is owned by the caller.

  • The node or lifecycle state transitions.

  • Activation state management (handled by the framework).

Override points:
  • on_service_request: implement to handle incoming requests while active.

  • Override _on_configure only for additional setup; call super()._on_configure(state) first.

  • Do not override _on_request_wrapper.

Parameters:
  • name (str)

  • service_name (str)

  • srv_type (type[SrvT] | None)

  • qos_profile (QoSProfile | None)

  • callback_group (CallbackGroup | None)

  • dependencies (Sequence[str])

  • priority (int)

_on_configure(state)

Extension point. Calls super if overridden; creates the ROS service.

Override in subclasses for additional setup. Call super()._on_configure(state) first.

Parameters:

state (rclpy.lifecycle.node.LifecycleState)

Return type:

rclpy.lifecycle.node.TransitionCallbackReturn

abstractmethod on_service_request(request, response)

Extension point. Implement to handle incoming service requests while active.

Follows the rclpy service callback convention: fill in response fields and return it. Called only while the component is active.

Parameters:
  • request (Any) – The incoming service request object.

  • response (Any) – A default-constructed response object to fill in.

Returns:

The filled-in response object.

Return type:

Any

_release_resources()

Extension point. Override to release additional resources; call super()._release_resources() last.

Return type:

None

class lifecore_ros2.components.lifecycle_service_client_component.LifecycleServiceClientComponent(*args, **kwargs)

Bases: ServiceComponent, Generic

Service client component that creates a ROS client and gates calls through the lifecycle.

The client is created on configure, kept across deactivate, and destroyed automatically during cleanup, shutdown, or error. Outbound calls (call, call_async, wait_for_service) raise RuntimeError while the component is inactive.

Note

Futures from call_async are not cancelled on deactivate; the application owns them.

Owns:
  • The ROS Client instance (created on configure, kept across deactivate, released automatically during cleanup, shutdown, or error).

Does not own:
  • The service name, service type, or QoS profile (inherited from ServiceComponent).

  • The callback group — it is borrowed from the application; lifetime is owned by the caller.

  • The node or lifecycle state transitions.

  • Activation state management (handled by the framework).

Override points:
  • This class is usable directly without subclassing.

  • Override _on_configure for additional setup; call super()._on_configure(state) first.

  • Do not override call, call_async, or wait_for_service.

Parameters:
  • name (str)

  • service_name (str)

  • srv_type (type[SrvT] | None)

  • qos_profile (QoSProfile | None)

  • callback_group (CallbackGroup | None)

  • dependencies (Sequence[str])

  • priority (int)

_on_configure(state)

Extension point. Calls super if overridden; creates the ROS client.

Override in subclasses for additional setup. Call super()._on_configure(state) first.

Parameters:

state (rclpy.lifecycle.node.LifecycleState)

Return type:

rclpy.lifecycle.node.TransitionCallbackReturn

call(request, timeout_service=None, timeout_call=None)

Call the service synchronously. Raises RuntimeError if not active.

Parameters:
  • request (Any) – The service request object.

  • timeout_service (float | None) – Optional timeout in seconds to wait for the service to become available before sending the request. Raises TimeoutError if the service does not become available in time.

  • timeout_call (float | None) – Optional timeout in seconds for the synchronous call itself. None waits indefinitely for the response.

Returns:

The service response object.

Raises:
  • RuntimeError – if the component is not active.

  • ComponentNotConfiguredError – if the component has not been configured.

  • TimeoutError – if timeout_service is specified and the service is not available.

Return type:

Any

call_async(request, timeout_service=None)

Call the service asynchronously. Raises RuntimeError if not active.

Note

Futures are not cancelled on deactivate; the application owns them.

Parameters:
  • request (Any) – The service request object.

  • timeout_service (float | None) – Optional timeout in seconds to wait for the service to become available before submitting the request. Raises TimeoutError if the service does not become available in time.

Returns:

A Future that resolves to the service response.

Raises:
  • RuntimeError – if the component is not active.

  • ComponentNotConfiguredError – if the component has not been configured.

  • TimeoutError – if timeout_service is specified and the service is not available.

Return type:

rclpy.task.Future

wait_for_service(timeout=None)

Wait for the service to become available. Raises RuntimeError if not active.

Parameters:

timeout (float | None) – Optional timeout in seconds. None waits indefinitely.

Returns:

True if the service is available; False if the timeout elapsed.

Raises:
Return type:

bool

_release_resources()

Extension point. Override to release additional resources; call super()._release_resources() last.

Return type:

None

class lifecore_ros2.components.lifecycle_watchdog_component.LifecycleWatchdogComponent(*args, **kwargs)

Bases: LifecycleTimerComponent

Watchdog component that polls component or node health and logs actionable diagnostics.

Observes one or more targets that expose a .health property (such as LifecycleComponent or LifecycleComponentNode) on a fixed polling interval. For each target the watchdog:

  • logs a WARN when health level is DEGRADED,

  • logs an ERROR when health level is ERROR (includes last_error if set),

  • logs an additional WARN labelled STALE when the level has been non-OK for longer than stale_threshold seconds.

The watchdog is purely read-only: it never triggers lifecycle transitions. Polling runs only while the component is active (between _on_activate and _on_deactivate). OK and UNKNOWN levels are silent.

Staleness is tracked from the first time the current level was observed. The clock resets each time the level changes.

Parameters:
  • name (str) – Unique component name within the node.

  • targets (Sequence[_WatchableHealth]) – Objects to watch. Each must expose a .health property returning a HealthStatus. Accepts LifecycleComponent or LifecycleComponentNode instances.

  • poll_period (float) – Polling interval in seconds. Must be > 0.

  • stale_threshold (float) – Seconds after which a persistently non-OK level is labelled STALE in the log. Must be > 0.

  • callback_group (CallbackGroup | None) – Optional callback group forwarded to the underlying ROS timer. None selects the node default group.

  • dependencies (Sequence[str]) – Names of other components that must be transitioned before this one.

  • priority (int) – Tie-breaking ordering hint within the resolved transition order.

Raises:

ValueError – If poll_period or stale_threshold is not strictly positive.

property stale_threshold: float

Staleness threshold in seconds.

_on_configure(state)

Create the poll timer and initialize per-target tracking state.

Calls super()._on_configure(state) first to create the underlying ROS timer.

Parameters:

state (rclpy.lifecycle.node.LifecycleState)

Return type:

rclpy.lifecycle.TransitionCallbackReturn

_release_resources()

Clear tracking state and release the underlying timer.

Return type:

None

on_tick()

Poll each watched target and log actionable diagnostics.

Called on every timer tick while the component is active. Behaviour per target:

  • DEGRADED → WARN log with reason.

  • ERROR → ERROR log with reason and last_error if set.

  • Non-OK for longer than stale_threshold → additional WARN labelled STALE.

  • OK and UNKNOWN → no log.

Return type:

None

class lifecore_ros2.components.lifecycle_parameter_component.ParameterMutability(*values)

Bases: Enum

Runtime mutability model for component-owned parameters.

STATIC = 'static'

Parameter cannot be changed at runtime; any write is rejected regardless of lifecycle state.

ACTIVE = 'active'

Parameter can be written only while the owning component is active.

class lifecore_ros2.components.lifecycle_parameter_component.LifecycleParameter(name, default_value, mutability=ParameterMutability.STATIC, description=None)

Bases: object

Definition of a parameter owned by a lifecycle component.

Definitions are structural component metadata. They can be registered before configure and are preserved across cleanup. The actual ROS 2 parameter declaration happens during configure.

Parameters:
name: str
default_value: Any
mutability: ParameterMutability = 'static'
description: str | None = None
class lifecore_ros2.components.lifecycle_parameter_component.LifecycleParameterComponent(*args, **kwargs)

Bases: LifecycleComponent

Lifecycle-aware owner for local ROS 2 parameters on the parent node.

The component owns only parameters registered through declare_lifecycle_parameter. Parameter definitions are preserved across cleanup, while runtime values, configured ownership tracking, and callback registration are lifecycle state.

Runtime writes are accepted only while the component is active. Static parameters reject all runtime writes. Parameters not owned by this component are ignored so multiple parameter components can attach callbacks to the same node safely.

Owned parameter update flow while active is ordered and explicit: on_pre_set_owned_parameters runs first, then on_validate_owned_parameters (which delegates to validate_parameter_update by default), then on_post_set_owned_parameters after internal value tracking is updated.

Owned ROS 2 parameters are declared on the parent node during configure and are not undeclared during cleanup or shutdown. A subsequent configure cycle reuses the existing node-level value. Parameter names are scoped as <component_name>.<parameter_name> to avoid collisions across components.

Parameters:
  • name (str)

  • callback_group (CallbackGroup | None)

  • dependencies (Sequence[str])

  • priority (int)

declare_lifecycle_parameter(name, default_value, *, mutability=ParameterMutability.STATIC, description=None)

Register a component-owned parameter definition.

Calling this before configure records local component metadata. The ROS 2 parameter is declared on the parent node during configure.

Parameters:
  • name (str) – Local parameter name, without the component prefix.

  • default_value (Any) – Default value used when the ROS 2 parameter is absent.

  • mutability (ParameterMutability) – Runtime mutability policy.

  • description (str | None) – Optional ROS 2 parameter description.

Raises:
  • ValueError – If name is empty or already registered.

  • RuntimeError – If called while the component has configured runtime state.

Return type:

None

has_parameter(name)

Return whether this component has a registered definition for name.

Parameters:

name (str)

Return type:

bool

get_parameter_value(name)

Return the tracked value for a configured owned parameter.

Raises:
  • KeyError – If name is not registered by this component.

  • ComponentNotConfiguredError – If the component has no configured value for the registered parameter.

Parameters:

name (str)

Return type:

Any

on_pre_set_owned_parameters(parameters)

Transform owned parameter updates before validation.

Called only when the component is active and at least one owned parameter is being written. parameters contains only the owned subset of the original batch. The returned list replaces those entries before the validation callbacks run.

This is the first application-visible hook in the owned-parameter write pipeline. Use it to rewrite or normalize incoming values before validation. For most components, validate_parameter_update is the simpler extension point.

The default implementation returns parameters unchanged.

Parameters:

parameters (list[rclpy.parameter.Parameter])

Return type:

list[rclpy.parameter.Parameter]

on_validate_owned_parameters(parameters)

Validate active owned parameter updates as a batch.

Called only when the component is active and at least one owned parameter passes pre-filtering. By the time this hook runs, type compatibility and mutability (STATIC rejection) have already been checked by the framework. This hook handles application-level constraints.

This is the batch-validation hook for the owned-parameter write pipeline. Override it only when validation depends on relationships across multiple owned parameters in the same batch. For simple per-parameter rules, prefer validate_parameter_update.

The default implementation delegates each parameter to validate_parameter_update. Override this method directly only for cross-parameter validation; prefer validate_parameter_update for per-parameter rules.

Parameters:

parameters (list[rclpy.parameter.Parameter])

Return type:

rcl_interfaces.msg.SetParametersResult

validate_parameter_update(name, old_value, new_value)

Validate one active parameter update.

Returns None to accept the update. Return a string to reject it with that reason. This is the simplest validation extension point: the default on_validate_owned_parameters implementation calls it once per owned parameter after on_pre_set_owned_parameters and before on_post_set_owned_parameters. Override on_validate_owned_parameters instead for advanced batch validation.

Parameters:
  • name (str)

  • old_value (Any)

  • new_value (Any)

Return type:

str | None

on_post_set_owned_parameters(parameters)

React to successful active owned parameter updates.

Called after the component’s internal value tracking has been updated. get_parameter_value already reflects the new values when this hook runs. parameters carries the scoped names (<component>.<name>).

This is the final application-visible hook in the owned-parameter write pipeline. Use it for side effects that should observe the accepted, already-stored values.

Parameters:

parameters (list[rclpy.parameter.Parameter])

Return type:

None

_on_configure(state)

Declare and read owned ROS 2 parameters on the parent node.

Parameters:

state (rclpy.lifecycle.node.LifecycleState)

Return type:

rclpy.lifecycle.node.TransitionCallbackReturn

_release_resources()

Clear runtime tracking and remove parameter callbacks.

Clears _parameter_values and _configured_parameters. Does not call node.undeclare_parameter; ROS 2 parameters remain on the parent node across cleanup cycles so that a subsequent configure reuses their values (see _declare_or_read_parameter).

Return type:

None

class lifecore_ros2.components.lifecycle_parameter_observer_component.WatchState(*values)

Bases: StrEnum

Availability state recorded for a watched remote parameter after an initial read.

This state is testable via get_observed_parameter. Logging may explain the condition, but the state itself is the contract — not warnings.

UNKNOWN_NODE = 'unknown_node'

Remote node could not be identified as available within the read timeout.

UNKNOWN_PARAMETER = 'unknown_parameter'

Remote node responded but the watched parameter was absent or not set.

UNAVAILABLE = 'unavailable'

Initial read could not complete due to a timeout, transport error, or other transient reason.

VALUE_AVAILABLE = 'value_available'

An initial value was read and stored successfully.

class lifecore_ros2.components.lifecycle_parameter_observer_component.ObservedParameterEvent(node_name, parameter_name, value, previous_value, source)

Bases: object

A single observed change for a remote parameter.

Passed to per-watch callbacks and the on_observed_parameter_event hook. Represents a fact already accepted by the remote node. The observer has no validation authority.

Parameters:
  • node_name (str)

  • parameter_name (str)

  • value (object)

  • previous_value (object | None)

  • source (Literal['initial_read', 'parameter_event'])

node_name: str

Full name of the remote node that owns the parameter.

parameter_name: str

Name of the changed parameter on the remote node.

value: object

New value as accepted by the remote node.

previous_value: object | None

Last value known to this observer before the change, or None if not previously observed.

source: Literal['initial_read', 'parameter_event']

Event source label. Built-in callbacks receive live parameter events; initial reads update snapshots.

class lifecore_ros2.components.lifecycle_parameter_observer_component.ObservedParameterSnapshot(node_name, parameter_name, state, value, previous_value)

Bases: object

Current observation state for a single watched parameter.

Query via get_observed_parameter. Check state before using value.

Parameters:
  • node_name (str)

  • parameter_name (str)

  • state (WatchState)

  • value (object | None)

  • previous_value (object | None)

node_name: str

Full name of the remote node that owns the parameter.

parameter_name: str

Name of the watched parameter on the remote node.

state: WatchState

Availability state. Inspect this before relying on value.

value: object | None

Latest value observed, or None when state is not VALUE_AVAILABLE.

previous_value: object | None

Value observed before the most recent change, or None if not previously observed.

class lifecore_ros2.components.lifecycle_parameter_observer_component.ParameterWatchHandle(node_name, parameter_name)

Bases: object

Identifies a registered parameter watch.

Returned by watch_parameter. Carries the watch coordinates for reference.

Parameters:
  • node_name (str)

  • parameter_name (str)

node_name: str
parameter_name: str
class lifecore_ros2.components.lifecycle_parameter_observer_component.LifecycleParameterObserverComponent(*args, **kwargs)

Bases: LifecycleComponent

Lifecycle-aware observer for parameters owned by remote ROS 2 nodes.

Watches may be registered before configure. During configure, the component subscribes to /parameter_events for live change observation and optionally reads initial values from each remote node. Missing nodes or parameters do not fail configure; each watch records an explicit WatchState that is testable via get_observed_parameter.

User callbacks and the on_observed_parameter_event hook run only while the component is active. Snapshot updates from live events happen regardless of activation state so that get_observed_parameter always reflects the latest observed value.

The component never declares, validates, rejects, or owns remote parameters. It observes facts already accepted by the remote node.

Note

_read_initial_parameter uses AsyncParameterClient and rclpy.spin_until_future_complete. For production use, prefer a multi-threaded executor to avoid blocking the lifecycle transition thread. Override _read_initial_parameter in tests to inject a stub.

Parameters:
  • name (str)

  • read_timeout_sec (float)

  • callback_group (CallbackGroup | None)

  • dependencies (Sequence[str])

  • priority (int)

watch_parameter(*, node_name, parameter_name, read_initial=True, callback=None)

Register a parameter on a remote node for observation.

Must be called before configure. The watch records an explicit WatchState for the initial read outcome when the component is configured.

Parameters:
  • node_name (str) – Full name of the remote node that owns the parameter (e.g. "/sensor_node").

  • parameter_name (str) – Name of the parameter on the remote node.

  • read_initial (bool) – If True, attempt to read the current value during configure.

  • callback (Callable[[ObservedParameterEvent], None] | None) – Optional per-watch callable invoked for this specific node/parameter pair while the component is active. Use on_observed_parameter_event instead when one component-wide hook should handle all observed parameters.

Returns:

A ParameterWatchHandle identifying the registered watch.

Raises:
  • ValueError – If a watch for this node/parameter pair is already registered.

  • RuntimeError – If the component is already configured.

Return type:

ParameterWatchHandle

get_observed_parameter(node_name, parameter_name)

Return the current observation snapshot for a watched parameter.

Returns None if no watch is registered for the given node/parameter pair.

Parameters:
  • node_name (str) – Full name of the remote node.

  • parameter_name (str) – Name of the parameter on the remote node.

Return type:

ObservedParameterSnapshot | None

on_observed_parameter_event(node_name, parameter_name, event)

React to an observed parameter change while active.

Called for every watched parameter that changes while the component is active. This is the component-wide hook: unlike callback=... on watch_parameter, it is not tied to one watch. Override it when the same reaction should apply across all observed parameters owned by this component instance.

If a watch-specific callback was registered with watch_parameter, that callback runs first for the matching watch and this hook runs afterward. The default implementation is a no-op.

Parameters:
  • node_name (str) – Full name of the remote node that owns the parameter.

  • parameter_name (str) – Name of the changed parameter.

  • event (ObservedParameterEvent) – The observed event carrying the new and previous values.

Return type:

None

_on_configure(state)

Subscribe to /parameter_events and optionally read initial values.

Parameters:

state (rclpy.lifecycle.node.LifecycleState)

Return type:

rclpy.lifecycle.node.TransitionCallbackReturn

_release_resources()

Destroy the parameter event subscription created during configure.

Return type:

None