Skip to content

Run a sampled PID loop against a simulated plant

Observe a 100 ms PID controller drive an LED PWM while a first-order plant model responds in firmware to setpoint and disturbance changes.

Gateway Gus: I want you to keep the simulated-plant boundary visible and explain every output change from setpoint, measurement, and stored controller state., your practice guide

Gateway Gus: I want you to keep the simulated-plant boundary visible and explain every output change from setpoint, measurement, and stored controller state.
Predict the reading, then compare it with the measurement.

Wokwi ESP32

Third party Tool

Tier 1 · Web · No account

Version tested: Compiled and booted by the Wokwi gate (ESP32 Arduino core 3.3.11); captured in the Wokwi web editor on 2026-09-10. Date: 2026-09-10.

Open the ESP32 editor, paste diagram.json, then paste sketch.ino.

Open Wokwi to paste in the files (new tab)

Get the files

Use both prepared files. This is a paste-in setup; saving a project requires a Wokwi account.

diagram.json

1,115 bytes · Circuit connections

Download

sketch.ino

1,607 bytes · ESP32 program

Download

  1. Use the launch button above to open the ESP32 editor in Wokwi.
  2. Select the editor’s diagram.json tab and replace all its text with the supplied diagram.json.
  3. Select the sketch.ino tab, replace all its text with the supplied sketch.ino, then click Start Simulation.

Steps

