- ROS2 Jazzy installed and sourced before build or run:
source /opt/ros/jazzy/setup.bash
safe_driverepository available as a sibling checkout:../safe_driverelative to this repository root
- Rust toolchain (stable) with
cargo - Gazebo demo packages installed:
ros-jazzy-turtlebot3-gazeboros-jazzy-turtlebot3-bringupros-jazzy-turtlebot3-descriptionros-jazzy-nav2-bringupros-jazzy-ros-gz
If cargo check or cargo build fails with ROS2 type support errors, source ROS2 first and retry.
source /opt/ros/jazzy/setup.bash
cargo build --release --manifest-path ros2_nodes/path_planner_node/Cargo.toml
cargo build --release --manifest-path ros2_nodes/dwa_planner_node/Cargo.toml
cargo build --release --manifest-path ros2_nodes/slam_node/Cargo.toml
cargo build --release --manifest-path ros2_nodes/ekf_localizer_node/Cargo.toml
cargo build --release --manifest-path ros2_nodes/waypoint_navigator_node/Cargo.tomlcargo build --workspace
cargo test --workspace --lib --tests- Role: Global path planning with A*
- Subscriptions:
/goal_pose(geometry_msgs/PoseStamped)RUST_NAV_ODOM_TOPIC(nav_msgs/Odometry, default/odom)/map(nav_msgs/OccupancyGrid)
- Publications:
/planned_path(nav_msgs/Path)
- Configuration:
RUST_NAV_ODOM_TOPICDWA_GOAL_THRESHOLDDWA_ROBOT_RADIUS
- Notes:
- Rebuilds its A* planner whenever
/mapupdates - Converts occupied grid cells into A* obstacles
- Uses the selected odometry topic pose as the robot start pose
- Publishes
/planned_pathin the same global frame named by the latest/map.header.frame_id
- Rebuilds its A* planner whenever
- Role: Local trajectory planning and velocity command generation
- Subscriptions:
/scan(sensor_msgs/LaserScan)RUST_NAV_ODOM_TOPIC(nav_msgs/Odometry, default/odom)/planned_path(nav_msgs/Path)
- Publications:
/cmd_vel(geometry_msgs/Twist)
- Configuration:
RUST_NAV_ODOM_TOPIC
- Role: Scan matching and occupancy-grid mapping
- Subscriptions:
/scan(sensor_msgs/LaserScan)SLAM_INPUT_ODOM_TOPIC(nav_msgs/Odometry, default/odom)
- Publications:
/map(nav_msgs/OccupancyGrid)/slam_pose(geometry_msgs/PoseStamped) when corrected mode is enabled/slam_odom(nav_msgs/Odometry) when corrected mode is enabled
- Configuration:
SLAM_INPUT_ODOM_TOPICSLAM_OUTPUT_POSE_TOPICSLAM_OUTPUT_ODOM_TOPICSLAM_USE_CORRECTED_FRAMESLAM_CORRECTED_FRAME_ID
- Notes:
- In default mode, the Gazebo demo keeps
/mapin the selected odom frame and integrates scans from raw odom poses - In corrected mode,
slam_nodeblends odom delta with ICP relative motion, publishes/slam_poseplus/slam_odom, and integrates/mapinSLAM_CORRECTED_FRAME_ID(mapby default)
- In default mode, the Gazebo demo keeps
- Role: Filter wheel odometry into a smoother navigation odom stream
- Subscriptions:
/odom(nav_msgs/Odometry) by default
- Publications:
/ekf_pose(geometry_msgs/PoseStamped)/ekf_odom(nav_msgs/Odometry)
- Configuration:
EKF_INPUT_ODOM_TOPICEKF_OUTPUT_ODOM_TOPICEKF_OUTPUT_POSE_TOPIC
- Notes:
- Wraps
rust_robotics_localization::EKFLocalizer - Uses raw odometry pose as measurement and raw twist as control input
- Provides a filtered odom source for the planner / mission nodes
- Wraps
- Role: Mission-level sequencing of multiple 2D goals
- Subscriptions:
RUST_NAV_ODOM_TOPIC(nav_msgs/Odometry, default/odom)
- Publications:
/goal_pose(geometry_msgs/PoseStamped)/mission_status(std_msgs/String)/mission_markers(visualization_msgs/MarkerArray)
- Configuration:
RUST_NAV_ODOM_TOPICRUST_NAV_GLOBAL_FRAME: frame id used for/goal_poseand/mission_markersheaders, defaultodomWAYPOINT_NAV_WAYPOINTS: semicolon-delimitedx,ymission stringWAYPOINT_NAV_FRAME:maporrelative_startWAYPOINT_NAV_GOAL_TOLERANCE: waypoint reach tolerance [m]WAYPOINT_NAV_LOOP: whether to restart after the last waypoint
- Notes:
- Waits for the selected odometry topic before sending the first goal
- Republishes the active
/goal_poseevery 2 seconds until the planner reacts relative_startresolves waypoints as offsets from the robot pose seen on the first odom sample- In the current Gazebo demo,
WAYPOINT_NAV_FRAME=mapmeans "absolute in the selected global frame", which defaults toodom - Publishes human-readable mission / recovery summaries on
/mission_status - Publishes RViz markers for the resolved route, active goal, and current mission state on
/mission_markers
TurtleBot3 Gazebo
/scan /odom /cmd_vel
| | ^
v | |
+-----------+ |
| slam_node | ----- +
+-----------+ /map
|
v
+-------------------+
| path_planner_node | ---> /planned_path
+-------------------+ |
^ ^ v
| | +--------------+
/ekf_odom /goal_pose ---> | dwa_planner |
^ +--------------+
| |
+----------------------+ v
| ekf_localizer_node | /cmd_vel
+----------------------+
^
|
+-------------------------+
| waypoint_navigator_node |
+-------------------------+
source /opt/ros/jazzy/setup.bash
export ROS_DOMAIN_ID=42 # recommended if another ROS graph is already active on the machine
export TURTLEBOT3_MODEL=burger
./ros2_nodes/launch/run_gazebo_demo.shThe wrapper script starts navigation_demo.launch.py, which:
- launches Gazebo server for
turtlebot3_world.world - can optionally launch the Gazebo GUI client with
enable_gazebo_gui:=true - forwards the upstream TurtleBot3 world spawn defaults (
x=-2.0,y=-0.5) as launch arguments - adds an extra
ros_gz_bridgesubscription so/cmd_velacceptsgeometry_msgs/Twist - can optionally publish a legacy identity
map -> odomstatic transform withpublish_map_odom_tf:=true - can optionally publish a scan-matching
map -> odomtransform withenable_slam_map_odom_tf:=true - waits 5 seconds for Gazebo topics to appear
- starts
slam_node,path_planner_node, anddwa_planner_nodefromtarget/release
If you want RViz alongside Gazebo:
ENABLE_RVIZ=true ./ros2_nodes/launch/run_gazebo_demo.shIf you need a headless Gazebo server run:
ENABLE_GAZEBO_GUI=false ./ros2_nodes/launch/run_gazebo_demo.shIf you explicitly want the legacy map -> odom alias for RViz:
PUBLISH_MAP_ODOM_TF=true ./ros2_nodes/launch/run_gazebo_demo.shIf you want the corrected SLAM frame:
ENABLE_SLAM_CORRECTED_FRAME=true ./ros2_nodes/launch/run_gazebo_demo.shThat switches the planner stack to /slam_odom, uses map as the global frame, and enables map_odom_tf_broadcaster.py to estimate map -> odom from /slam_odom against the raw odom stream. In corrected mode, slam_node now quality-gates ICP before mixing it into the corrected pose: high-error or outlier matches fall back to raw odom, while borderline matches are attenuated via a reduced blend alpha.
Corrected mode also enables:
/slam_diagnostics(std_msgs/String) with per-scan ICP convergence,icp_error_mean(mean NN distance in meters per point),blend_alpha,gate_reason, and applied correction deltas/slam_ground_truth_status(std_msgs/String) with relative-start Gazebo ground-truth error metrics computed fromgz topic -e -t /world/default/dynamic_pose/info --json-output
The ground-truth monitor defaults to GROUND_TRUTH_ENTITY_NAME=$TURTLEBOT3_MODEL, subtracts the first world pose sample, and compares /ekf_odom plus /slam_odom against that relative ground-truth trajectory. Override GROUND_TRUTH_GZ_POSE_TOPIC or GROUND_TRUTH_ENTITY_NAME if your Gazebo world uses different names.
The RViz layout is stored at navigation_demo.rviz.
Demo video: gazebo_demo.mp4
source /opt/ros/jazzy/setup.bash
export ROS_DOMAIN_ID=42
export TURTLEBOT3_MODEL=burger
export NAV_ODOM_TOPIC=/ekf_odom
export WAYPOINT_NAV_FRAME=relative_start
export WAYPOINT_NAV_WAYPOINTS="0.4,0.0;0.1,0.4"
./ros2_nodes/launch/run_gazebo_mission_demo.shThe mission wrapper uses WAYPOINT_NAV_FRAME=relative_start by default, so the demo waypoints above are interpreted as offsets from the first odom pose observed by waypoint_navigator_node. Its default mission is a verified two-waypoint route, (0.4, 0.0) -> (0.1, 0.4). navigation_demo.launch.py still exposes spawn_x / spawn_y and forwards the upstream TurtleBot3 world defaults (x=-2.0, y=-0.5) for reproducibility.
The mission wrapper reuses navigation_demo.launch.py and enables waypoint_navigator_node with:
enable_ekf_localizer:=trueraw_odom_topic:=/ekf_odomenable_rviz:=trueby default inrun_gazebo_mission_demo.sh(override withENABLE_RVIZ=false)nav_odom_topic:=/ekf_odomnav_global_frame:=odomdwa_goal_threshold:=0.3waypoint_frame:=relative_startWAYPOINT_NAV_WAYPOINTS: semicolon-delimited 2D missionWAYPOINT_NAV_LOOP:trueorfalseWAYPOINT_NAV_GOAL_TOLERANCE: waypoint completion radius
If you want the corrected SLAM frame in the mission demo:
export ENABLE_SLAM_CORRECTED_FRAME=true
./ros2_nodes/launch/run_gazebo_mission_demo.shThat changes the mission stack to:
nav_odom_topic:=/slam_odomnav_global_frame:=mapenable_slam_map_odom_tf:=truebase_tf_odom_topic:=/ekf_odom
waypoint_navigator_node also watches for stalled progress on the active waypoint. When odom does not move by at least WAYPOINT_NAV_STUCK_PROGRESS_DISTANCE within WAYPOINT_NAV_STUCK_TIMEOUT, it transitions into a simple recovery sequence: cancel -> settle -> rotate -> backoff -> reissue goal.
For observability during the mission demo:
/mission_statusreports the current mission state, active waypoint, and recovery phase/mission_markersvisualizes the resolved route, active goal, and a text status overlay in RViz/slam_diagnosticssummarizes ICP health,blend_alpha,gate_reason, and applied SLAM correction per scan/slam_ground_truth_statusreports raw-vs-corrected odom error against Gazebo ground truth in corrected modeodom_tf_broadcaster.pyrepublishesbase_tf_odom_topicas dynamic TF from the raw odom frame to the robot base frame- by default
/map,/planned_path,/goal_pose, and/mission_markersall use the same honest global frame,odom - with
ENABLE_SLAM_CORRECTED_FRAME=true,/map,/planned_path,/goal_pose, and/mission_markersswitch tomap, while map_odom_tf_broadcaster.py supplies dynamicmap -> odom navigation_demo.rviztherefore usesodomas its fixed frame by default
Example looping square:
export WAYPOINT_NAV_FRAME=relative_start
export WAYPOINT_NAV_WAYPOINTS="0.4,0.0;0.0,0.4;0.4,0.0"
export WAYPOINT_NAV_LOOP=true
./ros2_nodes/launch/run_gazebo_mission_demo.shsource /opt/ros/jazzy/setup.bash
export ROS_DOMAIN_ID=89
export TURTLEBOT3_MODEL=burger
export ENABLE_RVIZ=false
export ENABLE_GAZEBO_GUI=false
./ros2_nodes/launch/run_navigation_smoke_test.shThe smoke script wraps run_gazebo_mission_demo.sh and verifies:
waypoint_navigator_nodeexposes/mission_status/map,/planned_path, and/mission_markersshare the selected nav odom frame id- typed
ros2 topic echo /mission_markers visualization_msgs/msg/MarkerArray --oncesucceeds tf2_echo odom base_footprintresolves the dynamic TF mirrored from the selected nav odom topic- the mission finishes with
mission complete,cleared active navigation goal,planned path cleared, andpublished stop command after path clear
The script defaults to WAYPOINT_NAV_FRAME=relative_start and the verified two-waypoint route (0.4, 0.0) -> (0.1, 0.4), but it respects the same mission tuning environment variables as run_gazebo_mission_demo.sh.
To run the smoke in corrected mode:
export ENABLE_SLAM_CORRECTED_FRAME=true
./ros2_nodes/launch/run_navigation_smoke_test.shIn corrected mode, the script additionally verifies tf2_echo map odom.
When ENABLE_SLAM_GROUND_TRUTH_MONITOR=true as well, it also checks that /slam_ground_truth_status reaches status=ok and includes slam_xy_error=.
To verify the corrected-frame ICP gate without Gazebo variance, run the synthetic acceptance smoke:
source /opt/ros/jazzy/setup.bash
ROS_DOMAIN_ID=88 ./ros2_nodes/launch/run_slam_icp_acceptance_test.shThat starts slam_node alone, feeds deterministic synthetic odom plus /scan, and waits for /synthetic_slam_diagnostics to report status=icp_ok, gate_reason=accepted, and blend_applied=true. This is a controlled positive test for clean scan-to-scan matches; it does not replace the Gazebo ground-truth revaluation below.
To re-evaluate corrected-frame accuracy across several pre-defined waypoint missions, run the matrix script. It starts a fresh Gazebo + navigation stack per scenario and writes one metrics row per scenario to CSV and JSONL.
source /opt/ros/jazzy/setup.bash
./ros2_nodes/launch/run_navigation_revaluation_matrix.shBy default, generated reports are ignored by git and written under:
reports/slam_revaluation/navigation_revaluation_<UTC timestamp>.csv
reports/slam_revaluation/navigation_revaluation_<UTC timestamp>.jsonl
Each row records the scenario, exit code, mission completion flag, waypoint string, last ground-truth metrics (raw_xy_error, slam_xy_error, RMSE/max fields, improvement_xy, slam_better_xy), and last SLAM ICP diagnostics (icp_error_mean, blend_alpha, gate_reason, plus status/gate counts observed in the captured smoke output).
Useful overrides:
ROS_DOMAIN_ID_BASE=210 \
SLAM_REVALUATION_REPORT_DIR=/tmp/rust_robotics_slam_reports \
./ros2_nodes/launch/run_navigation_revaluation_matrix.shTo test whether corrected SLAM can recover from intentionally degraded odom input, enable the biased odom profile set:
SLAM_REVALUATION_ODOM_PROFILE_SET=biased \
./ros2_nodes/launch/run_navigation_revaluation_matrix.shThat keeps /ekf_odom as the raw baseline used by /slam_ground_truth_status, but feeds slam_node through /slam_input_odom for biased profiles. The bundled odom profiles are:
raw_realistic: raw EKF odom as SLAM inputodom_xy_scale_1pct:ENABLE_SLAM_INPUT_ODOM_BIAS=true SLAM_INPUT_ODOM_XY_SCALE=1.01odom_yaw_drift_1deg_per_m:ENABLE_SLAM_INPUT_ODOM_BIAS=true SLAM_INPUT_ODOM_YAW_BIAS_PER_METER=0.017453292519943295
To run a small ICP tuning sweep, enable the tuning profile set:
SLAM_REVALUATION_PROFILE_SET=tuning \
./ros2_nodes/launch/run_navigation_revaluation_matrix.shThat runs each scenario with these profiles:
default: built-in ICP gating defaultslow_alpha:SLAM_ICP_BLEND_ALPHA=0.10strict_error:SLAM_ICP_REJECT_ERROR=0.011strict_low_alpha:SLAM_ICP_BLEND_ALPHA=0.10 SLAM_ICP_REJECT_ERROR=0.011
Report rows include profile, profile_description, and profile_env, so tuning runs can be grouped by scenario or by ICP profile.
When odom profiles are enabled, rows also include odom_profile, odom_profile_description, and odom_profile_env.
To summarize a report after a run:
python3 scripts/summarize_slam_revaluation.py \
reports/slam_revaluation/navigation_revaluation_<UTC timestamp>.csvThe summary prints odom/profile-level mission completion counts, slam_better_xy counts, average/min/max improvement_xy, scenario winners, and aggregate ICP gate/status counts. It can also read older reports that do not have odom/profile columns; those rows are treated as odom_profile=raw_realistic and profile=default.
Edit the SCENARIOS=(...) list in that script to add routes; very long or four-plus-hop missions may time out the smoke waiter in simulation. Treat this report as measurement data first. Do not turn improvement_xy into a hard CI threshold until the scenario variance is understood.
ros2 topic pub --once /goal_pose geometry_msgs/msg/PoseStamped \
"{header: {frame_id: 'map'}, pose: {position: {x: 0.5, y: 0.0}, orientation: {w: 1.0}}}"slam_nodereceives/scanand/odom, then publishes/map.ekf_localizer_nodeconverts/odominto/ekf_odomand/ekf_pose.waypoint_navigator_nodepublishes the current mission waypoint on/goal_pose.path_planner_noderebuilds A* from/mapand publishes/planned_path.dwa_planner_nodefollows/planned_pathwhile using/ekf_odomfor state and publishes/cmd_vel.- If waypoint progress stalls,
waypoint_navigator_nodeclears the active goal, publishes a short recovery maneuver on/cmd_vel, and then republishes the same waypoint. - TurtleBot3 moves toward the requested goal in Gazebo.
ros2 topic list
ros2 topic echo /scan --once
ros2 topic echo /odom --once
ros2 topic echo /ekf_odom --once
ros2 topic echo /map --once
ros2 topic echo /planned_path --qos-durability transient_local --once
ros2 topic echo /mission_status --once
ros2 topic echo /cmd_vel geometry_msgs/msg/Twist --oncerobot_radius(default0.4): obstacle inflation radius [m]map_occupancy_threshold(compiled default60): occupied-cell threshold in the SLAM-producedOccupancyGridmap_frame_id(default"map"): output path frame
DWA_GOAL_THRESHOLD(default0.3): terminal tolerance [m]DWA_ROBOT_RADIUS(default0.35): collision radius [m]look_ahead_points(default10): target index offset on global pathpredict_time,dt,max_speed,max_yaw_rate: standard DWA tuning terms
map_resolution(default0.2): occupancy-grid cell size [m]map_width(default300): number of cells in xmap_height(default300): number of cells in yoccupied_log_odds/free_log_odds: Bayesian update weightsicp_max_iterations(from algorithm defaults): ICP optimization limitSLAM_INPUT_ODOM_TOPIC(default"/odom"): odom source used for scan integration and ICP correctionSLAM_OUTPUT_POSE_TOPIC(default"/slam_pose"): corrected pose output topicSLAM_OUTPUT_ODOM_TOPIC(default"/slam_odom"): corrected odom output topicSLAM_USE_CORRECTED_FRAME(defaultfalse): whether to integrate/mapand outputs inSLAM_CORRECTED_FRAME_IDSLAM_CORRECTED_FRAME_ID(default"map"): corrected global frame name used by/map,/slam_pose, and/slam_odomSLAM_ICP_POINT_STRIDE(default1): use every N-th laser hit for scan-to-scan ICP only (occupancy map still uses the full scan). Values2–16thin out points to reduce noise and CPU; if the subsampled count would fall below four points, the node falls back to full resolution for that frame.- ICP blend gating (corrected mode only; unset uses built-in defaults):
SLAM_ICP_BLEND_ALPHA,SLAM_ICP_FULL_WEIGHT_ERROR,SLAM_ICP_REJECT_ERROR,SLAM_ICP_FULL_WEIGHT_ITERATIONS,SLAM_ICP_REJECT_ITERATIONS,SLAM_ICP_FULL_WEIGHT_TRANSLATION_CORRECTION,SLAM_ICP_MAX_TRANSLATION_CORRECTION,SLAM_ICP_FULL_WEIGHT_YAW_CORRECTION,SLAM_ICP_MAX_YAW_CORRECTION,SLAM_ICP_FULL_WEIGHT_TRANSLATION_MOTION,SLAM_ICP_FULL_WEIGHT_YAW_MOTION.SLAM_ICP_FULL_WEIGHT_ERRORandSLAM_ICP_REJECT_ERRORapply to mean nearest-neighbor ICP error [m/point] (not the legacy sum over all points). The built-in mean-error window is full weight at0.007and reject at0.011; on startup with corrected mode,slam_nodelogs all resolved numeric values. - Tuning note (Gazebo TurtleBot3 burger smoke, 2026-04): Headless
run_navigation_revaluation_matrix.shwithSLAM_REVALUATION_PROFILE_SET=tuningshowed the previousSLAM_ICP_REJECT_ERROR=0.014default allowed small attenuated corrections that made corrected SLAM about 4-10 mm worse than raw EKF odom in the bundled scenarios. Tightening the reject threshold to0.011made the tested scenarios raw-equivalent by rejecting those weak matches. Loosening the mean-error gate far above defaults often increasedslam_xy_errorrelative to raw odom—noisy ICP matches were being rejected for a reason.SLAM_ICP_POINT_STRIDE=2in the same scenario also tended to worsenimprovement_xyversus stride1. Use small steps and compareslam_ground_truth_status(improvement_xy,slam_better_xy) across several runs before changing shipped defaults. - Biased odom note (Gazebo TurtleBot3 burger smoke, 2026-04):
SLAM_REVALUATION_ODOM_PROFILE_SET=biasedcompleted 9/9 bundled runs with the current strict ICP gate. Theodom_xy_scale_1pctprofile made corrected SLAM about 1-2 mm worse than raw because ICP was rejected and the biased odom passed through. Theodom_yaw_drift_1deg_per_mprofile stayed raw-equivalent overall and improvedlong_two_legsby about 2 mm. This confirms the bias harness works, but scan-to-scan ICP still needs a controlled acceptance case before claiming raw-better corrected SLAM. - Synthetic acceptance smoke:
run_slam_icp_acceptance_test.shstarts onlyslam_node, publishes deterministic synthetic odom plus scan data, and requiresstatus=icp_ok gate_reason=accepted blend_applied=trueon/synthetic_slam_diagnostics. Use it as the positive-control check that clean ICP matches can still pass the strict gate.
This launch helper is for evaluation only. It subscribes to RAW_ODOM_TOPIC, anchors the first pose, applies drift to relative motion, and republishes the result to SLAM_INPUT_ODOM_TOPIC when ENABLE_SLAM_INPUT_ODOM_BIAS=true. The ground-truth monitor still compares raw /ekf_odom against /slam_odom, so the raw baseline remains honest while only SLAM's odom input is degraded.
ENABLE_SLAM_INPUT_ODOM_BIAS(defaultfalse): start the biased odom helperSLAM_INPUT_ODOM_TOPIC(defaultRAW_ODOM_TOPIC, or/slam_input_odomwhen bias is enabled): topic consumed byslam_nodeBIASED_SLAM_ODOM_TOPIC(default/slam_input_odom): default biased output topic used by the wrappersSLAM_INPUT_ODOM_XY_SCALE(default1.0): scale relative x/y motion from the initial odom anchorSLAM_INPUT_ODOM_YAW_SCALE(default1.0): scale relative yaw from the initial odom anchorSLAM_INPUT_ODOM_YAW_BIAS_RAD(default0.0): constant yaw offset applied to relative motionSLAM_INPUT_ODOM_YAW_BIAS_PER_METER(default0.0): yaw drift added per meter of relative travel
EKF_INPUT_ODOM_TOPIC(default"/odom"): raw odom input topicEKF_OUTPUT_ODOM_TOPIC(default"/ekf_odom"): filtered odom output topicEKF_OUTPUT_POSE_TOPIC(default"/ekf_pose"): filtered pose output topic
RUST_NAV_ODOM_TOPIC(default"/odom"unless launch overrides it): mission odom input topicWAYPOINT_NAV_WAYPOINTS(default"0.5,0.0;0.5,0.5;0.0,0.5"): mission waypoints interpreted in the frame selected byWAYPOINT_NAV_FRAMEWAYPOINT_NAV_FRAME(default"map"):mapfor absolute goals,relative_startfor offsets from the initial odom poseWAYPOINT_NAV_GOAL_TOLERANCE(default0.35): distance threshold for waypoint completion [m]WAYPOINT_NAV_LOOP(defaultfalse): restart the mission after the last waypointWAYPOINT_NAV_STUCK_TIMEOUT(default6.0): no-progress timeout before recovery begins [s]WAYPOINT_NAV_STUCK_PROGRESS_DISTANCE(default0.05): minimum odom motion that resets the stuck timer [m]WAYPOINT_NAV_MAX_RECOVERY_ATTEMPTS(default2): recovery retries allowed per waypoint before the mission failsWAYPOINT_NAV_RECOVERY_SETTLE_SECONDS(default0.5): stop-and-settle time after sendingnavigation_cancel[s]WAYPOINT_NAV_RECOVERY_ROTATE_SECONDS(default1.4): in-place rotation duration [s]WAYPOINT_NAV_RECOVERY_BACKOFF_SECONDS(default0.9): reverse-motion duration [s]WAYPOINT_NAV_RECOVERY_ROTATE_SPEED(default0.7): angular velocity during the rotate phase [rad/s]WAYPOINT_NAV_RECOVERY_BACKOFF_SPEED(default0.08): reverse linear speed magnitude during the backoff phase [m/s]
run_gazebo_demo.shreports missing binaries:- Rebuild all ROS2 nodes in release mode. The launch flow intentionally uses
target/releaseonly.
- Rebuild all ROS2 nodes in release mode. The launch flow intentionally uses
- Topics appear to come from unrelated robots or old simulations:
- Set a dedicated
ROS_DOMAIN_IDbefore launch, for exampleexport ROS_DOMAIN_ID=42.
- Set a dedicated
path_planner_nodelogsplanner is not ready yet; waiting for /map:- Confirm
slam_nodeis running and/mapis being published.
- Confirm
path_planner_nodelogsrobot pose from /odom is not available yet:- Confirm the selected odom topic is publishing (
/odomor/ekf_odomdepending on launch mode).
- Confirm the selected odom topic is publishing (
A* failed for start=... goal=...:- The goal may be outside the current map bounds or inside an occupied cell.
- No robot motion despite
/planned_path:- Check
/cmd_veloutput fromdwa_planner_nodeand verify TurtleBot3 Gazebo is subscribed to/cmd_vel.
- Check
ekf_localizer_nodeis running but/ekf_odomstays silent:- Confirm raw
/odomexists and thatEKF_INPUT_ODOM_TOPICmatches it.
- Confirm raw
- Mission demo does not advance to the next waypoint:
- Check the selected mission odom topic and confirm the robot is entering
WAYPOINT_NAV_GOAL_TOLERANCEaround the active waypoint.
- Check the selected mission odom topic and confirm the robot is entering
- Mission demo repeatedly logs recovery attempts:
- Lower
WAYPOINT_NAV_STUCK_TIMEOUTonly if odom is stable enough; otherwise increase it or reduceWAYPOINT_NAV_STUCK_PROGRESS_DISTANCEso slow-but-valid motion is not classified as stuck.
- Lower
- RViz shows
/mapbut not the robot or path:- Confirm
/map,/planned_path, and the selected nav odom topic share the same frame id and that RViz is using theodomfixed frame from navigation_demo.rviz. If you explicitly enabledPUBLISH_MAP_ODOM_TF=true, also confirm the alias transform is present.
- Confirm