Chapter 6: Force and Compliant Interaction Control

Lesson 1: Motivation for Force Control

This lesson explains why regulating interaction forces with the environment is a fundamentally different objective from regulating motion, and why purely position-based control is inadequate and potentially unsafe during contact. Starting from well-known manipulator dynamics, we introduce simple contact models, derive interaction stiffness, and use these to justify force and impedance control architectures that will be developed in later lessons.

1. From Position Tracking to Interaction Objectives

Up to this point, control objectives were mainly formulated as motion-tracking tasks: the end-effector should follow a desired joint-space or task-space trajectory \( \mathbf{q}_d(t) \) or \( \mathbf{x}_d(t) \) with small tracking error. The canonical joint-space dynamics (without external contact) are

\[ \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{M}(\mathbf{q}) \) is the inertia matrix, \( \mathbf{C}(\mathbf{q},\dot{\mathbf{q}})\dot{\mathbf{q}} \) captures Coriolis and centrifugal terms, and \( \mathbf{g}(\mathbf{q}) \) is gravity. A standard model-based controller (e.g. computed-torque) shapes the closed-loop dynamics to behave like a well-damped second-order system, focusing on motion error \( \mathbf{e}_q = \mathbf{q} - \mathbf{q}_d \).

In interaction tasks (polishing, assembly, human–robot collaboration, surface following), the quality of performance is mainly determined by the forces exerted on the environment: normal forces should stay inside a safe band, tangential forces should match process constraints, and impulsive forces should be minimized. Let \( \mathbf{F} \) denote the generalized contact force at the end-effector and \( \mathbf{F}_d \) a desired force (or wrench).

The central issue is that motion and force at the contact are coupled. Pushing a rigid wall by an additional \( 1 \,\text{mm} \) may create hundreds of Newtons of extra force, while the same displacement in free space creates none.

flowchart TD
  T0["Robotic task"] --> T1["Free-space motion?"]
  T1 -->|yes| GOAL1["Primary goal: \ntrack trajectory x_d(t)"]
  T1 -->|no| T2["Task involves contact with environment"]
  T2 --> T3["Identify interaction goals: \nforce bands, stiffness, safety"]
  T3 --> T4["Choose control focus"]
  T4 -->|dominant motion| C1["Motion-centric control \nwith force limits"]
  T4 -->|dominant force| C2["Force-centric or impedance control"]
  C1 --> MOTIV["Need to understand \nmotion-force coupling"]
  C2 --> MOTIV
        

This lesson develops simple analytical models for motion–force coupling, showing rigorously that:

  • Pure position tracking can yield unbounded contact forces when the environment is stiff.
  • Closed-loop stability and safety depend on the combined robot–environment dynamics.
  • Force-centric or impedance objectives are mathematically natural for contact tasks.

2. Contact Modeling and Generalized Forces

We recall the mapping between task-space wrenches and joint torques. For an end-effector position/orientation vector \( \mathbf{x} \in \mathbb{R}^m \) with Jacobian \( \mathbf{J}(\mathbf{q}) = \partial \mathbf{x}/\partial \mathbf{q} \), a contact wrench \( \mathbf{F} \in \mathbb{R}^m \) induces joint torques

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

Accounting for contact, the joint-space dynamics become

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

The environment must now be modeled to close the loop between \( \mathbf{x} \) and \( \mathbf{F} \). In many tasks a local linear approximation of the environment normal force is appropriate:

\[ F_n = \begin{cases} 0, & \text{if } x_n \le x_s,\\[4pt] k_e (x_n - x_s) + b_e \dot{x}_n, & \text{if } x_n > x_s, \end{cases} \]

where:

  • \( x_n \) is displacement along the surface normal,
  • \( x_s \) is the (unknown or partially known) surface location,
  • \( k_e \) is environment stiffness,
  • \( b_e \) is environment damping.

For analytical insight, we will use a 1-DOF translational model with generalized coordinate \( x \) interacting with a stiff wall at \( x = x_s \). The robot is modeled as a mass–spring–damper plus control input:

\[ m \ddot{x} + b \dot{x} + k_r (x - x_0) = u - F_e(x,\dot{x}), \]

