Chapter 15: Learning-Augmented Control (Non-RL Focus)

Lesson 2: Residual / Delta-Model Learning

This lesson introduces residual (a.k.a. delta-model) learning as a way to correct modeling errors in robot dynamics and kinematics. We start from a nominal physics-based model and learn a data-driven correction term that augments model-based controllers such as computed-torque and operational-space control. We rigorously formulate residual and delta models, derive closed-loop properties, and give multi-language implementations (Python, C++, Java, MATLAB/Simulink, and Wolfram Mathematica).

1. Conceptual Overview

Assume you already have a nominal rigid-body model from previous robotics courses and earlier chapters: \( M(q)\ddot q + C(q,\dot q)\dot q + g(q) = \tau \) for joint position \( q \), velocity \( \dot q \), and torque \( \tau \). In reality, unmodeled friction, flexibilities, and disturbances make the true dynamics deviate from this expression.

Residual learning adds a learned correction term on top of a nominal model. In continuous time we may write the true dynamics as

\[ M(q)\ddot q + C(q,\dot q)\dot q + g(q) = \tau + d(q,\dot q,\ddot q,t), \]

where \( d(\cdot) \) is an unknown disturbance or modeling error. We choose a feature vector \( z = \phi(q,\dot q,\ddot q,q_d,\dot q_d,\ddot q_d,\dots) \) and approximate the disturbance by a parametric function \( r_\theta(z) \approx d(q,\dot q,\ddot q,t) \), trained from data.

In discrete time, with state \( x_k \) and input \( u_k \), a nominal model predicts \( f_\mathrm{nom}(x_k,u_k) \). Residual learning models the mismatch:

\[ x_{k+1} = f_\mathrm{nom}(x_k,u_k) + r_\theta(z_k), \quad z_k = \phi(x_k,u_k). \]

A closely related idea is the delta model, which directly learns the state increment \( \Delta x_k = x_{k+1} - x_k \) instead of the next state:

\[ \Delta x_k = \varphi_\theta(z_k), \quad x_{k+1} = x_k + \Delta x_k. \]

Intuitively, residual/delta models ask learning to solve only the hard part of the modeling problem (the mismatch), leaving the easy and well-understood part (rigid-body dynamics) to analytic models.

flowchart TD
  R["Reference trajectory r_k"] --> C0["Baseline controller u_nom_k"]
  C0 --> SUM["Sum"]
  RES["Residual model u_res_k = r_theta(z_k)"] --> SUM
  SUM --> U["Total torque u_k"]
  U --> P["Robot plant"]
  P --> Y["Measured state x_k"]
  Y --> E["Tracking error e_k"]
  E --> FEAT["Feature builder z_k = phi(x_k, r_k, e_k)"]
  FEAT --> RES
        

The baseline controller (e.g. computed-torque) is designed with a nominal model. The residual model adds a learned feedforward term \( u_\mathrm{res} \) to compensate the remaining error.

2. Mathematical Formulation of Residual and Delta Models

2.1 Residual modeling for robot dynamics

In rigid-body form, the true dynamics can be written as

\[ M(q)\ddot q + C(q,\dot q)\dot q + g(q) + f_\mathrm{nl}(q,\dot q,\ddot q,t) = \tau, \]

where \( f_\mathrm{nl} \) collects unmodeled terms such as friction, flexibility, and actuator nonlinearities. A nominal model uses \( \hat M,\hat C,\hat g \) and ignores \( f_\mathrm{nl} \):

\[ \hat M(q)\ddot q + \hat C(q,\dot q)\dot q + \hat g(q) = \tau. \]

Define the torque residual

\[ r^\ast(q,\dot q,\ddot q,t) := \bigl(M(q)-\hat M(q)\bigr)\ddot q + \bigl(C(q,\dot q)-\hat C(q,\dot q)\bigr)\dot q + \bigl(g(q)-\hat g(q)\bigr) + f_\mathrm{nl}(q,\dot q,\ddot q,t). \]

We choose features \( z = \phi(q,\dot q,\ddot q, q_d,\dot q_d,\ddot q_d) \) and approximate the true residual by some parametric function \( r_\theta: \mathbb{R}^m \to \mathbb{R}^n \):

