Open-loop and closed-loop control: compare plans with position feedback

Explore open-loop and closed-loop control by moving an axis along a planned path. Calculate how gain errors, drift, initial position, and sensor bias change tracking, then connect or disconnect the feedback path.

By 14 min read

What you will learn

  • Identify whether measured position can change a controller's command.
  • Derive a scheduled velocity command from a nominal motion model.
  • Calculate position error during motion and after the target stops.
  • Separate drift, gain mismatch, initial offset, and sensor bias.
  • Explain when feedback helps and when measurement errors can hurt tracking.

Before you start

A motion plan can place an axis exactly where you want it. That result depends on the axis following the model and starting where the plan expects. A position measurement gives the controller a way to respond when either condition fails.

This lesson compares open-loop and closed-loop control on the same four-metre move. You will calculate both trajectories, disconnect the measurement path, and check whether a correction improves the true position.

Trace the open-loop and closed-loop control paths

An open-loop position controller selects its command without using the resulting position to update that command. Its schedule can still use a detailed model, a clock, or a known disturbance. Logging a position measurement does not close the loop if the command ignores it.

A closed-loop position controller returns measured position to the command calculation. The axis changes position, the sensor reports that change, and the controller adjusts what the axis receives.

Information pathWhat changes the command?
Plan → command → axisThe scheduled plan
Plan and measured position → command → axis → measured positionThe plan and the measured tracking error

Lynch and Park's control overview follows this flow through sensors, controllers, actuators, and robot motion. Open or closed describes a particular loop boundary. A position controller can operate open loop while a motor drive underneath it closes an inner speed loop.

Define the axis and the motion plan

Use one straight axis. Its true position is x, its velocity command is u, and a positive dimensionless gain g maps command to actual velocity. A signed disturbance velocity d adds to that motion:

dx/dt = gu + d

This equation treats velocity response as immediate. Modern Robotics' velocity-input lesson uses this modeling choice when lower-level drives can follow velocity requests. Here d represents extra signed velocity, measured in m/s; it is not a force or torque.

QuantityMeaning
x, rTrue and reference position, in metres
uVelocity command, in m/s
gActual velocity gain, default 1
dZero before 2 s, then the selected disturbance velocity
x₀Both axes' initial position, default 0 m
bConstant position sensor bias, in metres

The reference moves from 0 m at 1 m/s for four seconds. It then stays at 4 m. With time t measured in seconds, r(t) = min(t, 4) metres.

The reference velocity v is 1 m/s before 4 s and zero afterward. Position remains continuous at 4 s, while the reference velocity changes instantly. We use the value after a change when reporting a command at that exact time.

Turn a model into a scheduled command

Suppose the controller's nominal model is dx/dt = ĝu, with estimated gain ĝ = 1 and no disturbance. Solving that model for the desired velocity gives the feedforward command u = v / ĝ = v.

That command is 1 m/s for four seconds, then zero. It follows the reference velocity without waiting for a position error. The same scheduled term will remain part of the closed-loop controller.

Feedforward control extends this idea to a joint with inertia and drag. Its speed experiment predicts torque from the desired acceleration, then uses feedback to correct model mismatch and unexpected loads.

For the actual gain g and the disturbance step in this lesson, the open-loop position follows directly from integration:

x open(t) = x₀ + g r(t) + d after × max(0, t − 2 s)

With g = 1, d = 0, and x₀ = 0, this schedule tracks the reference exactly. A repeatable, calibrated task can use such a plan without continuous position correction, provided its errors meet the task's requirements.

Open loop retains an unknown initial offset. It also accumulates error from an unmodeled velocity disturbance. The model-uncertainty lesson separates uncertain parameter values from missing physics and disturbance assumptions.

Let measured position change the command

Let the sensor report y = x + b. Compare that measurement with the reference and multiply the measured error by a nonnegative gain K:

y = x + b
e measured = r − y
u = v + K(r − y)