where \( m \), \( b \), \( k_r \) are effective robot parameters, \( x_0 \) is a bias position, and \( F_e \) is the environment reaction force of the form above.

3. Why Pure Position Control is Dangerous in Contact

Consider a simple proportional position controller in task space for the 1-DOF model:

\[ u = k_p (x_d - x), \]

where \( x_d \) is a desired position given by a trajectory planner designed under free-space assumptions. Suppose that this trajectory commands the robot to penetrate the wall, i.e. \( x_d > x_s \).

At steady state in contact with negligible velocity (\( \dot{x} \approx 0 \), \( \ddot{x} \approx 0 \)), the dynamics reduce to

\[ k_r (x - x_0) \approx u - F_e(x) = k_p (x_d - x) - k_e (x - x_s). \]

Solving for the equilibrium position \( x^\ast \):

\[ k_r (x^\ast - x_0) = k_p (x_d - x^\ast) - k_e (x^\ast - x_s), \]

\[ (k_r + k_p + k_e) x^\ast = k_p x_d + k_e x_s + k_r x_0, \]

\[ x^\ast = \frac{k_p x_d + k_e x_s + k_r x_0}{k_r + k_p + k_e}. \]

The steady-state contact force equals:

\[ F_e^\ast = k_e (x^\ast - x_s) = \frac{k_e}{k_r + k_p + k_e} \bigl(k_p (x_d - x_s) + k_r (x_0 - x_s)\bigr). \]

If we choose the reference frame such that \( x_0 = x_s \) (robot mechanical spring centered at the surface), this simplifies to

\[ F_e^\ast = \frac{k_e k_p}{k_r + k_p + k_e} (x_d - x_s). \]

Several key observations follow:

  • For a stiff environment \( k_e \rightarrow \infty \), the factor \( \dfrac{k_e k_p}{k_r + k_p + k_e} \rightarrow k_p \), so \( F_e^\ast \approx k_p (x_d - x_s) \). A tiny position overshoot in the planner can produce a very large force proportional to \( k_p \).
  • Increasing \( k_p \) to improve tracking in free space directly amplifies contact forces.
  • The controller has no representation of a desired force \( F_d \). Any reasonable force objective (e.g. staying below a safety limit \( F_{\max} \)) is at best enforced by ad hoc saturation on \( u \).

Thus, even in this trivial 1-DOF case, position control is poorly matched to contact tasks: the controlled variable is displacement, but the task objective is force.

4. Interaction Stiffness and Closed-Loop Dynamics

Consider the linearized closed-loop dynamics of the 1-DOF robot in contact under PD position control:

\[ u = k_p (x_d - x) - k_d \dot{x}. \]

Neglecting the internal robot spring \( k_r \) for simplicity (typical for high-bandwidth actuators) and choosing \( x_0 = x_s \), we obtain

\[ m \ddot{x} + (b + k_d) \dot{x} + (k_p + k_e) x = k_p x_d + k_e x_s. \]

The homogeneous dynamics are governed by the characteristic polynomial

\[ m \lambda^2 + (b + k_d) \lambda + (k_p + k_e) = 0. \]

The system is asymptotically stable if and only if

\[ m > 0,\quad b + k_d > 0,\quad k_p + k_e > 0. \]

For continuous-time dynamics, these conditions are easily satisfied by choosing \( k_d > -b \) and \( k_p > -k_e \). However:

  • In practice, control is implemented digitally; large \( k_p + k_e \) leads to lightly damped or unstable discrete-time dynamics at a given sampling period.
  • The effective interaction stiffness (how the environment perceives the robot) is dominated by \( k_p + k_e \). This can make the robot appear very stiff and non-compliant, which is undesirable for safety and for many tasks (e.g. surface following).

A more appropriate specification is to choose a desired interaction stiffness \( k_{\text{int}} \) and damping \( b_{\text{int}} \), and design the controller such that the closed-loop mapping \( x_d \mapsto F_e \) (or \( F_d \mapsto x \)) has those properties. This is precisely the domain of impedance and admittance control, but the mathematical motivation stems from the inadequacy of naive position control derived above.

5. Multi-Language Example: 1-DOF Robot Pushing a Wall

