AnyLearn
All lessons
Roboticsintermediate

Inverse Kinematics: From Pose to Joint Angles

Flip the FK problem: given a desired end-effector pose, find the joint angles that achieve it. Master analytical closed-form IK for the 2-link arm, the elbow-up/elbow-down duality, atan2 arithmetic, and the basics of numerical IK via the Jacobian.

Not signed in โ€” your progress and quiz score won't be saved.
Lesson progress1 / 9

The inverse kinematics problem

Inverse kinematics (IK) is the reverse of FK: given a desired end-effector pose TdesiredT_{desired}, find joint angles qq such that T0EE(q)=TdesiredT_0^{EE}(q) = T_{desired}. IK is fundamentally harder than FK:

  • Multiple solutions โ€” the same pose may be reachable by several joint configurations (elbow-up vs. elbow-down).
  • No solution โ€” the target may be outside the robot's workspace.
  • Infinite solutions โ€” a redundant robot (n>6n > 6 DOF) has extra freedom; infinitely many qq reach the same pose.

Two broad approaches: analytical (closed-form, fast, exact, but arm-specific) and numerical (iterative, general, but slower and convergence-sensitive). Industrial robots almost always use analytical IK in the inner loop.

Full lesson text

All 9 steps on one page โ€” for reading, reference, and search.

Show

1. The inverse kinematics problem

Inverse kinematics (IK) is the reverse of FK: given a desired end-effector pose TdesiredT_{desired}, find joint angles qq such that T0EE(q)=TdesiredT_0^{EE}(q) = T_{desired}. IK is fundamentally harder than FK:

  • Multiple solutions โ€” the same pose may be reachable by several joint configurations (elbow-up vs. elbow-down).
  • No solution โ€” the target may be outside the robot's workspace.
  • Infinite solutions โ€” a redundant robot (n>6n > 6 DOF) has extra freedom; infinitely many qq reach the same pose.

Two broad approaches: analytical (closed-form, fast, exact, but arm-specific) and numerical (iterative, general, but slower and convergence-sensitive). Industrial robots almost always use analytical IK in the inner loop.

2. Analytical IK for the 2-link planar arm

For a 2-link arm with link lengths l1,l2l_1, l_2, target position (x,y)(x, y) (ignoring orientation), FK gives:

x=l1c1+l2c12,y=l1s1+l2s12x = l_1 c_1 + l_2 c_{12}, \qquad y = l_1 s_1 + l_2 s_{12}

where c12=cosโก(q1+q2)c_{12} = \cos(q_1+q_2), s12=sinโก(q1+q2)s_{12} = \sin(q_1+q_2). Square and add:

x2+y2=l12+l22+2l1l2cosโกq2x^2 + y^2 = l_1^2 + l_2^2 + 2 l_1 l_2 \cos q_2

Solve for q2q_2:

cosโกq2=x2+y2โˆ’l12โˆ’l222l1l2\cos q_2 = \frac{x^2 + y^2 - l_1^2 - l_2^2}{2 l_1 l_2}

If the right-hand side has magnitude greater than 1, the target is unreachable. Otherwise q2=ยฑarccosโก(โ‹…)q_2 = \pm \arccos(\cdot) โ€” two solutions, giving the two elbow configurations.

3. Elbow-up and elbow-down solutions

The sign of q2q_2 selects the configuration:

  • q2>0q_2 > 0: elbow-up (joint 2 bends counter-clockwise, arm curves upward)
  • q2<0q_2 < 0: elbow-down (joint 2 bends clockwise, arm curves downward)

Both configurations reach the same (x,y)(x, y). In practice, the robot controller picks one based on:

  1. Joint limits (one solution may violate them).
  2. Shortest-path continuity (stay near the current configuration).
  3. Obstacle avoidance.

With q2q_2 known, q1q_1 follows from the FK equations:

