Kinematic redundancy: use the motion a task leaves free

Split a three-link arm’s joint rates into a primary solution and null-space motion. Check the exact projector, compare damping leakage, and measure why a finite step can move a tool with zero initial velocity.

By 12 min read

What you will learn

  • Define redundancy and nullity for a specified robot task.
  • Split joint rates into a minimum-norm primary solution and a null component.
  • Verify that an exact projector preserves the primary instantaneous velocity.
  • Identify leakage from a damped secondary map and drift from a finite step.

Before you start

A robot can have several joint motions that produce the same tool velocity. That freedom lets a controller change the arm’s posture while maintaining its primary task. The useful question is which motions preserve that task, and for how long.

We will add a third revolute joint to a planar arm. You will calculate an exact null-space motion, see its guarantee fail under a damped replacement, and measure the error from holding its rates for a finite time.

Define what the task leaves free

Redundancy depends on the task. Three independent joints can be redundant for a two-coordinate position task, while a task that also specifies tool orientation can use all three freedoms.

At a fixed configuration, the Jacobian J maps n joint rates to the chosen task velocity. The rank-nullity relation counts the local freedom:

dim null(J) = n − rank(J)

For a regular two-dimensional position task with three joints, rank J = 2 and nullity = 1. One independent joint-rate direction produces zero tool-position velocity. Multiples of that direction form J’s null space.

Rank can fall at a singular configuration. Then nullity increases, even as the tool loses an available velocity direction. Modern Robotics distinguishes these rank and redundancy cases.

This lesson uses three links of 2 m, 1 m, and 1 m. The earlier two-link examples had only 2 m and 1 m links. The shoulder stays at the world origin, with x right and y up.

Let q = (q₁, q₂, q₃). The shoulder angle q₁ is absolute; q₂ and q₃ are relative to their preceding links. Positive angles turn counterclockwise, and calculations use radians.

At q = (0°, 90°, −90°), the first joint beyond the shoulder is at (2, 0) m. The next joint is at (2, 1) m, and the tool is at (3, 1) m. Each Jacobian column is the tool velocity from moving that joint at 1 rad/s while holding the others still:

J =
[ −1, −1, 0 ]
[ 3, 1, 1 ]

ṗ = Jq̇

The entries have units m/rad. For example, the third joint rotates the final 1 m link upward, giving the column (0, 1). The first joint rotates the whole tool displacement (3, 1), giving (−1, 3).

Split primary and null-space motion

Choose a requested tool velocity v. The pseudoinverse gives q̇_primary = J⁺v, the smallest Euclidean joint-rate vector among the least-squares solutions. If v lies in J’s column space, that solution produces v exactly.

An arbitrary additional joint-rate request z can contain motion that would alter the primary task. The exact null-space projector N selects its component in null(J):

N = I − J⁺J
q̇ = J⁺v + Nz

JN = 0, N² = N, Nᵀ = N

The identity JN = 0 explains the task guarantee. Adding Nz leaves Jq̇_primary unchanged. The other two identities say N is an orthogonal projector: applying it twice has the same effect as applying it once.

If the request is unattainable, the primary result is JJ⁺v. Adding exact null motion preserves that best fit and its residual. It cannot create a missing tool direction.

The primary and null components are orthogonal in joint-rate coordinates. Adding a nonzero null component therefore increases the total squared rate norm. This is how the minimum-norm solution fits within the full family of solutions. Modern Robotics explains the pseudoinverse’s minimum-norm property.

Calculate a complete rate solution

Use the bent configuration above and request v = (0.5, 0.25) m/s. The exact minimum-norm rates are:

q̇_primary = (1/6, −2/3, 5/12) rad/s
n = (−1, 1, 2)/√6

Check Jn = 0. Since the null space has dimension one, N = nnᵀ. Multiplying the outer product gives:

N = (1/6) ×
[ 1, −1, −2 ]
[ −1, 1, 2 ]
[ −2, 2, 4 ]