To strengthen intuition, we implement a simple discrete-time simulation of the 1-DOF system:

\[ m \ddot{x} + b \dot{x} = u - F_e,\quad F_e = \begin{cases} 0, & x \le x_s,\\ k_e (x - x_s), & x > x_s, \end{cases} \]

with a PD position controller and a crude force-limited variant that saturates the control input when the contact force exceeds a threshold \( F_{\max} \). This is not a principled force controller, but it numerically illustrates the problems that motivate force/impedance control.

5.1 Python (NumPy) Implementation


import numpy as np

m = 1.0       # mass
b = 1.0       # viscous damping
k_p = 200.0   # position gain
k_d = 20.0    # velocity gain
k_e = 5e3     # environment stiffness (very stiff)
x_s = 0.0     # wall at x = 0
F_max = 80.0  # crude force limit

dt = 0.0005
T = 1.0
N = int(T / dt)

# desired trajectory: step from -0.02 to +0.03 m (penetrates wall)
def x_d(t):
    return -0.02 if t < 0.1 else 0.03

x = -0.02
v = 0.0

xs = np.zeros(N)
Fs = np.zeros(N)
us = np.zeros(N)
ts = np.linspace(0.0, T, N)

for i, t in enumerate(ts):
    # environment force
    if x <= x_s:
        F_e = 0.0
    else:
        F_e = k_e * (x - x_s)

    # PD position control
    e = x_d(t) - x
    u = k_p * e - k_d * v

    # crude force limit
    if F_e > F_max:
        # reduce actuation in same direction as penetration
        u = u - (F_e - F_max)

    # dynamics integration (explicit Euler)
    a = (u - F_e - b * v) / m
    v = v + dt * a
    x = x + dt * v

    xs[i] = x
    Fs[i] = F_e
    us[i] = u

# xs: position trajectory
# Fs: contact forces
# us: control inputs
# These can be plotted (time vs x and time vs F_e) to visualize force spikes.
      

5.2 C++ Implementation (Core Loop)


#include <iostream>
#include <vector>
#include <cmath>

int main() {
    const double m = 1.0;
    const double b = 1.0;
    const double k_p = 200.0;
    const double k_d = 20.0;
    const double k_e = 5000.0;
    const double x_s = 0.0;
    const double F_max = 80.0;
    const double dt = 0.0005;
    const double T = 1.0;
    const int N = static_cast<int>(T / dt);

    auto x_d = [](double t) {
        return (t < 0.1) ? -0.02 : 0.03;
    };

    double x = -0.02;
    double v = 0.0;

    std::vector<double> xs(N), Fs(N), us(N);

    for (int i = 0; i < N; ++i) {
        double t = i * dt;

        double F_e = (x <= x_s) ? 0.0 : k_e * (x - x_s);

        double e = x_d(t) - x;
        double u = k_p * e - k_d * v;

        if (F_e > F_max) {
            u -= (F_e - F_max);
        }

        double a = (u - F_e - b * v) / m;
        v += dt * a;
        x += dt * v;

        xs[i] = x;
        Fs[i] = F_e;
        us[i] = u;
    }

    // Print final values as a sanity check
    std::cout << "Final x = " << xs.back()
              << ", Final F_e = " << Fs.back() << std::endl;
    return 0;
}
      

5.3 Java Implementation (Core Loop)


public class ForceControlMotivation1DOF {

    static double x_d(double t) {
        return (t < 0.1) ? -0.02 : 0.03;
    }

    public static void main(String[] args) {
        double m = 1.0;
        double b = 1.0;
        double k_p = 200.0;
        double k_d = 20.0;
        double k_e = 5000.0;
        double x_s = 0.0;
        double F_max = 80.0;
        double dt = 0.0005;
        double T = 1.0;
        int N = (int) (T / dt);

        double x = -0.02;
        double v = 0.0;

        double[] xs = new double[N];
        double[] Fs = new double[N];

        for (int i = 0; i < N; i++) {
            double t = i * dt;

            double F_e = (x <= x_s) ? 0.0 : k_e * (x - x_s);

            double e = x_d(t) - x;
            double u = k_p * e - k_d * v;

            if (F_e > F_max) {
                u -= (F_e - F_max);
            }

            double a = (u - F_e - b * v) / m;
            v += dt * a;
            x += dt * v;

            xs[i] = x;
            Fs[i] = F_e;
        }

        System.out.println("Final x = " + xs[N - 1]
                + ", Final F_e = " + Fs[N - 1]);
    }
}
      

