Roboter
Robot kinematics tells you where the robot is — dynamics tells you how much torque each motor must produce to get there. Control theory closes the loop, ensuring the robot actually reaches and holds its target despite gravity, friction, inertia, and disturbances. From Newton-Euler equations computing joint torques to PID tuning, feedforward control, impedance control, and force-torque regulation, this guide takes you from the physics of a single rotating link all the way to advanced compliant control for human-robot interaction. Every concept is grounded in real industrial hardware, real motor datasheets, and real commissioning practice.
Robot dynamics answers: how much torque must each motor produce to make the robot move as desired? Kinematics ignores forces — dynamics puts them front and centre. The three contributions to joint torque are inertial torque (I·α, proportional to acceleration), gravity torque (m·g·d, proportional to centre-of-gravity offset), and Coriolis/centrifugal torques (proportional to velocity squared). At slow speeds gravity dominates; at high speeds inertia and Coriolis dominate. Understanding these forces is the difference between a motor that just barely works and one correctly sized with margin.
Adjust link parameters and joint state. See how much torque each physical effect demands. This is the dynamic model running inside every robot controller at 1 kHz — making it visible makes it understandable.
Compare inertia values for common robot link geometries. Slide the axis offset to see the parallel axis theorem — moving the rotation axis a small distance from the CoM dramatically increases inertia.
A robot in static equilibrium holds its position against gravity — motors produce torques equal and opposite to gravitational torques. Dynamics adds inertia: resistance to angular acceleration (τ = I·α). Even in zero gravity, torque is required to accelerate. In industrial robots, dynamic torques often exceed static (gravity) requirements during fast moves. A KUKA KR 6 with a 6 kg payload makes moves at 2000 mm/s and 10000 mm/s² — inertial torques dominate gravity by 3:1 at these accelerations. The matrix equation of motion for a full n-DOF robot: τ = M(q)·q̈ + C(q,q̇)·q̇ + g(q) + f(q̇). M(q) is the configuration-dependent inertia matrix, C captures Coriolis and centrifugal effects, g is the gravity vector, and f captures friction.
// Equation of motion for n-DOF robot
// τ = M(q)·q̈ + C(q,q̇)·q̇ + g(q) + f(q̇)
//
// M(q): n×n inertia matrix — configuration-dependent, always positive definite
// C(q,q̇): n×n Coriolis/centrifugal matrix
// g(q): n×1 gravity vector
// f(q̇): friction vector (viscous + Coulomb)
//
// 2-DOF planar: Link masses m1, m2; lengths L1, L2; CoM at lc1=L1/2, lc2=L2/2
// M(q) = [ I1+I2+m1*lc1²+m2*(L1²+lc2²+2*L1*lc2*cos(q2)) I2+m2*(lc2²+L1*lc2*cos(q2)) ]
// [ I2+m2*(lc2²+L1*lc2*cos(q2)) I2+m2*lc2² ]
//
// g(q) = [ -(m1*lc1+m2*L1)*g*cos(q1) - m2*g*lc2*cos(q1+q2) ]
// [ - m2*g*lc2*cos(q1+q2) ]
//
// Key insight: M(q) changes with configuration by up to 8:1 ratio.
// This is why fixed PID gains give poor performance — the "plant" changes.
Moment of inertia (I) is the rotational equivalent of mass — it quantifies resistance to angular acceleration. Unlike mass (a scalar), I depends on both mass distribution AND the axis of rotation. For a point mass m at radius r: I = m·r². For distributed bodies: I = ∫r²dm. The parallel axis theorem: I_new = I_cm + m·d², where d is the distance between the new axis and the centre-of-mass axis. This theorem is critical in robot design: a motor at the end of a long link contributes far more inertia than one at the joint. Modern CAD software computes inertia tensors automatically. The full 3D inertia is a 3×3 symmetric matrix (the inertia tensor), but for planar robots a single scalar suffices.
// Moments of inertia for common robot link geometries
//
// Uniform rod (length L, mass m), about CENTRE:
// I_cm = (1/12)*m*L²
//
// Uniform rod, about ONE END (parallel axis theorem):
// I_end = (1/12)*m*L² + m*(L/2)² = (1/3)*m*L² ← 4× larger!
//
// Hollow cylinder (R_outer, R_inner), about symmetry axis:
// I = (1/2)*m*(R_o² + R_i²)
//
// Solid disk: I = (1/2)*m*R²
// Sphere: I = (2/5)*m*R²
//
// PARALLEL AXIS THEOREM:
// I_joint = I_cm + m*d² (d = distance CM → joint axis)
//
// COMPOSITE LINK (structure + motor + gearbox + cables):
// I_total = Σ(I_cm_i + m_i * d_i²)
//
// Example — KUKA KR 6 Link 2 (approximate):
// Aluminium tube 2.8 kg: I ≈ 0.093 kg·m²
// Motor + gearbox 1.8 kg: I ≈ 0.044 kg·m²
// Wiring/covers 0.4 kg: I ≈ 0.004 kg·m²
// Total link 2: I ≈ 0.141 kg·m² about joint 2
// Payload 6 kg at 650mm: I_pay = 6 × 0.65² = 2.54 kg·m² ← dominant!
// → Payload doubles effective inertia in extended pose
Gravity torque is the torque required to hold the robot stationary against gravity. It depends on the total mass below each joint multiplied by its horizontal distance to the joint axis — the static moment. For a horizontal arm, gravity torque is maximum. For a vertical arm (pointing up or down), it is zero. Controllers always run gravity compensation: without it, the robot sags when it decelerates to a stop. When you enter the payload mass into a robot controller, you are not just setting a safety limit — you are updating the gravity compensation model. Wrong payload = wrong gravity compensation = position droop at low speeds and false torque-limit trips at high speeds.
// Gravity torque — 2-DOF planar robot
import numpy as np
m1, m2 = 2.5, 1.8 # kg
L1, L2 = 0.35, 0.25 # m
lc1, lc2 = 0.175, 0.125 # m (CoM at mid-link)
g = 9.81
def gravity_torques(q1_deg, q2_deg):
q1 = np.radians(q1_deg)
q2 = np.radians(q2_deg)
# Joint 1 supports weight of both links
tau1 = -(m1*g*lc1*np.cos(q1)
+ m2*g*(L1*np.cos(q1) + lc2*np.cos(q1+q2)))
# Joint 2 only supports weight of link 2
tau2 = -m2*g*lc2*np.cos(q1+q2)
return tau1, tau2
for q1,q2,desc in [(0,0,'Both horizontal'),(90,0,'Link1 up, Link2 horiz'),
(45,-45,'Folded back'),(0,90,'Link2 vertical')]:
t1,t2 = gravity_torques(q1,q2)
print(f'{desc:30s}: τ1={t1:7.2f} N·m τ2={t2:6.2f} N·m')
# Both horizontal : τ1= -9.35 N·m τ2= -2.21 N·m
# Link1 up, Link2 horiz : τ1= 0.00 N·m τ2= -2.21 N·m
# Folded back : τ1= -5.08 N·m τ2= 0.00 N·m
# Link2 vertical : τ1= -8.58 N·m τ2= 0.00 N·m
Every robot joint is driven by a brushless permanent magnet synchronous motor (PMSM/BLDC) paired with a precision gearbox. The motor converts electrical energy into mechanical torque. The gearbox transforms torque and speed: multiplying torque by N and dividing speed by N. The servo drive closes current, velocity, and position loops in hardware at up to 50 kHz. Understanding motor constants, gearbox efficiencies, inertia matching, and thermal ratings is essential for selecting actuators, diagnosing performance issues, and understanding why control parameters behave as they do.
Explore the BLDC speed-torque characteristic. The continuous operating envelope (solid cyan area) is bounded by thermal limits. The peak region (amber) can only be used briefly. Set your required load point and see if the motor is correctly sized.
Find the gear ratio that satisfies torque, speed, and inertia matching requirements. The curve shows inertia ratio vs gear ratio. The optimal inertia-matching point (green line) and the recommended ratio (dot) are highlighted.
The most commonly missed motor sizing check. Set up to 4 operating phases with different torques and durations. The RMS torque must stay below the motor's continuous rating. If it doesn't, the motor will overheat in steady-state operation.
PMSM/BLDC motors are the universal choice for robot joints. Key motor constants: Kt (N·m/A) — torque per ampere; Ke (V·s/rad) — back-EMF per rad/s; by motor physics Kt = Ke in SI units. Resistance R (Ω) — determines copper losses P = I²R. Inductance L (H) — determines current loop bandwidth. Rotor inertia J_r (kg·m²) — the motor's own mass. The speed-torque curve is linear: τ(ω) = τ_stall·(1 - ω/ω_no_load). Operating above the continuous envelope causes overheating — the critical design check is that RMS torque over the duty cycle stays below the continuous rating. Motor selection is iterative: required torque → current → thermal check → inertia ratio check → voltage/speed check.
// BLDC Motor fundamentals — example joint motor
//
// Motor constants:
// Kt = 0.35 N·m/A (torque constant)
// Ke = 0.35 V·s/rad (back-EMF = Kt in SI)
// R = 0.8 Ω (winding resistance)
// L = 4.2 mH (inductance)
// J = 0.00025 kg·m² (rotor inertia)
//
// Torque: τ = Kt × I
// Back-EMF: V_emf = Ke × ω
// Terminal eq: V = I×R + L×dI/dt + V_emf
// Steady-state: I = (V - Ke×ω) / R
//
// Speed-torque (V = 240V bus):
// τ_stall = Kt × V/R = 0.35 × 240/0.8 = 105 N·m (only at ω=0)
// ω_no_load = V/Ke = 240/0.35 = 686 rad/s = 6550 rpm
// At ω=3000rpm (314 rad/s): I = (240 - 0.35×314)/0.8 = 162 A → too high
// → Operating point must stay within continuous envelope
//
// Continuous rating (thermal limit):
// I_cont = 12 A → τ_cont = 0.35×12 = 4.2 N·m
// Copper losses: 12² × 0.8 = 115 W (motor rated for this)
// At I_peak = 36 A: τ_peak = 12.6 N·m, P_loss = 1037 W → 2s max
//
// RMS torque sizing:
// τ_rms = sqrt(Σ τ_i² × t_i / T_cycle) ≤ τ_continuous
Three gearbox types dominate robotics. Harmonic drives (strain wave gears): ratio 50–320 in one stage, near-zero backlash (<1 arcminute), high torque density, compact. Used in: KUKA LBR iiwa, all cobots, FANUC small robots. Efficiency 70–85% — lower than alternatives. Cycloidal drives (Nabtesco RV series): ratio 10–170, zero backlash, high torque density, efficiency 85–90%. Industry standard for joints 1–3 of medium and large serial robots (FANUC, Yaskawa). Planetary gears: ratio 4–100 per stage, some backlash (5–15 arcminutes) but highest efficiency (95–98%), compact. Used in joints 4–6 of many robots. The gear ratio N appears squared in reflected inertia reduction (I_reflected = I_load/N²) — this is the most powerful tool for inertia matching.
// Gearbox sizing — torque, speed, and inertia
//
// Reflected load inertia: I_reflected = I_load / N²
// Output torque: τ_out = τ_motor × N × η
// Output speed: ω_out = ω_motor / N
//
// KUKA LBR iiwa joint 1 (harmonic drive, N=160):
// Motor peak torque: 12 N·m
// Output peak: 12 × 160 × 0.82 = 1574 N·m (η=82%)
// Link inertia: 5.2 kg·m²
// Reflected inertia: 5.2 / 160² = 0.000203 kg·m²
// Motor inertia: 0.000210 kg·m²
// Inertia ratio: 0.97:1 ← perfect match!
//
// Gearbox type comparison (same joint, same requirements):
// ─────────────────────────────────────────────────────────────
// Type Ratio Backlash Efficiency Backdrivable
// Harmonic 160 < 1 arcm 70-85% With effort
// Cycloidal 57 < 1 arcm 85-90% No
// Planetary 100 5-15 arcm 95-98% Yes
// ─────────────────────────────────────────────────────────────
//
// Harmonic drive brands: Harmonic Drive AG (SHF, CSD, SHD series)
// Cycloidal brands: Nabtesco (RV-E, RV-C), Sumitomo
// Planetary brands: Neugart, Shimpo, Apex Dynamics
A servo drive converts a motion command into 3-phase PWM currents. Modern drives close the current loop at 10–50 kHz using Field-Oriented Control (FOC/vector control), which decomposes stator current into torque-producing (Iq) and flux-producing (Id) components — enabling precise torque control across all speeds. The cascade control structure: current loop (10-50 kHz) → velocity loop (1-5 kHz) → position loop (250 Hz - 1 kHz). Bandwidth ratios must be at least 5-10× between adjacent loops. Encoders are 23-bit (8 million counts/rev) for position measurement. EtherCAT communication at 250 µs cycle gives deterministic real-time control. Industrial drives: Siemens SINAMICS S210/S120, Beckhoff AX5000/AX8000, Allen-Bradley Kinetix, Panasonic MINAS A6.
// Servo drive cascade control structure
//
// ROBOT CONTROLLER (1 kHz EtherCAT)
// q_d(t) → trajectory generator → θ_d, ω_d, τ_ff
// ↓
// POSITION LOOP (1 kHz)
// θ_d →[+]→ Kp_pos ─────────────────→ ω_d
// [-]← θ_meas (23-bit encoder)
// ↓
// VELOCITY LOOP (4 kHz)
// ω_d →[+]→ Kp_vel + Ki_vel/s ───→ I_q_d
// [-]← ω_meas (encoder diff)
// ↓
// CURRENT LOOP / FOC (20 kHz)
// Iq_d, Id_d → Park/Clarke → V_abc → SVPWM → IGBT → 3-phase motor
//
// Typical starting gains:
// Position Kp: 50-200 (1/s)
// Velocity Kp: 0.1-5.0 (N·m·s/rad)
// Velocity Ki: 10-500 (N·m/rad)
// Current Kp: 10-200 (V/A)
//
// Key specs:
// EtherCAT cycle: 250 µs (4 kHz) or 1000 µs (1 kHz)
// Encoder res: 23-bit = 8,388,608 counts/rev = 0.000043°
// Current loop BW: 2-5 kHz
// Velocity loop BW: 100-500 Hz
// Position loop BW: 10-100 Hz
//
// Auto-tuning: inject chirp → measure freq response → compute gains
// Most modern drives (Beckhoff, Siemens) have one-click auto-tune
PID is the foundation of virtually all industrial motor control. Despite its simplicity — only three terms — it can be hard to tune on robot joints where the plant is nonlinear, coupled, and configuration-dependent. Understanding exactly what P, I, and D each do, how they interact, and how to tune them systematically transforms PID from a black art into a precise engineering tool. This section builds from the basic equation through transfer functions, Bode plots, stability margins, and practical tuning methods used by servo engineers in the field.
Simulate a PID-controlled robot joint in real time. Adjust gains and see the step response change instantly. Try the Ziegler-Nichols preset to see a well-tuned starting point. Add a disturbance torque and watch how integral action rejects it.
The engineer's stability analysis tool. Increase Kp and watch the phase margin shrink — when it hits zero, the system oscillates. Add transport delay (digital sampling latency) to see why high-bandwidth systems are hard to stabilise. Target: GM > 6 dB, PM > 45°.
u(t) = Kp·e(t) + Ki·∫e(t)dt + Kd·de/dt. Proportional (Kp): immediate reaction to current error. Increase Kp → faster response, higher bandwidth, but toward instability. Too high → oscillation. Integral (Ki): accumulated error. Eliminates steady-state offset — the robot always reaches its exact target. Acts slowly. Too high → slow oscillation and windup. Derivative (Kd): rate of change of error. Anticipates future error — slows the approach before overshoot. Acts as a damper. Too high → amplifies noise, causes chatter. Velocity-form PID: Δu = Kp·(eₙ-eₙ₋₁) + Ki·eₙ·dt + Kd·(eₙ-2eₙ₋₁+eₙ₋₂)/dt — avoids integrator windup naturally and gives bumpless transfer when switching modes.
// Discrete PID — velocity form (industrial standard)
struct PID {
float Kp, Ki, Kd, dt;
float e_prev = 0, e_prev2 = 0, u = 0;
float u_min = -1e9, u_max = 1e9;
float update(float setpoint, float measured) {
float e = setpoint - measured;
// Velocity form: Δu = Kp*(e-e_prev) + Ki*e*dt + Kd*(e-2*e_prev+e_prev2)/dt
float delta_u = Kp*(e - e_prev)
+ Ki*e*dt
+ Kd*(e - 2*e_prev + e_prev2)/dt;
u = fclamp(u + delta_u, u_min, u_max); // anti-windup built-in
e_prev2 = e_prev; e_prev = e;
return u;
}
};
// Typical robot joint PID ranges:
// Position loop (outer):
// Kp: 50-300 (rad/s per rad error)
// Ki: 5-50 (eliminates gravity droop at rest)
// Kd: 0-5 (rarely needed — inner loop handles damping)
//
// Velocity loop (inner, fast):
// Kp: 0.5-10 (N·m per rad/s error)
// Ki: 50-500 (fast integral, removes velocity droop)
//
// Practical tuning start:
// 1. Zero Ki and Kd
// 2. Increase Kp until oscillation (Ku)
// 3. Set Kp = 0.6*Ku
// 4. Add Ki = Kp/10, increase until offset eliminated in < 100ms
// 5. Add Kd = Kp/10 if overshoot remains
A control system is stable if its output settles rather than growing without bound. Stability is governed by the open-loop transfer function L(jω) = C(jω)·P(jω). The Bode plot shows magnitude and phase vs frequency. Key metrics: Gain margin (GM): how much gain can increase before oscillation — must be ≥6 dB. Phase margin (PM): how much additional phase lag before instability — should be 45°–70°. Bandwidth (BW): frequency where closed-loop magnitude drops 3 dB — the "speed" of the loop. Position loop: 10–100 Hz. Velocity loop: 100–500 Hz. Current loop: 1–5 kHz. Bandwidth ratios between nested loops must be at least 5–10×. Transport delay (from digital sampling, encoder processing) adds phase lag proportional to frequency — it is the main bandwidth limiter in digital servo systems.
// Frequency domain analysis — Python/scipy
from scipy import signal
import numpy as np
# Plant model: single inertia J with damping B
# Velocity output, torque input: P(s) = 1/(J*s + B)
J, B = 0.005, 0.02
P = signal.TransferFunction([1], [J, B])
# Velocity PI controller: C(s) = Kp + Ki/s = (Kp*s + Ki)/s
Kp, Ki = 2.0, 80.0
C = signal.TransferFunction([Kp, Ki], [1, 0])
# Open loop L(s) = C(s)*P(s)
L_num = np.polymul([Kp, Ki], [1])
L_den = np.polymul([1, 0], [J, B])
L = signal.TransferFunction(L_num, L_den)
# Bode analysis
w = np.logspace(0, 4, 1000)
w, mag, phase = signal.bode(L, w)
# Gain crossover (|L| = 0 dB)
gain_lin = 10**(mag/20)
cross_idx = np.argmin(np.abs(gain_lin - 1))
w_cross = w[cross_idx]
bw_hz = w_cross / (2*np.pi)
phase_margin = 180 + phase[cross_idx]
print(f'Bandwidth: {bw_hz:.1f} Hz')
print(f'Phase margin: {phase_margin:.1f}° (target > 45°)')
print(f'Gain margin: from -180° phase crossing')
# Transport delay effect: phase lag = -ω*T_delay (radians)
# At BW=200Hz with T=1ms: lag = 2π*200*0.001 = 1.26 rad = 72°!
# → Delay is the primary bandwidth limiter in digital systems
Pure feedback (PID) is reactive — it only acts after error develops. Feedforward control uses a model to predict what input is needed BEFORE error occurs. For robot control: velocity feedforward (Kff_v·ω_d) preloads the motor to overcome friction/damping; acceleration feedforward (Kff_a·α_d) preloads for inertia; gravity feedforward (g(q)) compensates gravity before any sag occurs. The result: much lower tracking errors during motion. A well-tuned feedforward + light PID vastly outperforms a heavily-tuned PID alone. All industrial robot controllers implement feedforward automatically — when you correctly enter the payload parameters, you improve feedforward accuracy, not feedback gains.
// Feedforward + PID — combined position controller
//
// Total control:
// u = Kff_a * q̈_d ← acceleration FF (predict inertia torque)
// + Kff_v * q̇_d ← velocity FF (predict friction/damping)
// + Kff_g * g(q) ← gravity FF (predict gravity torque)
// + Kp * (q_d - q) ← proportional error
// + Ki * ∫(q_d - q)dt ← integral (steady-state)
// + Kd * (q̇_d - q̇) ← derivative (damping)
//
// Ideal: Kff_a = J_total, Kff_v = B, Kff_g = 1.0
// With perfect FF: PID only handles payload variation,
// temperature drift, friction changes → gains can be much lower
//
// Tracking error comparison (90° move, 1.0s trapezoidal):
// PID only (high gains): peak error 8.2 mm TCP
// PID + velocity FF: peak error 3.1 mm TCP
// PID + velocity + accel FF: peak error 0.9 mm TCP
// Full computed-torque + PID: peak error 0.2 mm TCP
//
// Setting FF gains (practical procedure):
// 1. Zero all, command trapezoidal move, note tracking error shape
// 2. If error follows velocity shape → increase Kff_v
// 3. If error peaks at start/end of move → increase Kff_a
// 4. If error persists at rest → increase Kff_g (gravity comp)
// 5. Fine-tune PID to handle residuals
Beyond PID lies model-based and task-space control strategies that enable robots to do things a simple PID cannot. Computed torque control cancels the robot's nonlinear behaviour entirely, leaving a linear system. Impedance control makes the robot behave like a configurable spring-damper — essential for any contact task. Force control directly regulates the forces applied to the environment. These methods enable mirror-finish polishing, sub-millimetre peg insertion, safe human handguiding, and robot-assisted surgery. All are now accessible via standard industrial controllers: ABB Force Control, KUKA.ForceTorqueControl, Universal Robots Polyscope force mode.
A 2-DOF robot tracks a circular path. Toggle between pure PID and computed torque control to see the tracking error difference. Reduce model accuracy to simulate parameter uncertainty. The improvement factor shows how much CTC reduces tracking error.
Drag the target position (cyan dot) and watch the robot comply against the wall. Adjust virtual stiffness — high K makes the robot rigid (fights the wall), low K makes it compliant (yields easily). This is the behaviour needed for safe human contact and delicate assembly.
The inertia matrix M(q) of a robot arm changes by up to 8:1 as the arm folds or extends. A fixed PID must be detuned for worst-case (maximum inertia = arm extended), meaning sluggish response in all other configurations. Computed Torque Control (CTC) pre-cancels all nonlinear effects: τ = M̂(q)·(q̈_d + Kd·ė + Kp·e) + Ĉ(q,q̇)·q̇ + ĝ(q). After applying this torque, the closed-loop dynamics become simply ë + Kd·ė + Kp·e = 0 — a linear, decoupled second-order system. Same gains give identical response everywhere in the workspace. The hat (ˆ) denotes model estimates — errors in the model appear as disturbances that the PD feedback must reject.
# Computed Torque Control — 2-DOF planar robot
import numpy as np
def inertia_matrix(q, m1, m2, lc1, lc2, L1, I1, I2):
c2 = np.cos(q[1])
m11 = I1+I2+m1*lc1**2+m2*(L1**2+lc2**2+2*L1*lc2*c2)
m12 = I2+m2*(lc2**2+L1*lc2*c2)
m22 = I2+m2*lc2**2
return np.array([[m11,m12],[m12,m22]])
def coriolis(q, qdot, m2, L1, lc2):
h = -m2*L1*lc2*np.sin(q[1])
return np.array([h*qdot[1]**2 + 2*h*qdot[0]*qdot[1], -h*qdot[0]**2])
def gravity(q, m1, m2, lc1, lc2, L1, g=9.81):
c1, c12 = np.cos(q[0]), np.cos(q[0]+q[1])
return np.array([-(m1*lc1+m2*L1)*g*c1 - m2*g*lc2*c12,
-m2*g*lc2*c12])
def computed_torque(q, qdot, q_d, qdot_d, qddot_d, params, Kp, Kd):
e = q_d - q
de = qdot_d - qdot
qddot_cmd = qddot_d + Kd*de + Kp*e # desired accel with PD correction
M = inertia_matrix(q, **params)
C = coriolis(q, qdot, params['m2'], params['L1'], params['lc2'])
G = gravity(q, **params)
return M @ qddot_cmd + C + G
# With CTC, gains can be much lower than pure PID:
Kp = np.diag([400, 400]) # same response everywhere!
Kd = np.diag([40, 40]) # critically damped (ζ = Kd/(2√Kp) = 1.0)
print('Natural freq:', np.sqrt(400)/(2*np.pi), 'Hz')
print('Damping ratio:', 40/(2*np.sqrt(400)))
In pure position control, a robot touching a surface is infinitely stiff — it fights contact forces to reach its target. For delicate operations (assembly, human collaboration, surgery), this rigidity is dangerous. Impedance control replaces the rigid position target with a force-displacement relationship: F = K·(x_d - x) + B·(ẋ_d - ẋ). The robot behaves like a virtual spring-damper. K (stiffness) controls how firmly the robot holds its target. K = 0: the robot is "force-free". B (damping) controls how motion is resisted. In practice: high stiffness for free-space precision, low stiffness during contact transitions, moderate stiffness for compliant assembly. Each of the 6 Cartesian DOF can have independent stiffness/damping values.
# Cartesian impedance control — stiffness profiles
import numpy as np
# Stiffness matrix K (diagonal — independent per DOF)
# Units: N/m for translation, N·m/rad for rotation
profiles = {
'free_space_rigid': np.diag([5000, 5000, 5000, 200, 200, 200]),
'contact_assembly': np.diag([ 500, 500, 2000, 50, 50, 100]),
'polishing': np.diag([ 50, 50, 3000, 20, 20, 50]),
'human_handguide': np.diag([ 10, 10, 10, 5, 5, 5]),
'surgical': np.diag([ 30, 30, 30, 10, 10, 10]),
}
# Control law: τ = Jᵀ · (K·e + B·ė)
# J: Jacobian matrix (maps Cartesian forces to joint torques)
# e = x_d - x (6D Cartesian error: 3 position + 3 orientation)
# ė = ẋ_d - ẋ (6D velocity error)
# Peg insertion example:
# Z-axis: low stiffness (500 N/m) — allows compliance into hole
# XY-axes: moderate (2000 N/m) — guides peg to centre via contact
# As peg contacts chamfer at angle:
# Contact force F_contact → Cartesian deflection Δx = F/K
# Deflection guides peg toward centre → insertion succeeds
# With pure position control:
# Robot fights contact → jams → servo fault
print('Deflection at 10N contact force:')
for task, K in profiles.items():
defl_z = 10/K[2,2]*1000 # mm
print(f' {task:25s}: {defl_z:.1f} mm deflection in Z')
Force control directly regulates the force the robot applies to the environment. It requires a force/torque (F/T) sensor — a 6-axis sensor at the wrist (ATI Gamma/Delta, Robotiq FT 300). Hybrid position/force control divides the task space: some directions controlled by position (free directions), others by force (contact directions). Example: surface polishing — control force in Z (normal, perpendicular to surface) while controlling position in XY (path along the surface). This is the workhorse of grinding, deburring, and polishing. Force PI controller: steady-state force error eliminated by integral. Typical: F_target = 10–50 N, force loop bandwidth 5–10 Hz, inner position loop at 100+ Hz.
# Hybrid position/force control — surface following
import numpy as np
class HybridController:
def __init__(self, K_pos, K_force, Ki_force, S, dt=0.001):
"""
S: selection vector — 1=force control, 0=position per DOF
"""
self.K_pos = K_pos
self.K_force = K_force
self.Ki_force = Ki_force
self.S = np.diag(S)
self.Sc = np.eye(6) - self.S # complement
self.integral = np.zeros(6)
self.dt = dt
def update(self, x_d, x, f_d, f_meas):
pos_err = x_d - x
force_err = f_d - f_meas
self.integral += force_err * self.dt
v_force = self.S @ (self.K_force * force_err
+ self.Ki_force * self.integral)
v_pos = self.Sc @ (self.K_pos * pos_err)
return v_force + v_pos
# Polishing task: control normal force (Z), follow path (XY)
hybrid = HybridController(
K_pos=np.diag([100,100,0,10,10,10]),
K_force=np.diag([0,0,0.03,0,0,0]),
Ki_force=np.diag([0,0,0.4,0,0,0]),
S=[0,0,1,0,0,0]
)
print('Force control applications:')
print(' Grinding: 20-50 N, ±2 N control')
print(' Deburring: 5-20 N, self-adapts to surface')
print(' Polishing: 2-10 N, constant contact pressure')
print(' Assembly: < 5 N, position-dominated with force monitoring')
print(' F/T sensors: ATI Gamma (±32N), ATI Delta (±165N)')
Commissioning is where dynamics and control knowledge is applied to real hardware. Servo drives must be tuned for each joint and payload. Resonances must be identified and filtered. Payload inertia must be measured or estimated. Friction must be modelled. The whole system must be made robust to temperature variation, wear, and part variability. This section covers the systematic procedures that experienced engineers use to take a robot system from first power-on to production-ready performance, including the diagnostic signs that tell you exactly which parameter to adjust.
Describe the step response you observe on your real robot. The tool diagnoses the problem and tells you exactly which gain to adjust. This is the mental model every servo commissioning engineer uses.
A structural resonance in your robot makes it unstable above a certain bandwidth. Design a notch filter to suppress it and extend your achievable bandwidth. Toggle the notch on and off to see how much bandwidth you recover.
Golden rule: always tune the innermost loop first, then work outward — never the other way around. (1) Current loop: auto-tuned by the drive, verify bandwidth 2–5 kHz. (2) Velocity loop: start with only Kp. Increase until oscillation appears (Ku). Note the oscillation period (Tu). Apply Ziegler-Nichols or bandwidth-based tuning. Add Ki slowly until steady-state velocity error is eliminated in <50 ms. (3) Position loop: bandwidth = velocity BW / 10. Kp_pos = 2π·BW_pos. Add Kd_pos only if significant overshoot remains. (4) Add feedforward: velocity FF first (reduces constant-velocity error), then acceleration FF (reduces acceleration/deceleration error). (5) Test with full payload — re-tune if tracking errors increase significantly.
// Servo tuning procedure — bandwidth-based method
//
// ══ Step 1: Velocity loop ═════════════════════════════
// Target BW: 200 Hz (typical industrial joint)
// Kp_vel = 2*pi*BW_target * J_total
// = 2*pi*200 * 0.003 = 3.77 N·m/(rad/s)
// Ti = 5 / BW_target = 5/200 = 0.025 s
// Ki_vel = Kp_vel / Ti = 3.77/0.025 = 151 N·m/rad
//
// Test: velocity step 10 rpm
// Target: rise time 5-20ms, overshoot < 10%, settling < 50ms
//
// ══ Step 2: Position loop ════════════════════════════
// BW_pos = BW_vel / 10 = 20 Hz
// Kp_pos = 2*pi*20 = 125.7 (1/s)
//
// Test: position step 5mm
// Target: rise 20-50ms, overshoot < 5%, settling < 150ms
//
// ══ Step 3: Feedforward ══════════════════════════════
// Command constant-velocity move:
// If tracking error follows velocity profile → increase Kff_v
// Command trapezoidal move:
// If error peaks at accel/decel → increase Kff_a
// Iterate until tracking error < 0.1° during motion
//
// ══ Performance targets (6 kg payload robot) ═════════
// Joint tracking error during move: < 0.5°
// Position error at rest: < 0.01°
// TCP repeatability: ±0.02 mm
// Step overshoot: < 5%
// Settling time (10mm step): < 150 ms
// Following error at 100 mm/s TCP: < 0.3 mm
Real robot joints are not rigid — gearboxes, couplings, and link structures have resonance frequencies where small forces cause large oscillations. If control bandwidth exceeds a structural resonance, the controller excites rather than damps it, causing violent oscillations that can break the robot. Identification: inject a low-amplitude frequency sweep (chirp) into the torque command and measure the velocity response. Common resonances: harmonic drive torsional resonance 50–200 Hz; link bending mode 30–150 Hz; gearbox chatter 10–50 Hz. Filters: a notch filter at the resonance frequency eliminates it in a narrow band. A low-pass filter on velocity feedback attenuates encoder noise above its cutoff. Both are standard in all industrial servo drives. Rule: set control bandwidth at least one octave (2×) below the lowest structural resonance.
# Resonance ID and notch filter design
from scipy import signal
import numpy as np
# Inject chirp signal at low amplitude (5% rated torque)
def make_chirp(f_start=10, f_end=500, duration=5, fs=4000):
t = np.arange(0, duration, 1/fs)
return t, signal.chirp(t, f0=f_start, f1=f_end,
t1=duration, method='logarithmic') * 0.05
# After measuring response: identify peaks in freq response
# Common finding: peak at 120 Hz (harmonic drive torsional mode)
f_resonance = 120 # Hz
# Design notch filter: Q=3, fs=4000Hz
def notch_filter(f_notch, Q, fs=4000):
w0 = 2*np.pi*f_notch/fs # normalized frequency
b, a = signal.iirnotch(w0/np.pi, Q)
return b, a
b, a = notch_filter(120, Q=3)
w, H = signal.freqz(b, a, fs=4000, worN=2000)
idx = np.argmin(np.abs(w-120))
print(f'Notch depth @ 120 Hz: {20*np.log10(abs(H[idx])):.1f} dB')
# Should be > -20 dB attenuation
# Rule of thumb: after adding notch:
# Bandwidth can be increased by 30-100% before instability
# Phase lag at BW (from notch): < 15° for Q=3 (acceptable)
# Low-pass filter on velocity feedback (tame encoder noise)
# Cutoff = 3 × velocity loop bandwidth = 3 × 200 = 600 Hz
sos_lpf = signal.butter(2, 600, fs=4000, btype='low', output='sos')
print('LPF phase lag @ 200Hz:', -signal.group_delay(
signal.butter(2, 600, fs=4000, output='ba'), [200], fs=4000)[1][0]*200, '°')
When a robot changes its payload, its dynamic model changes. Incorrectly specified payload causes: (1) wrong gravity compensation — robot sags when stationary; (2) wrong inertia feedforward — poor tracking during fast moves; (3) incorrect safety force limits in cobots — false collision detections or, worse, missed detections. Modern robot controllers have automatic payload identification: command a series of specific motions, measure joint torques, solve a least-squares problem to identify mass, centre of gravity, and inertia tensor. ABB: LoadIdentify (2 minutes, fully automatic). KUKA: LoadData identification routine. Universal Robots: built-in payload estimator. If your robot "sags, oscillates at stops, or triggers false safety stops", incorrect payload data is the first thing to check.
# Payload identification — least-squares estimation
import numpy as np
# Model: τ_payload = J^T * W(q) * [m, m*rx, m*ry, m*rz]
# where W(q) is the gravity wrench regressor, built from FK
def build_regressor_row(J, g_in_flange):
"""
Build one row of the regressor matrix.
J: 3×n Jacobian (linear velocity part only)
g_in_flange: 3×1 gravity vector in flange frame
Returns 4 columns: [m, m*rx, m*ry, m*rz] coefficients
"""
# Simplified: gravitational force at TCP
F_gravity_cols = np.vstack([g_in_flange, # mass term
np.zeros((3,3))]) # + moment terms
return J.T @ F_gravity_cols[:3, :]
# Procedure:
print('Payload identification procedure:')
print('1. Attach payload and secure safely')
print('2. Move robot to 15+ diverse orientations')
print('3. At each pose (static): measure joint torques')
print('4. Build regressor matrix Y from FK + Jacobians')
print('5. Solve: [m, m*rx, m*ry, m*rz] = (Y^T Y)^-1 Y^T τ')
print('6. Enter result into controller payload table')
print()
print('Verification tests:')
print(' Static: hold arm at 45°, gravity comp ON — no sag')
print(' Dynamic: no false collision alarms at rated speed')
print(' Accuracy: mass ±0.1 kg, CoG ±5 mm (typical)')
print()
print('Wrong payload symptoms:')
print(' Sag at low speed → gravity comp wrong → check mass/CoG')
print(' Oscillation at stops → inertia FF wrong → check inertia')
print(' False collision faults → model mismatch → re-identify')
Every real robot application has specific dynamic and control requirements. Arc welding demands sub-millimetre path accuracy at constant TCP speed — tracking errors become visible as weld bead defects. Grinding requires force control to maintain consistent material removal despite surface variation. High-speed pick-and-place pushes motors to their dynamic limits simultaneously. Collaborative robot assembly requires compliant, force-limited interaction. Understanding the control requirements of your specific application lets you choose the right robot, configure it correctly, and diagnose performance issues systematically rather than by trial and error.
A robot follows a surface with random height variation (±5 mm — like a real casting). Pure position control digs in at high spots and lifts off at low spots. Force control maintains constant contact. Tune the PI gains to see the force quality change.
| Application | Control mode | Key requirement | F/T sensor? | Typical robots |
|---|---|---|---|---|
| Arc welding | Position (CNT path) | TCP speed ±2% | Optional (TAST) | FANUC Arc Mate, ABB IRB 1600 |
| Surface grinding | Hybrid force/position | F_normal 20–50 N | Required | FANUC M-20iD, KUKA KR 10 |
| Deburring | Force control | F_normal 5–20 N | Required | ABB IRB 2600, UR10e |
| Polishing | Force + path | F_normal 2–10 N | Required | FANUC CRX-10iA, UR5e |
| Assembly (peg/hole) | Impedance control | K 50–500 N/m | Recommended | KUKA LBR iiwa, Franka FR3 |
| Pick and place | Position (joint space) | Cycle time | No | ABB IRB 360, FANUC M-3iA |
| Human handguide | Admittance/impedance | K < 20 N/m | Built-in joints | UR e-Series, LBR iiwa, Doosan |
| Spot welding | Position + gun force | Gun force 2–4 kN | No (gun sensor) | FANUC R-2000iC, KUKA KR 210 |
Arc welding is among the most demanding applications for robot path control. Weld bead quality depends on: constant TCP speed (±2% — speed variation changes heat input and bead width), precise path following (±0.5 mm from programmed path), and correct torch orientation (±0.5°). These requirements demand: quintic or higher velocity profiles, full feedforward including Coriolis compensation for circular welds, and continuous path mode (CNT in FANUC, CONT in ABB, C_PTP in KUKA) to avoid speed dips at waypoints. The most common welding defect traced to robot control is "scalloping" — TCP speed drops to near-zero at every fine-stop waypoint, causing cold spots and bead width variation. Solution: switch to continuous path mode with appropriate corner rounding radius.
// Arc welding motion quality
//
// Path accuracy requirements (automotive body welding):
// TCP path deviation: ±0.5 mm (visible bead wander)
// TCP speed variation: ±2% (±3 mm/s at 150 mm/s)
// Arc length: ±0.5 mm (torch-to-work distance)
//
// Interpolation error for circular welds:
// Max chord error: Δ = R*(1-cos(φ/2)) ≈ R*φ²/8
// R=80mm, φ=5° steps: Δ = 0.076mm ✓
// R=80mm, φ=10° steps: Δ = 0.30mm — borderline!
// → Use ≤5° steps for circular welds OR arc interpolation
//
// Speed continuity:
// FINE stop mode: decelerates to ZERO at every waypoint
// CNT/CONT mode: robot blends through corner at speed
// → Always use CNT for welding seams
//
// Arc voltage sensing (TAST) — torch height control:
// v_arc_high → TCP too far → move closer
// v_arc_low → TCP too close → move away
// PI control: Kp=2mm/V, Ki=5mm/(V·s), BW~5Hz
//
// Welding robot specs:
// FANUC Arc Mate 100iD: 6kg, 1373mm, ±0.08mm
// ABB IRB 1600-6/1.45: 6kg, 1450mm, ±0.05mm
// KUKA KR 6 R1840: 6kg, 1840mm, ±0.04mm
// Yaskawa MA1440: 6kg, 1440mm, ±0.08mm
Grinding and deburring require the robot to maintain a controlled contact force against the workpiece. Pure position control fails because: workpiece geometry varies ±2 mm (castings), tool wear changes effective tool length by 0.1–0.5 mm/hour, and fixture variation adds ±0.5 mm. Force control maintains consistent material removal rate regardless. Hardware: ATI Delta or Gamma 6-axis F/T sensor at the wrist (1 kHz measurement). Control: force PI loop in Z (normal) direction, position control in XY (path). Typical parameters: 20–30 N normal force, force loop bandwidth 5 Hz. The force loop is intentionally slow — faster than ~10 Hz causes instability because the rigid workpiece surface creates a very stiff contact (high gain × high stiffness = instability).
# Force control — grinding/deburring
class GrindingForceController:
def __init__(self, F_target, Kp=0.03, Ki=0.5, dt=0.001):
self.F_target = F_target # N, e.g. 25N for aluminium
self.Kp = Kp # m/s per N
self.Ki = Ki # m/s² per N
self.dt = dt
self.integral = 0.0
self.F_filt = F_target
self.alpha = 0.15 # low-pass filter (noisy F/T data)
def update(self, F_measured):
# Low-pass filter the F/T reading
self.F_filt = self.alpha*F_measured + (1-self.alpha)*self.F_filt
error = self.F_target - self.F_filt
self.integral += error * self.dt
# Returns: velocity correction in contact-normal direction
return self.Kp*error + self.Ki*self.integral
# Production parameters (aluminium die casting deburring):
# Tool: carbide burr, 12mm Ø, 25,000 rpm
# Normal force: 20-30 N (nominal 25 N)
# Path speed: 40-80 mm/s along the seam
# F/T sensor: ATI Gamma SI-130-10 at 1 kHz
# Force BW: ~5 Hz (surface contact stiffness limits this)
#
# Quality metrics:
# Material removal: 0.15 ± 0.02 mm³/mm (consistent)
# Surface finish: Ra ≤ 3.2 µm (no gouging)
# Cycle time: 45 s/casting vs 120 s manual
#
# Why position control fails:
# Surface varies ±1.5mm per casting
# At Ks=10 N/mm: 1.5mm position error → 15N force variation
# → Some passes remove too much, others skip entirely
High-speed pick-and-place — a delta robot picking chocolates at 150 picks/minute — is the most demanding application for dynamic performance. The robot must: accelerate from rest to 4 m/s, decelerate to rest, and settle within 2 mm in 300 ms. Motor torques during acceleration hit 300–500% of continuous rating. Thermal management relies on short duty cycle (high peak, fast, then dwell). For delta robots, the parallel kinematic structure couples all three motors during any move — the dynamic model is more complex than a serial arm. Constraint forces from the parallel chains appear in the equations of motion. All delta robots ship pre-tuned for their rated speed — never exceed these limits without consulting the manufacturer. The speed rating assumes the correct end-effector mass.
// Delta robot pick-and-place — cycle time & thermal analysis
//
// ABB IRB 360 FlexPicker — standard 'ice cream cone' move
// (25mm vertical + 150mm horizontal, 1 kg payload)
//
// Motion profile:
// Peak TCP speed: 10 m/s
// Peak TCP acceleration: 100 m/s² = 10.2 g
// Motor peak torque: 8.0 N·m (350% of 2.3 N·m cont)
// Cycle time: 0.58 s (103 picks/min standard)
// Rated max: 150 picks/min (T=0.4s)
//
// RMS torque check at 150 picks/min:
// Cycle = 0.4s: 0.1s @ 8 N·m peak + 0.3s @ 1 N·m idle
// τ_rms = sqrt((8²×0.1 + 1²×0.3)/0.4) = sqrt(16.75) = 4.1 N·m
// Motor continuous: 2.3 N·m → 4.1 > 2.3 !!
// → Motor IS overloaded at 150 picks/min (liquid cooled!)
// → With liquid cooling: continuous rating rises to ~5 N·m ✓
//
// Settling time:
// Carbon-fibre links: very low structural damping
// Active anti-sway: extra derivative impulse at final phase
// Reduces settling: 120ms → 40ms (3× improvement)
// Vision trigger: add 15-50ms latency
//
// Throughput limit calculation:
// T_cycle = T_pick + T_place + T_transit + T_settle + T_vision
// = 0.08 + 0.08 + 0.18 + 0.04 + 0.05 = 0.43s
// Theoretical max: 140 picks/min (rated 150 = with motor reserve)
Inertia calculations, PID tuning, computed torque control, harmonic drives, RMS torque, impedance, force control — real dynamics and control engineering tested.
A robot link is a solid aluminium rod: mass 2 kg, length 0.4 m, rotating about one end. The motor must accelerate it at α = 5 rad/s². What torque is required (ignoring gravity)?
A PID controller has parameters Kp=50, Ki=10, Kd=2. The error is 5 mm and has been present for 0.5 s. The error derivative is -3 mm/s (error decreasing). What is the total control output?
What is "computed torque control" and what is its main advantage over a simple PID?
A servo motor has peak torque 8 N·m and rotor inertia 0.0002 kg·m². Load inertia reflected to motor is 0.0010 kg·m². What is the available acceleration and the inertia ratio?
What is impedance control and when is it used instead of position control?
A harmonic drive gearbox has ratio N=100. Motor inertia is 0.0003 kg·m², link inertia is 3 kg·m². What is the reflected load inertia and inertia ratio?
What causes integral windup in a PID controller and how is it prevented?
A robot performs a circular weld at 150 mm/s TCP speed, 80 mm radius. What centripetal acceleration acts on the TCP?
What is the difference between position control and torque control modes in a servo drive? Which do cobots use?
A motor has continuous rating 5 N·m and peak 15 N·m. Duty: 60% at 4 N·m, 40% at 12 N·m. Will it overheat?