Now request an additional third-joint rate through z = (0, 0, 0.5) rad/s. Projection gives Nz = (−1/6, 1/6, 1/3) rad/s. The combined result is q̇ = (0, −0.5, 0.75) rad/s.

Multiply by J: the x velocity is 0.5 m/s, and the y velocity is 0.25 m/s. All three joint contributions changed as needed to preserve the task. The third joint’s final rate is 0.75 rad/s; z was an additional preference before projection, not a hard target for the final joint rate.

Change the secondary request

Keep the exact projector selected and change the secondary joint 3 request. The combined joint rates change while the primary tool velocity stays fixed. The secondary leakage readout, ‖Jq̇_secondary‖₂, stays zero up to floating-point error.

Three joints, two position coordinates

Add a secondary joint request and check the tool velocity

This arm has three links of 2 m, 1 m, and 1 m. The primary calculation uses the exact pseudoinverse. Compare two maps for the secondary request z = (0, 0, γ) rad/s.

0.50
0.25
0.50
0.20

The shoulder angle is absolute; joints 2 and 3 use relative angles. Positive angles turn counterclockwise. Changing the configuration preserves the velocity request, secondary request, map, and time step.

These buttons restore complete examples. The secondary map can change all three rates, even though the unprojected request names only joint 3. It does not promise that joint 3 reaches γ.

One joint Euler step, in world coordinates (m)

Three-link arm: initial tool (3.000, 1.000), held-rate endpoint (3.099, 1.045) metersBoth axes use equal meter scales. Black solid links show the selected configuration. Amber dashed links show the angles after holding the computed rates for 0.20 seconds. The blue cross marks the linear prediction (3.100, 1.050) meters. The resulting endpoint differs from that prediction by 0.005213 meters.-4-40044xy
Black links show the start; amber dashed links show q + hq̇. The blue cross shows p + hJq̇. Their endpoint difference measures the local linear approximation error. The angle increment holds rates constant and imposes no collision or joint-limit constraints.

Instantaneous tool velocities (m/s)

Requested velocity (0.500, 0.250), produced velocity (0.500, 0.250) meters per secondThis separate velocity plane has equal x and y scales. The black open square marks the request. The blue dot and dashed vector show the primary velocity. The amber open circle and solid vector show the combined velocity. A gray dotted connector shows the secondary contribution when their endpoints differ.-1-10011xy
Blue: the exact primary solution. Amber: primary plus the chosen secondary rates. The square, dot, and ring coincide when both calculations preserve the complete request. Zero velocity sits at the plot origin.
Joint angles (degrees)
(0.000, 90.000, -90.000)
Position task rank
2
Joint-space nullity
1
Tool position (m)
(3.000, 1.000)
Requested tool velocity (m/s)
(0.500, 0.250)
Primary rates (rad/s)
(0.167, -0.667, 0.417)
Secondary rates (rad/s)
(-0.167, 0.167, 0.333)
Combined rates (rad/s)
(0.000, -0.500, 0.750)
Primary tool velocity (m/s)
(0.500, 0.250)
Secondary tool velocity (m/s)
(0.000, 0.000)
Produced tool velocity (m/s)
(0.500, 0.250)
Requested residual (m/s)
(0.000, 0.000)
Secondary leakage (m/s)
0.000000
Linear prediction (m)
(3.100, 1.050)
Held-rate endpoint (m)
(3.099, 1.045)
Finite-step mismatch (m)
0.005213

Secondary leakage is ‖Jq̇_secondary‖₂. Requested residual is v − Jq̇_combined. At a singular pose, an exact secondary projection preserves the primary fit while an unavailable part of the request remains as a residual.

Position Jacobian J (m/rad)
RowJoint 1Joint 2Joint 3
ẋ-1.000-1.0000.000
ẏ3.0001.0001.000
Exact null-space projector N
RowJoint 1Joint 2Joint 3
Joint 10.167-0.167-0.333
Joint 2-0.1670.1670.333
Joint 3-0.3330.3330.667