5.4 MATLAB/Simulink Script


m   = 1.0;
b   = 1.0;
k_p = 200.0;
k_d = 20.0;
k_e = 5e3;
x_s = 0.0;
F_max = 80.0;

dt = 5e-4;
T  = 1.0;
N  = round(T / dt);

x = -0.02;
v = 0.0;

xs = zeros(N,1);
Fs = zeros(N,1);
ts = (0:N-1)' * dt;

for i = 1:N
    t = ts(i);
    if t < 0.1
        xd = -0.02;
    else
        xd = 0.03;
    end

    if x <= x_s
        F_e = 0;
    else
        F_e = k_e * (x - x_s);
    end

    e = xd - x;
    u = k_p * e - k_d * v;

    if F_e > F_max
        u = u - (F_e - F_max);
    end

    a = (u - F_e - b * v) / m;
    v = v + dt * a;
    x = x + dt * v;

    xs(i) = x;
    Fs(i) = F_e;
end

% Plot results
figure; subplot(2,1,1);
plot(ts, xs); ylabel('x (m)'); grid on;
subplot(2,1,2);
plot(ts, Fs); ylabel('F_e (N)'); xlabel('t (s)'); grid on;
      

A Simulink diagram would mirror this loop using Integrator blocks for x and v, a MATLAB Function block or simple arithmetic blocks for F_e, the PD law and saturation on u.

5.5 Wolfram Mathematica Implementation


m   = 1.0;
b   = 1.0;
kP  = 200.0;
kD  = 20.0;
kE  = 5000.0;
xS  = 0.0;
fMax = 80.0;

xDes[t_] := Piecewise[{ {-0.02, t < 0.1}, {0.03, t >= 0.1} }];

dt = 0.0005;
tEnd = 1.0;
steps = Round[tEnd/dt];

x  = -0.02;
v  = 0.0;

data = Reap[
  Do[
    t = n*dt;
    fE = If[x <= xS, 0.0, kE (x - xS)];
    e  = xDes[t] - x;
    u  = kP e - kD v;
    If[fE > fMax, u = u - (fE - fMax)];
    a  = (u - fE - b v)/m;
    v  = v + dt a;
    x  = x + dt v;
    Sow[{t, x, fE}],
    {n, 0, steps}
  ]
][[2, 1]];

ListLinePlot[
  {data[[All, {1, 2}]], data[[All, {1, 3}]]},
  PlotLegends -> {"x(t)", "F_e(t)"},
  GridLines -> Automatic
]
      

In all implementations, increasing k_p or the environment stiffness k_e leads to very large and oscillatory contact forces under pure position control, numerically confirming the analytical arguments from Sections 3 and 4.

6. Design Flow: From Task Specification to Force-Aware Control

The main lesson from the analysis is that task requirements must be expressed not only in terms of motion but also in terms of forces, and the control structure must reflect those requirements.

flowchart TD
  A["Specify task: surface following, insertion, collaboration"] --> B["Define motion constraints (position, orientation)"]
  B --> C["Define force constraints (normal force band, limits)"]
  C --> D["Model environment locally (stiffness, damping, friction)"]
  D --> E["Analyze robot-environment interaction dynamics"]
  E --> F["Decide control objective: motion, force, or impedance"]
  F --> G["Select architecture: position with limits, hybrid, impedance"]
  G --> H["Tune gains to meet stability and interaction stiffness goals"]
        

Subsequent lessons in this chapter will formalize hybrid position/force, impedance, and admittance control, all of which follow this general design flow but implement different control objectives mathematically.

7. Problems and Solutions

Problem 1 (Steady-State Force under Position Control): Consider the 1-DOF system in Section 3 with dynamics \( m \ddot{x} + b \dot{x} = u - F_e(x) \) and environment force \( F_e(x) = k_e (x - x_s) \) for \( x > x_s \), zero otherwise. The controller is pure proportional position control \( u = k_p (x_d - x) \). Assume \( x_d > x_s \) and that the steady-state position \( x^\ast \) lies in contact (\( x^\ast > x_s \)). Derive the steady-state contact force \( F_e^\ast \).

