Section 3: Visualizing Robots
Estimated Reading Time: 9 minutes Bloom's Level: Apply, Analyze Key Learning: RViz visualization, debugging URDF issues
From URDF File to 3D Visualizationβ
You've created URDF files with links, joints, and physics properties. But how do you actually see your robot?
Two tools do this:
- RViz (Visualization): Shows 3D robot structure, TF frames, sensor data
- Gazebo (Simulation): Simulates physics, gravity, collisions
Both read the URDF file and render the robot in 3D.
RViz: Visualizing Robot Structureβ
Launching RViz with Your Robotβ
# Method 1: Using a launch file (easiest)
ros2 launch simple_robot_description display.launch.py
# Method 2: Manual launch
ros2 run robot_state_publisher robot_state_publisher --ros-args -p robot_description:="$(cat simple_robot.urdf)"
ros2 run joint_state_publisher_gui joint_state_publisher_gui
ros2 run rviz2 rviz2
The launch file does three things:
- robot_state_publisher: Publishes TF transforms from URDF
- joint_state_publisher_gui: Let you move joints with sliders
- rviz2: Visualizes everything in 3D
What You'll Seeβ
RViz window
ββ 3D view: Your robot rendered in 3D
ββ Sliders: Move each joint
ββ TF tree: Shows frame hierarchy
ββ Property panel: Configure visualization
Interacting with RVizβ
Navigation:
- Left click + drag: Rotate view
- Middle click + drag: Pan view
- Scroll wheel: Zoom in/out
Joint Control (with GUI):
- Sliders: Move each joint angle
- Watch the robot move in real-time
- Verify that joint axes are correct
Understanding Coordinate Frames (TF)β
What are Frames?β
Every link in your URDF has a coordinate frameβa 3D origin point with axes (X, Y, Z).
Base Link Frame
β (origin)
X (red) β right
Y (green) β forward
Z (blue) β up
ROS 2 maintains the relationship between all frames using TF (Transform Framework).
Visualizing TF in RVizβ
- Launch RViz with your robot
- In left panel: Add β By topic β /tf_static (or /tf)
- In left panel: Check "TF" checkbox
- In the 3D view, you'll see coordinate axes at each joint
What you see:
- Red arrow: X-axis
- Green arrow: Y-axis
- Blue arrow: Z-axis
Each axis pair shows that frame's origin and orientation.
Debugging Frame Issuesβ
If your robot looks wrong:
β Robot is upside down
- Check Z-axis (blue) in base_link. Should point UP, not down.
- Fix: Adjust origin or joint axes
β Robot appears stretched
- Some joint axes might be pointing wrong direction
- Check that revolute joint axes align with visual geometry
β Links overlap weirdly
- Check origin values (xyz) for each link
- Verify parent-child relationships make sense
Visualization Errors and Fixesβ
Error 1: URDF Won't Loadβ
Error: Failed to load URDF
Causes:
- XML syntax error (missing closing tag)
- Missing parent/child link definition
- File path doesn't exist
Fix:
check_urdf simple_robot.urdf
# Shows exactly where the error is
Error 2: Robot Doesn't Appear in RVizβ
RViz empty 3D window (no robot)
Causes:
robot_state_publishernot running- TF frames not being published
- URDF has zero-sized links
Fix:
# Check if robot_state_publisher is running
ros2 topic list | grep tf
# Manually start it
ros2 run robot_state_publisher robot_state_publisher \
--ros-args -p robot_description:="$(cat simple_robot.urdf)"
Error 3: Joint Rotates Wrong Directionβ
Expected: Move elbow up/down
Actual: Moves left/right
Cause: Joint axis points wrong direction
Fix: Check the <axis> tag:
<!-- β Wrong: Rotates side-to-side -->
<axis xyz="1 0 0"/> <!-- X-axis -->
<!-- β
Correct: Rotates up/down -->
<axis xyz="0 1 0"/> <!-- Y-axis -->
Error 4: Collision Geometry Doesn't Match Visualβ
RViz shows a thin box, but collision sphere blocks movement
Cause: Visual and collision geometries are too different
Fix: Keep them similar (or identical):
<visual>
<geometry>
<box size="0.1 0.1 0.4"/> <!-- 1m long box -->
</geometry>
</visual>
<collision>
<geometry>
<box size="0.1 0.1 0.4"/> <!-- Same as visual -->
</geometry>
</collision>
Gazebo: Physics Simulationβ
Launching Gazebo with Your Robotβ
# With Gazebo
ros2 launch simple_robot_description display.launch.py use_gazebo:=true
# Gazebo window opens showing your robot
What Happens in Gazeboβ
- Physics: Gravity pulls robot down
- Collision: Links can't pass through objects
- Motors: Joints can move with simulated forces
- Sensors: Simulated lidar, camera, etc.
Gazebo vs. RVizβ
| Feature | RViz | Gazebo |
|---|---|---|
| Visualization | β Yes | β Yes |
| Physics | β No | β Yes |
| Gravity | β No | β Yes |
| Collisions | β No | β Yes |
| Joint Control | β Via GUI | β Via ROS 2 commands |
| Sensor Simulation | β No | β Yes |
Debugging in Gazeboβ
Robot falls through the ground
- Cause: Bad collision geometry or bad inertia
- Fix: Check
<collision>shapes and<inertia>values
Robot vibrates or explodes
- Cause: Inertia values too small
- Fix: Increase inertia matrix values
Joint moves but doesn't look right
- Cause: Collision geometry blocking movement
- Fix: Simplify collision shapes or increase joint limits
Visualizing the Humanoid Robotβ
The humanoid robot is more complexβlet's understand its structure:
head (sphere)
β (neck_joint)
base_link (torso)
/ \
l_shoulder r_shoulder
β β
l_upper_arm r_upper_arm
β β
l_elbow r_elbow
β β
l_lower_arm r_lower_arm
β β
l_hand r_hand
To visualize the humanoid:
# Set up the robot description
export ROBOT_URDF="humanoid.urdf"
# Launch RViz
ros2 launch humanoid_robot_description display.launch.py
# In RViz:
# 1. Look at the left panel (tree view)
# 2. You should see: world β base_link β head, l_shoulder, r_shoulder, l_hip, r_hip
# 3. Use sliders to move each joint
# 4. Watch how child links move with parents
Common Visualization Issuesβ
Issue: All Links Appear at Originβ
Problem: All robot parts appear stacked at (0, 0, 0)
Cause: Missing <origin> tags in joints
Example of problem:
<joint name="shoulder_joint" type="revolute">
<parent link="torso"/>
<child link="arm"/>
<!-- β Missing: <origin xyz="0.15 0 0" rpy="0 0 0"/> -->
<axis xyz="0 1 0"/>
</joint>
Fix: Add origin to specify where joint connects
<joint name="shoulder_joint" type="revolute">
<parent link="torso"/>
<child link="arm"/>
<!-- β
Specifies arm starts 0.15m to the side -->
<origin xyz="0.15 0 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
Issue: Robot Has Floating/Broken Appearanceβ
Problem: Links look disconnected or floating
Cause: Joint parent/child order is wrong
Fix: Check parent/child links exist:
# List all links
grep '<link name' simple_robot.urdf
# List all joints and check parent/child
grep -A 2 '<joint name' simple_robot.urdf | grep -E 'parent|child'
Debugging Workflowβ
When something looks wrong:
Step 1: Validate URDF syntax
check_urdf humanoid.urdf
# Should output: OK
Step 2: Visualize in RViz
ros2 launch humanoid_robot_description display.launch.py
# Look for missing parts, strange positions, or disconnected links
Step 3: Enable TF visualization
- In RViz: Add β By topic β /tf
- Look at coordinate frame axes
- Check if they align with visual geometry
Step 4: Test in Gazebo
ros2 launch humanoid_robot_description display.launch.py use_gazebo:=true
# Watch if robot falls realistically
# Check if joints move smoothly
Step 5: Check console for error messages
- ROS 2 logs show problems
- Look for warnings about missing frames or bad inertia
Mental Model: From URDF to Screenβ
Here's how URDF becomes a 3D visualization:
simple_robot.urdf (XML file)
β
URDF Parser
β
Robot Model
ββ base_link (2.0 kg box)
ββ link_1 (0.8 kg box)
ββ link_2 (0.3 kg box)
ββ Joints (connect them)
β
TF Transform Tree
base β link_1 β link_2
β
RViz Renderer
β
3D View on Screen
Each step transforms the data until you see the robot.
Try It Yourselfβ
Exercise 1: Visualize simple_robot.urdf
- Build the package:
colcon build --packages-select simple_robot_description - Source install:
source install/setup.bash - Launch:
ros2 launch simple_robot_description display.launch.py - Move the joint slidersβdoes the robot move correctly?
Exercise 2: Find URDF Errors
- Break the URDF: Change a parent link name in a joint
- Run
check_urdf simple_robot.urdfβ what error appears? - Fix it and validate again
Exercise 3: Visualize TF Tree
- In RViz, add TF visualization
- See the coordinate axes at each joint
- Verify that base_link β link_1 β link_2 sequence makes sense
Key Takeawaysβ
β
RViz visualizes robot structure without physics
β
Gazebo simulates with physics (gravity, collisions)
β
TF (transforms) connects all coordinate frames
β
Use check_urdf to validate before visualizing
β
Visual and collision geometries should be similar
β
Joint axes must point the right direction
β
RViz errors usually mean URDF problemsβcheck with check_urdf
Next: Hands-On Exercisesβ
Now it's time to practice! Create, modify, and debug your own URDF files.
π Next: Exercises
Or review:
Section Status: Complete β