Rank 2; nullity 1. Produced tool velocity: (0.500, 0.250) m/s. The exact secondary component leaves the primary instantaneous velocity unchanged.

All joint rates use rad/s and equal Euclidean weights. Calculations retain more precision than the readouts. The fixed configurations use exact rank formulas; this small experiment does not implement a general-purpose SVD.

Try Null motion only to set the primary request to zero. Then vary the time step and compare the held-rate endpoint with the initial tool position. The instantaneous velocity test and the finite endpoint comparison answer different questions.

The experiment uses four fixed configurations so its exact-rank formulas remain explicit. At each pose, it minimizes tool-velocity error first, then joint-rate norm. The secondary map adds the selected preference afterward.

Count the null space at singular poses

With all three angles zero, the straight arm reaches (4, 0) m. Its position Jacobian has rows (0, 0, 0) and (4, 2, 1). Rank is 1, so nullity is 3 − 1 = 2.

The position task still has two requested coordinates, but horizontal velocity is unavailable at that instant. For v = (0.5, 0.25) m/s, the exact primary fit produces (0, 0.25) m/s and leaves residual (0.5, 0) m/s. Every exact null addition preserves that fit.

At q = (0°, 180°, 0°), the last two links fold back along the first. The tool reaches the shoulder, and the Jacobian has rows (0, 0, 0) and (0, −2, −1). It also has rank 1 and nullity 2.

These extra null directions come from rank loss. They do not restore the missing task direction. At a regular configuration, this three-joint arm has one redundant position-task direction.

Adding tool orientation as a third output changes the calculation. Its Jacobian gains the row (1, 1, 1). At the worked bent pose, this full pose map has rank 3, leaving no null direction that preserves all three outputs.

Check what damping changes

A damped inverse uses Jλ# = Jᵀ(JJᵀ + λ²I)⁻¹. Replacing J⁺ with that inverse inside I − J⁺J generally destroys the exact null-space property:

Nλ = I − Jλ#J
JNλ = λ²(JJᵀ + λ²I)⁻¹J

That last expression is generally nonzero. A component along an exact null direction still stays in the null space, but other components can leak into the task. Nλ also generally fails the projector identity Nλ² = Nλ.

The comparison keeps the primary solution exact and changes only the secondary map. At the default pose with λ = 0.5 m/rad, the produced velocity becomes approximately (0.553691, 0.280201) m/s. The secondary component adds about 0.061603 m/s of task-space leakage.

Damping the primary inverse would also alter the primary fit. Our comparison isolates the secondary-map effect. Moe and colleagues discuss null-space task priorities and cases where damped schemes lose strict priority.

Keep the instantaneous guarantee local

The exact identity uses J at the current configuration. Hold q̇ for h seconds and update the joints to q_next = q + hq̇. Forward kinematics at q_next generally differs from the linear prediction p + hJq̇.

For the worked combined rates and h = 0.2 s, the linear prediction is (3.1, 1.05) m. The actual forward-kinematics endpoint is approximately (3.098584, 1.044983) m. Their distance is about 0.005213 m.

In the worked bent pose, pure null motion also has finite drift when its initial rates remain fixed. With z = (0, 0, 0.5), zero primary request, and h = 0.2 s, the tool moves about 0.003333 m from its starting point. Reducing h to 0.1 s reduces that error to about 0.000833 m, close to the factor of four expected from a second-order local error.

An ideal continuous command q̇(t) in null(J(q(t))) can preserve position along its trajectory. A practical discrete controller must recompute the Jacobian and account for numerical and tracking errors. Differential inverse kinematics develops that repeated local solve.

Secondary requests can come from a posture cost, such as z = −k∇H(q). They can also come from a learned policy that proposes joint motion while a primary controller handles the tool task. Projection acts on that proposal using the current model and metric; a model error can change the physical result.

Equal Euclidean joint-rate weights define the projector used here. Different weights define a different minimum-norm problem. A projected preference also provides no hard guarantee about joint bounds or collision clearance; use joint limits in inverse kinematics to examine explicit constraints.

