---
title: Deterministic ROS 2 Simulations
url: https://www.emergentmind.com/topics/deterministic-simulations-using-ros-2-nodes
type: topic
---

# Deterministic ROS 2 Simulations

Deterministic simulation using ROS 2 nodes describes methods and libraries that transform the inherently nondeterministic execution of Robot Operating System 2 (ROS 2) applications into reproducible, bit-exact processes, independently of hardware concurrency or OS scheduling noise. Determinism in this context refers to the guarantee that, given the same initial graph and inputs, the sequence of callback executions and their effects (messages, state, outputs) is identical on every run and across all platforms. This property is essential for scientific benchmarking, continuous integration, and system verification in robotics. Two primary methodological axes have emerged: deterministic scheduling for simulation (as in RSLCPP), and deterministic real-time operation for deployed systems, including ROS 2 nodes written in asynchronous Rust via R2R [2601.07052], [2505.21323].

## 1. The Nondeterminism Problem in ROS 2

ROS 2 is architected as an asynchronous, distributed middleware leveraging multi-process and multi-threaded execution. This design introduces inherent nondeterminism in simulation and deployment:

- Scheduler-dependent callback ordering: The rclcpp executor dequeues ready callbacks based on OS thread scheduling, which is not reproducible across runs or machine architectures.
- Temporal misalignment: Publication and inter-process communication delays depend on scheduler state, hardware concurrency, and system load (notably in DDS, intra-process, and shared memory transports).
- Variable callback runtimes: CPU sharing, cache contention, and background load all affect per-callback compute time, producing run-to-run divergence in sensor fusion, trajectory estimates, or map-building.

This nondeterminism complicates verification, performance regression testing, and benchmarking, since identical input does not guarantee identical output in repeated simulation runs. Empirical evidence confirms that, in vanilla ROS 2, repeated runs diverge even on a single host, and this effect magnifies across CPUs and architectures, producing inconsistent final states and pose estimates in SLAM or localization [2601.07052].

## 2. Deterministic Simulation via RSLCPP

The ROS Simulation Library for C++ (RSLCPP) provides a methodology and toolkit to achieve bit-exact deterministic simulation of ROS 2 graphs:

- Aggregation: All nodes are loaded into a single process using node composition, eliminating inter-process communication noise.
- Single-threaded execution: The RSLExecutor event loop supersedes the standard rclcpp executor, collecting all "ready" entities (timers, subscriptions, services) into a FIFO queue drained completely before advancing simulated time.
- Simulation time decoupling: Wall time is decoupled from simulation time via a discrete-event scheduler, and passage of simulated time is advanced only after all scheduled and triggered callbacks at the current time have been executed.
- Zero-copy transport: Topics utilize intra-process, zero-copy transport to eliminate system-level jitter.
- Delay modeling: Realistic latencies are introduced by intercepting `.publish()` calls and enqueueing delayed sends, which are released into the simulation at specified times.

The core execution loop maintains three data structures: a ready queue for immediate callbacks (std::deque), a timer queue sorted by expiry (std::priority_queue), and a delayed publication queue (std::priority_queue). The event loop pseudo-code is:

```cpp
while (!job->finished()) {
  rclcpp_executor_->spin_some(); // Enqueue ready callbacks
  process_delayed_pubs(t_now);
  execute_ready_queue(); // Drain FIFO/prio queue
  if (job->finished()) break;
  t_next = min(timer_queue.top().expiry, delayed_pub_queue.top().scheduled_time);
  orchestrator_->get_clock()->set_now(t_next);
}
```

This structure guarantees deterministic ordering of all callbacks and decouples simulation from real time, so identical outcomes are assured across all runs and platforms for a given job setup [2601.07052].

## 3. Integration, API, and Configuration

RSLCPP is designed for transparent adoption in existing ROS 2 C++ workflows:

- Nodes are loaded into the simulation via a "Job" object specifying which components to instantiate and providing finishing conditions (e.g., stopping after 10 simulated seconds).
- No changes are required to node implementation code; interception of timer and publish APIs is handled via a lightly patched rclcpp.
- Users configure simulation launch through standard launch files and dynamic parameters. Delay models and callback priorities are adjustable by parameter (e.g., `/rslcpp/delay_model/<topic_name>` for custom deterministic latency).
- The ready queue can be FIFO or priority sorted to explore alternative scheduling policies.

Fixed time-step or event-driven progression is toggled by configuring a minimum time step or advancing the event loop to the next entity expiry. Deterministic simulation is verified by matching final-state hashes (bit-exactness) or application metrics (e.g., RMSE in odometry) across repeated runs [2601.07052].

