
Autonomous Maze Navigation
TurtleBot 4 · ROS 2 · LiDAR · Team MERRIS
ENAE450 is the Robotics Programming course at the University of Maryland, taught on the TurtleBot 4 platform using ROS 2. The final competition required teams to build a fully autonomous navigation stack capable of guiding the robot from a Start Zone to a Finish Zone in a physical box-built maze — completing the route, spinning 180 degrees, and stopping without any human intervention. Team MERRIS competed in two formats: a pre-mapped race with a 3-minute teleoperation window to scout and save a map beforehand, and a novel environment race where the robot navigated completely blind with no prior map and no manual assistance once running.
The two race formats demanded fundamentally different software approaches. The pre-mapped race used a classical localization and planning stack: SLAM Toolbox built a map during the teleoperation window, which was then used by AMCL for localization and Nav2 for path planning against a goal pose at the maze exit. The novel environment race used a custom left-hand wall-following finite state machine running at 20 Hz, reading LiDAR sectors through a sliding-window moving-average filter and publishing velocity commands directly to the robot base. Both stacks ran on a distributed architecture split between the TurtleBot 4's onboard Raspberry Pi 4 and a host PC communicating over Fast DDS on the RAL lab network, sharing a single ROS 2 graph with the robot.
The competition results were mixed — the pre-mapped stack consistently planned a valid path and navigated most of the maze, but a costmap inflation misconfiguration caused the robot to stop just before the exit in the best run. The wall-follower reached the end of the maze in its best exploration attempt but made contact with the exit wall and failed to complete the final 180-degree spin. The failure modes were documented, analyzed through ROS bag data extraction and odometry trajectory plotting, and used to identify concrete improvements for a hypothetical next iteration.
System Architecture
ROS 2 stack distributed across two machines — onboard Raspberry Pi 4 for low-level control, host PC for navigation.
Hardware
TurtleBot 4
The TurtleBot 4 is a differential-drive mobile robot built on a Roomba Create 3 base. The onboard Raspberry Pi 4 handled low-level ROS 2 communication, interfacing with the Create 3 for wheel odometry and velocity commands on /cmd_vel. The primary sensor was an RPLiDAR providing 2D laser scans used for both mapping during the teleoperation window and real-time obstacle detection during autonomous runs. Heavier navigation processing — AMCL, Nav2, the goal publisher — was offloaded to a host PC connected over Fast DDS on the RAL lab network, sharing a single ROS 2 graph with the robot.
ROS 2 Topics
Key Data Flows
Four core topics connected all components of the navigation stack. /scan carried raw LiDAR readings from the RPLiDAR into both the SLAM mapper and the wall-follower's LiDAR processing pipeline. /odom provided wheel odometry for localization and was recorded in MCAP ROS bag format for post-run trajectory analysis. /tf carried coordinate frame transforms tying together the robot's sensor frame, base frame, and map frame. /cmd_vel carried velocity commands from whichever navigation system was active — Nav2's path executor in the pre-mapped race, or the wall-follower's direct output in the novel environment race.
Sensor Processing
LiDAR Sector Parsing & Filtering
Raw /scan messages contain a flat array of range readings indexed by angle — hundreds of values per frame at competition frequency. Rather than processing every ray at control-loop speed, the scan was partitioned into named sectors (front, left, right, back) using angular thresholds computed from the message's angle_min and angle_increment fields. Invalid readings (inf, NaN, out-of-range) were rejected before routing. Each sector's readings were fed into a SensorMA sliding-window moving-average filter — maintaining a running sum and a circular sample buffer — to smooth per-sector distances and suppress single-ray noise before any state machine decision was made. This architecture decoupled sensor noise handling from control logic, making the wall-follower more robust to spurious LiDAR returns near maze corners.
SensorMA Filter
Circular sample buffer — maintains a fixed window of readings, oldest value overwritten each update
Running sum — O(1) update: add new reading, subtract oldest, no full-array recomputation
Per-sector averaging — each named sector (front/left/right/back) maintains its own independent SensorMA instance
Noise rejection — invalid rays (inf/NaN/out-of-range) discarded before entering any filter
Results & Analysis
* Time taken from rosbag, not necessarily indicative of actual runtime
Pre-Mapped Failure
Costmap Inflation Misconfiguration
The Nav2 costmap inflation radius — which determines how much clearance the planner maintains from walls — was tuned against the test environment, not the competition maze. In the real maze, this caused the robot to treat the exit corridor as impassable and stop just before finishing. The fix was known (reduce the inflation radius further), but time constraints prevented retuning against the actual maze geometry before the competition run. An additional issue was a recurring action server error on startup that required a full WSL restart to resolve, costing preparation time.
Novel Environment Failure
3-Corner Looping Edge Case
The wall-follower's left-hand algorithm encountered a consistent failure mode when the robot entered a triangular region formed by three maze corners. The sequence: the robot detects no left wall and turns left; it crawls forward until a wall is found on the left; it begins driving, but due to imperfect turn accuracy is angled slightly away from the wall; the slight angle causes it to detect no left wall again and begin another left turn; the turn logic requires clear space ahead, so the robot turns approximately 180° and reverses course. This was a structural edge case in the algorithm — only a junction-tracking approach, which explicitly records decision points, would reliably handle it.
All race and exploration trajectories were reconstructed by extracting /odom position data from MCAP ROS 2 bag recordings using the rosbags library, writing to CSV, and plotting with Matplotlib. The top-down trajectory plots provided ground truth for diagnosing failure modes — confirming where the robot reversed, where it looped, and how far into the maze it reached in each attempt.
Retrospective
What worked, what didn't, and what we'd change.
01
What Worked
Building a LiDAR diagnostic node early in development paid off throughout tuning. A simple node printing live sector distances at 20 Hz made it straightforward to verify which direction the robot considered "front," how far it thought it was from a wall, and whether the sector-routing logic was correct — critical information that would otherwise require interpreting RViz visualizations under competition pressure. Nav2's path visualization in RViz also helped significantly: even when the planned path was wrong, being able to see what the planner was thinking made diagnosis fast.
02
What Didn't Work
The costmap inflation parameter caused problems that were not fully resolved in time. The value that worked in the test environment stopped the robot at the competition exit. A recurring action server startup error also required full WSL restarts to fix, which cost valuable time during the competition. The wall-follower's 3-corner looping failure was a structural algorithm limitation — the left-hand rule cannot handle multiply-connected mazes or topology edge cases that create oscillating turn sequences.
03
What We'd Change
Three concrete improvements: first, tune the costmap inflation radius against the real maze geometry rather than the test setup, ideally through a parameter file adjustable on competition day without touching source code. Second, replace pure wall-following with a junction-tracking algorithm that explicitly records and marks decision points — this handles more complex topologies and would eliminate the looping failure. Third, consolidate the startup sequence into a single launch file that brings up localization, Nav2, and the goal publisher in the correct order automatically, removing the manual sequencing that caused the action server issues.
Stack
Documents & Media
Final competition report and video recordings from the RAL laboratory runs.
Competition Report
ENAE450 Final Report — Team MERRIS
Full report: hardware platform, distributed ROS 2 architecture, pre-mapped and wall-following navigation implementations, race results, odometry trajectory analysis, and retrospective.
Video Recording
Lab Recording
Robot Mapping Demo
TurtleBot 4 mapping the competition maze during the teleoperation window — SLAM Toolbox building the occupancy grid in real time.
Video Recording
Lab Recording
Novel Environment Run
Wall-following FSM navigating the maze completely blind — no prior map, no human intervention once running.