35 min

The 2-link arm: the worked example this course keeps returning to

Two links, two joints, one plane: the smallest machine that still has every hard problem in robot kinematics inside it.

Where you are. You know forward kinematics is a fold over the chain. This lesson runs that fold end to end on the one arm this course will keep coming back to, and finds the first thing that genuinely surprises people.

A coin, a table, and your own arm

Put your forearm flat on a table, elbow down, palm down. Keep it there; the whole point is that nothing lifts. What you now have is a two-joint arm working in a plane: your shoulder turning your upper arm, your elbow turning your forearm, both swivelling about vertical axes.

Put a coin on the table about half an arm’s length away and touch it with your fingertip.

Now look at the shape your arm is making, and where your elbow sits relative to the straight line from shoulder to coin. Lift your hand, swing your elbow to the other side of that line, and put your fingertip back on the same coin. It goes. Same shoulder, same coin, a visibly different arm.

Try for a third. There isn’t one. Two shapes reach that coin and no others, and you cannot slide smoothly from one to the other without the fingertip leaving the coin. If yours seems to glide between them, your wrist and shoulder are cheating by adding freedom the idealised two-joint arm does not have; and if one of the two feels impossible, that is a joint limit, which gets a lesson of its own.

Two more things while you are down there. Slide the coin all the way out until you can only just touch it: at that distance there is exactly one way to reach it, arm dead straight, no elbow swing left. And slide the coin all the way in, close to your shoulder: below some radius there is no arm shape that gets your fingertip onto it at all, because your forearm is in the way.

One point, two answers. One ring where the two answers collapse into one. And a hole in the middle with no answer. Everything in the next four lessons is a formalisation of what your arm just did on that table.

The idea in one paragraph

The 2-link planar arm is two rigid links and two rotating joints, all in one flat plane. It is the fruit fly of robotics: small enough that you can derive every equation by hand in a page, rich enough that it already exhibits multiple inverse solutions, a workspace with a hole in it, a singular boundary where control blows up, and a Jacobian worth looking at. Its forward kinematics falls out of school trigonometry in three lines, and those three lines are also what you get by multiplying four homogeneous transforms together, which is the moment where the abstract machinery of the last three lessons starts paying rent. Every method you build on this arm carries over to a 6-axis industrial robot; the industrial robot just has more factors in the same product.

two revolute joints in a plane · the worked example this course keeps coming back to y x θ1 θ2 l1 l2 elbow end-effector the pose FK computes θ1 is measured from the world x-axis · θ2 from link 1 extended (dashed) Forward kinematics x = l1 cos θ1 + l2 cos(θ1 + θ2) y = l1 sin θ1 + l2 sin(θ1 + θ2) φ = θ1 + θ2 same walk, written as transforms: T_0E = Rz(θ1)·Tx(l1)·Rz(θ2)·Tx(l2) two angles in · exactly one pose out
The two-link planar arm: theta 1 at the base measured from the world x-axis, theta 2 at the elbow measured from link 1, link lengths l1 and l2, and the forward-kinematics equations they produce

Wider than the screen; scroll it sideways.

The convention that bites everybody

That last definition is not a formality. It is the single most common bug in hand-written kinematics, and it is worth spending a paragraph on before any algebra.

Joint angles on a serial arm are relative. θ2\theta_2 says how far link 2 is turned away from link 1, because that is what the elbow motor physically does: it rotates one link with respect to the other. It knows nothing about the world. If you turn the shoulder and leave the elbow motor completely alone, θ2\theta_2 does not change, but link 2 swings through the world all the same.

So the direction link 2 points in the world is θ1+θ2\theta_1 + \theta_2. The angles add because both joints rotate about the same axis, out of the plane, and rotations about a shared axis compose by adding.

correct: θ2 measured from link 1 the bug: θ2 read off the x-axis θ1 = 40° θ2 = 50° (0.77, 1.34) link 2 points along 40° + 50° = 90° θ1 = 40° θ2 = 50° (1.22, 1.18) link 2 points along 50°, and 40° of arm went missing same two numbers in · fingertips 0.48 apart on links of 1.00 and 0.70 · nothing crashes, the arm is simply elsewhere
The same pair of joint angles read two ways: measured from link 1 the fingertip lands at 0.77 and 1.34, measured wrongly from the world x-axis it lands at 1.22 and 1.18

Wider than the screen; scroll it sideways.

Three lines of trigonometry