## 4. Experimental Demonstrations and Performance Characteristics

Evaluation of RSLCPP determinism uses synthetic and real-world benchmarks:

- Synthetic graph of 8 nodes, with timers and inter-node subscriptions, subject to multiple event frequencies (10 Hz, 20 Hz, etc.), and state computed by a Xorshift update.
- Results from 100 runs on six distinct architectures (Intel, AMD, ARM): bit-exact matching in all final-state hashes (0 deviations), demonstrating full determinism.
- LiDAR odometry benchmark (KISS-ICP on KITTI): RSLCPP eliminated RMSE variability and divergence seen in vanilla ROS 2, achieving identical trajectories and positional error for all runs and architectures.

A performance trade-off is observed: single-threaded execution is up to 20% slower in wall-clock than native, multi-threaded ROS 2, but high-throughput simulation can be achieved by running many concurrent worker processes in a cluster environment [2601.07052].

## 5. Real-Time Determinism in Async Rust ROS 2 Nodes

Deterministic behavior for deployed, real-time R2R (asynchronous Rust ROS 2) nodes is achieved not by simulation but by strict control of thread priorities, callback isolation, and classical response-time analysis:

- Each node executes Node::spin_once() in a high-priority thread (Linux SCHED_FIFO, p=21), with all RMW/DDS-internal threads inheriting this priority.
- Every ROS entity (subscription, timer, etc.) is assigned its own OS thread, which runs a single futures::LocalPool executor instance. Threads are isolated (pinned to the same CPU as the spin thread) and scheduled according to Rate-Monotonic priorities (shorter period ⇒ higher priority).
- Message sampling events are funneled through bounded-capacity MPSC channels, and each callback is an async task awaiting its channel input.
- Scheduling analysis is performed using the classic fixed-point formula for response-time analysis:

  $$
  R_i = C_i + \sum_{h \in hp(i)} \lceil R_i / T_h \rceil C_h
  $$

  where $C_i$ is the measured 99th-percentile execution time, $T_h$ are the periods of higher-priority callbacks, and $hp(i)$ is the set of higher-priority tasks [2505.21323].

- Experimental evaluation using a synthetic 5-topic chain (varying $T$, $C$) and an autonomous-driving LiDAR-odometry case study demonstrates that this approach achieves bounded 99th-percentile latencies and that schedulability predicted by response-time analysis matches observed results.

## 6. Practical Guidance and Limitations

- For deterministic simulation: Use RSLCPP to aggregate nodes into a single process, enforce single-threaded scheduling, and decouple simulation from wall time. Use published API to set delay models and callback priorities as needed. Debug using simulation time traces and callback-order hooks.
- For deterministic real-time node execution in Rust: Assign per-entity threads, fixed priorities by Rate-Monotonic order, isolate all scheduling to a fixed CPU core with SCHED_FIFO, and verify schedulability using measured callback execution times with response-time analysis.
- For benchmarking and CI: Verify bit-exactness using state hashes or metric traces; automate regression via golden-output diffs (e.g., rosbag2 replay and comparison).
- Trade-offs: Deterministic simulation via RSLCPP sacrifices multi-core parallelism and is up to 20% slower in wall time, but enables rigorous, reproducible evaluation. Per-callback threading for real-time guarantees increases context-switch and memory overhead, but achieves analyzable, FIFO-isolated execution [2601.07052], [2505.21323].
- Limitations: Vanilla ROS 2 scheduling order is fixed by entity creation, so strict interleaving or synchronization beyond FIFO must be explicitly implemented. RSLCPP and the described R2R techniques require specific executor and process configurations not enabled by default in ROS 2 distributions.

## 7. Significance and Prospects for Deterministic ROS 2

Deterministic execution, whether for simulation or deployed systems, addresses long-standing challenges in reproducibility for the robotics research community. The RSLCPP system enables code-free, drop-in deterministic simulation for any ROS 2 C++ node graph, supporting scientific reproducibility, regression test automation, and hardware-agnostic benchmarking. Rate-monotonic scheduling and response-time analysis in Rust-based ROS 2 nodes similarly extend deterministic guarantees to real-time embedded applications. A plausible implication is that, as methodology and tooling mature, deterministic simulation and analyzable execution will become standard practice for both continuous integration and safety-critical application development in robotics [2601.07052], [2505.21323].

Source: https://www.emergentmind.com/topics/deterministic-simulations-using-ros-2-nodes