Reproduce the simulation experiment
This procedure starts the world and records new episodes. It was assembled from the checked-in launchers and harnesses; the editorial review did not reinstall ROS or rerun the VM. The retained results came from one Ubuntu 24.04 ARM64 VM, ROS 2 Jazzy and Gazebo Harmonic 8.15.0. A second-machine reproduction remains to be done.
Commands below use Bash and start at the repository root. Use separate terminals as labelled. Do not run this on a physical robot: the harness changes the Gazebo model pose and publishes directly to /cmd_vel.
1. Prerequisites and isolation
Required: ROS 2 Jazzy, Gazebo Harmonic, ros_gz_bridge, Python with rclpy and NumPy. Plotting tools additionally need matplotlib; screen recording needs ffmpeg, scrot and an X11 desktop. The Nav2 reference additionally uses navigation2, nav2_bringup, slam_toolbox and explore_lite from m-explore-ros2.
The robot's external visual meshes are not distributed here. Follow the mesh note. Missing visuals do not turn a model into a hardware-validated replica. On Parallels, the graphics setup is a separate prerequisite.
In every terminal, from the repository root:
source /opt/ros/jazzy/setup.bash
export NAV_ROOT="$PWD/config/navigation"
export ROS_DOMAIN_ID=20
export GZ_PARTITION=dume
Use an isolated VM session with no other controller publishing velocity commands. The recording script currently hardcodes domain 20 / partition dume. The Nav2 series runner uses a broad pkill on slam_toolbox processes, so do not use it alongside unrelated SLAM work. The launcher checks for one known server process form; that guard is not a universal duplicate-server detector.
2. Start the world · terminal A
cd "$NAV_ROOT/sim"
bash ./run_sim.sh gui
Keep this terminal running. The launcher starts Gazebo and a ROS bridge. In terminal B, after the common environment block:
ros2 topic hz /scan
Expect approximately 10 Hz; stop this inspection with Ctrl+C before starting a harness. Check scan angles and maximum range if the world/model has been changed. The policy expects the documented scan geometry and 6 m normalization.
3. Inspect and generate weights · terminal B
cd "$NAV_ROOT/policy"
python3 write_weights.py --version v03
python3 write_weights.py --version v04
python3 write_weights.py --empty
The script prints synthetic input responses and writes the named local files. Those responses are sanity checks, not a navigation test. The zero network produces half-speed forward motion because of the node's output scaling.
Optional fast development check:
python3 desksim.py grid weights_v03.npy
python3 desksim.py validate weights_v02.npy ../evidence/run-003/003.05.json
The desk simulator uses simplified 2D geometry and kinematics. Do not count its outcome as an independent Gazebo or hardware result. It has been used during policy development, so its scenarios are not held out.
4. Record a door episode · terminal B
cd "$NAV_ROOT/policy"
export OUT="$NAV_ROOT/out/review-door-101"
mkdir -p "$OUT"
WEIGHTS=weights_v03.npy bash ./record_run.sh 101.01 "$OUT" 60
python3 plot_run.py "$OUT/map_101.01.png" "$OUT/101.01.json"
Use a new output folder / run ID; the existing recorder can overwrite files. The absolute output path avoids path changes inside the series runners. The script assumes X11 display :0, the GDM Xauthority path and a 1728×1084 screen. Adapt those recording settings for your desktop, or omit recording and call the harness directly:
python3 run_door.py 101.02 "$OUT" --weights weights_v03.npy --timeout 60
The harness still calls scrot; the original evidence workflow expects an X11 session. It resets the model pose, starts the policy, samples true pose and stops on the door criterion, stall or timeout. The retained standard-start v03 episode (003.15) reports door_crossed, 22.78 s stored duration and 4.983 m sampled path. These are reference observations, not exact acceptance bounds for another host.
Read <id>.json, <id>_trace.jsonl, the node log and the video together. t_end_s includes cleanup; the last trajectory sample is closer to the event time. collision is a scan/stall proxy, not a measured contact event.
5. Compare starts and obstacle cases
From terminal B:
cd "$NAV_ROOT/policy"
mkdir -p "$NAV_ROOT/out/series-v03"
bash ./run_series.sh series_003_15_20.txt "$NAV_ROOT/out/series-v03"
Plan entries specify run, weights, start, scenario and boxes. Read the plan before running it. The older series_003_06_14.txt uses v02; it intentionally includes failures. Run a frozen version under matched starts if you want a controlled comparison. Record the policy node, weight file and harness hashes with each new series.
6. Run the three-lap mission
cd "$NAV_ROOT/policy"
export OUT="$NAV_ROOT/out/review-lanes-102"
mkdir -p "$OUT"
HARNESS=run_explore.py WEIGHTS=weights_v04.npy RUN_ARGS='--lanes 0,0.4,0.8' \
bash ./record_run.sh 102.01 "$OUT" 420
python3 mapper.py "$OUT/102.01.json" "$OUT/102.01_trace.jsonl" "$OUT/map_102.01.png"
The harness supplies /odom_truth to the scheduler. It advances the network's lane-offset input after each detected lap. In retained run 004.01, three laps finished with t_end_s=320.64 and path_len_m=73.253. The label explored means the schedule ended. The projected scan-hit image is built offline with true pose; it is not proof of complete area coverage or SLAM accuracy.
7. Run the configured Nav2 reference
Use the same world / bridge, with no policy harness active. Install/build the dependencies separately according to their maintained instructions. If explore_lite is built in a workspace, source its install/setup.bash in each terminal that launches it.
Terminal B, after the common environment block:
cd "$NAV_ROOT"
cp /opt/ros/jazzy/share/nav2_bringup/params/nav2_params.yaml baseline-nav2/nav2_params_default.yaml
python3 baseline-nav2/patch_nav2_params.py
python3 baseline-nav2/truth_odom_tf.py --ros-args -p use_sim_time:=true
Keep the true-odometry node running. In terminal C, with the same environment:
cd "$NAV_ROOT"
ros2 launch nav2_bringup navigation_launch.py \
params_file:="$NAV_ROOT/baseline-nav2/nav2_params.yaml" \
use_sim_time:=true autostart:=true
In terminal D, with the same environment:
cd "$NAV_ROOT"
mkdir -p "$NAV_ROOT/out/nav2-series"
bash baseline-nav2/nav2_series.sh baseline-nav2/series_005_c1.txt "$NAV_ROOT/out/nav2-series"
The series starts a fresh slam_toolbox instance before each episode and adds the specified obstacles. Read its process-management behavior before using it. The retained standard-start reference is 005.01: door_crossed, 16.62 s / 4.026 m. The checked-in parameter patch replaces the packaged controller with RPP; this is not stock Nav2.
To inspect the separate frontier-exploration task, keep a fresh slam_toolbox map and the Nav2 / truth-odometry nodes active, with explore_lite discoverable:
cd "$NAV_ROOT/policy"
export OUT="$NAV_ROOT/out/nav2-frontier-105"
mkdir -p "$OUT"
HARNESS=../baseline-nav2/run_nav2_explore.py bash ./record_run.sh 105.10 "$OUT" 420
Read the frontier log and saved map. Do not compare its end time as a speedup over the three-lap mission: termination criteria differ.
8. Stop and review
Stop each owned harness and launch with Ctrl+C, then stop the simulator terminal. Check that the controller / bridge processes you started have exited before using the same domain again. Do not issue a global reset or kill unrelated work to clean up your experiment.
Keep original JSON and traces unchanged. Summarize outcomes with precise definitions, record actual /clock and RTF for timing studies, and distinguish observed failures from hypotheses about their cause.
9. Rebuild the publication data
From the repository root, using a Python environment with NumPy:
python3 config/navigation/study/tools/build_publication.py
python3 config/navigation/study/tools/render_guides.py
python3 -m http.server 8765 --bind 127.0.0.1 --directory pages
Open http://127.0.0.1:8765. The build script regenerates reviewed figures, the playback subset, run ledger data and source hashes from the evidence. It does not run Gazebo, edit weights or publish a website. Review editorial HTML / Markdown separately when adding new runs.