Now the derivation, which is genuinely small. Walk the chain.

The elbow sits at the far end of link 1, which points along θ1\theta_1:

elbow=(l1cosθ1,  l1sinθ1)\text{elbow} = \left(l_1\cos\theta_1,\; l_1\sin\theta_1\right)

Link 2 starts there and points along θ1+θ2\theta_1 + \theta_2, so add its contribution:

x=l1cosθ1+l2cos(θ1+θ2)y=l1sinθ1+l2sin(θ1+θ2)ϕ=θ1+θ2\begin{aligned} x &= l_1\cos\theta_1 + l_2\cos(\theta_1 + \theta_2) \\ y &= l_1\sin\theta_1 + l_2\sin(\theta_1 + \theta_2) \\ \phi &= \theta_1 + \theta_2 \end{aligned}

In words: the fingertip is the elbow plus a step of length l2l_2 in the direction link 2 is pointing, and the hand’s heading is whatever both joints have added up to. That is the whole of the 2-link arm’s forward kinematics.

Now the same thing as a transform product, in the notation of the last two lessons:

T0E(θ1,θ2)=Rz(θ1)Tx(l1)Rz(θ2)Tx(l2)T_{0E}(\theta_1, \theta_2) = R_z(\theta_1)\,T_x(l_1)\,R_z(\theta_2)\,T_x(l_2)

Read it left to right as instructions to a person walking the arm: turn by θ1\theta_1, march l1l_1 forward, turn by θ2\theta_2, march l2l_2 forward. Each factor is a 4x4 matrix from your own transforms library. Multiply them and the translation column of the result reproduces the two trigonometric lines exactly, and the rotation block encodes ϕ\phi.

This is not a claim to take on trust. Run both over ten thousand random configurations and they agree to 8.9e-16, which is double-precision rounding rather than any real disagreement. That “two independent implementations must agree” pattern is how kinematics gets tested for real, forever after: a hand-derived closed form on one side, a general routine on the other, and a property test in between.

Interactive: drag the fingertip of a 2-link arm and watch both joint angles follow. With links of 1.00 and 0.70, the reachable ring runs from 0.30 to 1.70 from the base, and each interior point has two arm shapes behind it.

One point, two arms

Drag that widget to a point and switch elbow branches, and you have the thing your own arm did on the table.

Take the target (0.90, 0.60), comfortably inside the reachable ring. Exactly two configurations put the fingertip there:

θ1\theta_1θ2\theta_2hand heading ϕ\phi
Branch A-5.4°+103.2°+97.9°
Branch B+72.7°-103.2°-30.5°

y x θ2 > 0 θ2 < 0 same point base θ = (-5.4°, +103.2°) elbow swings below the dashed line hand ends up pointing at +97.9° θ = (+72.7°, -103.2°) elbow swings above it hand ends up pointing at -30.5° fingertip: (0.90, 0.60) both times links l1 = 1.00 and l2 = 0.70 the two branches are the sign of θ2 · which one looks like "elbow up" depends on where the target sits
Two different joint-angle pairs put the same fingertip on the same point, with the elbow on opposite sides of the line to the target and the hand pointing in two completely different directions

Wider than the screen; scroll it sideways.

The two θ2\theta_2 values are equal and opposite; that is not a coincidence, and it falls out of the law of cosines when you do inverse kinematics in a few lessons. The sign of θ2\theta_2 decides which side of the straight line from base to fingertip the elbow sits on: positive puts it on the clockwise side, negative on the counterclockwise side. Those are the two branches, and textbooks call them elbow-up and elbow-down.

Look again at the third column of that table. The hand heading differs by more than 128 degrees between the two branches, and you did not get to choose it. Two joints buy you two numbers of control, and you spent both on x and y. Orientation is whatever falls out. That is not a limitation of the solver; it is a property of the mechanism, and it is the subject of the next lesson.

Why a toy is the right thing to study

Two links in a plane is not a simplification you will outgrow. It is the case that isolates the phenomena.

Throughout this course the arm has l1=1.00l_1 = 1.00 and l2=0.70l_2 = 0.70. Unequal lengths on purpose: with equal links a special case appears at the centre of the reachable area that would hide behind the general result. The numbers are unitless, and you can read them as metres for a large industrial arm or as decimetres for something desk-sized. Nothing in the mathematics cares.

Check yourself

1. Why do θ1 and θ2 simply add to give the hand’s heading, and when would that stop working?