\[ r_\theta(z) \approx r^\ast(q,\dot q,\ddot q,t). \]

2.2 Residual regression problem

Suppose we collect a dataset of \( N \) samples during robot operation:

  • \( z_i \in \mathbb{R}^m \): features (state, reference, errors),
  • \( y_i \in \mathbb{R}^n \): observed residual targets obtained from sensor data.

For torque residuals, one common construction is

\[ y_i := \tau_i^\mathrm{meas} - \tau_i^\mathrm{nom}, \]

where \( \tau_i^\mathrm{meas} \) is the torque that actually produced the motion (estimated from current and motor constants), and \( \tau_i^\mathrm{nom} \) is the torque computed from the nominal model for the same sample.

The residual learning problem is then a standard supervised regression:

\[ \min_{\theta} J(\theta) := \frac{1}{N} \sum_{i=1}^N \bigl\| y_i - r_\theta(z_i) \bigr\|^2 + \lambda \, \Omega(\theta), \]

where \( \Omega(\theta) \) is a regularizer (e.g. squared Euclidean norm) and \( \lambda \ge 0 \).

2.3 Delta models in discrete time

For discrete-time control, it is often numerically convenient to learn the state increment. For state \( x_k \) and input \( u_k \), define

\[ \Delta x_k := x_{k+1} - x_k. \]

A delta model uses features \( z_k = \phi(x_k,u_k) \) and predicts \( \Delta x_k \):

\[ \Delta x_k \approx \varphi_\theta(z_k), \quad x_{k+1} = x_k + \varphi_\theta(z_k). \]

If a nominal discrete-time model \( f_\mathrm{nom}(x_k,u_k) \) is available, residual and delta views are related by

\[ r_\theta(z_k) = f_\theta(x_k,u_k) - f_\mathrm{nom}(x_k,u_k), \quad \varphi_\theta(z_k) = f_\theta(x_k,u_k) - x_k. \]

In practice, one usually chooses whichever target \( y_i \) yields numerically well-scaled values and smooth dependence on \( z_i \).

3. Closed-Loop Integration and Stability Considerations

3.1 Residual-augmented computed-torque control

Consider standard joint-space tracking with a computed-torque controller designed using the nominal model:

\[ \tau_\mathrm{nom} = \hat M(q)\bigl(\ddot q_d + K_d(\dot q_d - \dot q) + K_p(q_d - q)\bigr) + \hat C(q,\dot q)\dot q + \hat g(q), \]

with positive-definite gains \( K_p,K_d \). Define the tracking error and its derivative:

\[ e := q_d - q, \quad \dot e := \dot q_d - \dot q. \]

Using the true dynamics with disturbance \( d(q,\dot q,\ddot q,t) \) defined in Section 1, the closed-loop error equation (after standard manipulations you have seen in nonlinear control for manipulators) becomes

\[ M(q)\ddot e + C(q,\dot q)\dot e + K_d \dot e + K_p e = d(q,\dot q,\ddot q,t). \]

With a residual feedforward term \( r_\theta(z) \), we command

\[ \tau = \tau_\mathrm{nom} + r_\theta(z), \]

and the error dynamics become

\[ M(q)\ddot e + C(q,\dot q)\dot e + K_d \dot e + K_p e = d(q,\dot q,\ddot q,t) - r_\theta(z). \]

If the residual model were exact, \( r_\theta(z) \equiv d(q,\dot q,\ddot q,t) \), the right-hand side would vanish, and we would recover the ideal linear error dynamics induced by the computed-torque design. In practice there is a modeling error

\[ \varepsilon(z) := d(q,\dot q,\ddot q,t) - r_\theta(z), \]

so the residual-augmented controller reduces but does not entirely eliminate modeling error.

3.2 Simple Lyapunov bound with residual error

Use the standard Lyapunov function for tracking:

\[ V(e,\dot e) = \frac{1}{2}\dot e^\top M(q)\dot e + \frac{1}{2} e^\top K_p e. \]

Under the usual skew-symmetry property of rigid-body dynamics, \( \dot M(q) - 2C(q,\dot q) \) is skew-symmetric, one obtains the derivative along closed-loop trajectories