Solution:

At steady state, \( \dot{x} = \ddot{x} = 0 \), so the dynamics give \( 0 = u - F_e(x^\ast) \), i.e.

\[ k_p (x_d - x^\ast) = k_e (x^\ast - x_s). \]

Solving for \( x^\ast \):

\[ k_p x_d - k_p x^\ast = k_e x^\ast - k_e x_s \quad \Rightarrow \quad (k_p + k_e) x^\ast = k_p x_d + k_e x_s, \]

\[ x^\ast = \frac{k_p x_d + k_e x_s}{k_p + k_e}. \]

The steady-state contact force is then

\[ F_e^\ast = k_e (x^\ast - x_s) = \frac{k_e}{k_p + k_e} \, k_p (x_d - x_s) = \frac{k_e k_p}{k_p + k_e} (x_d - x_s). \]

In the limit of very stiff environment \( k_e \rightarrow \infty \), we obtain \( F_e^\ast \approx k_p (x_d - x_s) \).

Problem 2 (Effective Interaction Stiffness): Using the result of Problem 1, show that for finite but large \( k_e \), the mapping from commanded penetration \( \Delta x_d = x_d - x_s \) to steady-state force can be interpreted as an effective interaction stiffness \( k_{\text{int}} \). Express \( k_{\text{int}} \) in terms of \( k_p \) and \( k_e \), and discuss the limit cases \( k_p \ll k_e \) and \( k_p \gg k_e \).

Solution:

From Problem 1 we have \( F_e^\ast = \frac{k_e k_p}{k_p + k_e} (x_d - x_s) \). Defining \( \Delta x_d = x_d - x_s \), we can write

\[ F_e^\ast = k_{\text{int}} \, \Delta x_d, \quad k_{\text{int}} = \frac{k_e k_p}{k_p + k_e}. \]

Thus the effective interaction stiffness is the parallel combination of \( k_p \) and \( k_e \): \( 1/k_{\text{int}} = 1/k_p + 1/k_e \). In the limit \( k_p \ll k_e \), we have \( k_{\text{int}} \approx k_p \), so the robot is the limiting stiffness. In the opposite limit \( k_p \gg k_e \), we get \( k_{\text{int}} \approx k_e \), and the environment dominates. In either case, \( k_{\text{int}} \) is not explicitly specified in a design; it emerges from the combination of controller and environment.

Problem 3 (Closed-Loop Damping with PD Control): For the mass–damper system with PD position control in contact:

\[ m \ddot{x} + b \dot{x} = k_p (x_d - x) - k_d \dot{x} - k_e (x - x_s), \]

derive the characteristic polynomial and identify the damping ratio \( \zeta \) in terms of \( m \), \( b + k_d \), and \( k_p + k_e \). Hint: compare with the standard second-order form \( \ddot{x} + 2 \zeta \omega_n \dot{x} + \omega_n^2 x = 0 \).

Solution:

Rearranging the homogeneous dynamics around equilibrium yields

\[ m \ddot{x} + (b + k_d) \dot{x} + (k_p + k_e) x = 0. \]

Dividing by \( m \) we obtain

\[ \ddot{x} + \frac{b + k_d}{m} \dot{x} + \frac{k_p + k_e}{m} x = 0. \]

Matching with \( \ddot{x} + 2 \zeta \omega_n \dot{x} + \omega_n^2 x = 0 \), we identify

\[ \omega_n^2 = \frac{k_p + k_e}{m}, \quad 2 \zeta \omega_n = \frac{b + k_d}{m}. \]

Hence

\[ \omega_n = \sqrt{\frac{k_p + k_e}{m}}, \quad \zeta = \frac{b + k_d}{2 \sqrt{m (k_p + k_e)}}. \]

Increasing \( k_e \) or \( k_p \) increases \( \omega_n \) while decreasing \( \zeta \) for fixed \( b + k_d \), making the system more oscillatory and sensitive to sampling.

