Chapter 4: Task-Space (Operational-Space) Control

Lesson 2: Operational-Space Control Structure (concept + equations)

This lesson introduces the mathematical structure of task-space (operational-space) control for robot manipulators. Starting from joint-space dynamics and known kinematics, we derive the operational-space dynamics, define the task-space inertia \( \boldsymbol{\Lambda}(\mathbf{q}) \), and show how to synthesize a model-based controller that shapes the closed-loop behavior of the end-effector. We then map the resulting task-space wrench to joint torques and illustrate the full control loop in multiple programming languages.

1. From Joint Space to Task Space

You have already seen the standard joint-space dynamics of an \( n \)-DOF rigid manipulator:

\[ \mathbf{M}(\mathbf{q})\ddot{\mathbf{q}} + \mathbf{C}(\mathbf{q},\dot{\mathbf{q}})\dot{\mathbf{q}} + \mathbf{g}(\mathbf{q}) = \boldsymbol{\tau} , \]

where \( \mathbf{q} \in \mathbb{R}^n \) are joint coordinates, \( \mathbf{M}(\mathbf{q}) \) is the symmetric positive-definite inertia matrix, \( \mathbf{C}(\mathbf{q},\dot{\mathbf{q}})\dot{\mathbf{q}} \) collects Coriolis/centrifugal terms, and \( \mathbf{g}(\mathbf{q}) \) is gravity. It is often convenient to group nonlinear terms as

\[ \mathbf{h}(\mathbf{q},\dot{\mathbf{q}}) \triangleq \mathbf{C}(\mathbf{q},\dot{\mathbf{q}})\dot{\mathbf{q}} + \mathbf{g}(\mathbf{q}), \quad \mathbf{M}(\mathbf{q})\ddot{\mathbf{q}} + \mathbf{h}(\mathbf{q},\dot{\mathbf{q}}) = \boldsymbol{\tau}. \]

A task-space (operational-space) output is a differentiable function of the joints, for instance the end-effector position and orientation:

\[ \mathbf{x} = \mathbf{f}(\mathbf{q}) \in \mathbb{R}^m, \quad m \le n. \]

Using the manipulator Jacobian \( \mathbf{J}(\mathbf{q}) = \frac{\partial \mathbf{f}}{\partial \mathbf{q}} \), we have the task-space velocity and acceleration relations:

\[ \dot{\mathbf{x}} = \mathbf{J}(\mathbf{q})\dot{\mathbf{q}}, \qquad \ddot{\mathbf{x}} = \mathbf{J}(\mathbf{q})\ddot{\mathbf{q}} + \dot{\mathbf{J}}(\mathbf{q},\dot{\mathbf{q}})\dot{\mathbf{q}}. \]

Operational-space control aims to directly shape \( \ddot{\mathbf{x}} \) (and thus the behavior of \( \mathbf{x} \)) by constructing a control law in task coordinates and mapping it back to joint torques \( \boldsymbol{\tau} \).

2. Operational-Space Dynamics Derivation

The link between joint torques and task-space wrenches is given by the principle of virtual work. For a task-space wrench \( \mathbf{F} \in \mathbb{R}^m \) applied at the end-effector, the joint torques are

\[ \boldsymbol{\tau} = \mathbf{J}(\mathbf{q})^{\top} \mathbf{F}. \]

Substitute this into the joint-space dynamics (ignore external joint torques other than those induced by \( \mathbf{F} \)):

\[ \mathbf{M}(\mathbf{q})\ddot{\mathbf{q}} + \mathbf{h}(\mathbf{q},\dot{\mathbf{q}}) = \mathbf{J}(\mathbf{q})^{\top}\mathbf{F}. \]

Solve for \( \ddot{\mathbf{q}} \):

\[ \ddot{\mathbf{q}} = \mathbf{M}(\mathbf{q})^{-1}\mathbf{J}(\mathbf{q})^{\top}\mathbf{F} - \mathbf{M}(\mathbf{q})^{-1}\mathbf{h}(\mathbf{q},\dot{\mathbf{q}}). \]

Substitute into the task-space acceleration relation:

\[ \begin{aligned} \ddot{\mathbf{x}} &= \mathbf{J}\ddot{\mathbf{q}} + \dot{\mathbf{J}}\dot{\mathbf{q}} \\ &= \mathbf{J}\mathbf{M}^{-1}\mathbf{J}^{\top}\mathbf{F} - \mathbf{J}\mathbf{M}^{-1}\mathbf{h} + \dot{\mathbf{J}}\dot{\mathbf{q}}. \end{aligned} \]