\[ \dot V = - \dot e^\top K_d \dot e + \dot e^\top \varepsilon(z). \]

Assume that the residual modeling error is locally Lipschitz in \( e,\dot e \) near the desired trajectory. For example, suppose there exist constants \( c_1,c_2 \ge 0 \) such that

\[ \|\varepsilon(z)\| \le c_1 \|e\| + c_2 \|\dot e\|. \]

Then, using Cauchy–Schwarz and Young-type inequalities, one can derive bounds of the form

\[ \dot V \le - \alpha_1 \|\dot e\|^2 + \alpha_2 \|e\|^2, \]

with suitable constants \( \alpha_1,\alpha_2 > 0 \) that depend on \( K_d \) and the Lipschitz constants. This is a standard input-to-state stability (ISS) situation: if the residual error \( \varepsilon \) remains small, the tracking error remains bounded and can be made arbitrarily small by choosing sufficiently large gains and a sufficiently accurate residual model.

Thus, as long as the learned residual does not introduce large unmodeled dynamics (e.g. oscillatory behavior) and is trained on data that cover the operating region of interest, residual learning can be added without destroying the qualitative stability properties of a well-designed nominal controller.

4. Training Pipelines for Residual / Delta Models

There are two standard workflows:

  1. Offline residual learning: collect trajectories using a robust baseline controller, estimate residual targets, train a regression model, then deploy.
  2. Online or iterative residual learning: periodically update the residual model during operation or experiment cycles.
flowchart TD
  A["Design baseline controller with nominal model"] --> B["Run robot experiments"]
  B --> C["Log (x_k, u_k, x_{k+1}) and nominal predictions"]
  C --> D["Compute residual or delta targets y_k"]
  D --> E["Train regressor r_theta or phi_theta"]
  E --> F["Integrate trained model in controller"]
  F --> G{"Performance satisfactory?"}
  G -->|no| B
  G -->|yes| H["Deploy residual-augmented controller"]
        

For robot control, data efficiency and safety are crucial:

  • Use safe baseline controllers (e.g. robust or conservative adaptive controllers) during data collection.
  • Regularize residual models so that they vanish near the equilibrium when data are scarce, reducing the risk of destabilizing corrections.
  • Restrict residual updates to bandwidths slower than the main feedback loop to avoid interaction with fast dynamics.

5. Python Implementation — Residual Torque Learning

We implement a simple residual torque learner in Python. For robotics modeling, one may use roboticstoolbox-python and for learning PyTorch. Here we show a minimal example for a 1-DOF rotary joint, where the nominal model is slightly wrong and a small neural network learns the residual torque.


import numpy as np
import torch
from torch import nn

# True and nominal parameters for a 1-DOF rotary arm
I_true = 1.2
b_true = 0.3
g_true = 9.81

I_nom = 1.0
b_nom = 0.4
g_nom = 9.0

dt = 0.002

def true_ddq(q, dq, tau):
    # True acceleration
    return (tau - b_true * dq - g_true * np.sin(q)) / I_true

def nominal_tau(q, dq, ddq_des):
    # Nominal inverse dynamics: tau_nom = I_nom * ddq_des + b_nom * dq + g_nom * sin(q)
    return I_nom * ddq_des + b_nom * dq + g_nom * np.sin(q)

class ResidualNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(4, 64),
            nn.Tanh(),
            nn.Linear(64, 1)
        )

    def forward(self, x):
        return self.net(x)

# Data collection with a simple PD baseline
def collect_data(num_steps=20000):
    q = 0.0
    dq = 0.0
    qd = 0.5
    dqd = 0.0

    Kp = 20.0
    Kd = 4.0

    inputs = []
    targets = []

    for k in range(num_steps):
        e = qd - q
        de = dqd - dq
        ddq_des = Kp * e + Kd * de
        tau_nom = nominal_tau(q, dq, ddq_des)

        # Assume commanded torque equals tau_nom during data collection
        ddq = true_ddq(q, dq, tau_nom)

        # Features: [q, dq, ddq_des, e]
        z = np.array([q, dq, ddq_des, e], dtype=np.float32)
        # Residual target: tau_true - tau_nom
        tau_true = tau_nom  # because we use tau_nom in simulation
        # Here we artificially introduce model error as an unknown disturbance
        disturbance = 0.2 * np.tanh(dq) + 0.1 * np.sin(3.0 * q)
        tau_true = tau_true + disturbance

        y = tau_true - tau_nom

        inputs.append(z)
        targets.append(np.array([y], dtype=np.float32))

        # Simulate forward with the true dynamics including the disturbance
        ddq_true = (tau_true - b_true * dq - g_true * np.sin(q)) / I_true
        dq = dq + dt * ddq_true
        q = q + dt * dq

    X = torch.tensor(np.stack(inputs))
    Y = torch.tensor(np.stack(targets))
    return X, Y

