Exercise: Model and Tune a Closed-Loop Axis
This exercise uses a small software model before hardware tuning. The goal is not a perfect physics model; it is to learn how gain, saturation, delay, and load affect a closed-loop axis.
Learning Objectives
By the end of this exercise, you should be able to implement a simple discrete plant, tune P and PI/PID gains, read step-response behavior, identify windup, and define safe hardware tuning steps.
Prerequisites
You should know feedback-control terms, PID terms, basic Python, and the difference between position, velocity, and acceleration.
Task
Simulate a position axis with command saturation. Tune it so a step from 0 to 1.0 m reaches the target with less than 10% overshoot and settles within 0.02 m.
Buildable Code
Save and run this as axis_pid_demo.py.
Ts = 0.01
steps = 500
setpoint = 1.0
position = 0.0
velocity = 0.0
integral = 0.0
previous_error = 0.0
Kp = 18.0
Ki = 3.0
Kd = 2.0
max_force = 4.0
mass = 1.0
damping = 1.2
history = []
for k in range(steps):
error = setpoint - position
integral += error * Ts
derivative = (error - previous_error) / Ts
raw_force = Kp * error + Ki * integral + Kd * derivative
force = max(-max_force, min(max_force, raw_force))
# simple anti-windup: undo integration when saturated in the same direction
if force != raw_force and (raw_force * error) > 0:
integral -= error * Ts
acceleration = (force - damping * velocity) / mass
velocity += acceleration * Ts
position += velocity * Ts
previous_error = error
history.append((k * Ts, setpoint, position, force, error))
for row in history[::25]:
print(f"t={row[0]:.2f}s set={row[1]:.2f} pos={row[2]:.3f} force={row[3]:.2f} err={row[4]:.3f}")
print(f"final position={position:.3f}, final error={setpoint-position:.3f}")
Expected Behavior
The position should rise toward 1.0 m, overshoot only modestly, and settle near the target. The force should saturate early, then reduce as the error shrinks.
Verification Steps
- Run the script unchanged and record final error.
- Set
Ki = 0and compare steady-state behavior. - Increase
Kpuntil overshoot becomes unacceptable. - Increase
Kdto add damping. - Set
max_force = 1.0and observe slower response and saturation. - Remove the anti-windup block and compare recovery.
Common Failure Symptoms
- Oscillation grows: gains too high or damping too low.
- Slow response:
Kptoo low or force limit too small. - Final offset remains: no integral action or too much friction/load.
- Big overshoot after saturation: integral windup.
Debugging Guidance
Change one gain at a time. Print or plot setpoint, position, force, and error. If the command is saturated most of the time, tuning cannot fix the undersized actuator. Increase actuator capability or reduce acceleration demand.
Extension Challenge
Add a one-sample measurement delay and retune the controller. Then add measurement noise and compare derivative on error versus derivative on measurement.
Concise Explained Solution
A workable tuning uses enough Kp to move quickly, enough Kd to damp overshoot, and small Ki to remove residual error. The force limit is part of the design, not a nuisance: when force saturates, anti-windup prevents the integral term from accumulating an impossible command.
Further Reading
- Control Tutorials for MATLAB and Simulink, PID step response.
- Astrom and Murray, Feedback Systems.
- Brett Beauregard, practical PID implementation notes.