Screens captured against Wokwi ESP32 Compiled and booted by the Wokwi gate (ESP32 Arduino core 3.3.11); captured in the Wokwi web editor on 2026-09-10 on 2026-09-10; the tool may have moved on — the text steps are the contract.

  1. 1 Step 1

    Do
    Paste the supplied diagram and sketch into Wokwi; inspect the potentiometer, disturbance button, and LED PWM output.
    You will see
    Power: setpoint VCC connects to ESP32 3.3 V; GND returns to ground (diagram.json line 12). Setpoint signal connects to ESP32 GPIO34 (diagram.json line 12). Disturbance button connects ESP32 GPIO13 to ground when pressed (diagram.json line 13). Output LED anode connects to ESP32 GPIO2; its cathode returns through r1 to ground (diagram.json line 14). The output LED’s series resistor r1 is 220 Ω (diagram.json line 8).
    Why it matters
    GPIO34 supplies the requested setpoint, GPIO13 injects the later disturbance, and GPIO2 exposes controller output through the LED. The resistor limits LED current.
    Step 1: A setpoint potentiometer, disturbance button, and PWM LED connect to the ESP32. The ring marks the loop's physical inputs and output.
    Step 1 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)
  2. 2 Step 2

    Do
    In Wokwi's sketch editor, inspect the 100 ms schedule, anti-windup guard, and first-order plant update in the sketch.
    You will see
    Set sample interval and plant time constant: const float SAMPLE_S=0.1f, PLANT_TAU_S=1.2f; (sketch.ino line 4). Set the PID gains: const float KP=2.0f, KI=0.9f, KD=0.08f; (sketch.ino line 5). Detect saturation in the error direction: bool pushingFurther=(output>=100.0f && error>0) || (output<=0.0f && error<0); (sketch.ino line 33). Update the integral only when allowed: if (!pushingFurther) integral=candidate; (sketch.ino line 34). Describe the software plant equation: // Software-in-the-loop plant: y[k+1] = y[k] + dt/tau * (u-y[k]). (sketch.ino line 37). Advance the simulated plant: measured += (SAMPLE_S/PLANT_TAU_S)*(output-measured); (sketch.ino line 38).
    Why it matters
    The sample period and plant time constant define the later response. The saturation guard prevents the integral from growing farther into a limit, while the first-order update advances the simulated measured value.
    Step 2: The sample period, saturation guard, and first-order plant update are visible. The ring marks the software-in-the-loop boundary.
    Step 2 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)
  3. 3 Step 3

    Do
    In the Simulation toolbar, start the run and read the Serial Monitor heading.
    You will see
    Input: run the supplied PID sketch in Wokwi. Observed: "PID LOOP ESP32 READY". Observed: "MODEL=first_order_in_firmware sample_ms=100 tau_s=1.2 output=LED_PWM". Expected: the model boundary and sample period are stated at startup.
    Why it matters
    The plant is modeled by firmware in this run. The declared schedule is 100 ms. The declared time constant is 1.2 s. The LED PWM is an output indicator, not a physical plant measurement.
    Step 3: The startup record identifies the in-firmware first-order plant and 100 ms loop. The ring marks the model boundary.
    Step 3 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)
  4. 4 Step 4

    Do
    In the Serial Monitor panel, follow the first controller sample rows.
    You will see
    Input: leave the supplied potentiometer setting unchanged. Observed: "setpoint=68.4 measured=52.4 output=62.3 saturated=NO model=SIMULATED". Observed later: "setpoint=68.4 measured=55.8 output=61.9 saturated=NO model=SIMULATED". Expected: setpoint, measurement, command and saturation in each row.
    Why it matters
    The setpoint remains 68.4 in both rows. The modeled measurement rises from 52.4 to 55.8. The output changes from 62.3 to 61.9. Both rows declare their simulated-model status.
    Step 4: Serial rows report setpoint, measured, output, saturation, and model=SIMULATED. The ring marks one complete sample record.
    Step 4 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)
  5. 5 Step 5

    Do
    In the Serial Monitor panel, let the modeled measurement approach the potentiometer setpoint.
    You will see
    Input: leave the setpoint at 68.4. Observed: "setpoint=68.4 measured=63.5 output=65.4 saturated=NO model=SIMULATED". Observed later: "setpoint=68.4 measured=64.3 output=65.9 saturated=NO model=SIMULATED". Expected: measured rises toward the unchanged setpoint.
    Why it matters
    The modeled measurement rose from 63.5 to 64.3. The setpoint remained 68.4. The command changed slightly as the error narrowed. The rows explicitly label the plant as simulated.
    Step 5: The simulated measurement approaches the setpoint as output leaves saturation. The ring marks the settled trend.
    Step 5 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)
  6. 6 Step 6

    Do
    On the Wokwi circuit canvas, press Disturb plant once.
    You will see
    Input: press Disturb plant once on the Wokwi circuit canvas. Observed before: "setpoint=68.4 measured=59.8 output=63.2 saturated=NO model=SIMULATED". Observed: "DISTURBANCE applied=-25.0 to simulated plant". Observed after: "setpoint=68.4 measured=40.2 output=100.0 saturated=YES model=SIMULATED".
    Why it matters
    The disturbance lowered the modeled measurement from 59.8 to 40.2. The setpoint stayed at 68.4. The controller drove the output to its 100.0 limit. The monitor explicitly marks the plant as simulated.
    Step 6: real Wokwi monitor shows the -25 disturbance, measured 40.2, and saturated output 100.0; the ring marks the event and first response.
    Step 6 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)
  7. 7 Step 7

    Do
    In Wokwi's Serial Monitor, continue for at least twelve samples after the disturbance.
    You will see
    Input: continue for twelve or more 100 ms samples after the disturbance. Observed: "setpoint=68.4 measured=58.0 output=75.7 saturated=NO model=SIMULATED". Observed later: "setpoint=68.4 measured=62.6 output=69.2 saturated=NO model=SIMULATED". Expected: measured moves back toward the unchanged 68.4 setpoint.
    Why it matters
    The modeled measurement rose from 58.0 to 62.6. The output fell from 75.7 to 69.2 as error narrowed. Both rows report no saturation. These serial samples show recovery, not a physical plant measurement.
    Step 7: real Wokwi monitor shows post-disturbance measured values rising while output falls; the ring marks recovery rows through 62.6 and 69.2.
    Step 7 · Wokwi ESP32; numbered callout added to a real capture. Enlarge screenshot (new tab)

Chapter checks

These questions refer to the chapter’s examples. Use the return links to review their answers.

  1. A fan must hold cabinet temperature near a target while heat load changes when processors wake and sleep. Which control shape is the best first loop choice?

    Return to the chapter’s knowledge check
  2. A refrigerated cabinet runs a fixed fan schedule, but door openings now vary by hour. The cloud service can suggest setpoints, yet network delays are sometimes several seconds. Which design record best fits the risk?

    Return to the chapter’s knowledge check

Caution

The first-order plant is simulated in firmware; the potentiometer is only a setpoint and the LED is only a PWM command indicator. This does not prove process physics, sensor quality, stability, actuator limits, fault response, or safe tuning. Use conservative limits and representative hardware evidence before controlling a real plant.

Return to Open-Loop and Closed-Loop Systems · Browse Labs