Problem 4 (Need for Force Measurement): Using the torque mapping \( \boldsymbol{\tau}_\text{contact} = \mathbf{J}^\top \mathbf{F} \), argue why, in general, an accurate force controller cannot rely solely on joint position/velocity measurements and a rigid environment model. Discuss the role of uncertainties in \( \mathbf{J}(\mathbf{q}) \) and in the contact location.

Solution:

A desired wrench \( \mathbf{F}_d \) would translate into a joint torque command \( \boldsymbol{\tau}_d = \mathbf{J}(\mathbf{q})^\top \mathbf{F}_d \). However, this assumes:

  • Exact knowledge of the Jacobian \( \mathbf{J}(\mathbf{q}) \),
  • Exact knowledge of where the contact occurs (point of application),
  • Rigid environment behavior consistent with the model used in planning.

In reality, compliance in the robot and environment, unknown friction, and modeling errors in \( \mathbf{J}(\mathbf{q}) \) and the contact frame cause the realized force to deviate from \( \mathbf{F}_d \). Without direct force or torque measurement (via wrist force–torque sensors, joint torque sensors, or motor current observers), the controller has no feedback on these deviations and cannot correct them. This motivates the use of explicit force sensing in interaction control architectures.

Problem 5 (Task Classification): Consider three tasks: (a) free-space point-to-point motion, (b) wiping a table with constant normal force, (c) a peg-in-hole insertion with precise alignment and low contact force. Sketch a high-level decision logic on whether each task is more naturally formulated as a position, force, or impedance control problem.

Solution:

flowchart TD
  S["Start: choose task"] --> A["Task (a): \nfree-space motion"]
  S --> B["Task (b): \nconstant normal force on surface"]
  S --> C["Task (c): \ninsertion with alignment \nand low forces"]
  A --> A1["Use motion-centric \nposition control"]
  B --> B1["Control normal force; \nallow tangential motion"]
  C --> C1["Use compliant impedance: \nlow stiffness normal, \nprecise tangential"]
      

Task (a) is naturally a position problem. Task (b) primarily requires regulating normal force while allowing freedom in tangential motion, so a force or hybrid position/force formulation is appropriate. Task (c) requires both position accuracy (alignment) and compliant interaction (low insertion forces); an impedance formulation is most natural, with low stiffness normal to the hole axis and higher stiffness tangentially.

8. Summary

In this lesson we started from familiar robot dynamics and introduced simple contact models to formalize motion–force coupling. For a 1-DOF example, we proved that pure position control can yield large and poorly controlled contact forces, and that closed-loop properties depend on the combined robot–environment stiffness and damping.

We defined the notion of effective interaction stiffness and showed how it emerges from the controller and environment, rather than being a directly specified design parameter. Numerical simulations in Python, C++, Java, MATLAB and Mathematica illustrated how high-gain position control leads to force spikes in stiff contact.

These analyses provide the mathematical motivation for the force- and impedance-based control architectures studied in the remaining lessons of this chapter.

9. References

  1. Raibert, M.H., & Craig, J.J. (1981). Hybrid position/force control of manipulators. ASME Journal of Dynamic Systems, Measurement, and Control, 103(2), 126–133.
  2. Hogan, N. (1985). Impedance control: An approach to manipulation. Part I–III. ASME Journal of Dynamic Systems, Measurement, and Control, 107(1), 1–24.
  3. Salisbury, J.K. (1980). Active stiffness control of a manipulator in Cartesian coordinates. Proceedings of the 19th IEEE Conference on Decision and Control, 95–100.
  4. Khatib, O. (1987). A unified approach for motion and force control of robot manipulators: The operational space formulation. IEEE Journal of Robotics and Automation, 3(1), 43–53.
  5. Colgate, J.E., & Hogan, N. (1988). Robust control of dynamically interacting systems. International Journal of Control, 48(1), 65–88.
  6. Anderson, R.J., & Spong, M.W. (1988). Bilateral control of teleoperators with time delay. IEEE Transactions on Automatic Control, 34(5), 494–501.
  7. Seraji, H., & Colbaugh, R. (1993). Force tracking in impedance control. International Journal of Robotics Research, 12(1), 20–30.