Rearrange to isolate \( \mathbf{F} \):

\[ \mathbf{J}(\mathbf{q})\mathbf{M}(\mathbf{q})^{-1}\mathbf{J}(\mathbf{q})^{\top}\mathbf{F} = \ddot{\mathbf{x}} + \mathbf{J}(\mathbf{q})\mathbf{M}(\mathbf{q})^{-1}\mathbf{h}(\mathbf{q},\dot{\mathbf{q}}) - \dot{\mathbf{J}}(\mathbf{q},\dot{\mathbf{q}})\dot{\mathbf{q}}. \]

Assume \( \mathbf{J}(\mathbf{q}) \) has full row rank (\( m \) independent task coordinates). Then \( \mathbf{J}\mathbf{M}^{-1}\mathbf{J}^{\top} \) is symmetric positive definite and invertible. Define the operational-space inertia matrix:

\[ \boldsymbol{\Lambda}(\mathbf{q}) \triangleq \left( \mathbf{J}(\mathbf{q})\mathbf{M}(\mathbf{q})^{-1}\mathbf{J}(\mathbf{q})^{\top} \right)^{-1}. \]

Then we obtain the compact operational-space dynamics:

\[ \begin{aligned} \mathbf{F} &= \boldsymbol{\Lambda}(\mathbf{q})\ddot{\mathbf{x}} + \boldsymbol{\Lambda}(\mathbf{q}) \mathbf{J}(\mathbf{q})\mathbf{M}(\mathbf{q})^{-1} \mathbf{h}(\mathbf{q},\dot{\mathbf{q}}) - \boldsymbol{\Lambda}(\mathbf{q}) \dot{\mathbf{J}}(\mathbf{q},\dot{\mathbf{q}})\dot{\mathbf{q}} \\ &\triangleq \boldsymbol{\Lambda}(\mathbf{q})\ddot{\mathbf{x}} + \boldsymbol{\mu}(\mathbf{q},\dot{\mathbf{q}}) + \mathbf{p}(\mathbf{q}), \end{aligned} \]

where the task-space Coriolis/centrifugal term and gravity term are defined as

\[ \begin{aligned} \boldsymbol{\mu}(\mathbf{q},\dot{\mathbf{q}}) &\triangleq \boldsymbol{\Lambda}(\mathbf{q}) \mathbf{J}(\mathbf{q})\mathbf{M}(\mathbf{q})^{-1} \mathbf{C}(\mathbf{q},\dot{\mathbf{q}})\dot{\mathbf{q}} - \boldsymbol{\Lambda}(\mathbf{q}) \dot{\mathbf{J}}(\mathbf{q},\dot{\mathbf{q}})\dot{\mathbf{q}}, \\ \mathbf{p}(\mathbf{q}) &\triangleq \boldsymbol{\Lambda}(\mathbf{q}) \mathbf{J}(\mathbf{q})\mathbf{M}(\mathbf{q})^{-1}\mathbf{g}(\mathbf{q}). \end{aligned} \]

In summary, the operational-space dynamics take the form

\[ \boldsymbol{\Lambda}(\mathbf{q})\ddot{\mathbf{x}} + \boldsymbol{\mu}(\mathbf{q},\dot{\mathbf{q}}) + \mathbf{p}(\mathbf{q}) = \mathbf{F}. \]

Positive definiteness of \( \boldsymbol{\Lambda}(\mathbf{q}) \). Since \( \mathbf{M}(\mathbf{q}) \) is positive definite and \( \mathbf{J}(\mathbf{q}) \) has full row rank, for any nonzero \( \mathbf{y} \in \mathbb{R}^m \) we have

\[ \mathbf{y}^{\top} \mathbf{J}\mathbf{M}^{-1}\mathbf{J}^{\top}\mathbf{y} = (\mathbf{J}^{\top}\mathbf{y})^{\top} \mathbf{M}^{-1} (\mathbf{J}^{\top}\mathbf{y}) > 0, \]

so \( \mathbf{J}\mathbf{M}^{-1}\mathbf{J}^{\top} \) is positive definite and its inverse \( \boldsymbol{\Lambda}(\mathbf{q}) \) is positive definite. This guarantees that each task coordinate behaves like a point mass with configuration-dependent inertia.

3. Operational-Space Control Law

Suppose we are given a desired smooth task trajectory \( \mathbf{x}_d(t) \) with \( \dot{\mathbf{x}}_d(t), \ddot{\mathbf{x}}_d(t) \). Define the tracking error