net = ResidualNet()
optimizer = torch.optim.Adam(net.parameters(), lr=1e-3)
loss_fn = nn.MSELoss()

X, Y = collect_data()

for epoch in range(20):
    idx = torch.randint(0, X.shape[0], (1024,))
    xb = X[idx]
    yb = Y[idx]

    pred = net(xb)
    loss = loss_fn(pred, yb)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

# Use in control loop
def control_step(q, dq, qd, dqd):
    Kp = 20.0
    Kd = 4.0
    e = qd - q
    de = dqd - dq
    ddq_des = Kp * e + Kd * de
    tau_nom = nominal_tau(q, dq, ddq_des)
    z = torch.tensor([[q, dq, ddq_des, e]], dtype=torch.float32)
    tau_res = float(net(z).detach().numpy()[0, 0])
    tau_cmd = tau_nom + tau_res
    return tau_cmd
      

In a multi-DOF manipulator, one would typically compute tau_nom using a library such as roboticstoolbox or pinocchio, construct a multi-dimensional feature vector (containing joint states and desired accelerations), and train a vector-output network \( r_\theta(z) \in \mathbb{R}^n \).

6. C++ Implementation — Linear Residual Model with Eigen

In C++, libraries such as Eigen (for linear algebra) and pinocchio (for rigid-body dynamics) are common in robot control stacks (e.g. in ros_control). Below is a simple residual model of the form \( r_\theta(z) = W z \) with online gradient updates.


#include <Eigen/Dense>

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

struct ResidualModel {
    MatrixXd W;
    double eta;

    ResidualModel(int out_dim, int in_dim, double eta_)
        : W(MatrixXd::Zero(out_dim, in_dim)), eta(eta_) {}

    VectorXd predict(const VectorXd &phi) const {
        return W * phi;
    }

    void update(const VectorXd &phi, const VectorXd &target) {
        VectorXd err = predict(phi) - target;
        // SGD step: W = W - eta * err * phi^T
        W.noalias() -= eta * (err * phi.transpose());
    }
};

// Nominal computed-torque (here just as an interface)
VectorXd computeNominalTorque(const VectorXd &q,
                              const VectorXd &dq,
                              const VectorXd &qd,
                              const VectorXd &dqd,
                              const VectorXd &ddqd);

VectorXd buildFeatures(const VectorXd &q,
                       const VectorXd &dq,
                       const VectorXd &qd,
                       const VectorXd &dqd,
                       const VectorXd &ddqd) {
    // Example: stack [q; dq; qd; dqd; ddqd]
    int n = q.size();
    VectorXd phi(5 * n);
    phi.segment(0, n)      = q;
    phi.segment(n, n)      = dq;
    phi.segment(2 * n, n)  = qd;
    phi.segment(3 * n, n)  = dqd;
    phi.segment(4 * n, n)  = ddqd;
    return phi;
}

// One control step with residual augmentation and optional online learning
VectorXd controlStepResidual(ResidualModel &residual,
                             const VectorXd &q,
                             const VectorXd &dq,
                             const VectorXd &qd,
                             const VectorXd &dqd,
                             const VectorXd &ddqd,
                             const VectorXd &tau_meas,
                             bool do_update) {
    VectorXd phi = buildFeatures(q, dq, qd, dqd, ddqd);
    VectorXd tau_nom = computeNominalTorque(q, dq, qd, dqd, ddqd);
    VectorXd tau_res = residual.predict(phi);
    VectorXd tau_cmd = tau_nom + tau_res;

    if (do_update) {
        // Residual target: tau_meas - tau_nom
        VectorXd target = tau_meas - tau_nom;
        residual.update(phi, target);
    }

    return tau_cmd;
}
      