K has units 1/s, so K times a position error has velocity units. If the sensor reports a position behind the reference, the correction increases the command. If it reports a position ahead, the correction decreases the command and can request reverse motion.

Modern Robotics' feedforward-plus-feedback treatment adds the desired velocity to a position correction. That source also develops integral feedback. This experiment uses only the proportional term, so some disturbances leave a lasting error.

Disconnecting the measurement path removes the entire correction. Setting K = 0 gives the same command and trajectory, even if the diagram still shows a connected path. A zero-gain connection has no influence on motion.

Solve the error between scheduled changes

Define true error as e = r − x. Since measured error is e − b, substituting the command into the axis equation gives:

de/dt = (1 − g)v − d + gKb − gKe
λ = gK
a = (1 − g)v − d + λb

During each interval with fixed v and d, the equation is de/dt = a − λe. For connected feedback with K positive, its exact solution is:

e∞ = a / λ
e(t₀ + Δt) = e∞ + [e(t₀) − e∞] exp(−λΔt)
T = 1 / λ

An interval equilibrium predicts what would happen if those inputs continued indefinitely. The reference moves for only four seconds, so its moving equilibrium may never occur. At 2 s and 4 s, carry the continuous position into the next interval and use the new inputs.

For K = 0 or a disconnected path, use de/dt = (1 − g)v − d. Error then changes linearly within each interval; there is no exponential correction. The code handles this branch without dividing by zero.

After the reference stops, connected feedback with positive K approaches e∞ = b − d/(gK). With zero feedback gain and nonzero d, the position keeps drifting and no finite error limit exists.

Follow unexpected drift through the hold

Use the defaults: g = 1, K = 1/s, b = 0, and x₀ = 0. Both axes track exactly until 2 s. Then a disturbance of −0.25 m/s starts.

For the connected axis, the reference-velocity term cancels because g = 1. From 2 s onward, de/dt = 0.25 − e, with e(2) = 0. Thus e(t) = 0.25[1 − exp(−(t − 2))] when the numerical time is in seconds.

At 6 s:

QuantityOpen-loop axisConnected axis
Reference position4 m4 m
True position3.000000 m3.754579 m
True error1.000000 m0.245421 m
Command0 m/s+0.245421 m/s
Actual velocity−0.250000 m/s−0.004579 m/s

The positive connected command nearly cancels the negative drift. At the long-time limit, a +0.25 m/s command exactly balances it, leaving a +0.25 m position error. Proportional correction needs that error to keep producing the balancing command.

At 4 s, the connected command drops by exactly 1 m/s because the reference velocity stops. The axis position does not jump. The command plot keeps separate curve segments at this change, so it does not draw a false gradual transition.

Separate gain mismatch from initial offset

Now set d = b = x₀ = 0 and use g = 0.75, K = 1/s. The open-loop axis covers only 3 m by 4 s and stays there. During the move, the connected error follows de/dt = 0.25 − 0.75e.

If motion continued forever, the connected error would approach 1/3 m. Once the target stops, the forcing term disappears and the remaining error decays toward zero. At 6 s the connected axis reaches 3.929326 m.

An initial position error behaves differently. Restore g = 1 with no disturbance or sensor bias, but start both axes at x₀ = +0.5 m. The open-loop axis keeps that +0.5 m lead through the move and hold.

The connected lead is 0.5 exp(−t) metres for K = 1/s. At 6 s it is only 0.001239 m. These cases show why a derivative or instantaneous velocity match alone does not establish correct position.

Judge feedback by physical tracking

Use an otherwise calibrated axis with b = +0.25 m and no disturbance. The sensor reports a position ahead of the true position, so the controller slows the axis. With g = K = 1 numerically, true error becomes 0.25[1 − exp(−t)] metres.

At 6 s, true position is 3.750620 m, while measured position is 4.000620 m. The measured error is −0.000620 m, even though true error is +0.249380 m. The calibrated open-loop axis remains exactly on the 4 m reference in this particular comparison.