\[ \mathbf{e} \triangleq \mathbf{x} - \mathbf{x}_d, \qquad \dot{\mathbf{e}} \triangleq \dot{\mathbf{x}} - \dot{\mathbf{x}}_d. \]

Let \( \mathbf{K}_P, \mathbf{K}_D \in \mathbb{R}^{m \times m} \) be symmetric positive-definite gain matrices. We choose a desired task-space acceleration shaping law

\[ \ddot{\mathbf{x}}_r \triangleq \ddot{\mathbf{x}}_d - \mathbf{K}_D \dot{\mathbf{e}} - \mathbf{K}_P \mathbf{e}. \]

The operational-space control law is then

\[ \begin{aligned} \mathbf{F} &= \boldsymbol{\Lambda}(\mathbf{q})\ddot{\mathbf{x}}_r + \boldsymbol{\mu}(\mathbf{q},\dot{\mathbf{q}}) + \mathbf{p}(\mathbf{q}), \\ \boldsymbol{\tau} &= \mathbf{J}(\mathbf{q})^{\top}\mathbf{F}. \end{aligned} \]

Closed-loop task-space dynamics. Assuming perfect modeling and neglecting unmodeled disturbances, the true task-space dynamics satisfy

\[ \boldsymbol{\Lambda}(\mathbf{q})\ddot{\mathbf{x}} + \boldsymbol{\mu}(\mathbf{q},\dot{\mathbf{q}}) + \mathbf{p}(\mathbf{q}) = \mathbf{F}. \]

Substituting the control law:

\[ \begin{aligned} \boldsymbol{\Lambda}\ddot{\mathbf{x}} + \boldsymbol{\mu} + \mathbf{p} &= \boldsymbol{\Lambda}\ddot{\mathbf{x}}_r + \boldsymbol{\mu} + \mathbf{p} \\ \Rightarrow\quad \boldsymbol{\Lambda}(\ddot{\mathbf{x}} - \ddot{\mathbf{x}}_r) &= \mathbf{0}. \end{aligned} \]

Using the definition of \( \ddot{\mathbf{x}}_r \) and \( \mathbf{e} \),

\[ \begin{aligned} \ddot{\mathbf{x}} - \ddot{\mathbf{x}}_r &= \ddot{\mathbf{x}} - \ddot{\mathbf{x}}_d + \mathbf{K}_D \dot{\mathbf{e}} + \mathbf{K}_P \mathbf{e} \\ &= \ddot{\mathbf{e}} + \mathbf{K}_D \dot{\mathbf{e}} + \mathbf{K}_P \mathbf{e}. \end{aligned} \]

Hence

\[ \boldsymbol{\Lambda}(\mathbf{q}) \left( \ddot{\mathbf{e}} + \mathbf{K}_D \dot{\mathbf{e}} + \mathbf{K}_P \mathbf{e} \right) = \mathbf{0}. \]

Since \( \boldsymbol{\Lambda}(\mathbf{q}) \) is positive definite, the only solution is

\[ \ddot{\mathbf{e}} + \mathbf{K}_D \dot{\mathbf{e}} + \mathbf{K}_P \mathbf{e} = \mathbf{0}, \]

i.e., each component of the task error behaves as a second-order linear system with characteristic polynomial \( s^2 + K_{D,i} s + K_{P,i} \) (for diagonal gains), which is exponentially stable for positive gains. This is the key structural property: operational-space control shapes task-space behavior directly.

4. Control Structure Overview

The controller can be seen as an outer loop in task coordinates and an inner map that converts the desired task-space wrench into joint torques.

flowchart TD
  Xd["Desired task trajectory: x_d, x_d_dot, x_d_ddot"] --> ERR["Compute task error: e, e_dot"]
  ERR --> XREF["Compute desired task acceleration x_ddot_ref"]
  XREF --> DYN["Evaluate robot model: M(q), h(q,q_dot), J(q), J_dot(q,q_dot)"]
  DYN --> OPS["Compute Lambda(q), mu(q,q_dot), p(q)"]
  OPS --> FCTRL["Compute task wrench F"]
  FCTRL --> TAU["Map to joint torques: tau = J(q)^T F"]
  TAU --> ACT["Send tau to low-level torque controllers"]
        

In redundant manipulators, one usually adds a null-space torque that does not affect the task; this will be treated systematically in the next lesson on redundancy handling.

5. Algorithmic Steps and Numerical Considerations

