Forward kinematics, inverse kinematics, Jacobians, and feedback control — why they work, and why they aren't enough.
Before we can understand why robot learning is revolutionary, we need to understand what it replaces. Every robotics course starts with the same object: a planar manipulator — a robot arm that moves in a flat 2D plane.
The SO-100 arm that LeRobot supports has 6 degrees of freedom (DOF). That's a lot of complexity. So we'll strip it down to the simplest possible case: a 2-DOF arm with two links of equal length, connected by two revolute joints. Think of it as your upper arm and forearm, but operating on a flat table.
The arm lives in two spaces simultaneously. In joint space, we describe its configuration as two angles: θ1 (the shoulder angle) and θ2 (the elbow angle). In task space (also called Cartesian space), we describe the position of the end-effector as (x, y) coordinates.
The simulation below shows the 2-DOF arm. Drag the target (the orange circle) and watch the arm try to reach it by solving for the right joint angles. This is inverse kinematics — the hard direction. The easy direction, computing (x, y) from (θ1, θ2), is called forward kinematics.
Drag the orange target. The arm solves inverse kinematics to reach it. Gray zone = unreachable (beyond arm's total length). Link length l = 1.0 each.
Forward kinematics is the easy direction: given the joint angles (θ1, θ2) and link lengths (l1, l2), compute where the end-effector is in (x, y) coordinates.
The first link starts at the origin and extends at angle θ1. Its tip is at (l1 cos θ1, l1 sin θ1). The second link starts at that tip and extends at angle θ1 + θ2 (because θ2 is measured relative to the first link). So the end-effector position is:
Notice how the second link's contribution depends on both angles. This is the first hint that joint space and task space are non-linearly related — a fact that will matter enormously when we try to go in the reverse direction.
Let's verify this geometrically. The arm reaches up and to the right (θ1 = 45°), then bends further counterclockwise by 60°. The x-coordinate is small because the second link points mostly upward. The y-coordinate is large because both links contribute positive y-components.
Adjust the joint angles with the sliders. Watch how the end-effector position changes. The hand-calculated example (θ₁=45°, θ₂=60°) is pre-loaded.
Inverse kinematics (IK) is the hard direction: given a desired end-effector position p* = (x*, y*), find joint angles (θ1, θ2) that reach it. We're solving:
For our 2-DOF arm with equal link lengths, there's an analytical solution using the law of cosines. The distance from origin to target is d = √(x*² + y*²). Then:
Notice the ± in the θ2 equation. This means most reachable points have two valid solutions — an "elbow-up" and an "elbow-down" configuration. The robot must choose one. This ambiguity is tame for 2 DOF but becomes a nightmare for 6-DOF arms, where infinitely many joint configurations can reach the same point.
The simulation below shows the configuration space (C-space) — the (θ1, θ2) plane. Each point is a joint configuration. The green region is where the arm reaches the target. The gray region is where it doesn't. With obstacles, forbidden regions appear as holes in C-space.
The left panel shows the arm. The right panel shows C-space (θ₁ vs θ₂). The orange dot marks the current configuration. Drag the target in the arm view to see the solution point move in C-space. Both elbow-up and elbow-down solutions are shown.
Drag target in left panelForward kinematics gives us position from angles: p = p(q). But what about velocities? If we wiggle the joints at rates q̇ = (θ̇1, θ̇2), how fast does the end-effector move?
The answer is the Jacobian matrix J(q), the matrix of partial derivatives of p with respect to q. It maps joint velocities to end-effector velocities:
For our 2-DOF arm, we differentiate the forward kinematics equations:
This is a 2×2 matrix (2 task-space dimensions, 2 joint-space dimensions). The first column tells you what happens to (ẋ, ẏ) when you rotate joint 1. The second column tells you what happens when you rotate joint 2.
The Jacobian changes with configuration — it depends on q. At some configurations, the Jacobian becomes singular (its determinant is zero). This means the arm loses a degree of freedom: no matter how you move the joints, the end-effector can't move in certain directions. These configurations are called singularities, and they're the bane of classical robotics.
Set joint velocities with the sliders. The Jacobian maps them to end-effector velocity (shown as an arrow). Watch the arrow shrink near singularities (θ₂ ≈ 0° or 180°).
Full inverse kinematics solves for absolute angles. Differential IK takes a shortcut: instead of asking "what angles reach the target?", it asks "which way should I move the joints right now to get closer?"
We want the end-effector to move with velocity ṗ*. We know ṗ = J(q) q̇. So we need:
But J might not be square (more joints than task dimensions), or it might be singular. The robust solution uses the pseudoinverse J+ = JT(J JT)−1:
This gives the joint velocity vector with minimum norm that achieves the desired end-effector velocity. For our 2×2 case, the pseudoinverse equals the regular inverse (when it exists), but for redundant arms (more joints than needed), the pseudoinverse elegantly handles the extra degrees of freedom.
The algorithm is simple: at each timestep, compute the error Δp = p* − p(q), multiply by the pseudoinverse to get a joint velocity, take a small step, and repeat.
python import numpy as np def differential_ik(target, q, l1, l2, alpha=0.1, tol=1e-3, max_iter=200): """Solve IK via Jacobian pseudoinverse iteration.""" for _ in range(max_iter): # Forward kinematics p = np.array([ l1 * np.cos(q[0]) + l2 * np.cos(q[0] + q[1]), l1 * np.sin(q[0]) + l2 * np.sin(q[0] + q[1]) ]) # Error dp = target - p if np.linalg.norm(dp) < tol: return q # Jacobian s1, c1 = np.sin(q[0]), np.cos(q[0]) s12, c12 = np.sin(q[0]+q[1]), np.cos(q[0]+q[1]) J = np.array([ [-l1*s1 - l2*s12, -l2*s12], [ l1*c1 + l2*c12, l2*c12] ]) # Pseudoinverse step J_pinv = np.linalg.pinv(J) q = q + alpha * J_pinv @ dp return q
Differential IK tells us which direction to move the joints. But in the real world, things go wrong: the motor overshoots, the table vibrates, the gripper slips. Without feedback, these errors accumulate and the arm drifts off course.
Feedback control adds a correction term based on the current error. The simplest version is proportional (P) control:
Here kp is the proportional gain. When Δp is large (the arm is far from the target), the correction is strong. When Δp is small, the correction fades. This prevents overshoot while ensuring convergence.
In practice, roboticists use PID control (proportional + integral + derivative) or more sophisticated model-predictive controllers. But the principle is the same: measure the error, correct for it, and repeat at high frequency (typically 100-1000 Hz).
Drag the target. Adjust kp to see how feedback gain affects trajectory tracking. Low gain: slow convergence. High gain: oscillation. The trail shows the end-effector path.
So far our arm operates in an empty plane. Real robots share space with objects, humans, and other robots. The arm must reach its target while avoiding collisions — and this is where the classical pipeline starts to crack.
With a static obstacle, the problem is manageable. We can precompute the obstacle region in configuration space — the set of (θ1, θ2) configurations where the arm intersects the obstacle — and plan a path that avoids it.
But what about a moving obstacle? Imagine a human reaches across the table while the arm is executing a trajectory. The classical pipeline must:
Each step must complete within a single control cycle (~10ms). Detection requires real-time computer vision. Modeling requires updating a complex geometric representation. Replanning requires solving a constrained optimization problem. And any single failure in this chain means the arm either freezes (safe but useless) or collides (dangerous).
Joint limits add another layer of complexity. Real motors can't rotate 360° — they have physical stops. The IK solver must find solutions within the feasible range, which may not exist even when the target is geometrically reachable. And joint velocity limits mean the arm can't just jump to any configuration instantly.
The arm must reach the teal target while avoiding the red obstacle. Toggle the obstacle on/off to see how it constrains the solution. Drag the obstacle to see the arm reconfigure.
We've now seen the full classical pipeline: forward kinematics tells us where the arm is, inverse kinematics tells us where it should be, the Jacobian connects velocities, feedback control corrects errors, and path planning avoids obstacles. Each piece is elegant. Together, they're fragile.
Capuano et al. identify four specific failure modes:
The classical stack has perception, planning, dynamics, and control as separate modules. Each is developed and tested independently. But they must communicate through hand-designed interfaces, and the failure of any single module cascades through the entire system. We saw this in Chapter 1 — 0.956 ≈ 0.74 success rate with six 95%-reliable modules.
Classical controllers consume joint angles and maybe a point cloud. They don't look at camera images. They don't read language instructions. They don't feel tactile pressure. Each modality requires a separate processing pipeline and a separate interface to the controller. A learned policy can consume all modalities in a single forward pass.
The dynamics equations we use assume rigid links, known inertias, no friction, no backlash, and no contact forces. Real robots have flexible joints, uncertain inertias, significant friction, gearbox backlash, and constantly changing contact conditions. The gap between model and reality — the sim-to-real gap — is often larger than the safety margin.
Perhaps the most damning limitation: classical methods don't get better with more experience. A Jacobian controller that has been running for a year performs identically to one running for a day. It learns nothing from its history. Meanwhile, scaling laws in deep learning show that performance improves predictably with more data, more compute, and more parameters.
| Property | Classical | Learned |
|---|---|---|
| Multi-component pipeline | 6+ modules, hand-designed interfaces | 1 network, end-to-end |
| Multimodal input | Separate processing per modality | All modalities in one forward pass |
| Physical model | Analytical (rigid body, known params) | Implicit (learned from data) |
| Scaling with data | No improvement | Predictable improvement |
| Novel situations | Fails unless pre-engineered | Generalizes from similar training data |
Now we can see the full picture. Classical robotics builds a precise model of the world and computes optimal actions analytically. Robot learning skips the model and maps observations directly to actions using a neural network trained on demonstrations.
The key question is: when does each approach win?
| Scenario | Classical Wins | Learning Wins |
|---|---|---|
| Structured factory | ✓ Known geometry, fixed objects | |
| Deformable objects | ✓ Physics too complex to model | |
| Known dynamics | ✓ Optimal control possible | |
| Novel environments | ✓ Generalizes from training data | |
| Safety-critical (surgery) | ✓ Provable guarantees | |
| Language instructions | ✓ Multimodal input natural | |
| High precision (<0.1mm) | ✓ Calibrated analytical models | |
| Contact-rich tasks | ✓ Learns from demonstration |
Side-by-side comparison. The classical pipeline has many boxes connected by arrows. The learning pipeline has one box. Click each to highlight the data flow.
You now understand the classical robotics stack — what it can do, how it works, and why it isn't enough for unstructured environments. Here's where the journey continues:
| Chapter | What You'll Learn | Connection to This Chapter |
|---|---|---|
| Ch 3: RL Foundations | MDPs, rewards, policy optimization | Replaces feedback control with learned optimization |
| Ch 4: Imitation Learning | Behavior cloning, DAgger, action chunks | Replaces the IK solver with learned demonstrations |
| Ch 5: Policies (ACT, DiffPol) | Specific neural network architectures | The actual networks that replace the classical pipeline |
| Ch 6: VLAs | Foundation models for robotics | One model that understands vision + language + action |
The concepts from this chapter — forward kinematics, the Jacobian, singularities — reappear throughout robot learning. Even learned policies must ultimately command joint velocities. The Jacobian still governs how the arm moves. Understanding these fundamentals helps you debug learned policies when they fail: is the policy predicting bad actions, or is the arm in a singular configuration where no action works well?