In a real implementation, tau_meas would be estimated from motor currents and actuator models; the code above can run inside a standard real-time control loop (e.g. in ROS) with the matrix sizes and learning rate eta tuned to respect timing constraints.

7. Java Implementation — Lightweight Residual Linear Model

While Java is less common for low-level robot control, it appears in higher-level stacks (e.g. ROSJava) and simulation environments. Libraries such as EJML or Apache Commons Math can support linear algebra. Below is a minimal residual torque model using plain arrays.


public class ResidualModel {
    private final int outDim;
    private final int inDim;
    private final double[][] W;
    private final double eta;

    public ResidualModel(int outDim, int inDim, double eta) {
        this.outDim = outDim;
        this.inDim = inDim;
        this.eta = eta;
        this.W = new double[outDim][inDim];
    }

    public double[] predict(double[] phi) {
        double[] y = new double[outDim];
        for (int i = 0; i < outDim; ++i) {
            double s = 0.0;
            for (int j = 0; j < inDim; ++j) {
                s += W[i][j] * phi[j];
            }
            y[i] = s;
        }
        return y;
    }

    public void update(double[] phi, double[] target) {
        double[] err = predict(phi);
        for (int i = 0; i < outDim; ++i) {
            err[i] -= target[i];
        }
        for (int i = 0; i < outDim; ++i) {
            for (int j = 0; j < inDim; ++j) {
                W[i][j] -= eta * err[i] * phi[j];
            }
        }
    }
}
      

This class can be integrated into a Java-based control or simulation loop, where phi is built from joint states and references, and target is computed as the torque residual \( \tau^\mathrm{meas} - \tau^\mathrm{nom} \).

8. MATLAB/Simulink Implementation — Residual Block

MATLAB and Simulink are widely used in control engineering. A common pattern is:

  • Use the Robotics System Toolbox or custom dynamics functions to compute nominal torques.
  • Implement the residual model in a MATLAB Function block in Simulink.
  • Train parameters offline using Optimization or Deep Learning Toolbox.

Below is a simple MATLAB function implementing an affine residual model \( r_\theta(z) = W z + b \) for a single joint:


function tau_cmd = residual_controller(q, dq, qd, dqd, ddqd, params)
% params.W : 1 x m row vector
% params.b : scalar
% Build features z = [q; dq; qd; dqd; ddqd]
z = [q; dq; qd; dqd; ddqd];

% Nominal torque from rigid-body model
tau_nom = nominal_torque(q, dq, ddqd);

% Residual torque
tau_res = params.W * z + params.b;

% Command torque
tau_cmd = tau_nom + tau_res;
end
      

In Simulink, this function can be called from a MATLAB Function block. The structure params can be updated between experiments using MATLAB scripts that fit params.W and params.b from logged data via lsqnonlin or deep-learning tools.

9. Wolfram Mathematica Implementation — Delta Model Fit

Mathematica is convenient for symbolic manipulations and for training small neural or regression models via NetTrain. The following snippet shows how to fit a delta model for a scalar state \( x_k \) and input \( u_k \).


(* Assume data is a list of triples {xk, uk, xk1} *)
ClearAll[buildDataset, deltaNet, trainedNet];

buildDataset[data_List] := Module[{zList, dxList},
  zList = data[[All, {1, 2}]]; (* {xk, uk} *)
  dxList = data[[All, 3]] - data[[All, 1]]; (* delta x *)
  Thread[zList -> dxList]
];

deltaNet[inDim_Integer] := NetChain[{
    LinearLayer[16],
    Tanh,
    LinearLayer[1]
  },
  "Input" -> inDim
];

trainDeltaModel[data_List] := Module[{ds, net},
  ds = buildDataset[data];
  net = deltaNet[2];
  trainedNet = NetTrain[net, ds];
  trainedNet
];

(* Closed-loop prediction step: x_{k+1} = x_k + phi_theta(z_k) *)
predictNextState[net_, xk_, uk_] := Module[{dx},
  dx = net[{xk, uk}];
  xk + dx
];
      