Verify the split in Python

This standard-library example uses exact fractions for the linear calculations. It then uses trigonometry to evaluate one finite joint step. The inverse formula applies to this full-row-rank worked matrix.

from fractions import Fraction as F
from math import cos, sin, pi, hypot

J = ((F(-1), F(-1), F(0)), (F(3), F(1), F(1)))
dot = lambda a, b: sum(x*y for x, y in zip(a, b))
a, b, c = dot(J[0], J[0]), dot(J[0], J[1]), dot(J[1], J[1])
det = a*c - b*b
plus = tuple(((c*J[0][i] - b*J[1][i])/det,
              (a*J[1][i] - b*J[0][i])/det) for i in range(3))
N = tuple(tuple(F(i == k) - plus[i][0]*J[0][k]
                - plus[i][1]*J[1][k] for k in range(3))
          for i in range(3))
v, z = (F(1, 2), F(1, 4)), (F(0), F(0), F(1, 2))
primary = tuple(dot(row, v) for row in plus)
secondary = tuple(dot(row, z) for row in N)
combined = tuple(x+y for x, y in zip(primary, secondary))
produced = tuple(dot(row, combined) for row in J)
assert all(dot(row, secondary) == 0 for row in J)
assert produced == v

q, h = (0.0, pi/2, -pi/2), 0.2
next_q = tuple(x + h*float(rate) for x, rate in zip(q, combined))
heading = 0.0
x = y = 0.0
for length, angle in zip((2, 1, 1), next_q):
    heading += angle
    x += length*cos(heading)
    y += length*sin(heading)
prediction = (3 + h*float(produced[0]), 1 + h*float(produced[1]))
fmt = lambda values: "(" + ", ".join(f"{float(x):.6f}" for x in values) + ")"
print("primary:", fmt(primary))
print("secondary:", fmt(secondary))
print("combined:", fmt(combined))
print("produced:", fmt(produced))
print("linear prediction:", fmt(prediction))
print("held-rate endpoint:", fmt((x, y)))
print(f"finite-step mismatch: {hypot(x-prediction[0], y-prediction[1]):.6f} m")

Expected output:

primary: (0.166667, -0.666667, 0.416667)
secondary: (-0.166667, 0.166667, 0.333333)
combined: (0.000000, -0.500000, 0.750000)
produced: (0.500000, 0.250000)
linear prediction: (3.100000, 1.050000)
held-rate endpoint: (3.098584, 1.044983)
finite-step mismatch: 0.005213 m

The fraction assertions verify exact task preservation in the linear map. The last line measures a separate effect: the nonlinear position map over a finite step.

Try two null-space calculations

Exercise 1. Keep the worked bent pose and v = (0.5, 0.25) m/s, but set z = (0, 0, −0.5) rad/s. Find the secondary and combined rates. Does the tool velocity change? Is the combined rate norm smaller than the primary norm?

Show solution 1

Linearity reverses the secondary component to (1/6, −1/6, −1/3) rad/s. Adding the primary rates gives (1/3, −5/6, 1/12) rad/s. Multiplying by J still produces (0.5, 0.25) m/s.

The primary and secondary vectors are orthogonal. Their squared norms add: 31/48 + 1/6 = 13/16. The combined norm is √13/4 ≈ 0.901388 rad/s, larger than the primary norm √93/12 ≈ 0.803638 rad/s.

Exercise 2. At the straight configuration, J has rows (0, 0, 0) and (4, 2, 1). Find two independent null vectors, then explain why a request (0.5, 0) m/s remains impossible even though nullity is two.

Show solution 2

The vectors (1, −2, 0) and (0, 1, −2) both satisfy 4q̇₁ + 2q̇₂ + q̇₃ = 0. They are independent, and they span the two-dimensional null space.

Every produced velocity has x component zero because the first row of J is zero. Adding any combination of the null vectors leaves the produced velocity unchanged. More ways to preserve a task cannot supply a direction that the task map has lost.

Sources and further reading