Both joints rotate about the same axis, perpendicular to the plane, and rotations about a shared axis compose by adding their angles. It stops working the moment two joint axes are not parallel, which is the normal case in 3D: a wrist twisting about x after a shoulder turning about z composes by full matrix or quaternion multiplication, and no scalar addition shortcut exists. The planar arm is the special case where rotation happens to be one-dimensional.

2. With l1 = 1.00 and l2 = 0.70, what is the fingertip pose at θ = (0°, 0°), and at (90°, -90°)?

At (0°, 0°) the arm lies straight along +x, so the fingertip is at (1.70, 0.00) with heading 0°. At (90°, -90°) link 1 points straight up to the elbow at (0.00, 1.00), then the elbow turns back by 90° so link 2 points along +x again: the fingertip is at (0.70, 1.00) with heading 0°. Sketch the second one; it is the classic L-pose, and it is a good check that you are treating θ2\theta_2 as relative.

3. Someone writes x = l1·cos θ1 + l2·cos θ2. Their unit test at θ1 = 0 passes. What has slipped through, and how big is it?

They dropped the relative-angle convention: link 2’s world direction is θ1+θ2\theta_1 + \theta_2, not θ2\theta_2. At θ1=0\theta_1 = 0 the two expressions are identical, which is why the test passes. Away from zero the error is real: at θ1=40\theta_1 = 40^\circ, θ2=50\theta_2 = 50^\circ the fingertip is 0.48 out of position, on an arm whose full reach is 1.70. Any test suite for kinematics must exercise every joint at a non-zero angle simultaneously.

4. Two configurations reach (0.90, 0.60). Why can you not simply pick whichever is nearer to where the arm is now?

You often can, and that is a reasonable default. But not always: the nearer branch may put a joint past its limit, may drive the elbow through an obstacle or through the arm’s own base, and may be on the far side of the straight-arm boundary, where crossing between branches requires passing through a configuration that the controller handles badly. Branch selection is a real decision with real consequences, not a tiebreak.

5. Both branches reach the same point, but the hand headings differ by more than 128°. What does that tell you about what two joints can buy?

Two joints give you two degrees of freedom, and planar task space has three: x, y and heading. Spend both of them on position and the heading is fully determined; it is an output, not an input. The only choice left is which of the two branches to take, and that offers exactly two headings out of a possible 360. Controlling position and orientation independently in the plane needs a third joint.

6. Why is checking a hand-derived formula against a general transform product a stronger test than checking either one against a handful of hand-computed poses?

Because the two implementations fail in different ways. A dropped θ1+\theta_1 + in the trigonometry and a transposed rotation block in the matrix code are unrelated mistakes, so agreement across ten thousand random configurations is real evidence rather than a coincidence. Hand-computed test poses, by contrast, are usually the easy poses, and the easy poses are exactly the ones where common bugs are invisible.

Do this

Work code/fk_2link.py. Budget half an hour.

  1. Implement fk_trig(t1, t2) straight from the three trigonometric lines above. Return (x, y, phi).

  2. Implement fk_transforms(t1, t2) as the four-factor product Rz(t1) · Tx(L1) · Rz(t2) · Tx(L2), using the transforms library you completed earlier. Pull x and y out of the translation column, and recover phi from the rotation block with atan2(R[1,0], R[0,0]).

  3. Run python fk_2link.py. The built-in cross-check compares the two implementations over ten thousand random angle pairs and asserts they agree to within 1e-9. When it passes, the numbers you get should be the ones in this lesson: (0°, 0°) gives (1.700, 0.000) and (90°, -90°) gives (0.700, 1.000).

  4. Deliberately break it. Change cos(t1 + t2) to cos(t2) in the trigonometric version only, and watch which configurations the cross-check reports. Confirm that the failure vanishes when t1 = 0. This is the bug from the gotcha above, and having watched it hide from you once is worth more than reading about it.

Solution: solutions/fk_2link.py. Read it only after step 3 passes.

What you can now do

You can derive the 2-link planar arm’s forward kinematics from trigonometry and from a product of homogeneous transforms, and show the two agree to machine precision. You can explain why joint angles are relative and what it costs when someone forgets, why a single fingertip position corresponds to two different arm shapes, and why on a two-joint arm the hand’s heading is something you receive rather than something you request.

What you can now do

You can derive the 2-link arm's forward kinematics two independent ways, get identical numbers, and explain why the same fingertip position has two different arms behind it.