In higher-dimensional systems, \( x_k \) and \( u_k \) can be represented as vectors; one can then choose a vector-output network and adjust LinearLayer dimensions accordingly.

10. Problems and Solutions

Problem 1 (Exact residual and error dynamics): Consider the computed-torque controller with residual feedforward:

\[ \tau = \hat M(q)\bigl(\ddot q_d + K_d(\dot q_d - \dot q) + K_p(q_d - q)\bigr) + \hat C(q,\dot q)\dot q + \hat g(q) + r_\theta(z). \]

Assume the true dynamics satisfy \( M(q)\ddot q + C(q,\dot q)\dot q + g(q) = \tau \) and that \( r_\theta(z) \equiv r^\ast(q,\dot q,\ddot q,t) \) exactly matches the disturbance defined in Section 2. Show that the tracking error dynamics reduce to

\[ M(q)\ddot e + C(q,\dot q)\dot e + K_d \dot e + K_p e = 0. \]

Solution: From the definition of the disturbance \( r^\ast(\cdot) \), the true dynamics can be written as

\[ M(q)\ddot q + C(q,\dot q)\dot q + g(q) = \tau_\mathrm{nom} + r^\ast(q,\dot q,\ddot q,t), \]

where \( \tau_\mathrm{nom} \) is the nominal part of the controller. Substituting \( \tau = \tau_\mathrm{nom} + r_\theta(z) \) and using \( r_\theta(z) = r^\ast(\cdot) \) gives

\[ M(q)\ddot q + C(q,\dot q)\dot q + g(q) = \hat M(q)\bigl(\ddot q_d + K_d(\dot q_d - \dot q) + K_p(q_d - q)\bigr) + \hat C(q,\dot q)\dot q + \hat g(q). \]

Assuming the nominal and true models share the same structure so that \( \hat M = M \), \( \hat C = C \), and \( \hat g = g \) under exact identification, the expression simplifies to

\[ M(q)\ddot q + C(q,\dot q)\dot q + g(q) = M(q)\bigl(\ddot q_d + K_d(\dot q_d - \dot q) + K_p(q_d - q)\bigr) + C(q,\dot q)\dot q + g(q). \]

Cancelling common terms and recalling \( e = q_d - q \), \( \dot e = \dot q_d - \dot q \), we obtain

\[ M(q)\ddot e + C(q,\dot q)\dot e + K_d \dot e + K_p e = 0, \]

proving the claim.

Problem 2 (Residual error as disturbance): Under the same setup as Problem 1, suppose the residual model is not exact and define \( \varepsilon(z) = r^\ast - r_\theta(z) \). Derive the error dynamics and show that the system behaves as if it were driven by an additive disturbance \( \varepsilon(z) \).

Solution: The derivation follows Section 3. Substitute \( r_\theta = r^\ast - \varepsilon \) into the dynamics:

\[ M(q)\ddot q + C(q,\dot q)\dot q + g(q) = \tau_\mathrm{nom} + r_\theta = \tau_\mathrm{nom} + r^\ast - \varepsilon. \]

Using the definition of \( r^\ast \) exactly cancels the nominal dynamics contribution, leaving

\[ M(q)\ddot e + C(q,\dot q)\dot e + K_d \dot e + K_p e = \varepsilon(z), \]

so the closed-loop error dynamics are those of the nominal controller perturbed by the residual error term \( \varepsilon(z) \).

Problem 3 (Linear residual delta model identification): For a discrete-time scalar system with nominal dynamics \( x_{k+1}^\mathrm{nom} = a x_k + b u_k \), suppose we learn a linear residual model \( r_\theta(z_k) = w_1 x_k + w_2 u_k \) with parameters \( \theta = (w_1,w_2) \). The training targets are \( y_k = x_{k+1} - x_{k+1}^\mathrm{nom} \). Derive the gradient of the mean squared error loss

\[ J(\theta) = \frac{1}{N} \sum_{k=1}^N \bigl(x_{k+1} - a x_k - b u_k - r_\theta(z_k)\bigr)^2 \]

with respect to \( w_1 \) and \( w_2 \).

Solution: Write the prediction error

\[ e_k(\theta) = x_{k+1} - a x_k - b u_k - (w_1 x_k + w_2 u_k). \]

