Technology · Notes
Where does the arm think it is?
Going from joint angles to a position is easy and always works. Going the other way is where the interesting problems are: a target can have two correct answers, or none, and a solver that hands back a number regardless is lying to you.
Three steps, each draggable. The algebra is exact — no iterative solver, no tolerance to tune.
Angles in, position out
Three links, three joints. Each link starts where the last one ended and points along the sum of every angle before it. Add them up and you have the tip.
The tool’s orientation is just the sum of the three angles, which is the planar case of rotations composing along the chain. One set of angles gives one pose, every time, with nothing to decide.
That is the entire forward problem, and it is why robot code that only ever plays back recorded joint angles is straightforward. The moment someone points at a spot and says go there, it stops being straightforward.
Position in, angles out — if there are any
Work backwards. If you fix where the tool must point, you also fix where the wrist must be — back off along the tool direction by the last link’s length. Now it is a two-link problem with a known target, and two links reaching a point is a triangle.
Solve it and you get an exact answer, no iteration. But notice: cosine is even, so +q₂ and −q₂ both satisfy it. Two different arm shapes, one identical tip position — elbow up and elbow down.
Both are correct. Picking one silently is how an arm swings through a configuration nobody asked for halfway along a path, because the solver quietly changed its mind about which branch it was on.
Then drag the target away, and toward the base. Beyond the outer circle there is no answer. Inside the inner one there is also no answer — the arm cannot fold that tightly — and that failure is the one that catches people, because a target sitting near your own base looks like the easiest ask in the world.
Drag toward the base. The inner dashed circle is a hole in the workspace — the arm cannot fold that tightly, and the target looks perfectly reasonable sitting in it.
The place where the arm runs out of directions
Ask how the tip moves when you drive each joint at one unit per second, and you get three vectors — one per joint. Stack them and that is the Jacobian: the map from joint speeds to tip velocity.
Usually those three vectors between them span the plane, so any tip velocity you want is achievable. Straighten the arm and they collapse onto a single line. In that configuration the arm cannot move its tip perpendicular to itself at all — not slowly, not with more torque. The direction is gone.
That is a singularity, and it is a physical fact rather than a numerical one. What makes it dangerous is the approach: near it, the joint speeds needed for a modest tip speed head toward infinity, so a naive controller commands a violent motion just before it fails.
This is the same object as the formation Jacobian in the drone swarm piece — a matrix relating a velocity you command to a velocity you observe, one layer down.
Straighten it and the three arrows collapse onto one line. The arm can still move its tip along that line, and cannot move it off the line at all — no matter how the joints are driven.
Why the return type matters
The solver on this page cannot return a pose without first saying whether one exists. Ask for something unreachable and you get a reason and the numbers behind it — how far the wrist would have to be, and how far it can actually go — not angles that happen to be NaN.
That is a deliberate choice, and it is the same one the segmentation piece argues for from the other direction. k-means will hand back four clusters for data with no structure in it. An inverse kinematics solver will hand back angles for a point the arm cannot reach. In both cases the output looks exactly like a real answer, and the only defence is a function signature that refuses to produce one.
The code is in lib/arm.ts, with tests pinning the round-trip through both solutions, the two failure modes, the boundary case where the branches coincide, and the Jacobian against a numerical derivative.