Previous
API
When you command a robot arm to move its end effector to a position in 3D space, something needs to figure out what angle each joint should be set to in order to reach that position. This is the inverse kinematics problem, and solving it requires a mathematical model of the arm’s physical structure: how long each link is, how each joint rotates, and what the limits of each joint are.
Most arm modules in the Viam registry include a kinematics file that describes this structure. For standard commercial arms like the UR5e, xArm6, or Viam Arm, the module handles kinematics automatically. You do not need to provide or configure a kinematics file for these arms.
This page is relevant if you are building a custom arm, using a module without a built-in kinematics file, or need to verify that a kinematics model matches your physical arm.
Forward kinematics answers the question: given the current angle of every
joint, where is the end effector? This is a straightforward calculation. You
start at the base, apply each joint angle and link length in sequence, and
arrive at the end effector’s position and orientation in space. Every time you
call GetEndPosition, the arm uses forward kinematics.
Inverse kinematics answers the reverse question: given a target position and
orientation for the end effector, what joint angles will get the arm there? This
is harder because there may be zero, one, or many solutions. The arm might be
able to reach the same point with the elbow up or elbow down, or it might not
be able to reach the point at all. Viam’s motion planner uses inverse kinematics
internally when you call Move.
A robot arm is modeled as a chain of rigid bodies (links) connected by joints:
Every joint has limits that define its range of motion:
Joint limits prevent the motion planner from computing solutions that would require the arm to bend past its physical limits.
Viam supports three formats for describing arm kinematics:
| Format | Description | When to use |
|---|---|---|
| SVA (Spatial Vector Algebra) | Viam’s native JSON format | Preferred for new arms, most detailed |
| DH (Denavit-Hartenberg) | Standard robotics convention, four parameters per joint | When converting from textbook DH parameters |
| URDF | XML format used by ROS and many manufacturers | When the manufacturer provides a URDF file |
Most registry arm modules use SVA internally. You rarely need to write a kinematics file from scratch unless you are building a custom arm.
The tool center point is the reference point on the end effector. By default, it is at the last link’s origin. If you attach a gripper or tool, you may need to define an offset so the TCP reflects the actual point of interaction (for example, the tip of a gripper or the center of a suction cup). This offset is configured through the frame system, not the kinematics file.
Most arm modules in the Viam registry ship with a kinematics file built into
the module. The module loads and applies the kinematics automatically when
viam-server starts.
Verify this by calling GetKinematics:
from viam.components.arm import Arm
arm = Arm.from_robot(machine, "my-arm")
kinematics = await arm.get_kinematics()
print(f"Kinematics format: {kinematics[0]}")
# kinematics[1] contains the raw kinematics data
myArm, err := arm.FromRobot(machine, "my-arm")
if err != nil {
logger.Fatal(err)
}
kinematicsType, kinematicsData, err := myArm.Kinematics(ctx, nil)
if err != nil {
logger.Fatal(err)
}
fmt.Printf("Kinematics format: %v\n", kinematicsType)
fmt.Printf("Kinematics data length: %d bytes\n", len(kinematicsData))
If this call succeeds and returns data, your arm module has kinematics built in. Proceed to step 4 to read joint and end effector data.
If the call fails or returns empty data, the module does not include kinematics. You will need to provide a kinematics file (steps 2-3).
The SVA format describes the arm as a sequence of links and joints in JSON. Here is a simplified example for a two-joint arm:
{
"name": "MyArm",
"kinematic_param_type": "SVA",
"links": [
{
"id": "base_link",
"parent": "world",
"translation": { "x": 0, "y": 0, "z": 162.5 },
"geometry": {
"x": 120,
"y": 120,
"z": 260,
"translation": { "x": 0, "y": 0, "z": 130 }
}
},
{
"id": "upper_arm_link",
"parent": "shoulder_pan_joint",
"translation": { "x": 0, "y": 0, "z": 245.0 }
}
],
"joints": [
{
"id": "shoulder_pan_joint",
"type": "revolute",
"parent": "base_link",
"axis": { "x": 0, "y": 0, "z": 1 },
"min": -360,
"max": 360
},
{
"id": "shoulder_lift_joint",
"type": "revolute",
"parent": "upper_arm_link",
"axis": { "x": 0, "y": 1, "z": 0 },
"min": -360,
"max": 360
}
]
}
Each field:
links[].id: unique name for the linklinks[].parent: the joint or frame this link attaches tolinks[].translation: offset in mm from the parent’s originlinks[].geometry: optional collision shape (uses type, x/y/z for box, r for sphere/capsule, l for capsule length)joints[].id: unique name for the jointjoints[].type: "revolute" (rotates) or "prismatic" (slides)joints[].parent: the link this joint attaches tojoints[].axis: the axis of rotation or translation (unit vector)joints[].min / joints[].max: joint limits in degrees (revolute)
or mm (prismatic)If your arm manufacturer provides a URDF file, you can reference it in your arm module’s configuration. URDF (Unified Robot Description Format) is an XML format that describes links, joints, visual meshes, and collision geometry.
A typical URDF structure:
<robot name="my_arm">
<link name="base_link">
<visual>
<geometry><cylinder length="0.1" radius="0.05"/></geometry>
</visual>
<collision>
<geometry><cylinder length="0.1" radius="0.05"/></geometry>
</collision>
</link>
<joint name="shoulder_pan" type="revolute">
<parent link="base_link"/>
<child link="upper_arm"/>
<axis xyz="0 0 1"/>
<limit lower="-3.14" upper="3.14" velocity="1.0"/>
</joint>
</robot>
To use a URDF file with your arm module, place the file in a location accessible
to viam-server and reference it in the module’s configuration. The exact
configuration depends on the module. Consult the module’s documentation for the
specific attribute name.
The Viam app can render a 3D visualization of your arm based on its kinematic model:
Verify the visualization by comparing it to the physical arm:
If the visualization does not match the physical arm, the kinematics file may have incorrect link lengths, joint axes, or joint limits.
Was this page helpful?
Glad to hear it! If you have any other feedback please let us know:
We're sorry about that. To help us improve, please tell us what we can do better:
Thank you!