Weekly Robotics logo
Weekly Robotics Beginner-friendly tutorials, every week
Robot Arm Kinematics: How Arms Know Where to Move
Control Systems

Robot Arm Kinematics: How Arms Know Where to Move

Forward and inverse kinematics are the mathematics that let a robot arm reach a target position. This guide explains the concepts without drowning you in equations.

Tell a robot arm to “put the gripper there” and a surprising amount of geometry has to happen first. The arm only knows how to set its joint angles — it has no direct way to move its fingertip to a point in space. Kinematics is the math that bridges that gap, translating between joint angles and the position of the end effector (the gripper or tool at the tip). Get it right and the arm reaches its target; get it wrong and it flails.

Forward vs. Inverse Kinematics

Kinematics runs in two directions, and keeping them straight is half the battle:

  • Forward kinematics (FK): Given the joint angles, where is the end effector? You know each motor’s angle and want the tip’s (x, y) position. This is the easy direction — there’s always exactly one answer, and you just plug angles into equations.
  • Inverse kinematics (IK): Given a target position, what joint angles get there? You know where you want the tip and need to work backward to the angles. This is the hard direction — it can have multiple answers, or none at all.

You use FK to predict where the arm currently points, and IK to command it toward a goal. Real robots lean heavily on IK, because humans think in terms of “go to this point,” not “set joint 2 to 47 degrees.”

Degrees of Freedom

Degrees of freedom (DOF) is the number of independent ways a mechanism can move — usually one per powered joint. A simple desktop arm might have 2 or 3 DOF; a human arm has roughly 7; industrial arms typically have 6, which is the minimum to reach any position and any orientation in 3D space. More DOF means more flexibility but harder math, since extra joints create more ways to reach the same point. We’ll keep things grounded with a flat, 2-link planar arm (2 DOF) you can sketch on paper.

Picture an arm with two straight segments lying flat on a table. The first link has length L1 and pivots at the base by angle θ1 (theta-1). The second link, length L2, is hinged to the end of the first and adds its own angle θ2 relative to the first link.

To find the tip, you walk out link by link. The first joint places the elbow; the second link continues from there, and crucially its direction in the world is θ1 + θ2 (its own bend plus whatever the first link already rotated). Adding the two segments’ horizontal and vertical contributions gives:

x y L1 L2 θ1 θ2 base elbow (x, y) end effector
The 2-link arm: link L1 swings from the base by θ1, link L2 bends at the elbow by θ2, and the two together place the end effector at (x, y).
x = L1·cos(θ1) + L2·cos(θ1 + θ2)
y = L1·sin(θ1) + L2·sin(θ1 + θ2)

The same two relationships, set apart as the key equations of forward kinematics:

x = L1·cos(θ1) + L2·cos(θ1 + θ2)
y = L1·sin(θ1) + L2·sin(θ1 + θ2) FK

That’s the whole of forward kinematics for this arm: feed in the two angles, get the tip’s (x, y). One input, one unambiguous output.

Forward Kinematics in Python

import math

def forward_kinematics(theta1, theta2, L1, L2):
    """Angles in radians, lengths in any consistent unit.
    Returns the (x, y) position of the arm's tip."""
    x = L1 * math.cos(theta1) + L2 * math.cos(theta1 + theta2)
    y = L1 * math.sin(theta1) + L2 * math.sin(theta1 + theta2)
    return x, y

# Example: both links 10 units, first joint at 45°, second at 30°
L1, L2 = 10.0, 10.0
x, y = forward_kinematics(math.radians(45), math.radians(30), L1, L2)
print(f"End effector at ({x:.2f}, {y:.2f})")

Inverse Kinematics: Working Backward

Now flip the problem. You’re handed a target (x, y) and must find θ1 and θ2. For a 2-link arm there’s a neat closed-form solution built on the law of cosines (the geometry rule relating a triangle’s sides to its angles).

The idea, conceptually:

  1. The base, the elbow, and the tip form a triangle with sides L1, L2, and the straight-line distance from base to target. The law of cosines turns that distance into the elbow angle θ2.
  2. With θ2 known, a bit of trigonometry on the same triangle gives the shoulder angle θ1 — partly the angle pointing straight at the target, partly a correction for how the elbow bends.

Two consequences fall out of this geometry, and they’re the heart of why IK is “hard”:

  • Multiple solutions. The elbow can usually bend two ways to reach the same point — elbow-up or elbow-down. Both are mathematically correct; you pick based on obstacles or joint limits.
  • No solution. If the target is farther than L1 + L2 (out of reach) or closer than |L1 − L2| (inside the arm’s dead zone), no angles work at all. Good IK code checks for this instead of returning nonsense.

Inverse Kinematics in Python

import math

def inverse_kinematics(x, y, L1, L2, elbow_up=True):
    """Returns (theta1, theta2) in radians, or None if unreachable."""
    dist_sq = x * x + y * y
    dist = math.sqrt(dist_sq)

    # Reachability check
    if dist > (L1 + L2) or dist < abs(L1 - L2):
        return None  # target is out of reach

    # --- Elbow angle (theta2) via the law of cosines ---
    cos_t2 = (dist_sq - L1 * L1 - L2 * L2) / (2 * L1 * L2)
    cos_t2 = max(-1.0, min(1.0, cos_t2))  # guard against float rounding
    theta2 = math.acos(cos_t2)
    if not elbow_up:
        theta2 = -theta2  # the other valid solution

    # --- Shoulder angle (theta1) ---
    k1 = L1 + L2 * math.cos(theta2)
    k2 = L2 * math.sin(theta2)
    theta1 = math.atan2(y, x) - math.atan2(k2, k1)

    return theta1, theta2

# Reach toward (12, 8) with two 10-unit links
result = inverse_kinematics(12.0, 8.0, 10.0, 10.0)
if result is None:
    print("Target out of reach")
else:
    t1, t2 = result
    print(f"theta1 = {math.degrees(t1):.1f}°, theta2 = {math.degrees(t2):.1f}°")

Flip elbow_up to False and you’ll get the other configuration that reaches the very same point — a hands-on way to see the multiple-solutions idea. You can sanity-check the result by feeding the returned angles back into forward_kinematics(); you should land on the (x, y) you asked for.

Our flat 2-link arm is the friendly case. A real 6-DOF arm moves in full 3D with twists and offsets at every joint, and writing those equations by hand is error-prone. Engineers standardize the description using DH parameters (Denavit–Hartenberg) — a compact, four-number recipe per joint that captures the geometry consistently. From there, you almost never solve IK by hand: libraries do it for you. Common choices include ROS MoveIt (a full motion-planning framework that also handles collisions) and Python’s ikpy for quick inverse-kinematics experiments. The 2-link math here is the mental model; the libraries scale it up.

Common Mistakes

  • Mixing degrees and radians. Python’s math functions expect radians. Convert with math.radians() going in and math.degrees() coming out. This single mistake causes more wrong arm positions than anything else.
  • Forgetting θ2 stacks on θ1. In FK, the second link’s world angle is θ1 + θ2, not just θ2. Drop the θ1 and your tip lands in the wrong place.
  • Not checking reachability. Calling acos() on a value outside [-1, 1] (which happens for unreachable targets) throws an error. Clamp the value and test the distance first, as the code above does.

Next week we leave the arm behind and tackle one of robotics’ grand challenges: SLAM — how a robot builds a map of an unknown space while figuring out its own location within it at the same time.