rosrustext_rosrs

Crates.iorosrustext_rosrs
lib.rsrosrustext_rosrs
version0.4.1
created_at2026-01-06 21:00:47.666424+00
updated_at2026-01-17 21:43:49.627889+00
descriptionrclrs adapter for rosrustext ROS 2 lifecycle + parameters parity
homepagehttps://github.com/convyares-FCSL/rosrustext
repositoryhttps://github.com/convyares-FCSL/rosrustext
max_upload_size
id2026822
size158,703
(convyares-FCSL)

documentation

README

rosrustext_rosrs

rclrs extension layer that targets tool parity (ROS-facing behavior) and user parity (developer ergonomics) for ROS 2 features, centered on the ROS-facing adapter and application-facing APIs.

Extension areas and status

Area Tool parity User parity
Lifecycle Implemented (services/events/bond/gating) Partial (gaps documented)
Parameters Implemented (services/events) Partial (watcher; no set-time validation hook)
Actions Not implemented Not implemented
Executor Not implemented Not implemented

Lifecycle parity (implemented)

  • Lifecycle services: change_state, get_state, get_available_states, get_available_transitions
  • transition_event publisher (one per accepted attempt, after completion)
  • Optional /bond heartbeats for Nav2 compatibility (feature bond)
  • ManagedPublisher/ManagedTimer gating while inactive (local suppression)

See docs/adapters/ros2rust/lifecycle/parity.md for tool vs user parity details.

Parameters parity (implemented baseline)

  • Parameter services: get_parameters, get_parameter_types, list_parameters, describe_parameters, set_parameters, set_parameters_atomically
  • parameter_events publisher (emitted on successful updates only)
  • ParameterWatcher helper for event-driven updates without polling
  • No set-time validation hook (updates are observable after apply)

See docs/adapters/ros2rust/parameters/parity.md for tool vs user parity details.

Compatibility / Parity Notes

  • Parameters parity uses rclrs::vendor::rcl_interfaces for ParameterEvent and parameter services.
  • This couples the adapter to rclrs 0.6.x (and rosidl_runtime_rs 0.5.x transitively).
  • This is an implementation detail dependency; if rclrs changes the vendored surface, we will pin/update accordingly.

Known differences vs rclcpp

  • change_state returns success=true once a transition is accepted; callback outcome is reflected in the final state and transition_event.

Publish outcome visibility

Use publish_with_outcome() when you need to know whether a message was suppressed due to lifecycle inactivity. publish() remains silent and returns Ok(()) either way.

use rosrustext_rosrs::lifecycle::{PublishOutcome, ManagedPublisher};

match publisher.publish_with_outcome(msg)? {
    PublishOutcome::Published => {}
    PublishOutcome::SuppressedInactive => {
        // Message was gated due to inactive lifecycle state.
    }
}

Lifecycle user parity gaps (current)

  • No set/replace callbacks API; create/try_new still default to no-op callbacks

Other extensions (not implemented)

  • Actions parity
  • Executor extensions

Build (ROS installed)

This crate is published on crates.io, but building requires ROS 2 and ROS message crates available via a ROS workspace environment (Cargo patching is typical).

cargo build \
  --manifest-path crates/rosrustext_rosrs/Cargo.toml \
  --features ros2,bond

Docs build on docs.rs without ROS (feature docsrs + rclrs/use_ros_shim). Runtime builds/tests require ROS 2 Jazzy with the environment sourced.

Feature matrix

  • ros2: enables ROS-facing tooling parity (parameter services/events and lifecycle services) and relies on rclrs::vendor::rcl_interfaces.
  • bond: publishes /bond heartbeats for Nav2 lifecycle manager compatibility (requires ros2).
  • lifecycle_msgs: exposes lifecycle message/service surfaces; no hidden deps.
  • docsrs: docs.rs-only shim for ROS-free builds; not intended for users.

Example commands (Jazzy)

ros2 lifecycle get /<node>
# Expect the current stable state (Unconfigured/Inactive/Active/Finalized)

ros2 lifecycle set /<node> configure
# success=true; a transition_event is published after completion

ros2 lifecycle set /<node> activate
# success=true; /bond heartbeats begin if `bond` is enabled

Minimal usage

Recommended constructor: LifecycleNode::create_with_callbacks.

use rclrs::{Context, CreateBasicExecutor, SpinOptions};
use rosrustext_rosrs::lifecycle::{CallbackResult, LifecycleCallbacksWithNode, LifecycleNode};
use rosrustext_rosrs::State;

struct Callbacks;

impl LifecycleCallbacksWithNode for Callbacks {
    fn on_configure(&mut self, node: &LifecycleNode, _state: &State) -> CallbackResult {
        let _ = node.name();
        CallbackResult::Success
    }
    fn on_activate(&mut self, _node: &LifecycleNode, _state: &State) -> CallbackResult { CallbackResult::Success }
    fn on_deactivate(&mut self, _node: &LifecycleNode, _state: &State) -> CallbackResult { CallbackResult::Success }
    fn on_cleanup(&mut self, _node: &LifecycleNode, _state: &State) -> CallbackResult { CallbackResult::Success }
    fn on_shutdown(&mut self, _node: &LifecycleNode, _state: &State) -> CallbackResult { CallbackResult::Success }
    fn on_error(&mut self, _node: &LifecycleNode, _state: &State) -> CallbackResult { CallbackResult::Success }
}

fn main() -> rosrustext_rosrs::Result<()> {
    let context = Context::default();
    let mut executor = context.create_basic_executor();

    let _lifecycle = LifecycleNode::create_with_callbacks(&executor, "lifecycle_demo", Box::new(Callbacks))?;
    executor.spin(SpinOptions::default());
    Ok(())
}

Builder APIs (managed vs raw)

Managed (lifecycle-gated):

use rclrs::{Context, CreateBasicExecutor};
use rosrustext_rosrs::lifecycle::LifecycleNode;
use rosrustext_rosrs::lifecycle_msgs::msg::State;

fn main() -> rosrustext_rosrs::Result<()> {
    let context = Context::default();
    let executor = context.create_basic_executor();
    let lifecycle = LifecycleNode::create(&executor, "demo")?;

    let _pub = lifecycle.publisher::<State>("state").create()?;
    let _timer = lifecycle
        .timer_repeating(std::time::Duration::from_millis(100))
        .callback(|| {})
        .create()?;
    Ok(())
}

Raw (non-managed):

use rclrs::{Context, CreateBasicExecutor};
use rosrustext_rosrs::NodeBuilderExt;
use rosrustext_rosrs::lifecycle_msgs::msg::State;

fn main() -> rosrustext_rosrs::Result<()> {
    let context = Context::default();
    let executor = context.create_basic_executor();
    let node = executor.create_node("demo")?;

    let _pub = node.publisher::<State>("state").create()?;
    let _timer = node
        .timer_repeating(std::time::Duration::from_millis(100))
        .callback(|| {})
        .create()?;
    Ok(())
}
Commit count: 89

cargo fmt