At each control cycle, the operational-space controller performs:

  1. Read joint states \( \mathbf{q}, \dot{\mathbf{q}} \).
  2. Compute task state \( \mathbf{x} = \mathbf{f}(\mathbf{q}) \) and \( \dot{\mathbf{x}} = \mathbf{J}(\mathbf{q})\dot{\mathbf{q}} \).
  3. Compute tracking error \( \mathbf{e}, \dot{\mathbf{e}} \).
  4. Compute desired task acceleration \( \ddot{\mathbf{x}}_r = \ddot{\mathbf{x}}_d - \mathbf{K}_D \dot{\mathbf{e}} - \mathbf{K}_P \mathbf{e} \).
  5. Evaluate joint-space dynamics \( \mathbf{M}, \mathbf{C}, \mathbf{g} \) and Jacobian \( \mathbf{J}, \dot{\mathbf{J}} \).
  6. Compute \( \boldsymbol{\Lambda}, \boldsymbol{\mu}, \mathbf{p} \) and then task wrench \( \mathbf{F} = \boldsymbol{\Lambda}\ddot{\mathbf{x}}_r + \boldsymbol{\mu} + \mathbf{p} \).
  7. Compute joint torques \( \boldsymbol{\tau} = \mathbf{J}^{\top}\mathbf{F} \) and send them to the low-level actuator controller.

Numerically, particular care is needed when \( \mathbf{J}\mathbf{M}^{-1}\mathbf{J}^{\top} \) is close to singular (e.g., near kinematic singularities), where one may use damping or task re-definition.

6. Python Implementation (NumPy + Robotics Libraries)

In Python, we can implement operational-space control using numpy for linear algebra and connect to a dynamics library such as pinocchio or roboticstoolbox for \( \mathbf{M}, \mathbf{h}, \mathbf{J} \).


import numpy as np

def op_space_control_step(q, qd, x_d, xd_d, xdd_d,
                          Kp, Kd,
                          M, h, J, Jdot):
    """
    One step of operational-space control.

    Parameters
    ----------
    q, qd : (n,) arrays
        Joint positions and velocities.
    x_d, xd_d, xdd_d : (m,) arrays
        Desired task position, velocity, acceleration.
    Kp, Kd : (m, m) arrays
        Task-space gain matrices (typically diagonal and positive).
    M : (n, n) array
        Joint-space inertia at q.
    h : (n,) array
        Joint-space nonlinear term C(q,qd)@qd + g(q).
    J : (m, n) array
        Task Jacobian at q.
    Jdot : (m, n) array
        Time derivative of J(q) evaluated at (q, qd).

    Returns
    -------
    tau : (n,) array
        Joint torques for this step.
    """
    # Task-space state
    # Here x, xd should be computed from the robot model; we pass them in or compute outside.
    # Assume we are given current x and xd:
    # x = f(q); xd = J @ qd
    # For modularity, let caller provide x, xd if needed.
    # For this core routine, we derive them from J:
    # WARNING: this assumes x and xd are known; here we only need xd for error derivative.

    # Caller should compute x and xd; for demo:
    # x = x_current
    # xd = J @ qd
    # For this snippet, assume x, xd known outside and precomputed.
    raise_not_implemented = False
    if raise_not_implemented:
        raise NotImplementedError("Provide current x and xd from the kinematics model.")

    # Example: assume x and xd are globals or closure variables (pseudo-code)
    # x, xd = current_task_state(q, qd)

    # Placeholders to indicate interface:
    x = np.zeros_like(x_d)
    xd = np.zeros_like(x_d)

    # Task-space error
    e = x - x_d
    ed = xd - xd_d

    # Desired task acceleration
    xdd_ref = xdd_d - Kd @ ed - Kp @ e

    # Lambda = (J M^-1 J^T)^-1
    Minv = np.linalg.inv(M)
    JMJT = J @ Minv @ J.T
    Lambda = np.linalg.inv(JMJT)

    # Task-space mu and p
    # Split h into Coriolis-like and gravity parts if available.
    # For the structure here we assume h = C(q,qd)@qd + g(q) and the library provides them separately.
    # Here, just demonstrate the structure:
    mu = Lambda @ (J @ Minv @ h) - Lambda @ (Jdot @ qd)

    # If you have g(q) explicitly, replace the next two lines by:
    # h_c = h_coriolis(q, qd)
    # g_vec = g(q)
    # mu = Lambda @ (J @ Minv @ h_c) - Lambda @ (Jdot @ qd)
    # p  = Lambda @ (J @ Minv @ g_vec)

    p = np.zeros_like(x_d)  # placeholder if gravity is already compensated in h

    # Task-space wrench
    F = Lambda @ xdd_ref + mu + p

    # Joint torques
    tau = J.T @ F
    return tau
      