Choose a control design around the task and available information:

  • A stable, repeatable process with known starting conditions can use a calibrated schedule when its accuracy is sufficient.
  • Position feedback can correct unplanned initial offsets and reduce drift within this model.
  • Sensors add calibration, installation, and maintenance work. Their errors enter the correction itself.
  • Feedback gains also need to respect delays, noise, actuator limits, and physical dynamics in the actual system.

This ideal axis includes none of those delays, velocity limits, inertias, or noisy samples. Its positive g and K always give stable first-order error dynamics. That result does not establish stability for a motor with actuator dynamics or a flexible joint.

Connect and disconnect the feedback path

The lab compares a permanently open-loop axis with the blue selected axis. Both start at the same chosen position and experience the same actual gain and disturbance. Changing a setting starts a new response from that initial condition; it does not switch the controller partway through an existing run.

Follow a plan, then use a measurement

Move four metres and hold the target

Both axes receive the same velocity schedule and physical disturbance. The blue axis can add a correction from its measured position. Change the feedback path to see which information reaches its command.

Schedule → command → axis position

Measured position → error → K × error → command

1.00
1.00
-0.25
0.00
0.00

The target moves at 1 m/s until 4 s, then stays at 4 m. The selected disturbance starts at 2 s and continues during the hold. Gain g multiplies the velocity command; sensor bias adds to true position. Commands can change instantly in this ideal model.

6.00
Position (m) for the open-loop and selected axesReference position, Open-loop position, Selected-axis position across eight seconds. Guides mark the scheduled disturbance at two seconds and the end of reference motion at four seconds. Selected time: 6.000000 seconds. Reference position: 4.000000. Open-loop position: 3.000000. Selected-axis position: 3.754579.02468-105Time (s)Position (m)
Gray dashes: target. Orange dashes: open-loop position. Solid blue: selected-axis position. Curves overlap when their values agree. With sensor bias, purple dots show the measured position; with zero bias, measured and true position coincide.
Command (m/s) for the open-loop and selected axesOpen-loop command, Selected-axis command across eight seconds. Guides mark the scheduled disturbance at two seconds and the end of reference motion at four seconds. Selected time: 6.000000 seconds. Open-loop command: 0.000000. Selected-axis command: 0.245421.02468-102Time (s)Command (m/s)
Orange dashes: scheduled open-loop command. Solid blue: selected-axis command. Separate curve segments preserve the sudden command change at 4 s. Readouts use the value just after each scheduled change. Guides mark 2 s and 4 s, including a zero disturbance at 2 s.
Reference position (m)
4.000000
Open-loop position (m)
3.000000
Selected-axis position (m)
3.754579
Measured position (m)
3.754579
True position error (m)
0.245421
Measured position error (m)
0.245421
Open-loop command (m/s)
0.000000
Selected-axis command (m/s)
0.245421
Selected-axis velocity (m/s)
-0.004579
Disturbance velocity (m/s)
-0.250000
Effective feedback gain (1/s)
1.000000
Hold error limit (m)
0.250000
Hold time constant (s)
1.000000

The hold error limit describes continued operation after 4 s with the same disturbance. It is a long-time prediction, even when the replay cursor is earlier. True error uses physical position; measured error uses the sensor reading.

The connected loop uses measured position to change its command. Compare tracking during motion with the hold after 4 s.

  • Start with Calibrated schedule. Both axes and the reference overlap. Feedback can be connected while its correction stays zero.
  • Select Unexpected drift, then disconnect the feedback path. Both physical trajectories become identical. The sensor reading remains available for inspection.
  • Select Incorrect velocity gain. Compare the tracking error during the move with its decay after 4 s.
  • Select Biased position sensor. Compare true error with measured error before judging accuracy.

The plotted positions use the exact piecewise solution. Samples only draw the curves; their spacing is not a controller update period or integration step. Commands and velocities can jump in this model, while positions stay continuous.

Reproduce the comparison in Python

This standard-library example calculates each constant-input interval directly. It reports the same 6 s comparison as the presets and includes a disconnected measurement path. The long-time limits assume the final reference and disturbance continue beyond the eight-second plot.

