Onboarding
Research Group — Intern Onboarding
Autonomous Mobile Robots Onboarding Plan
Learning route
How to use this page
Follow the sections in order. Start with the big picture so you know what you are building, confirm the tested environment, build the theory, then use the project walkthrough to connect every command to the full TurtleBot4 navigation system.
Start here — the big picture
What you are building
Goal in one sentence: make a simulated TurtleBot4 robot drive itself across a warehouse to a point you click, without hitting anything. Every command below is one piece of that single loop. Keep this table in mind — each step you run brings one of its stages to life.
| # | Stage | What it does in the loop |
|---|---|---|
| 0 | You click a goal in RViz | You pick the point on the map you want the robot to reach. This starts the loop below. |
| 1 | Lidar /scan | The robot "sees" walls and obstacles around it. |
| 2 | Map + AMCL | "Where am I on the map right now?" — localization. |
| 3 | Costmaps | "Which cells are safe to drive through, and which are dangerous?" |
| 4 | Planner | Draws a route from where the robot is to the goal. |
| 5 | Controller | Turns that route into wheel-speed commands. |
| 6 | Robot moves in Gazebo | Motion produces fresh /scan, /odom, and /tf data — which feeds straight back to step 1, and the whole loop repeats many times per second. |
Glossary — plain-language quick reference
| Term | In one sentence |
|---|---|
| ROS 2 | The "operating system" for the robot: a set of programs (nodes) that talk to each other by sending messages on named channels (topics). |
| Node / Topic | A node is one running program (e.g. the planner). A topic is a named channel it publishes to or reads from, like /scan or /cmd_vel. |
Lidar / /scan | A spinning laser sensor that measures distance to walls in every direction. Its readings arrive on the /scan topic. |
| SLAM | Simultaneous Localization And Mapping: driving the robot around to build a map for the first time, when no map exists yet. |
| Map | A saved 2D floor plan (.pgm image + .yaml metadata) that the robot reuses later instead of re-mapping. |
| Localization / AMCL | Figuring out where the robot is on a known map. AMCL is the algorithm Nav2 uses for this. |
| Particle cloud | The green dots in RViz — each is a guess of where the robot might be. They cluster tighter as AMCL becomes confident. |
Odometry / /odom | The robot's own estimate of how far its wheels have turned — a rough "dead-reckoning" position that drifts over time. |
TF / /tf | The system that tracks how all coordinate frames (map, robot, wheels, lidar) relate to each other in space. |
| Costmap | A grid that marks each cell as free, occupied, or "near an obstacle." Nav2 plans routes through low-cost (safe) cells. |
| Nav2 | The navigation stack: the collection of nodes (planner, controller, behavior tree, costmaps) that drives the robot to a goal. |
| Gazebo | The 3D physics simulator that plays the role of the "real world" and the robot's body for this project. |
| Docker / image / container | Docker packages ROS and all its dependencies into an image; a running copy of that image is a container. This keeps setup reproducible. |
| rocker | A helper that lets graphical apps (RViz, Gazebo) inside a Docker container show up on your Ubuntu desktop. |
Reproducible baseline
Tested Setup
A known-good configuration to start from. It is intentionally conservative for students using VMware or another Ubuntu VM.
| Item | Recommended baseline | Reason |
|---|---|---|
| Host | Windows + VMware Workstation, or native Linux | VMware works, but expect slower Gazebo rendering than native Linux. |
| Ubuntu VM | Ubuntu Desktop 26.04 LTS, 64-bit | This stack runs ROS 2 Jazzy in Docker, so ROS does not need to be installed on the host OS. |
| Memory | 8 GB recommended; 6 GB minimum | Gazebo + RViz + Nav2 is heavy. 4 GB is likely to feel unstable or very slow. |
| CPU | 4 cores recommended; 2 cores minimum | Software rendering and simulation both consume CPU. |
| Disk | 60 GB recommended; avoid the VMware 20 GB default | Docker images, Gazebo assets, and ROS packages can quickly fill a 20 GB disk. |
| Graphics | Use software rendering in VMware | If Gazebo opens to a blank/blue scene, launch rocker with LIBGL_ALWAYS_SOFTWARE=1. |
Create ~/tb4_docker/Dockerfile and build a local image named tb4-jazzy. This keeps the ROS 2 Jazzy environment reproducible and avoids installing ROS directly on the Ubuntu host.
FROM osrf/ros:jazzy-desktop-full
RUN apt-get update && apt-get install -y \
ros-jazzy-turtlebot4-simulator \
ros-jazzy-turtlebot4-desktop \
ros-jazzy-nav2-bringup \
ros-jazzy-slam-toolbox \
&& rm -rf /var/lib/apt/lists/*
SHELL ["/bin/bash", "-c"]
CMD ["bash"]mkdir -p ~/tb4_docker
cd ~/tb4_docker
docker build -t tb4-jazzy .If python3-rocker is unavailable in apt, install rocker with pipx. In VMware, pass software rendering as an environment variable and use a standalone -- before the image name so rocker stops parsing --env arguments.
sudo apt install -y pipx
pipx install rocker
pipx ensurepath
source ~/.bashrc
rocker --versionrocker --x11 --user --home --name tb4 --env LIBGL_ALWAYS_SOFTWARE=1 -- tb4-jazzy ...1. Name the container. Adding
--name tb4 means every later command can use docker exec -it tb4 ... instead of looking up a random container ID each time. If you skip this, run docker ps to find the ID and replace tb4 with it.2. Use your own username. Because
--home shares your real home directory, paths inside the container are the same as on the host. This page writes maps to ~/maps (which expands to /home/<your-username>/maps). Run whoami to see your username; do not copy someone else's path literally. Before launching the navigation stack, run these quick checks. If any expected result is missing, fix that layer first instead of continuing to Nav2.
| Check | Command | Expected result |
|---|---|---|
| Disk space | df -h / | Root filesystem has roughly 40 GB free after expanding the VM disk to 60 GB. |
| Docker works | docker run hello-world | The terminal prints Hello from Docker!. |
| Docker user permissions | docker ps | The command runs without sudo and shows the container table header. |
| ROS 2 Jazzy image | docker run --rm osrf/ros:jazzy-desktop-full printenv ROS_DISTRO | The output is jazzy. |
| rocker installed | rocker --version | The terminal prints a rocker version, for example rocker 0.3.0. |
| TurtleBot4 image | docker images | grep tb4-jazzy | The local image list contains tb4-jazzy. |
| ROS packages inside image | docker run --rm tb4-jazzy bash -lc "source /opt/ros/jazzy/setup.bash && ros2 launch turtlebot4_gz_bringup turtlebot4_gz.launch.py --show-args" | The command lists launch arguments such as slam, localization, nav2, and rviz. |
| GUI forwarding | rocker --x11 --user --home osrf/ros:jazzy-desktop-full rviz2 | An RViz window opens on the Ubuntu desktop. |
| Gazebo rendering | rocker --x11 --user --home --env LIBGL_ALWAYS_SOFTWARE=1 -- tb4-jazzy ros2 launch turtlebot4_gz_bringup turtlebot4_gz.launch.py | Gazebo opens and shows the warehouse world instead of a blank or blue scene. |
Reading track
Theoretical Foundation
These papers and official docs provide the concepts behind the navigation stack. They are grouped into phases so that each reading directly supports a concrete part of the system.
Set up the environment
Get something moving before reading anything
Run ROS 2 inside a container instead of installing it on your host. It keeps your system clean, makes switching between distros trivial, and works the same on Linux, macOS (Apple Silicon included), and Windows (WSL2). Install Docker, pull osrf/ros:jazzy-desktop-full, and use rocker for GUI and NVIDIA GPU passthrough. Only fall back to a bare-metal install if Docker truly does not fit your workflow.
ROS 2 Jazzy Jalisco is the current recommended LTS (supported through May 2029) and the default target for Nav2, TurtleBot4, and Gazebo Harmonic — start here. Humble Hawksbill (LTS, EOL May 2027) is acceptable only when extending an existing Humble codebase; new work should target Jazzy. Avoid non-LTS distros (Iron, Kilted) unless you have a specific reason.
The official Nav2 getting started guide. Spin up TurtleBot4 in Gazebo Harmonic and send it to a goal point. If you set up the Docker image above, the whole stack runs in a container — no system-wide install required.
The current Nav2 reference platform from Clearpath Robotics, with native ROS 2 support. Simulates with Gazebo (Harmonic on Jazzy, Fortress on Humble) out of the box — no hardware needed.
TurtleBot4 navigates to a clicked goal point in simulation. Can launch the stack, build a map with teleop, save it, and send a Nav2 goal.
Understand localization
How does the robot know where it is?
The algorithm behind Nav2's AMCL package. Explains how the robot uses particle filters to localize itself on a known map using laser scan data.
Before AMCL can localize, you need a map. SLAM Toolbox is the standard tool in Nav2 for building one from lidar data.
Can explain what AMCL is doing when the robot localizes. Understands the difference between mapping mode and localization mode.
Understand collision avoidance
How does the robot avoid obstacles in real time?
The algorithm behind Nav2's DWB controller. Only 8 pages, very clearly written. Explains how the robot samples velocity commands and picks the one that avoids obstacles while tracking the global path.
Costmaps are how Nav2 represents obstacles for both the global and local planner. Understanding inflation radius and layer configuration is essential for any real deployment.
Can tune costmap inflation radius and explain the effect. Understands the role of the local planner versus the global planner.
Understand the full system
How do all the modules fit together?
The official Nav2 architecture paper by its main author, Steve Macenski. Read this after running Nav2 for a few days — every design decision will make sense in context.
Watch alongside the Marathon 2 paper. The author walks through every component in a live setting, which helps connect the paper to actual code.
Can draw the full Nav2 pipeline from scratch: sensor → costmap → BT navigator → global planner → local controller → cmd_vel.
After the readings
Project Walkthrough: From Setup to Full Nav2 Loop
A step-by-step path from an empty machine to a working Nav2 loop. Each step explains what it does, the commands to run, and the result that proves it worked — so you can see how every piece connects into one navigation system.
Prepare the Ubuntu, Docker, and ROS 2 layer
Get a reproducible container environment ready before anything else
What this step does: Creates a reproducible robotics environment inside a container. The host Ubuntu VM only needs Docker and GUI forwarding; ROS 2 Jazzy, Nav2, Gazebo, and TurtleBot4 run inside Docker.
sudo apt update
sudo apt install -y ca-certificates curl
docker run hello-world
sudo usermod -aG docker $USER
docker pull osrf/ros:jazzy-desktop-fullTiming: docker pull downloads several GB and can take 10–30 minutes on a typical connection. A long pause with no output is normal — do not interrupt it.
Expected result: Hello from Docker! appears, docker ps works without sudo after re-login or a new shell, and docker run --rm osrf/ros:jazzy-desktop-full printenv ROS_DISTRO prints jazzy. Note: the docker ps permission only takes effect after you log out and back in (or open a fresh shell) following usermod.
Install rocker for GUI forwarding
Bridge containerized ROS tools to the VM display
What this step does: Allows graphical applications inside Docker, such as RViz and Gazebo, to appear on the Ubuntu desktop. This is the bridge between containerized ROS and the VM display.
sudo apt install -y pipx
pipx install rocker
pipx ensurepath
source ~/.bashrc
rocker --versionExpected result: The terminal prints a rocker version, for example rocker 0.3.0. If rocker is not found immediately after install, run source ~/.bashrc or open a new terminal.
Build the TurtleBot4 Docker image
Produce the reusable tb4-jazzy image for the whole project
What this step does: Extends the official ROS 2 Jazzy desktop image with TurtleBot4 simulation, Nav2 bringup, and SLAM Toolbox. This produces the reusable tb4-jazzy image used by the rest of the project.
FROM osrf/ros:jazzy-desktop-full
RUN apt-get update && apt-get install -y \
ros-jazzy-turtlebot4-simulator \
ros-jazzy-turtlebot4-desktop \
ros-jazzy-nav2-bringup \
ros-jazzy-slam-toolbox \
&& rm -rf /var/lib/apt/lists/*
SHELL ["/bin/bash", "-c"]
CMD ["bash"]mkdir -p ~/tb4_docker
cd ~/tb4_docker
docker build -t tb4-jazzy .Timing: The first docker build installs many ROS packages and can take 15–40 minutes. Later rebuilds are faster because Docker caches unchanged layers.
Expected result: docker images | grep tb4-jazzy shows tb4-jazzy:latest. The image is the base for TurtleBot4, Gazebo, SLAM, and Nav2 commands.
Start RViz and Gazebo, then fix VM rendering if needed
Confirm the GUI tools open and the warehouse world renders
What this step does: Confirms that graphical ROS tools can open and that the TurtleBot4 warehouse simulation can render. In VMware, Gazebo may load the world but show a blank or blue scene unless software rendering is enabled.
rocker --x11 --user --home osrf/ros:jazzy-desktop-full rviz2rocker --x11 --user --home --name tb4 --env LIBGL_ALWAYS_SOFTWARE=1 -- tb4-jazzy \
ros2 launch turtlebot4_gz_bringup turtlebot4_gz.launch.pyTiming: The first Gazebo launch downloads and caches world/robot models, so it can sit on a seemingly frozen screen for 1–3 minutes (longer with software rendering). This is normal — wait before assuming it crashed.
Expected result: RViz opens, Gazebo shows the warehouse world, and TurtleBot4 appears in the scene. If the robot seems visually slow, verify motion with /odom rather than relying only on animation.
Build a map with SLAM
Stitch a warehouse map from lidar and motion
What this step does: Uses the laser scan topic /scan and robot motion to build a map of the warehouse. SLAM is used when the robot does not already have a known map.
rocker --x11 --user --home --name tb4 --env LIBGL_ALWAYS_SOFTWARE=1 -- tb4-jazzy \
ros2 launch turtlebot4_gz_bringup turtlebot4_gz.launch.py slam:=true rviz:=trueExpected result: In RViz, the map grows as the robot moves. Conceptually, the robot is matching laser observations to its own motion and gradually stitching the warehouse map together.
Save and check the map
Turn the live SLAM map into reusable files
What this step does: Converts the live SLAM map into reusable files so the next run can use localization instead of rebuilding the map from scratch.
--name tb4, you can always address it as tb4 — no need to look up an ID. (If you forgot the name, run docker ps and use the value in the NAMES column.) The --home flag means your Ubuntu home folder is shared with the container, so a file saved to ~/maps inside the container appears in ~/maps on the host too. docker exec -it tb4 bash -lc \
"source /opt/ros/jazzy/setup.bash && mkdir -p ~/maps && \
ros2 run nav2_map_server map_saver_cli -f ~/maps/warehouse_map"
ls -lh ~/maps
cat ~/maps/warehouse_map.yamlExpected result: ~/maps/warehouse_map.pgm stores the map image, and ~/maps/warehouse_map.yaml stores metadata such as resolution, origin, and the image filename.
Start localization and Nav2 with the saved map
Switch from SLAM to map_server + AMCL + Nav2
What this step does: Stops using SLAM as the main mapping process and starts the normal navigation stack: map_server provides the saved map, AMCL localizes the robot, and Nav2 plans and controls navigation.
Ctrl-C in its terminal, or docker rm -f tb4) so the tb4 name is free to reuse here. Replace <your-username> with your real Ubuntu username — run whoami if unsure — because --home maps the container path to /home/<your-username>. rocker --x11 --user --home --env LIBGL_ALWAYS_SOFTWARE=1 --name tb4 -- tb4-jazzy \
ros2 launch turtlebot4_gz_bringup turtlebot4_gz.launch.py \
localization:=true nav2:=true rviz:=true \
map:=/home/<your-username>/maps/warehouse_map.yaml use_sim_time:=true autostart:=truedocker exec -it tb4 bash -lc \
"source /opt/ros/jazzy/setup.bash && ros2 daemon stop || true && ros2 daemon start && \
sleep 3 && ros2 node list | sort | \
grep -E 'map_server|amcl|bt_navigator|planner_server|controller_server|costmap|lifecycle'"Expected result: Use 2D Pose Estimate in RViz to set the robot's starting pose. Global Status should become Ok, and the Navigation 2 panel should show active localization and navigation.
Understand AMCL localization
See how particles converge to the robot's true pose
What this step does: AMCL compares the saved map with the robot's live laser scan to estimate where the robot is. The particle cloud is the set of possible robot poses; /amcl_pose is the final pose estimate.
docker exec -it tb4 bash -lc \
"source /opt/ros/jazzy/setup.bash && ros2 daemon stop || true && ros2 daemon start && \
sleep 5 && ros2 node info /amcl"
docker exec -it tb4 bash -lc \
"source /opt/ros/jazzy/setup.bash && timeout 8 ros2 topic echo /amcl_pose \
geometry_msgs/msg/PoseWithCovarianceStamped"Expected result: /amcl subscribes to /map, /scan, /tf, and /initialpose, and publishes /amcl_pose, /particle_cloud, and /tf. In RViz, Amcl Particle Swarm on /particle_cloud should show green particles.
Inspect global and local costmaps
See how map and sensor data become navigation risk
What this step does: Costmaps translate raw map and sensor data into navigation risk. The global costmap is used for long-range planning. The local costmap is a rolling window around the robot for immediate obstacle avoidance.
docker exec -it tb4 bash -lc \
"source /opt/ros/jazzy/setup.bash && ros2 topic list -t | grep costmap"Expected result: RViz can show /global_costmap/costmap and /local_costmap/costmap. The local costmap should move with the robot; the global costmap covers the larger map.
Send a goal and observe planning plus control
Watch the planner and controller drive the robot
What this step does: When a user clicks Nav2 Goal, the behavior tree starts the navigation task, the planner creates a global route, and the controller converts that route into real-time velocity commands.
# In RViz:
# 1. Click Nav2 Goal.
# 2. Choose a reachable point on free space.
docker exec -it tb4 bash -lc \
"source /opt/ros/jazzy/setup.bash && timeout 10 ros2 topic echo /cmd_vel_smoothed \
geometry_msgs/msg/TwistStamped"Expected result: The Navigation panel shows active feedback, distance remaining changes, and /cmd_vel_smoothed contains non-zero linear.x or angular.z values. If Gazebo animation is delayed, confirm motion with ros2 topic echo /odom --field pose.pose.position.
Test collision avoidance with inflation radius
Trade off safety buffer against path tightness
What this step does: inflation_radius expands obstacle cost outward. Larger values make the robot keep more distance from obstacles; smaller values let it pass closer to obstacles but increase collision risk.
docker exec -it tb4 bash -lc \
"source /opt/ros/jazzy/setup.bash && ros2 daemon stop || true && ros2 daemon start && sleep 3 && \
ros2 param set /global_costmap/global_costmap inflation_layer.inflation_radius 0.90 && \
ros2 param set /local_costmap/local_costmap inflation_layer.inflation_radius 0.90"
docker exec -it tb4 bash -lc \
"source /opt/ros/jazzy/setup.bash && ros2 daemon stop || true && ros2 daemon start && sleep 3 && \
ros2 param set /global_costmap/global_costmap inflation_layer.inflation_radius 0.20 && \
ros2 param set /local_costmap/local_costmap inflation_layer.inflation_radius 0.20"
docker exec -it tb4 bash -lc \
"source /opt/ros/jazzy/setup.bash && ros2 daemon stop || true && ros2 daemon start && sleep 3 && \
ros2 param set /global_costmap/global_costmap inflation_layer.inflation_radius 0.45 && \
ros2 param set /local_costmap/local_costmap inflation_layer.inflation_radius 0.45"Expected result: At 0.90, the purple/pink safety buffer becomes wider and the robot behaves more conservatively. At 0.20, the buffer becomes narrower and paths may pass closer to obstacles. Restore 0.45 after the comparison.
Explain the complete closed loop
Turn a list of commands into a system-level understanding
What this step does: Turns the project from a list of commands into a system-level understanding. The key point is feedback: once the robot moves, /odom, /tf, and /scan update, and the whole navigation stack replans and controls again.
docker exec -it tb4 bash -lc \
"source /opt/ros/jazzy/setup.bash && ros2 node list | sort"
docker exec -it tb4 bash -lc \
"source /opt/ros/jazzy/setup.bash && ros2 topic list -t"Ubuntu VM / Docker / ROS 2 Jazzy
-> tb4-jazzy image
-> Gazebo warehouse simulation
-> TurtleBot4 sensors: /scan, /odom, /tf
-> SLAM or map_server
-> AMCL localization: /amcl_pose, /particle_cloud
-> global and local costmaps
-> BT Navigator
-> Planner Server
-> Controller Server
-> Velocity Smoother and Collision Monitor
-> /cmd_vel_smoothed -> /cmd_vel -> /diffdrive_controller/cmd_vel
-> Robot motion in Gazebo
-> /odom, /tf, /scan feedback
-> system keeps updatingExpected result: A student can explain the project in plain language: the robot sees with lidar, localizes against a map, uses costmaps to decide safe space, plans a route, converts the route into velocity commands, moves, and feeds new sensor data back into the loop.
Beginner blockers
FAQ and Common Fixes
The most common issues beginners hit when setting up this stack, with fixes.
Gazebo opens, but the world is blue or blank.
This usually means the VM's OpenGL rendering is not compatible. Start rocker with --env LIBGL_ALWAYS_SOFTWARE=1 --. It is slower, but much more reliable in VMware.
docker: permission denied ... /var/run/docker.sock.
You ran sudo usermod -aG docker $USER but did not start a fresh session. Group membership only applies to new logins. Log out and back in (or reboot the VM), then confirm with docker ps — it should work without sudo.
cannot open display / Authorization required when RViz or Gazebo starts.
X11 forwarding is not reaching the container. Make sure you launch through rocker with --x11 (not plain docker run), and that you are running inside the Ubuntu desktop session, not an SSH-only shell. As a one-off unblock on the host you can run xhost +local:, then relaunch.
I literally typed <container_id> or <your-username> and it failed.
Those angle-bracket words are placeholders, not literal text. This page starts every container with --name tb4, so use tb4 directly (verify with docker ps). For the map path, replace <your-username> with the output of whoami.
docker: Conflict. The container name "/tb4" is already in use.
A previous container still holds the name. Remove it with docker rm -f tb4 (or stop the earlier terminal with Ctrl-C), then relaunch the rocker command.
The Ubuntu VM runs out of disk space.
20 GB is not enough for ROS, Docker images, Gazebo, and TurtleBot4 packages. Expand the VMware disk to about 60 GB, then grow the Linux partition with growpart and resize2fs.
VMware does not allow disk expansion.
Check whether the VM has snapshots. VMware often disables disk expansion while snapshots exist. Delete or consolidate snapshots, then expand the disk.
python3-rocker cannot be found by apt.
Use pipx instead: sudo apt install -y pipx, pipx install rocker, pipx ensurepath, then reload the shell with source ~/.bashrc.
rocker says the image argument is missing after --env.
Add a standalone -- between the environment variable and the image name: rocker --x11 --user --home --env LIBGL_ALWAYS_SOFTWARE=1 -- tb4-jazzy ....
ros2 is not found in the Ubuntu host terminal.
That is expected in the Docker workflow. ROS 2 lives inside the container. Use docker exec -it tb4 bash -lc "source /opt/ros/jazzy/setup.bash && ros2 ...".
ROS 2 CLI cannot find nodes or topics that should exist.
Restart ROS 2 daemon inside the container: ros2 daemon stop && ros2 daemon start, then retry the node or topic command.
The robot seems not to move even when Nav2 is active.
In VMware with software rendering, Gazebo can be very slow. Verify motion with /odom or /cmd_vel_smoothed instead of relying only on the animation.
Supplementary references
Keep these open throughout. Reach for them when you hit a wall.
The definitive reference when tuning any Nav2 component. Bookmark this and use it constantly.
Dynamic obstacles, custom plugins, multi-robot, GPS navigation, and real hardware deployment.
The RPP controller in Nav2 — a simpler and more robust alternative to DWB for many real-world use cases.
The current recommended global planner in Nav2, replacing the older NavFn. Supports SE2 and hybrid-A* planning for non-holonomic robots.
When stuck, these are the fastest ways to get answers. The Nav2 Discord is especially active, while ROS Answers is now best treated as a legacy archive.