In a real implementation, the quantities M, h, J, Jdot are obtained from a rigid-body dynamics library. For example, with pinocchio you would use pinocchio.crba for M, pinocchio.rnea for h, and pinocchio.computeJointJacobians / pinocchio.getFrameJacobian for the Jacobian.

7. C++ Implementation (Eigen + Rigid-Body Libraries)

In C++, we typically combine Eigen for linear algebra with a dynamics engine such as RBDL or Pinocchio. The snippet below focuses on the algebraic part, assuming calls to the library provide \( \mathbf{M}, \mathbf{h}, \mathbf{J}, \dot{\mathbf{J}} \).


#include <Eigen/Dense>

using Eigen::MatrixXd;
using Eigen::VectorXd;

struct OpSpaceGains {
    MatrixXd Kp;
    MatrixXd Kd;
};

VectorXd opSpaceControlStep(
    const VectorXd& q,
    const VectorXd& qd,
    const VectorXd& x,
    const VectorXd& xd,
    const VectorXd& x_d,
    const VectorXd& xd_d,
    const VectorXd& xdd_d,
    const OpSpaceGains& gains,
    const MatrixXd& M,
    const VectorXd& h,
    const MatrixXd& J,
    const MatrixXd& Jdot)
{
    const int m = x.size();

    // Errors
    VectorXd e  = x  - x_d;
    VectorXd ed = xd - xd_d;

    // Desired task acceleration
    VectorXd xdd_ref = xdd_d
                       - gains.Kd * ed
                       - gains.Kp * e;

    // Lambda = (J M^-1 J^T)^-1
    MatrixXd Minv = M.inverse();
    MatrixXd JMJT = J * Minv * J.transpose();
    MatrixXd Lambda = JMJT.inverse();

    // Task-space mu and p (gravity could be split if available)
    VectorXd mu = Lambda * (J * Minv * h) - Lambda * (Jdot * qd);
    VectorXd p  = VectorXd::Zero(m); // if gravity already in h

    VectorXd F = Lambda * xdd_ref + mu + p;

    // tau = J^T F
    VectorXd tau = J.transpose() * F;
    return tau;
}
      

With RBDL, for instance, you would call CompositeRigidBodyAlgorithm for M, InverseDynamics for h, and CalcPointJacobian6D or frame Jacobian routines for J.

8. Java Implementation (EJML Example)

Java does not have a canonical robotics library, but EJML provides efficient matrices. Below is a sketch of the controller core using EJML's SimpleMatrix.


import org.ejml.simple.SimpleMatrix;

public class OpSpaceController {

    public static SimpleMatrix step(
            SimpleMatrix q,
            SimpleMatrix qd,
            SimpleMatrix x,
            SimpleMatrix xd,
            SimpleMatrix x_d,
            SimpleMatrix xd_d,
            SimpleMatrix xdd_d,
            SimpleMatrix Kp,
            SimpleMatrix Kd,
            SimpleMatrix M,
            SimpleMatrix h,
            SimpleMatrix J,
            SimpleMatrix Jdot) {

        // Errors
        SimpleMatrix e  = x.minus(x_d);
        SimpleMatrix ed = xd.minus(xd_d);

        // Desired task acceleration
        SimpleMatrix xdd_ref = xdd_d
                .minus(Kd.mult(ed))
                .minus(Kp.mult(e));

        // Lambda = (J M^-1 J^T)^-1
        SimpleMatrix Minv = M.invert();
        SimpleMatrix JMJT = J.mult(Minv).mult(J.transpose());
        SimpleMatrix Lambda = JMJT.invert();

        // Task-space mu and p
        SimpleMatrix mu = Lambda.mult(J.mult(Minv).mult(h))
                .minus(Lambda.mult(Jdot.mult(qd)));

        SimpleMatrix p = new SimpleMatrix(mu.numRows(), 1);
        p.zero(); // assume gravity is handled in h

        SimpleMatrix F = Lambda.mult(xdd_ref).plus(mu).plus(p);

        // Joint torques tau = J^T F
        SimpleMatrix tau = J.transpose().mult(F);
        return tau;
    }
}
      

This structure can be integrated in a Java-based robotic framework or middleware (for example, via ROS nodes written in Java).

9. MATLAB / Simulink Implementation

MATLAB, together with the Robotics System Toolbox, provides ready-made functions for dynamics and Jacobians. A simple function that computes operational-space torques is:


