Use run_cudanav_rosbag_replay.py for release evidence. Unlike the older
exploratory runner described below, it refuses a non-empty output directory and
fails unless the input bag, selected DB3, controller configuration,
diagnostics, evaluation, commands, git commit, clean worktree, and physical GPU
identity are cryptographically bound in one manifest.
python3 scripts/run_cudanav_rosbag_replay.py \
--bag /data/erl_navigation/Prueba2 \
--evaluation-db /data/erl_navigation/Prueba2/rosbag2_2023_11_13-13_09_49_0.db3 \
--output-dir build/cudanav_rosbag/erl_prueba2 \
--controller-config ros2_ws/src/cuda_nav_bringup/config/controller.yaml \
--controller-command \
'ros2 launch my_nav shadow_replay.launch.py params_file:={controller_config} diagnostics_csv:={diagnostics_csv}' \
--profile release \
--use-sim-timeThe controller command is parsed directly into an argument vector; shell
operators are not executed. It must consume both {controller_config} and
{diagnostics_csv} or the binding gate fails. {out_dir} is also available.
Use repeated --bag-play-arg and --record-topic options for platform-specific
replay and recording settings.
For bags that already contain compatible sensor_msgs/PointCloud2, TF, and
nav_msgs/Path streams, the repository provides a native controller command:
--controller-command \
'ros2 launch cuda_nav_bringup cudanav_recorded_shadow.launch.py params_file:={controller_config} diagnostics_csv:={diagnostics_csv}'The native launch runs GPU KISS-ICP, voxel mapping, ESDF, the Nav2 CUDA MPPI controller, and a recorded-Path action adapter. LaserScan-only bags still need an explicit, documented conversion or platform launch; they are not silently accepted as PointCloud2 CudaNav evidence.
The release profile requires:
- a clean, full git commit and one or more identified NVIDIA GPUs;
- unchanged source-bag contents and selected DB3 SHA-256;
- a quality-passing shadow evaluation with at least 60 seconds of recorded motion and 100 CUDA MPPI diagnostic samples;
- controller config, diagnostics, evaluation, and command-to-input bindings;
- a content-addressed MCAP output recording with
metadata.yamland storage data; - positive recorded message counts for
/cuda_nav/cmd_vel,/cuda_nav/odom,/cuda_nav/occupancy, and/cuda_nav/esdf.
The default output recording also retains the CudaNav local map, local costmap,
component diagnostics, TF, source points, and recorded plan. Supplying custom
--record-topic values in a release run is rejected if any of the four
required CudaNav outputs is omitted.
Revalidate the directory, including the external source bag:
python3 scripts/validate_cudanav_rosbag.py \
build/cudanav_rosbag/erl_prueba2 --profile release--no-verify-source exists only for inspecting an archived evidence directory
after the external dataset has moved. Such a result does not prove that the
currently available source bag still matches the run.
This gate deliberately labels the result
shadow_controller_with_recorded_motion. Recorded robot motion cannot react to
replayed CUDA MPPI commands, so even a passing release-profile replay is not
closed-loop navigation evidence.
scripts/run_cuda_mppi_bag_eval.py is a thin orchestration wrapper for moving
the Nav2 CUDA MPPI controller beyond synthetic maps. It does not assume a
particular robot launch file; instead, pass the launch and mission commands
used by the target platform.
The harness can:
- start a Nav2/controller command,
- play a rosbag2 dataset,
- optionally send goals or waypoints,
- record selected topics into a new rosbag2 output,
- collect
cuda_mppi_controllerdiagnostics CSV, - render the diagnostics CSV into SVG/Markdown with
scripts/render_cuda_mppi_diagnostics.py.
python3 scripts/run_cuda_mppi_bag_eval.py \
--bag /data/site_run \
--output-dir build/cuda_mppi_bag_eval/site_run \
--ros-domain-id 101 \
--use-sim-time \
--controller-command 'ros2 launch my_nav bringup.launch.py params_file:=/path/to/cuda_mppi.yaml' \
--mission-command 'python3 scripts/send_waypoints.py --frame map' \
--duration 120If the launch file can accept a diagnostics path, use the placeholder:
--controller-command 'ros2 launch my_nav bringup.launch.py diagnostics_csv:={diagnostics_csv}'The command receives {out_dir} and {diagnostics_csv} placeholders before it
is started.
For a live robot, omit --bag and provide --duration:
python3 scripts/run_cuda_mppi_bag_eval.py \
--output-dir build/cuda_mppi_bag_eval/live_site_a \
--ros-domain-id 42 \
--controller-command 'ros2 launch my_robot nav2_cuda_mppi.launch.py' \
--mission-command 'python3 scripts/send_waypoints.py --file route.yaml' \
--duration 180The runner writes:
manifest.jsonwith commands, return codes, diagnostics path, and recorded topics,controller.log,mission.log,rosbag_play.log, androsbag_record.logwhen those subprocesses are used,topics/rosbag2 output unless--no-recordis set,diagnostics.svganddiagnostics.mdif the diagnostics CSV exists.
Set these parameters in the CUDA MPPI controller configuration to collect per-cycle diagnostics:
FollowPath:
diagnostics_log_period: 1.0
diagnostics_csv_path: /tmp/cuda_mppi_diagnostics.csvFor repeatable experiments, prefer an output path passed by the harness via
{diagnostics_csv} so logs stay with the recorded topics and manifest.
Use the diagnostics plot to inspect:
- solve-time spikes against the 20 Hz budget,
- sustained low valid-rollout ratio,
- all-colliding and retreat cycles,
- command saturation or oscillation.
Treat the exploratory runner as an evaluation harness, not a pass/fail benchmark by itself. The scenario, map, localization quality, costmap layers, footprint, and waypoint policy determine whether the run is comparable across commits.
After a run, combine recorded motion, LaserScan clearance, and optional CUDA MPPI diagnostics into one machine-readable and human-readable result:
python3 scripts/evaluate_mppi_rosbag.py /data/run/topics/run_0.db3 \
--diagnostics-csv /data/run/diagnostics.csv \
--output-dir build/mppi_rosbag_evaluation/runUse --command-topic, --odometry-topic, and --scan-topic when the robot
does not use the ERL-inspired topic names. The command writes
evaluation.json, evaluation.md, raw clearance samples, decoded motion CSVs,
and a per-check CSV. Its default gates cover command pairing, minimum recorded
clearance, 50 ms solve p95, valid-rollout ratio, and all-colliding cycles.
The report always records its evidence mode. Diagnostics replayed against a fixed bag are shadow-controller evidence; they are not labeled as closed-loop navigation success.
The open ERL-inspired navigation benchmark dataset contains five ROS 2 Humble runs (6 GB compressed, CC BY 4.0). Download, verify, extract, and inspect its Nav2 topic compatibility with:
python3 scripts/prepare_erl_navigation_bags.py --download --extractThe command writes build/datasets/erl_navigation/compatibility_report.json.
Each bag is classified as shadow_ready, adapter_required, or
insufficient_for_nav2_replay, and its scan, odometry, TF, command, map, and
plan topics are listed. Use the reported topic names to configure remappings
before passing a bag to run_cuda_mppi_bag_eval.py.
Recorded motion does not react to newly computed commands. Public bags are therefore suitable for sensor/costmap replay and shadow-mode command analysis, not by themselves for claims about closed-loop controller success.
To avoid downloading the full 6 GB archive, install remotezip, list its
members, and extract one selected run with HTTP range requests:
python3 -m pip install remotezip
python3 scripts/prepare_erl_navigation_bags.py --list-remote
python3 scripts/prepare_erl_navigation_bags.py \
--remote-member Prueba2/rosbag2_2023_11_13-13_09_49_0.db3The 2026-07-28 recorded-motion result for this run is documented in
results/mppi_real_rosbag_erl_prueba2_2026-07-28.md.
The rosbag2 SQLite databases can be inventoried on a machine without ROS:
python3 scripts/analyze_rosbag_db3.py /data/erl_navigation/extracted \
--json build/erl_offline_summary.json \
--csv build/erl_offline_topics.csvThe outputs report per-bag duration and per-topic message count, observed rate, time coverage, and serialized payload bytes. This inspects recording health and topic availability; it does not deserialize CDR message payloads.
Twist commands and Odometry poses can also be decoded without ROS:
python3 scripts/export_rosbag_motion.py /data/erl_navigation/extracted/Prueba5/*.db3 \
--output-dir build/prueba5_motionThis writes cmd_vel.csv, odometry.csv, and motion_summary.json, including
path length, displacement, observed speeds, command speeds, and stop ratio.
For latency-sensitive, smaller-batch deployments, the CUDA core can be built
with -DCUDA_MPPI_FAST_MATH=ON. It is disabled by default because it changes
floating-point behavior and may change an MPPI trajectory. See
results/mppi_fast_math_2026-07-12.md
for the measured speed/quality trade-off and build commands.