q1=atan2(y,x)โˆ’atan2(l2s2,l1+l2c2)q_1 = \text{atan2}(y, x) - \text{atan2}(l_2 s_2, l_1 + l_2 c_2)

This gives a unique q1q_1 for each sign of q2q_2, yielding exactly two (q_1, q_2) pairs for a reachable target.

4. Why atan2, not arctan

Use atan2(y, x) instead of arctan(y/x) for three reasons:

  1. Full-circle coverage. arctan returns angles in (โˆ’ฯ€/2,ฯ€/2)(-\pi/2, \pi/2); atan2 returns (โˆ’ฯ€,ฯ€](-\pi, \pi], covering all four quadrants.
  2. No division by zero. arctan(y/0) is undefined; atan2(y, 0) correctly returns ยฑฯ€/2\pm \pi/2.
  3. Sign disambiguation. arctan(-1/-1) equals arctan(1/1), so you cannot tell the angle is in the third quadrant. atan2 uses both signs independently.

In NumPy: np.arctan2(y, x). The argument order is (y first, x second) โ€” a classic gotcha. Robot IK code that uses np.arctan instead of np.arctan2 will produce wrong joint angles in half of configurations.

5. Worked Python implementation

import numpy as np

def ik_2link(x, y, l1=1.0, l2=0.8):
    """
    Analytical IK for a 2-link planar arm.
    Returns (q1_up, q2_up), (q1_down, q2_down) or None if unreachable.
    """
    cos_q2 = (x**2 + y**2 - l1**2 - l2**2) / (2 * l1 * l2)
    if abs(cos_q2) > 1.0:
        return None  # target unreachable

    q2_up   =  np.arccos(cos_q2)   # elbow-up
    q2_down = -np.arccos(cos_q2)   # elbow-down

    def solve_q1(q2):
        return np.arctan2(y, x) - np.arctan2(l2*np.sin(q2), l1 + l2*np.cos(q2))

    return (solve_q1(q2_up), q2_up), (solve_q1(q2_down), q2_down)

# Target: x=1.2, y=0.5
sols = ik_2link(1.2, 0.5)
for label, (q1, q2) in zip(["elbow-up", "elbow-down"], sols):
    print(f"{label}: q1={np.degrees(q1):.1f} deg, q2={np.degrees(q2):.1f} deg")

Always verify: pass each (q1,q2)(q_1, q_2) back through FK and confirm the position matches (x,y)(x, y) within numerical tolerance.

6. Singularities and unreachable poses

Two failure modes every IK implementation must handle:

Workspace boundary singularity. When โˆฃcosโกq2โˆฃ=1|\cos q_2| = 1, the arm is fully extended or fully folded. The elbow-up and elbow-down solutions merge into one; any small position error can flip the solution branch discontinuously. The robot jerks.

Internal singularity (kinematic singularity). At certain configurations the Jacobian loses rank โ€” the end-effector instantaneously cannot move in some direction, no matter what the joints do. For the 2-link arm this only happens at full extension/retraction. For 6-DOF arms there are additional wrist singularities (three wrist axes aligned) and elbow singularities.

Unreachable pose. cosโกq2>1โ‡’\cos q_2 > 1 \Rightarrow target too far; cosโกq2<โˆ’1โ‡’\cos q_2 < -1 \Rightarrow target inside the inner dead zone (less common). Always guard with if abs(cos_q2) > 1: return None.

7. Numerical IK: Jacobian iteration

For arms where closed-form solutions don't exist (or are too complex), use numerical IK:

  1. Start from a seed configuration q(0)q^{(0)}.
  2. Compute the current pose error ฮ”x=xdesiredโˆ’x(q(k))\Delta x = x_{desired} - x(q^{(k)}).
  3. Update: q(k+1)=q(k)+J+(q(k))โ€‰ฮ”xq^{(k+1)} = q^{(k)} + J^+(q^{(k)}) \, \Delta x

