ROS 2 Lyrical Luth · Lesson 18 of 86
URDF robot description
Links, joints, joint types, limits and validating a description.
Estimated time · 60–90 min
Learning goals
What you will understand
- Explain urdf robot description in your own words
- Use it in a small robotics example
- Verify the result instead of assuming it worked
Understand the idea first
The mental model
URDF is an XML description of a robot's structure: links (rigid bodies) connected by joints (fixed, revolute, continuous, prismatic). The tree has exactly one root link. Joints define the parent, child, origin, axis and limits.
Check a file with check_urdf and view the tree with urdf_to_graphviz. A URDF alone does not move anything: robot_state_publisher turns it plus joint values into TF frames. Use metres, kilograms and radians throughout.
Guided lesson
Work through these steps
- 1.
Source the ROS 2 Lyrical environment in a fresh terminal.
- 2.
Read the urdf robot description example and identify what each line does.
- 3.
Build only the affected package, source the workspace overlay, and run the example.
- 4.
Inspect the result from a second terminal with the ros2 CLI or RViz2 and compare it with the expected result.
Worked example
Read it before you run it
<robot name="mini_arm">
<!-- Root element naming the robot. -->
<link name="base_link"/>
<!-- The fixed base of the robot. -->
<link name="upper_arm"/>
<!-- A moving link. -->
<joint name="shoulder" type="revolute">
<!-- A joint that rotates within limits. -->
<parent link="base_link"/>
<!-- Connected to the base... -->
<child link="upper_arm"/>
<!-- ...and moves the upper arm. -->
<origin xyz="0 0 0.1" rpy="0 0 0"/>
<!-- Joint sits 10 cm above the base with no rotation offset. -->
<axis xyz="0 0 1"/>
<!-- Rotate about the Z axis. -->
<limit lower="-1.57" upper="1.57" effort="10" velocity="1.0"/>
<!-- Range in rad, maximum torque in N·m, speed in rad/s. -->
</joint>
<!-- End of the joint. -->
</robot>
<!-- End of the robot. -->What the example is doing
- 1.The ros2 commands query the running graph; they do not prove that a node's internal behavior is correct.
- 2.Build from the workspace root, then source install/setup.bash so the shell can discover the new package.
- 3.Use a second sourced terminal to inspect nodes and interfaces while the example runs.
Watch it run · Robot arm
See what this code does
The terminal types this lesson's practice solution and runs it. The scene shows the kind of robot behaviour that code drives. It plays by itself and loops.
Demo for URDF robot description. Expected result: robot name is: mini_arm
Practice code
Now type it yourself
Copy the starter into your ROS 2 package, replace every TODO, then build with colcon build and run it from a sourced terminal.
<robot name="mini_arm">
<link name="base_link"/>
<link name="upper_arm"/>
<link name="forearm"/>
<joint name="shoulder" type="revolute">
<parent link="base_link"/>
<child link="upper_arm"/>
<axis xyz="0 0 1"/>
<limit lower="-1.57" upper="1.57" effort="10" velocity="1.0"/>
</joint>
<!-- TODO: add a revolute joint "elbow" from upper_arm to forearm about the Y axis with the same limits -->
</robot>Expected output
robot name is: mini_armStuck? Show the full solution (try it yourself first)
<robot name="mini_arm">
<link name="base_link"/>
<link name="upper_arm"/>
<link name="forearm"/>
<joint name="shoulder" type="revolute">
<parent link="base_link"/>
<child link="upper_arm"/>
<axis xyz="0 0 1"/>
<limit lower="-1.57" upper="1.57" effort="10" velocity="1.0"/>
</joint>
<joint name="elbow" type="revolute">
<parent link="upper_arm"/>
<child link="forearm"/>
<axis xyz="0 1 0"/>
<limit lower="-1.57" upper="1.57" effort="10" velocity="1.0"/>
</joint>
</robot>Expected result
How you know it worked
- ROS_DISTRO is lyrical in every terminal used for the exercise.
- The complete package from the exercise builds and the expected graph entity appears in a second terminal.
Practical exercise
Apply the lesson
Write a URDF for a two-link arm with shoulder and elbow joints, validate it with check_urdf, generate the graph with urdf_to_graphviz, and view it in RViz2.
Before you continue
- ROS_DISTRO reports lyrical in every terminal you used
- The example builds and runs without errors
- You checked the result with a ros2 command, RViz2 or a test, not just by reading the code
If something goes wrong
Source /opt/ros/lyrical/setup.bash, build from the workspace root, then source install/setup.bash in that terminal.
Confirm both terminals use Lyrical, the same ROS_DOMAIN_ID, and compatible network/discovery settings.