function tau = opSpaceControlStep(q, qd, x, xd, x_d, xd_d, xdd_d, Kp, Kd, robot)
% OPSPACECONTROLSTEP  One control step of operational-space control.
%
% Inputs:
%   q, qd   : joint position and velocity (n x 1)
%   x, xd   : current task position and velocity (m x 1)
%   x_d, xd_d, xdd_d : desired task trajectory signals (m x 1)
%   Kp, Kd  : task-space gains (m x m)
%   robot   : rigidBodyTree model (Robotics System Toolbox)
%
% Output:
%   tau     : joint torques (n x 1)

    % Errors
    e  = x  - x_d;
    ed = xd - xd_d;

    % Desired task acceleration
    xdd_ref = xdd_d - Kd * ed - Kp * e;

    % Joint-space inertia and nonlinear terms
    M = massMatrix(robot, q');
    % generalized forces from inverseDynamics with zero acceleration
    h = inverseDynamics(robot, q', qd', zeros(size(q')));

    % End-effector Jacobian and its derivative (approx via finite difference
    % or robot-specific routine)
    eeName = robot.BodyNames{end};
    J = geometricJacobian(robot, q', eeName); % 6 x n for full spatial
    % For a pure position task, select top 3 rows:
    Jpos = J(1:3, :);

    % Approximate Jdot * qd via numerical differentiation or compute analytically
    Jdot_qd = zeros(size(Jpos, 1), 1); % placeholder

    Minv = inv(M);
    JMJT = Jpos * Minv * Jpos';
    Lambda = inv(JMJT);

    mu = Lambda * (Jpos * Minv * h) - Lambda * Jdot_qd;
    p  = zeros(size(mu)); % if gravity already in h

    F = Lambda * xdd_ref + mu + p;

    tau = Jpos' * F;
end
      

In Simulink, a common pattern is to wrap this function in a MATLAB Function block inside a control subsystem. The block receives q, qd, x, xd, x_d, xd_d, xdd_d from upstream blocks and outputs tau to the torque input of the plant model.

10. Wolfram Mathematica Implementation (Symbolic / Numeric)

Wolfram Mathematica is well suited for symbolic derivation of \( \boldsymbol{\Lambda}, \boldsymbol{\mu}, \mathbf{p} \) and numerical evaluation. A simplified sketch is:


(* Define joint and task variables *)
n = 2; (* example: planar 2R *)
q  = Array[q, n];
qd = Array[qd, n];

(* Define kinematics x = f(q): for instance, planar arm *)
l1 = 1; l2 = 1;
xPos[q1_, q2_] := l1 Cos[q1] + l2 Cos[q1 + q2];
yPos[q1_, q2_] := l1 Sin[q1] + l2 Sin[q1 + q2];
xVec = {xPos[q[[1]], q[[2]]], yPos[q[[1]], q[[2]]]};

(* Jacobian *)
J = D[xVec, {q}];

(* Assume symbolic inertia M(q) and nonlinear term h(q,qd) *)
M = { {m11[q[[1]], q[[2]]], m12[q[[1]], q[[2]]]},
     {m12[q[[1]], q[[2]]], m22[q[[1]], q[[2]]]} }
    ;
h = {h1[q[[1]], q[[2]], qd[[1]], qd[[2]]],
     h2[q[[1]], q[[2]], qd[[1]], qd[[2]]]}
    ;

(* Operational-space inertia *)
Lambda = Inverse[J . Inverse[M] . Transpose[J]] // Simplify;

(* Time derivative of J times qd *)
Jdot = D[J, {q}].qd; (* 3-tensor contracted with qd *)

(* Task-space nonlinear terms (symbolic forms) *)
mu = Lambda . (J . Inverse[M] . h) - Lambda . Jdot . qd;
(* For gravity p, separate g(q) from h if available *)

(* Control law (symbolic) *)
Kp = { {kp1, 0}, {0, kp2} };
Kd = { {kd1, 0}, {0, kd2} };

x    = xVec;
xd   = J . qd;
xDes = {x1d[t], x2d[t]};  (* user-defined trajectories *)
xdDes  = D[xDes, t];
xddDes = D[xDes, {t, 2}];

e  = x - xDes;
ed = xd - xdDes;

xddRef = xddDes - Kd . ed - Kp . e;

F = Lambda . xddRef + mu; (* ignoring p for brevity *)

(* Joint torques *)
tau = Transpose[J] . F // Simplify;
      

This environment is particularly helpful for verifying the analytical form of \( \boldsymbol{\Lambda}(\mathbf{q}) \) and exploring special configurations symbolically before implementing numerical code.

11. Problems and Solutions

Problem 1 (Positive Definiteness of Task-Space Inertia): Let \( \mathbf{M}(\mathbf{q}) \) be positive definite and \( \mathbf{J}(\mathbf{q}) \) have full row rank \( m \). Prove that \( \mathbf{J}\mathbf{M}^{-1}\mathbf{J}^{\top} \) is positive definite and thus \( \boldsymbol{\Lambda}(\mathbf{q}) \) is positive definite.

Solution: For any nonzero \( \mathbf{y} \in \mathbb{R}^m \), set \( \mathbf{z} \triangleq \mathbf{J}^{\top}\mathbf{y} \). Since \( \mathbf{J} \) has full row rank, \( \mathbf{J}^{\top} \) has trivial nullspace in \( \mathbb{R}^m \), hence \( \mathbf{y} \neq \mathbf{0} \Rightarrow \mathbf{z} \neq \mathbf{0} \). Then

\[ \mathbf{y}^{\top}\mathbf{J}\mathbf{M}^{-1}\mathbf{J}^{\top}\mathbf{y} = (\mathbf{J}^{\top}\mathbf{y})^{\top} \mathbf{M}^{-1} (\mathbf{J}^{\top}\mathbf{y}) = \mathbf{z}^{\top}\mathbf{M}^{-1}\mathbf{z}. \]

Because \( \mathbf{M}^{-1} \) is positive definite, \( \mathbf{z}^{\top}\mathbf{M}^{-1}\mathbf{z} > 0 \) for all nonzero \( \mathbf{z} \), hence \( \mathbf{J}\mathbf{M}^{-1}\mathbf{J}^{\top} \) is positive definite. Its inverse \( \boldsymbol{\Lambda}(\mathbf{q}) \) is therefore positive definite as well.

Problem 2 (Closed-Loop Dynamics in Operational Space): Consider the operational-space control law of Section 3 with constant diagonal gains \( \mathbf{K}_P = \mathrm{diag}(k_{P,1},\dots,k_{P,m}) \), \( \mathbf{K}_D = \mathrm{diag}(k_{D,1},\dots,k_{D,m}) \), where \( k_{P,i} > 0, k_{D,i} > 0 \). Show that the error dynamics are exponentially stable.

Solution: As derived earlier, the closed-loop error dynamics satisfy

\[ \ddot{\mathbf{e}} + \mathbf{K}_D \dot{\mathbf{e}} + \mathbf{K}_P \mathbf{e} = \mathbf{0}. \]

Because \( \mathbf{K}_P \) and \( \mathbf{K}_D \) are diagonal and positive definite, the system decouples into \( m \) scalar second-order ODEs:

\[ \ddot{e}_i + k_{D,i} \dot{e}_i + k_{P,i} e_i = 0, \quad i = 1,\dots,m. \]

The characteristic polynomial of the \( i \)-th mode is \( s^2 + k_{D,i}s + k_{P,i} \). With \( k_{D,i} > 0 \) and \( k_{P,i} > 0 \), both roots have strictly negative real part (by the Routh–Hurwitz criterion for second-order polynomials). Therefore all modes are exponentially stable, and the vector error \( \mathbf{e}(t) \) converges to zero exponentially fast.

Problem 3 (Operational-Space Inertia of a Planar 2R Manipulator): Consider a planar 2R manipulator with link lengths \( l_1, l_2 \) and joint-space inertia \( \mathbf{M}(\mathbf{q}) \). The end-effector planar position is \( \mathbf{x} = [x \; y]^{\top} \). Given the translational Jacobian

\[ \mathbf{J}(\mathbf{q}) = \begin{bmatrix} -l_1 \sin q_1 - l_2 \sin(q_1 + q_2) & -l_2 \sin(q_1 + q_2) \\ l_1 \cos q_1 + l_2 \cos(q_1 + q_2) & l_2 \cos(q_1 + q_2) \end{bmatrix}, \]

express the operational-space inertia \( \boldsymbol{\Lambda}(\mathbf{q}) \) as \( \boldsymbol{\Lambda}(\mathbf{q}) = (\mathbf{J}\mathbf{M}^{-1}\mathbf{J}^{\top})^{-1} \).

Solution: For \( n = m = 2 \), the inverse \( \mathbf{M}^{-1}(\mathbf{q}) \) exists and \( \mathbf{J}\mathbf{M}^{-1}\mathbf{J}^{\top} \) is a \( 2 \times 2 \) symmetric matrix. The operational-space inertia is

\[ \boldsymbol{\Lambda}(\mathbf{q}) = \left( \mathbf{J}(\mathbf{q})\mathbf{M}(\mathbf{q})^{-1}\mathbf{J}(\mathbf{q})^{\top} \right)^{-1}. \]

Writing \( \mathbf{A}(\mathbf{q}) \triangleq \mathbf{J}(\mathbf{q})\mathbf{M}(\mathbf{q})^{-1}\mathbf{J}(\mathbf{q})^{\top} \), we can compute its inverse explicitly: for a general \( 2 \times 2 \) matrix \( \mathbf{A} = \begin{bmatrix} a & b \\ b & d \end{bmatrix} \) with \( ad - b^2 \neq 0 \), \( \mathbf{A}^{-1} = \frac{1}{ad - b^2} \begin{bmatrix} d & -b \\ -b & a \end{bmatrix} \). Substituting the symbolic expressions of \( a, b, d \) obtained from the product yields \( \boldsymbol{\Lambda}(\mathbf{q}) \).

Problem 4 (Mapping Wrench to Joint Torques): Starting from the virtual work principle, show that the mapping between an end-effector wrench \( \mathbf{F} \) and joint torques \( \boldsymbol{\tau} \) must be \( \boldsymbol{\tau} = \mathbf{J}^{\top}\mathbf{F} \).

Solution: Let \( \delta \mathbf{q} \) be an arbitrary virtual joint displacement and \( \delta \mathbf{x} = \mathbf{J}(\mathbf{q})\delta \mathbf{q} \) the resulting virtual task displacement. The virtual work in task space is \( \delta W_x = \mathbf{F}^{\top}\delta \mathbf{x} \), while in joint space it is \( \delta W_q = \boldsymbol{\tau}^{\top}\delta \mathbf{q} \). Conservation of virtual work requires

\[ \boldsymbol{\tau}^{\top}\delta \mathbf{q} = \mathbf{F}^{\top}\delta \mathbf{x} = \mathbf{F}^{\top}\mathbf{J}(\mathbf{q})\delta \mathbf{q} = \left(\mathbf{J}(\mathbf{q})^{\top}\mathbf{F}\right)^{\top} \delta \mathbf{q}. \]

Since this must hold for all virtual displacements \( \delta \mathbf{q} \), we conclude \( \boldsymbol{\tau} = \mathbf{J}(\mathbf{q})^{\top}\mathbf{F} \).

12. Summary

In this lesson we constructed the operational-space representation of robot dynamics, starting from the joint-space equation of motion. The key object is the task-space inertia \( \boldsymbol{\Lambda}(\mathbf{q}) \), defined as the inverse of \( \mathbf{J}\mathbf{M}^{-1}\mathbf{J}^{\top} \), which is guaranteed to be positive definite when the Jacobian has full row rank.

Using this representation, we built a model-based controller that works directly in task space: a PD-like law in \( \mathbf{x} \) combined with inverse dynamics compensation in operational space. We showed that, under perfect modeling, the task-space tracking error obeys a decoupled linear second-order ODE with tunable gains. Finally, we mapped the structure to Python, C++, Java, MATLAB/Simulink, and Wolfram Mathematica implementations, preparing the ground for redundancy handling and task hierarchies in subsequent lessons.

13. References

  1. Khatib, O. (1987). A unified approach for motion and force control of robot manipulators: The operational space formulation. IEEE Journal on Robotics and Automation, 3(1), 43–53.
  2. Khatib, O. (1995). Inertial properties in robotic manipulation: An object-level framework. International Journal of Robotics Research, 14(1), 19–36.
  3. Slotine, J.-J. E., & Li, W. (1987). On the adaptive control of robot manipulators. International Journal of Robotics Research, 6(3), 49–59.
  4. Siciliano, B. (1990). Unified task-space formulation for robot control. International Journal of Control, 51(6), 1243–1266.
  5. Sciavicco, L., & Siciliano, B. (1988). A solution algorithm to the inverse kinematic problem for redundant manipulators. IEEE Journal on Robotics and Automation, 4(4), 403–410.
  6. Murray, R. M., Li, Z., & Sastry, S. S. (1994). A Mathematical Introduction to Robotic Manipulation. CRC Press.
  7. Yoshikawa, T. (1985). Manipulability of robotic mechanisms. International Journal of Robotics Research, 4(2), 3–9.
  8. Featherstone, R. (2008). Rigid Body Dynamics Algorithms. Springer.