where J+J^+ is the pseudoinverse of the Jacobian. Repeat until โˆฅฮ”xโˆฅ<ฯต\|\Delta x\| < \epsilon. Pitfalls:

  • Convergence not guaranteed near singularities (where JJ loses rank and J+J^+ blows up).
  • Local minima in workspace: the iteration may stop at a wrong configuration.
  • Joint limits must be enforced explicitly with clamping or projected-gradient steps.

The Jacobian J(q)J(q) โ€” what it is and how to build it โ€” is the subject of the next lesson.

8. Analytical IK decision flow

Steps from target position to joint angles:

flowchart TD
  IN["Desired position x y"]
  COS["Compute cos_q2 via law of cosines"]
  CHECK["Is abs(cos_q2) > 1?"]
  UNREACH["Unreachable: return None"]
  Q2["q2_up = arccos and q2_down = -arccos"]
  Q1["Compute q1 via atan2 for each q2"]
  OUT["Two solutions: elbow-up and elbow-down"]
  IN --> COS
  COS --> CHECK
  CHECK --> UNREACH
  CHECK --> Q2
  Q2 --> Q1
  Q1 --> OUT

9. Choosing and validating a solution

With two candidate solutions in hand, the controller must choose one. Standard industrial practice:

def select_solution(sols, q_current, joint_limits=None):
    """Pick the IK solution closest to current config."""
    best, best_dist = None, float('inf')
    for (q1, q2) in sols:
        if joint_limits:
            (lo1, hi1), (lo2, hi2) = joint_limits
            if not (lo1 <= q1 <= hi1 and lo2 <= q2 <= hi2):
                continue
        dist = (q1 - q_current[0])**2 + (q2 - q_current[1])**2
        if dist < best_dist:
            best, best_dist = (q1, q2), dist
    return best

After selection, always verify by running FK on the chosen angles and checking that the position error is below your tolerance (1e-6 m is typical). If FK and IK disagree, you have an algebra bug โ€” catch it here, not at the real robot.

Check your understanding

The lesson ends with a 5-question quiz. Take it in the player above to see your score.

  1. For a 2-link planar arm, the formula $\cos q_2 = \frac{x^2+y^2-l_1^2-l_2^2}{2l_1 l_2}$ gives $\cos q_2 = 1.3$. What does this mean?
    • The elbow-up solution has $q_2 = \arccos(1.3)$.
    • The target position is outside the robot's reachable workspace.
    • The two solutions coincide at a singularity.
    • Joint 2 must rotate more than 360 degrees.
  2. Why should you use `np.arctan2(y, x)` instead of `np.arctan(y/x)` in IK code?
    • `arctan2` is faster to compute than `arctan`.
    • `arctan2` returns angles in the full range $(-\pi, \pi]$ and handles $x=0$ without division by zero.
    • `arctan` only works for positive angles.
    • `arctan2` automatically applies DH conventions.
  3. For a 2-link arm reaching a reachable interior point, how many IK solutions exist (ignoring joint limits)?
    • Exactly one
    • Exactly two (elbow-up and elbow-down)
    • Infinitely many, because the arm is redundant
    • Four, one per quadrant
  4. At a kinematic singularity of a 2-link arm (fully extended), what happens to the IK solutions?
    • The two elbow solutions diverge to $q_2 = \pm 2\pi$.
    • The elbow-up and elbow-down solutions merge into one; small position errors cause large joint-angle jumps.
    • The arm gains an extra degree of freedom.
    • IK always returns $q_1 = q_2 = 0$.
  5. In numerical (Jacobian-based) IK, which update rule is used?
    • $q^{(k+1)} = q^{(k)} - J(q^{(k)}) \, \Delta x$
    • $q^{(k+1)} = q^{(k)} + J^+(q^{(k)}) \, \Delta x$ where $J^+$ is the pseudoinverse
    • $q^{(k+1)} = J^+(q^{(k)}) \, x_{desired}$
    • $q^{(k+1)} = q^{(k)} + J^\top(q^{(k)}) \, \Delta x^2$

Related lessons