Robot descriptions: URDF, the Project 4 input format¶
A Project 4 robot description is the text of a real, flat URDF file: an XML document whose
root element is <robot>. It reaches student code as one JSON string, the value of the
robot_description parameter, set with /param_server/set_param and read by your IK node
with /param_server/get_param (spec/IK_API.md). This is the same format as Project 3: your
Project 3 parser can be reused unchanged. Students parse the
XML themselves. Each starter ships a course-supplied XML parser as vendored source, which a
student MAY use or replace (see starter/README.md). XML plumbing is not the learning objective;
interpreting URDF is.
A description is the URDF exactly as a robot ships it, unmodified. Real robot URDFs, such as the PR2's, are valid descriptions, so the real-world XML variation listed below is required, not optional.
Where an input has no sensible meaning (duplicate names, a zero axis, nan), it is UNSPECIFIED:
you may do anything except crash or hang.
Keywords. MUST and MUST NOT are requirements; MAY is permitted but optional. An input marked UNSPECIFIED is one your runtime will not receive: you may do anything with it except crash or hang. OUT OF SCOPE is not part of the project at all.
Example¶
<?xml version="1.0"?>
<robot name="two_link_arm" xmlns:xacro="http://www.ros.org/wiki/xacro">
<!-- links may come before or after the joints that use them -->
<link name="base_link"/>
<joint name="shoulder" type="revolute">
<parent link="base_link"/>
<child link="upper_arm"/>
<origin xyz="0 0 0.1" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-3.14" upper="3.14" effort="10" velocity="1"/>
</joint>
<link name="upper_arm">
<visual><geometry><cylinder radius="0.05" length="0.5"/></geometry></visual>
</link>
<joint name="elbow_mount" type="fixed">
<parent link="upper_arm"/>
<child link="forearm"/>
<origin xyz="0.5 0 0" rpy="0 1.5707963267948966 0"/>
</joint>
<link name="forearm"/>
<gazebo reference="forearm"><material>Gazebo/Grey</material></gazebo>
</robot>
What is read¶
Only these parts of the document have meaning. Everything else MUST be ignored.
| Element / attribute | Required | Meaning |
|---|---|---|
<robot name="..."> |
root element MUST be robot |
name MAY be absent; it defaults to "robot". No required output depends on it. |
<link name="..."> |
at least one | A direct child of <robot>. A <link> with no name attribute MUST be rejected. |
<link> → first <visual> |
MAY be absent | Read for display only (see "Visual geometry"). It does not affect FK, but an invalid first <visual> MUST be rejected. |
<joint name="..." type="..."> |
MAY be none | A direct child of <robot>. A joint with no name or no type attribute MUST be rejected. |
<joint> → <parent link="..."/>, <child link="..."/> |
MUST | Direct children of the joint. link MUST name a link of the robot. |
<joint> → <origin xyz="x y z" rpy="r p y"/> |
MAY be absent | A missing <origin>, xyz, or rpy means all zeros, as in URDF. |
<joint> → <axis xyz="x y z"/> |
MAY be absent | Defaults to 1 0 0, as in URDF, and so does an <axis> with no xyz. Ignored for fixed joints, but a malformed xyz is still rejected. |
<joint> → <limit lower="..." upper="..."/> |
MUST for revolute and prismatic |
A revolute or prismatic joint with no <limit> element MUST be rejected. A missing lower or upper means 0; a present one MUST be a number. FK and the Jacobian MUST NOT clamp a requested configuration to it; only /ik/solve_robot results must lie within it (spec/IK_API.md). For continuous and fixed joints <limit> is ignored entirely, even if malformed. A lower greater than upper is UNSPECIFIED. |
"Direct child" is exact. <link> and <joint> elements nested anywhere else are not links
or joints of the robot, and MUST be ignored. Real URDFs contain such nested elements: PR2 has
hollow <joint name="..."> elements inside <gazebo> and <transmission> blocks.
UNSPECIFIED: a <joint> with more than one <parent>, <child>, <origin>, <axis> or
<limit>; empty or whitespace-only names; namespaced elements such as <xacro:link>.
Numbers¶
xyz, rpy, axis xyz, and the vector attributes of visual geometry each hold exactly three
numbers, separated by XML whitespace (space, tab, CR, LF) of any length, with optional leading
and trailing whitespace. A present attribute with any other count ("1 2", "1 2 3 4", "",
"0,0,1") MUST be rejected.
A number MUST be accepted if it is a finite decimal literal matching
[+-]?([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?, for example 1, -0.5, .25, 3.,
+1, 1.5e-1, -2E+0. A literal that underflows (1e-400) is 0. A token that is plainly not
a number (two, x, 1_000, 0,5) MUST be rejected. UNSPECIFIED: hexadecimal floats,
nan, inf, infinity, and literals that overflow (1e999). Check each token against the
pattern above before converting it: Python's float() also accepts 1_000, inf and nan, and
C's strtod accepts hexadecimal floats.
Visual geometry¶
Only a link's first <visual> is read. Later ones have no effect; whether an invalid later
<visual> is rejected is UNSPECIFIED. If present, the first one MUST contain a <geometry>
with one of these shapes, or the description MUST be rejected:
The shape is the first child element of <geometry>:
| Shape | Required attributes |
|---|---|
<box size="x y z"/> |
size, three numbers |
<cylinder radius="r" length="l"/> |
radius and length, numbers |
<sphere radius="r"/> |
radius, a number |
<mesh filename="..." scale="x y z"/> |
filename; scale is optional, three numbers if present |
A <visual> MAY carry an <origin> (same rules as a joint's) and a <material> (ignored by
the graded runtime). Any other shape (for example <capsule>) or an empty <geometry> MUST be
rejected. Visual geometry never changes kinematics; it exists so a viewer can draw the robot.
<collision> and <inertial> are ignored in Project 4.
XML features a description MAY use (and a conforming runtime MUST accept)¶
The description is well-formed XML 1.0 in UTF-8. Real URDFs use all of the following:
- leading whitespace before the first
<; - an XML declaration (
<?xml version="1.0" encoding="UTF-8"?>), and processing instructions; - comments anywhere, including comments that contain markup such as
<joint name="x">; - namespace declarations on
<robot>, such asxmlns:xacro="..."or a defaultxmlns="...". A flat URDF that merely carries them MUST load. (With a default namespace, Python's ElementTree reports tags as{uri}link: compare local names.) Unexpanded xacro is OUT OF SCOPE; - single- or double-quoted attribute values;
- the predefined entities (
& < > " ') and numeric character references ( ,A) in attribute values and text. Names are compared after this decoding; - CDATA sections (typically inside
<gazebo>); - self-closing (
<origin .../>) and paired (<origin ...></origin>) tags; - CRLF line endings, and any whitespace between elements and inside numeric attributes;
- unknown elements and attributes, at any depth:
<gazebo>,<transmission>,<material>,<mimic>,<safety_controller>,<calibration>,<dynamics>,<collision>,<inertial>, and so on; - links with no
<visual>, and joints that appear before the links they reference.
UNSPECIFIED: a leading byte-order mark (U+FEFF), any <!DOCTYPE>, an undeclared namespace
prefix, an entity reference other than the predefined ones, and leading whitespace before an XML
declaration (not well-formed XML 1.0: the declaration must come first). Text whose first non-whitespace character is { (the course's JSON robot format, JRDF) is
OUT OF SCOPE.
Size¶
A description MAY be large. Real robots ship URDFs of 100 KB and more (PR2 is 103,573
bytes). A runtime MUST accept a description whose set_param request line, and the
get_param reply that carries it back, are up to 1 MiB each. This includes the student's own
gateway and every node-to-node connection.
Kinematic semantics (URDF conventions, restated)¶
rpyis fixed-axis roll-pitch-yaw:R = Rz(yaw) · Ry(pitch) · Rx(roll). Equivalently, the frame is rotated about the fixed parent X axis by roll, then fixed Y by pitch, then fixed Z by yaw.- Joint local transform is
T_joint(q) = T_origin · T_motion(q), whereT_origin = Trans(xyz) · Rot(rpy)is expressed in the parent link's frame. T_motion(q)depends on the joint type:revoluteandcontinuous: rotation byqradians about the joint axis normalized to unit length, expressed in the joint frame (afterT_origin). A revolute axis MAY be non-unit, such as0 0 2or1 1 0.prismatic: translation byq · axisin the joint frame, with the axis as written, not normalized. An axis of2 0 0atq = 0.7moves1.4m. (Real URDFs use unit axes, where the normalized and unnormalized readings agree.)fixed: identity.- The child link's frame is the joint frame after motion, so a link's pose relative to its
parent link is exactly
T_joint(q). - The root link is the unique link that is no joint's child. The description does not name
the root; implementations MUST determine it. It is often not the first
<link>in the document. <mimic>is ignored: a mimic joint is driven like any other joint, by its own name.
Validity (what MUST be rejected)¶
What the IK services do while the newest description is invalid is given in spec/IK_API.md,
"Reading the robot". A description MUST be rejected if
any of the following holds:
- The parameter value is not a JSON string, is empty or whitespace-only, or is not
well-formed XML; or the root element is not
<robot>. <robot>has no direct-child<link>.- A link has no
nameattribute. A joint has nonameortypeattribute, or no<parent>or<child>element with alinkattribute. - A joint's
typeis not exactly one ofrevolute,continuous,prismatic, orfixed. This covers URDF'sfloatingandplanar(OUT OF SCOPE), unknown types, and case variants such asRevolute. - A joint's parent or child is not a link of the robot.
- The robot does not have exactly one root: every link is some joint's child (no root), or two or more links are no joint's child.
- A
revoluteorprismaticjoint has no<limit>, or a presentlower/upperis not a number. - A present vector attribute (
origin xyz,origin rpy,axis xyz, visual vectors) does not hold exactly 3 numbers, or a number attribute that is read is not a number (see "Numbers"). The number attributes read arelimit lowerandupper(revolute and prismatic joints),cylinder radiusandlength, andsphere radius; others (such aseffort) are ignored. - A link's first
<visual>is invalid (see "Visual geometry").
UNSPECIFIED, because they have no well-defined FK (your runtime MUST NOT crash or hang on them,
and may accept or reject them): duplicate link or
joint names; a joint whose parent equals its child; a link that is the child of two joints; a
cycle (reachable from the root or not) when exactly one root exists; a zero-length or non-finite
axis on a revolute, continuous or prismatic joint; non-finite numbers. A fixed joint's
axis is ignored, so axis xyz="0 0 0" on a fixed joint (Fetch and H2D ship it) MUST be
accepted.
The error text is UNSPECIFIED. A description that passes every check above and uses no UNSPECIFIED input MUST be accepted.
OUT OF SCOPE: xacro expansion, mimic behavior, floating and planar joints, the content
of <gazebo> and <transmission>, mesh loading and package:// resolution, JRDF, and
multiple robots at once.