You already have:
-
a saved map: classroom_map.yaml + classroom_map.pgm
-
TF frames (from view_frames):
robot_0/odom → robot_0/base_link → robot_0/laser
We will do map-based navigation using AMCL + Nav2.
Step 0 — Files & assumptions
Assume your saved map is here:
- ~/nav_class_assets/maps/classroom_map_simple.yaml
If not, locate it:
ls ~/nav_class_assets/maps
Make a directory inside nav_claass_assets, called worlds. Move to "worlds" and make a directory "include".
-
cd ~/nav_class_assets -
mkdir worlds -
cd worldsDownload robot.inc.txt and classroom.world and place them in the "worlds" directory. (change robot.inc.txt to robots.inc)
-
mkdir include directory
-
cd includedownload pioneer2dx.inc and place it in the "include" directory. (change pioneer2dx.inc.txt to pioneer2dx.inc)
## Note
1. Remember to modify the following line in `classroom.world`:
```text
include "/home/<your name>/nav_class_ws/install/Stage/share/stage/worlds/map.inc"
- 記得將下載後的
robots.inc.txt另存新檔為robots.inc - 記得將下載後的
pioneer2dx.inc.txt另存新檔為pioneer2dx.inc
Recommended Folder Structure: Based on the description, the recommended folder structure should be:
~/nav_class_assets/
├── maps/
│ ├── classroom_map_simple.yaml
│ └── classroom_map_simple.pgm
└── worlds/
├── classroom.world
├── robots.inc
└── include/
└── pioneer2dx.inc
Step 1 — Launch Stage with standard TF topics
Terminal 1:
source /opt/ros/jazzy/setup.bash
source ~/nav_class_ws/install/setup.bash
ros2 launch stage_ros2 stage.launch.py world:=/home/<your name>/nav_class_assets/worlds/classroom enforce_prefixes:=false
## Problem When Launching `stage_ros2`
When running the following command:
```bash
ros2 launch stage_ros2 stage.launch.py world:=/home/<your name>/nav_class_assets/worlds/classroom enforce_prefixes:=false
I encountered the following problem:
Error: map.inc does not exist in the specified path.
Solution
1. Search for the location of map.inc
First, search inside the ROS 2 workspace installation folder:
find $HOME/nav_class_ws/install -path '*/share/stage/worlds/map.inc' 2> /dev/null
If there is no output, it means the file was not found. In that case, broaden the search scope:
find /usr -path '*/share/stage/worlds/map.inc' 2> /dev/null
2. My Search Result
In my case, the file was found at:
/usr/local/share/stage/worlds/map.inc
3. Copy map.inc to the include Folder
Copy map.inc into the include folder under nav_class_assets/worlds:
cp /usr/local/share/stage/worlds/map.inc \
$HOME/nav_class_assets/worlds/include/map.inc
4. Modify classroom.world
Modify the first line of classroom.world to:
include "include/map.inc"
(Optional but recommended for VMs) throttle scan:
Terminal 2:
source /opt/ros/jazzy/setup.bash
source ~/nav_class_ws/install/setup.bash
ros2 run topic_tools throttle messages /base_scan 10.0 /scan
## Terminal 3: Validation
Open a new terminal and run:
```bash
source /opt/ros/jazzy/setup.bash
source ~/nav_class_ws/install/setup.bash
Check the publishing rate of /base_scan:
ros2 topic hz /base_scan
Check the publishing rate of /scan:
ros2 topic hz /scan
Step 2 — Prepare a Nav2 params file for robot_0 (one-time)
Install Nav2 if you do not have one. (Link)
1) Make sure the map YAML is valid
Run:
ls -lh /home/<your name>/nav_class_assets/maps/classroom_map.yaml
sed -n '1,50p' /home/<your name>/nav_class_assets/maps/classroom_map.yaml
A valid map YAML must look like this (example):
image: classroom_map_simple.pgm
mode: trinary
resolution: 0.05
origin: [-10.0, -7.5, 0.0]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.25
Most common mistake
image: points to a .pgm that doesn’t exist in the same folder.
Check:
grep '^image:' /home/<your name>/nav_class_assets/maps/classroom_map.yaml
ls -lh /home/<your name>/nav_class_assets/maps/
If image: classroom_map_simple.pgm, then that file must exist in the same directory:
/home/<your name>/nav_class_assets/maps/classroom_map.pgm.
✅ If you want zero risk, use the downloaded map you already have (e.g. classroom_map_simple.yaml + .pgm) and set map:=... in the launch command.
2) Make sure Nav2 params file is complete (missing DWB critics)
The error No critics defined for FollowPath happens when your params file does not include the DWB controller configuration block.
✅ Easiest fix: copy Nav2’s default params file and then only modify the few lines you need (frames + scan topic).
Step 2.1 Copy the default Nav2 params
mkdir -p ~/nav_class_assets/nav2
cp /opt/ros/jazzy/share/nav2_bringup/params/nav2_params.yaml \
~/nav_class_assets/nav2/nav2_stage_robot0.yaml
This default file includes the DWB critics list, so the controller will configure correctly.
Step 2.2 Edit only the required lines
Open it by vim or gedit:
vim ~/nav_class_assets/nav2/nav2_stage_robot0.yaml
Now change these keys (search with Ctrl+W in nano):
Another Choice: Step 2.1** 已經複製 `nav2_params.yaml` 至 `nav2`,並改名成 `nav2_stage_robot0.yaml`,我覺得網頁最下面就不要再提供 `nav2_stage_robot0.yaml`。因為按照網站步驟操作時,無法在 `.yaml` file 中搜尋到 `use_sim_time`。這是因為我複製的是 **Jazzy 官方預設的 `nav2_params.yaml`**,它本來就沒有把 `use_sim_time` 寫在 `.yaml` file 文字裡。所以我接下來會依照「我複製檔案過來後」繼續接著做,而不是下載網頁提供的檔案去做。
Edit the Nav2 Parameter File
Open the file:
gedit ~/nav_class_assets/nav2/nav2_stage_robot0.yaml
(A) Add use_sim_time: true Manually
Search the following section names one by one and add:
use_sim_time: true
under each corresponding:
ros__parameters:
Sections to edit:
amcl:bt_navigator:controller_server:planner_server:map_server:local_costmap:global_costmap:
Example Edits
amcl:
ros__parameters:
use_sim_time: true
bt_navigator:
ros__parameters:
use_sim_time: true
controller_server:
ros__parameters:
use_sim_time: true
planner_server:
ros__parameters:
use_sim_time: true
map_server:
ros__parameters:
use_sim_time: true
For local_costmap, the structure is usually nested:
local_costmap:
local_costmap:
ros__parameters:
use_sim_time: true
For global_costmap, the structure is also usually nested:
global_costmap:
global_costmap:
ros__parameters:
use_sim_time: true
(A) use_sim_time
Set use_sim_time: true for all servers (or at least for amcl/map_server/nav2 stack). In a VM sim with /clock, it should be true.
(B) Map file
Find yaml_filename: under map_server: and set it to your downloaded map:
map_server:
ros__parameters:
use_sim_time: true
yaml_filename: /home/lee/nav_class_assets/maps/classroom_map.yaml
## (C) AMCL Scan Topic, Base Frame, and Initial Pose
### Standard TF Version
Search for the `amcl` section and set it like this:
```yaml
amcl:
ros__parameters:
use_sim_time: true
base_frame_id: base_link # or "base_footprint", see the check below
scan_topic: /scan
set_initial_pose: true
initial_pose:
x: 0.0
y: 0.0
yaw: 0.0
How to Decide base_frame_id
In a new terminal, run:
source /opt/ros/jazzy/setup.bash
source ~/nav_class_ws/install/setup.bash
ros2 run tf2_ros tf2_echo odom base_link
If this command keeps printing transforms, then use:
base_frame_id: base_link
If it fails, try:
source /opt/ros/jazzy/setup.bash
source ~/nav_class_ws/install/setup.bash
ros2 run tf2_ros tf2_echo odom base_footprint
If this second command works, then use:
base_frame_id: base_footprint
(D) local_costmap
Search for:
local_costmap:
In Jazzy’s official file, the local costmap already uses:
global_frame: odomrobot_base_frame: base_linkscan :topic: /scan
So for this setup, you normally do not need to change the laser topic here.
Just confirm that it is already /scan, and add:
use_sim_time: true
if you have not already done so in (A).
Also, do not change these frames to robot_0/..., because your current Stage launch uses standard TF topics and your scan source is /base_scan, not /robot_0/base_scan.
The relevant part should look like this:
local_costmap:
local_costmap:
ros__parameters:
use_sim_time: true
global_frame: odom
robot_base_frame: base_link
...
scan:
topic: /scan
(E) global_costmap
Search for:
global_costmap:
In Jazzy’s official file, the global costmap already uses:
global_frame: maprobot_base_frame: base_linkscan:topic: /scan
So again, in this setup you usually only need to confirm the topic and add:
use_sim_time: true
Do not change the frames to robot_0/... unless you later redesign the whole TF and topic naming scheme.
The relevant part should look like this:
global_costmap:
global_costmap:
ros__parameters:
use_sim_time: true
global_frame: map
robot_base_frame: base_link
...
scan:
topic: /scan
(F) Map Server
The content about Map Server can be deleted, because it duplicates the content in (B) Map File.
(G) Lifecycle Manager Navigation
The content about adding lifecycle manager navigation can be deleted.
This is because Nav2’s official launch file already handles these lifecycle managers, so you do not need to modify the .yaml file for this part.
Note
The Quick Verification Checklist (after launch) content should be merged with Step 3.
Otherwise, if you do the quick verification checklist before Step 3, the terminal will not produce the correct output.
The revised version is shown below.
Step 3 — Start Nav2 Localization and Navigation
Terminal 3
source /opt/ros/jazzy/setup.bash
source ~/nav_class_ws/install/setup.bash
Launch Nav2:
ros2 launch nav2_bringup bringup_launch.py \
params_file:=/home/<your name>/nav_class_assets/nav2/nav2_stage_robot0.yaml \
use_sim_time:=True \
use_composition:=False \
autostart:=True
This brings up:
map_serverAMCL- Nav2 stack
Quick Verification Checklist
After Launch
Open a new terminal.
1. Check that the map is published
ros2 topic echo /map --once
2. Check that the controller server is active
The controller server should be active and should not show a critics error.
ros2 node list | grep controller
3. Check that Nav2 publishes cmd_vel
when you send a goal
ros2 topic list | grep cmd_vel
Step 4 — Open RViz and load Nav2 config
Terminal 4:
source /opt/ros/jazzy/setup.bash
rviz2
or
LIBGL_ALWAYS_SOFTWARE=1 rviz2 --ros-args -p use_sim_time:=true
In RViz:
-
Fixed Frame = map
-
Add displays:
- Map topic: /map
- LaserScan topic: /scan
- TF
## Problem When Running RViz2
When running:
```bash
rviz2
or:
LIBGL_ALWAYS_SOFTWARE=1 rviz2 --ros-args -p use_sim_time:=true
I encountered the following problem:
Error: Rendering issue. Some buttons in the RViz window keep flickering.
Solution
Use the following command instead:
QT_QPA_PLATFORM=xcb LIBGL_ALWAYS_SOFTWARE=true rviz2 --ros-args -p use_sim_time:=true
Explanation
This command forces RViz2 to use the xcb Qt platform backend and software rendering.
QT_QPA_PLATFORM=xcb
Forces Qt to use the X11/XCB platform backend.
LIBGL_ALWAYS_SOFTWARE=true
Forces OpenGL to use software rendering instead of hardware acceleration.
rviz2 --ros-args -p use_sim_time:=true
Starts RViz2 and enables simulation time.
Step 5 — Initialize localization (must do)
# Step 5 — Initialize Localization
AMCL needs an initial pose.
Before doing initialization, please open a terminal to bridge `/cmd_vel_nav` to `/cmd_vel`.
```bash
source /opt/ros/jazzy/setup.bash
source ~/nav_class_ws/install/setup.bash
ros2 run topic_tools relay /cmd_vel_nav /cmd_vel
Initialize the Robot Pose in RViz
In RViz:
- Change the view to
TopDownOrthoif possible. This makes it much easier to place the initial pose correctly. - Zoom and pan until you can clearly see the map area where the robot is.
- Look at the Stage window to identify where the robot actually is and which direction it is facing.
- In RViz, click 2D Pose Estimate.
- Click near the robot’s actual position on the map.
- Hold the left mouse button and drag to set the robot’s heading.
- The start point = robot position
- The arrow direction = robot heading.
- Release the mouse button to publish the initial pose.
- Wait a few seconds for AMCL to stabilize.
Expected Result
- The laser scan should align better with the map.
- The robot pose in RViz should become more reasonable and stable.
Note
下圖黃圈中的藍點是 robot base frame。
在 ROS / RViz 的慣例裡:
- 紅色 X 軸為機器人前方
- 綠色 Y 軸為機器人左方
- 藍色 Z 軸為機器人上方
所以在 TopDownOrtho 的俯視畫面中,機器人的朝向就是紅色軸指向的方向。
Quick troubleshooting checklist (most common issues)
## Most Common Issues
---
## 1. Robot Does Not Move
Check `/cmd_vel`:
```bash
ros2 topic echo /cmd_vel --once
If there is no output, the most likely reason is that you are not currently sending a navigation goal.
Please go back to RViz and repeat Step 6.
C) Scan Topic Not Reaching AMCL / Nav2
If you want to check the original laser scan, run:
ros2 topic echo /base_scan --once
If you want to check the throttled laser scan, run:
ros2 topic echo /scan --once
If both topics have data, it means:
- Stage is publishing the original laser scan correctly.
- The throttle node is correctly converting
/base_scanto/scan.
D) Robot Does Not Move
If the robot does not move, check whether Nav2 is publishing velocity commands and whether the relay is forwarding them to the robot.
ros2 topic echo /cmd_vel_nav --once
ros2 topic echo /cmd_vel --once
Case 1:/cmd_vel_nav Has Data and /cmd_vel
Also Has Data
This means:
- Nav2 is generating control commands.
- The relay is forwarding the commands correctly.
- The problem is not in the topic chain.
If the robot still does not move, check:
- Whether Stage is really subscribing to
/cmd_vel - Whether the robot is stuck by obstacles
- Whether the goal is too close
- Whether the local planner is only making small adjustments
Case 2:/cmd_vel_nav Has Data but /cmd_vel
Has No Data
This means:
- Nav2 is generating control commands.
- The relay is not forwarding the commands successfully.
Check:
- Whether the following command is still running:
- Whether the relay terminal was closed
- Whether the topic names are typed correctly
Case 3:/cmd_vel_nav Has No Data and /cmd_vel
Also Has No Data
This means:
- The problem is upstream of Nav2.
- Nav2 is not generating velocity commands at all.
Go back and check:
- Whether AMCL localization is successful
- Whether the goal is valid
- Whether
/scanis normal - Whether the local/global costmaps are normal
- Whether the controller or planner reports any errors
Download maps:
Download them here: (See also the maps in the attachments)