from math import expm1

def compare(g=1.0, k=1.0, d=-0.25, bias=0.0, x0=0.0,
            connected=True, time=6.0):
    gain = k if connected else 0.0
    rate = g * gain
    error = -x0
    for start, end, velocity, drift in [
        (0.0, 2.0, 1.0, 0.0),
        (2.0, 4.0, 1.0, d),
        (4.0, 8.0, 0.0, d),
    ]:
        elapsed = max(0.0, min(time, end) - start)
        forcing = (1.0 - g) * velocity - drift + rate * bias
        integral = elapsed if rate == 0 else -expm1(-rate * elapsed) / rate
        error += (forcing - rate * error) * integral
    reference = min(time, 4.0)
    opened = x0 + g * reference + d * max(0.0, time - 2.0)
    selected = reference - error
    measured = selected + bias
    command = (1.0 if time < 4.0 else 0.0) + gain * (error - bias)
    return selected, opened, measured, command

cases = [
    ("calibrated", dict(d=0.0)),
    ("gain mismatch", dict(g=0.75, d=0.0)),
    ("drift", {}),
    ("initial offset", dict(d=0.0, x0=0.5)),
    ("sensor bias", dict(d=0.0, bias=0.25)),
    ("zero gain", dict(k=0.0)),
    ("disconnected", dict(connected=False)),
]
for name, settings in cases:
    x, opened, measured, command = compare(**settings)
    print(f"{name}: x={x:.6f}; open={opened:.6f}; "
          f"measured={measured:.6f}; command={command:.6f}")

Expected output:

calibrated: x=4.000000; open=4.000000; measured=4.000000; command=0.000000
gain mismatch: x=3.929326; open=3.000000; measured=3.929326; command=0.070674
drift: x=3.754579; open=3.000000; measured=3.754579; command=0.245421
initial offset: x=4.001239; open=4.500000; measured=4.001239; command=-0.001239
sensor bias: x=3.750620; open=4.000000; measured=4.000620; command=-0.000620
zero gain: x=3.000000; open=3.000000; measured=3.000000; command=0.000000
disconnected: x=3.000000; open=3.000000; measured=3.000000; command=0.000000

The example supports the displayed 0–8 s interval. expm1(z) evaluates exp(z) − 1 accurately near zero, which keeps the response well behaved for a very small positive gain. Exact zero gain uses the linear branch.

Try it yourself

Exercise 1: follow a positive drift after the target stops

Use g = 1, K = 2/s, b = 0, x₀ = 0, and a +0.5 m/s disturbance starting at 2 s. Find both positions at 6 s and the connected axis's long-time true error and command.

Check your answer: Open-loop position is 4 + 0.5(6 − 2) = 6 m. The connected true error is −0.25[1 − exp(−8)] = −0.249916 m, so its position is 4.249916 m. Its command at 6 s is −0.499832 m/s.

The long-time true error is −0.25 m and command is −0.5 m/s. Multiplying that command by g and adding the +0.5 m/s disturbance gives zero actual velocity. The connected axis holds beyond the target because its negative position error supplies the balancing correction.

Exercise 2: disconnect a biased position measurement

Use the Biased position sensor preset at 6 s. Calculate true and measured errors with the path connected. Then disconnect it without changing the sensor bias. What happens to physical position, the displayed measurement, and the command?

Check your answer: With feedback connected, true position is 3.750620 m, true error is +0.249380 m, and measured error is −0.000620 m. The sensor reports 4.000620 m.

After starting a new run with the path disconnected, physical position is exactly 4 m and true error is zero. The sensor reports 4.25 m, so measured error is −0.25 m. The command is zero during the hold because the open-loop schedule ignores that measurement.

Displaying a measurement and using it to control motion are separate operations. This result depends on the otherwise calibrated axis and absence of disturbance in this preset.

Sources and further study

Continue with transfer functions to describe the input-output relationships behind these trajectories. Keep the reference, disturbance, and measurement error separate as you build that representation.