Then

\[ J(\theta) = \frac{1}{N} \sum_{k=1}^N e_k(\theta)^2. \]

The gradients are

\[ \frac{\partial J}{\partial w_1} = \frac{2}{N} \sum_{k=1}^N e_k(\theta) \frac{\partial e_k(\theta)}{\partial w_1} = - \frac{2}{N} \sum_{k=1}^N e_k(\theta) x_k, \]

\[ \frac{\partial J}{\partial w_2} = - \frac{2}{N} \sum_{k=1}^N e_k(\theta) u_k. \]

A gradient-descent step with step size \( \eta > 0 \) is then

\[ w_1^{\mathrm{new}} = w_1^{\mathrm{old}} + \frac{2 \eta}{N} \sum_{k=1}^N e_k(\theta) x_k, \quad w_2^{\mathrm{new}} = w_2^{\mathrm{old}} + \frac{2 \eta}{N} \sum_{k=1}^N e_k(\theta) u_k. \]

Problem 4 (ISS-type bound for residual error): Consider the Lyapunov function and inequality from Section 3. Assume that for some positive constants \( c_V,C_V \)

\[ c_V \bigl(\|e\|^2 + \|\dot e\|^2\bigr) \le V(e,\dot e) \le C_V \bigl(\|e\|^2 + \|\dot e\|^2\bigr). \]

Suppose also there exist \( \alpha_1,\alpha_2 > 0 \) such that

\[ \dot V \le - \alpha_1 \|\dot e\|^2 + \alpha_2 \|e\|^2. \]

Sketch how this implies local practical stability of the tracking error, and explain qualitatively what happens as the residual model accuracy increases.

Solution (sketch): Using standard comparison arguments, the inequality on \( \dot V \) implies that \( V \) decreases along trajectories except possibly when the position error term dominates the velocity term. For small enough residual error (which affects the constants \( \alpha_1,\alpha_2 \)), the derivative \( \dot V \) remains negative outside an arbitrarily small ball around the origin in the \( (e,\dot e) \) space, yielding local practical stability. As the residual model becomes more accurate, \( \varepsilon(z) \) shrinks, so \( \alpha_2 \) decreases and the ultimate bound on the tracking error shrinks; in the limit of perfect residual modeling, the bound collapses to zero and the nominal asymptotic stability is recovered.

11. Summary

Residual and delta-model learning provide a principled way to combine first-principles robot models with data-driven corrections. By treating learning as a regression problem on top of nominal dynamics, we retain the interpretability and structure of classical control while improving accuracy and performance. We derived the residual-augmented error dynamics for computed-torque control, obtained Lyapunov-based bounds under residual error, and showed how to implement these ideas in Python, C++, Java, MATLAB/Simulink, and Mathematica. In the next lesson, we will specialize residual learning to Gaussian process models and discuss their uncertainty quantification for control.

12. References

  1. Atkeson, C. G., Moore, A. W., & Schaal, S. (1997). Locally weighted learning. Artificial Intelligence, 11(1–2), 11–73.
  2. Schaal, S., Ijspeert, A., & Billard, A. (2003). Computational approaches to motor learning by imitation. Philosophical Transactions of the Royal Society of London A, 361(1811), 537–552.
  3. Nguyen-Tuong, D., & Peters, J. (2011). Model learning for robot control: a survey. Cognitive Processing, 12(4), 319–340.
  4. Johansson, R., & Norrlöf, M. (2002). Optimal motion control of industrial robots. IEEE Transactions on Automatic Control, 47(8), 1419–1434.
  5. Slotine, J.-J. E., & Li, W. (1987). On the adaptive control of robot manipulators. International Journal of Robotics Research, 6(3), 49–59.
  6. Deisenroth, M. P., & Rasmussen, C. E. (2011). PILCO: A model-based and data-efficient approach to policy search. Proceedings of the 28th International Conference on Machine Learning, 465–472. (Methodologically useful for GP-based model learning, even though framed as policy search.)
  7. Hjalmarsson, H. (2005). From experiment design to closed-loop control. Automatica, 41(3), 393–438.
  8. Ljung, L. (1999). System Identification: Theory for the User (2nd ed.). Prentice Hall.