Troubleshooting Siemens PID_Compact S7-1200 DC Motor Speed

David Krause15 min read
PID ControlSiemensTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Problem Description

On a Siemens SIMATIC S7-1215 DC/DC/DC controller running TIA Portal, the PID_Compact instruction is configured to regulate the speed of two small permanent-magnet DC motors that drive a plastic disc past a bolt. Two inductive proximity sensors detect the bolt passage and feed pulse counts into the PLC, where an SCL function block derives a rotational speed. Despite any setpoint value entered, the controller output (OutputPER) drives immediately to the maximum value (27648 or 100% duty cycle). The motor therefore runs flat-out on the first scan and remains saturated, regardless of whether the setpoint is 10% or 90% of full scale.

Symptoms typically include:

  • Output reaches saturation (OutputPER = 27648 or PWM duty 100%) within one or two PID cycles after the first process-value update.
  • Setpoint changes are ignored; the controller never recovers from saturation.
  • Integral term (I_ITVAL inside the instance DB) accumulates rapidly to its internal limit.
  • If a digital PWM output is used, the duty cycle latches to 100%.
Symptom class: This is a classic "output-saturated at first update" failure. The root cause is almost always one of four conditions: (1) sign inversion between process value and actuator, (2) the controller is being driven by a stale or zero feedback, (3) the gain is set far too high before any tuning has been performed, or (4) the PER/per-cent conversion is mismatched and the setpoint interpretation is wrong.

System Architecture

Before changing any code, document the I/O mapping. The S7-1215 DC/DC/DC variant (for example, 6ES7215-1AG40-0XB0) provides on-board:

  • 14 digital inputs (24 V DC), of which the first six are usable as HSC (high-speed counter) channels at up to 100 kHz single-phase or 80 kHz quadrature.
  • 10 digital outputs (24 V DC, transistor). The first four are usable as PWM outputs at 100 Hz to 100 kHz.
  • 2 analog inputs (0 to 10 V) on the CPU, expandable with SM 1231 / SM 1234 signal boards.

Reference: SIMATIC S7-1200 Programmable Controller System Manual.

Recommended wiring for the dual-motor speed-control application:

  • Feedback sensors: Inductive proximity sensors wired to the HSC-capable inputs. Use HSC channel 1 and HSC channel 2 in "Count continuously" mode. Each sensor pulse = one bolt passage; count over a fixed 100 ms or 1 s window to derive rpm.
  • Motor command: Two options. (a) PWM output driving the enable/direction input of a 4-quadrant DC driver (e.g., a Siemens SINAMICS V20 in DC-bus mode, or a third-party H-bridge such as a Cytron MDD10A or a PWM-controlled analog input on a driver). (b) Analog output 0 to 10 V from an SM 1232 AO4 module feeding the speed reference of the driver.
Grounding: Connect the M terminal of the inductive sensors to the CPU M terminal. For PWM control of a switching DC driver, place an RC snubber or schottky diode across the motor terminals to suppress inductive kick. The S7-1200 transistor outputs are rated 0.5 A per channel, which is more than enough to drive the optocoupler or enable line of an external driver.

Root Cause Analysis

Walk through the four likely causes in the order they should be ruled out.

1. Process value and setpoint are not on the same scale

PID_Compact has two parallel input variables for the process value:

  • Input — floating-point value in the configured physical unit (default: 0.0 to 100.0% of the configured range).
  • Input_PER — integer word (0 to 27648) mapped directly to the analog-input channel. Input_PER is automatically normalized inside the block.

If the configuration tool's Input/Output page is set to Input_PER, the block converts PER to the configured physical range using Input = Input_PER / 27648 * (ScaleHigh - ScaleLow) + ScaleLow. If the configuration is instead set to Input (floating point), passing a raw PER value into Input_PER is ignored; the value in Input is used directly. Mixing the two will leave the controller seeing 0% as 0 and any PER value above 0 as 100% because of the default config.

Check: Open the instance DB online and watch Input, Setpoint, and Input_PER in the watch table. They must all be in the same unit. If Setpoint reads 50.0 (rpm, % or whatever unit) and Input reads 0.0 because the wrong input mode is selected, the error is 50.0, the proportional term is Kp * 50, and the output slams to saturation on the first cycle.

2. Feedback scaling or sign error

The user reports that speed is derived by counting bolt passes in a fixed window. Two common bugs:

  • The speed computation returns a WORD that holds a raw PER-style value (0 to 27648) but the PID_Compact input mode is set to floating-point, in which case that word is treated as a very large normalized value.
  • The count is not gated on a stable time base, so the first value seen is 0 or a wild value, producing a huge initial error.

3. Proportional gain far too high before tuning

After dropping the PID block into the project, the default Gain is 1.0, TI = 20 s, TD = 0 s. If the user has manually set Gain = 100 "to make it respond", any non-zero error drives the output to saturation. The fix is to start with Gain = 1.0, TI = 10000 ms (effectively integral-only off), and verify the loop is even closed before tuning.

4. The actuator wiring is the inverse of the feedback sign

If increasing the actuator command reduces the process value (e.g., regenerative drive polarity reversed), the proportional term will be negative of the error, the integral will wind up in the wrong direction, and the controller will sit saturated at the lower limit rather than the upper. Less common on a single-quadrant DC drive but worth checking on a 4-quadrant driver.

PID_Compact Configuration in TIA Portal

Open the technology object and inspect each page in the inspector window.

Basic settings

Parameter Value / Action Why
Controller type Standard PID (continuous) For continuous output. Choose "PWM" only if you intentionally want PID_Compact to switch a digital output.
Input / output Match your sensor type: Input_PER if reading from analog input, Input if you supply the value yourself in SCL Mismatch is the most common cause of immediate saturation.
Setpoint Configured unit (rpm, %, etc.) Stay in one unit end to end.
Process value limits ScaleLow = 0, ScaleHigh = motor max rpm Defines normalization of PER and the working range of the controller.
Output limits OutputLow = 0%, OutputHigh = 100% (or driver-allowed max) Clamps the manipulated variable.

Output configuration

PID_Compact can target either an analog output (OutputPER, 0 to 27648) or a digital PWM output (OutputPWM, duty 0 to 100%). When OutputPWM is selected, the block takes over the configured digital output and updates the duty cycle every cycle. The PWM frequency and minimum pulse width are configured in the device configuration of the CPU under "Pulse generators". Reference: PID_Compact function manual (Siemens support entry 100746401).

Input/Output Signal Scaling

For the speed sensor being a digital counter rather than an analog tachogenerator, there is no native "Input_PER". Two clean approaches exist.

Approach A — supply the floating-point Input directly

Set the PID_Compact configuration to Input = floating-point and feed it a speed value in the configured unit. PID_Compact does not need the PER input at all; the call then looks like:

// FB "SpeedPID" instance block, called from OB1
"PID_Motor1"(Setpoint   := i_SetpointRPM,
             Input      := f_MeasuredRPM,
             Input_PER  := 0,           // unused
             ManualEnable := FALSE,
             ManualValue := 0.0,
             Reset      := b_Reset,
             OutputPER  := iw_OutputPER, // 0..27648 to analog module or
             OutputPWM  := q_MotorPWM);   // boolean TRUE/FALSE on duty

Approach B — scale to PER and use Input_PER

If the driver expects a 0 to 10 V analog command and the analog output is wired, scale the speed to a 0 to 27648 integer and write it into Input_PER at the same time the PER output is sent to the analog module. This route is only useful if you have a real analog process value from a tachogenerator. With a counter-derived speed, Approach A is simpler.

Converting rpm to PER (assumes ScaleLow = 0, ScaleHigh = MaxRPM):

f_Per := (f_MeasuredRPM / f_MaxRPM) * 27648.0;
iw_InputPER := REAL_TO_INT(LIMIT(0.0, f_Per, 27648.0));

PWM Output vs Analog Output

PWM on the S7-1200 digital outputs is the cleanest path for a small DC motor driven by a 4-quadrant H-bridge. Configure Pulse Generator 1 in the device configuration:

  • Output: Q0.0 (for example)
  • Time base: milliseconds
  • Period: 1 ms (1 kHz) for a 24 V DC motor in the few-hundred-rpm range. Higher frequencies reduce audible noise and ripple but increase switching losses in the driver.
  • Minimum pulse width: 0 µs (default).

When PID_Compact is in OutputPWM mode, OutputPWM is a boolean that the block itself sets via the configured digital output; the calling SCL should treat it as a write-only target. Reference: SIMATIC S7-1200 Easy Book.

Do not toggle OutputPWM in user code. The PID_Compact block owns the PWM channel in this mode. Driving the same output from another instruction creates a load conflict and a CPU fault.

PID Tuning Procedure

Follow this sequence in order. Do not skip steps.

Step 1 — Open-loop sanity check

Set ManualEnable = TRUE and write a small fixed value (10%) to ManualValue. Verify the motor actually responds to the command and that the feedback changes in the correct direction. If the feedback is zero or stuck, the PID can never be tuned — the problem is upstream.

Step 2 — Manual P-only step

Switch to automatic with Gain = 0.5, TI = 10000 ms, TD = 0 ms. Step the setpoint from 20% to 30%. The motor should accelerate and settle. If the output saturates immediately, reduce the gain by a factor of 5 and repeat. The correct gain order of magnitude for a small DC motor driving a low-inertia disc is usually between 0.2 and 2.0 (dimensionless, %-out / %-in).

Step 3 — Add integral action

Once the P-only step is stable and reaches the setpoint with a steady-state offset, reduce TI from 10 000 ms toward 1 000 ms in steps. Watch for oscillation. The integral time for a small disc with low friction typically lands between 500 ms and 2 000 ms.

Step 4 — Optional derivative

For a noisy digital feedback (counting discrete bolt passages), TD is usually left at 0. Derivative action amplifies quantization noise. If smoother response is required on the speed, use a first-order low-pass filter on the measured speed before feeding PID_Compact.

Step 5 — Use the built-in auto-tuning

PID_Compact supports online tuning via the Mode = 4 (pretuning) and Mode = 5 (fine tuning) settings on the ModeSet input. Pretuning runs a relay-feedback experiment; fine tuning adapts around the current operating point. Reference: PID_Compact function manual.

// Trigger pretuning at startup, then automatic control
IF b_StartTune THEN
    "PID_Motor1".ModeSet := 4; // pretuning
    "PID_Motor1".Mode := TRUE; // request transition
END_IF;
IF "PID_Motor1".Retain.Mode = 3 THEN // PID active, tuning done
    b_TuneDone := TRUE;
END_IF;

SCL Code Implementation

The following SCL function block implements speed measurement, scaling, and the PID call. It also includes a first-order low-pass filter on the measured speed to suppress quantization noise from the bolt count.

FUNCTION_BLOCK "FB_SpeedControl"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1

VAR_INPUT
    i_SetpointRPM      : REAL;      // target speed, rpm
    i_HSC_Count        : DINT;      // current HSC count from sensor
    i_Window_ms        : DINT;      // counting window, e.g. 1000
    i_MaxRPM           : REAL;      // scale high, e.g. 1500.0
    i_Reset            : BOOL;      // true to reset integrator
END_VAR

VAR_OUTPUT
    q_MeasuredRPM      : REAL;      // filtered speed, rpm
    q_OutputPER        : INT;       // 0..27648 to analog or PWM duty
    q_SaturatedHigh    : BOOL;
    q_SaturatedLow     : BOOL;
END_VAR

VAR
    f_PrevCount        : REAL;
    f_RawRPM           : REAL;
    f_FilteredRPM      : REAL;
    f_Tau_s            : REAL := 0.2;     // 200 ms filter time constant
    f_CycleTime_s      : REAL := 0.05;    // OB1 cycle 50 ms
    f_Alpha            : REAL;
    "PID_Motor1"       : PID_Compact;     // technology instance
END_VAR

BEGIN
    // 1) Compute raw speed from count delta
    f_RawRPM := (DINT_TO_REAL(i_HSC_Count) - f_PrevCount) * 60.0 * 1000.0
                / DINT_TO_REAL(i_Window_ms);
    f_PrevCount := DINT_TO_REAL(i_HSC_Count);

    // 2) First-order low-pass filter
    f_Alpha := f_CycleTime_s / (f_Tau_s + f_CycleTime_s);
    f_FilteredRPM := f_FilteredRPM + f_Alpha * (f_RawRPM - f_FilteredRPM);
    q_MeasuredRPM := f_FilteredRPM;

    // 3) PID_Compact call - Input is floating point rpm
    "PID_Motor1"(
        Setpoint     := i_SetpointRPM,
        Input        := f_FilteredRPM,
        Input_PER    := 0,                  // unused
        ManualEnable := FALSE,
        ManualValue  := 0.0,
        Reset        := i_Reset
    );

    // 4) Output to analog OR PWM - PID_Compact owns OutputPER/OutputPWM
    q_OutputPER     := "PID_Motor1".OutputPER;
    q_SaturatedHigh := "PID_Motor1".OutputHighLimitActive;
    q_SaturatedLow  := "PID_Motor1".OutputLowLimitActive;
END_FUNCTION_BLOCK

Dual-Motor Synchronization Strategy

The original goal of the application is not just equal speed but equal phase: the bolts on the two discs must pass the sensors at the same instant. Speed control alone is necessary but not sufficient. The recommended architecture is a master/follower cascade with a position-correction loop on top of the speed loops.

Layer 1 — Speed loops (PID_Compact on each motor)

Two independent speed loops, one per motor, each using a separate PID_Compact instance. Setpoint is the desired rpm.

Layer 2 — Position (phase) loop

Measure the time offset between the two sensor pulses. Drive that offset to zero with a slow outer loop (a single PID_Compact or even just an I-only controller) whose output is a small trim added to the master setpoint before it is sent to the follower. Typical update rate: 1 to 10 Hz, slower than the speed loop, with a time constant of a second or more.

// Position-error update, called each time both sensors fire
f_PhaseError_ms := f_FollowerPulseTime - f_MasterPulseTime;
// PI controller with very low bandwidth, output is rpm trim
f_TrimRPM := "PID_Phase".Update(f_PhaseError_ms, 0.0); // I-only or PI

// Master setpoint is fixed; follower setpoint is biased by trim
f_FollowerSetpoint := f_MasterSetpoint + f_TrimRPM;

Without the position loop, two motors running at the same rpm will drift out of phase over time, and the bolts will eventually pass the sensors seconds apart, which defeats the purpose of the test rig.

Anti-windup is mandatory for the position loop. Because the phase error is only updated on a sensor event, the integral term can sit idle for many seconds. The PID_Compact instance must have OutputHighLimit = +MaxTrim and OutputLowLimit = -MaxTrim set so the integrator does not run away during long no-event periods.

Verification and Commissioning

After applying the configuration changes, run a structured verification.

  1. Watch table: Add the instance DBs of both PID_Compact blocks and FB_SpeedControl. Confirm Setpoint, Input, and Output are in the same unit. Input should match the calculated rpm to within 1 to 2 rpm.
  2. Step response: In manual, set ManualValue = 0 and confirm the motor stops. Set ManualValue = 25 and confirm a stable speed around 25% of max. If the motor overshoots or oscillates strongly, halve the gain.
  3. Auto-tuning: Trigger pretuning (Mode 4) from the inspector. The block drives the motor through a relay-feedback cycle. Confirm no faults are raised in the diagnostics buffer.
  4. Saturation monitor: Use the OutputHighLimitActive and OutputLowLimitActive tags. If either stays TRUE for more than a few seconds after a setpoint change, the loop is over-driven; reduce gain.
  5. Dual-motor sync test: With the position loop enabled, log the time delta between sensor 1 and sensor 2 events. The mean should be within a few milliseconds of zero and the standard deviation within the sensor pulse width.

Troubleshooting Matrix

Observed behavior Likely cause Fix
Output goes to 100% on first scan, ignores setpoint Input mode mismatch: PER in floating-point config, or vice versa Match Input/Input_PER to configuration; or convert to PER before assigning
Output goes to 0% on first scan, motor stopped Sign inversion between actuator and feedback Invert actuator wiring, or set controller to "Invert control direction"
Output oscillates between 0% and 100% Gain too high or no integral action Reduce Gain by 5x; add TI; check for transport delay
Output stable but always offset from setpoint Integral action missing or TI too long Reduce TI toward 500 ms; verify I_ITVAL is non-zero in instance DB
Output saturates after a few seconds of stable control Anti-windup disabled and disturbance accumulates Enable integrator limiting via OutputLowLimit / OutputHighLimit
PWM output not present on the digital output Pulse generator not assigned to the same output, or another instruction owns the output Assign Pulse Generator to Q0.0; remove all other writes to that output
Speed reading stuck at 0 HSC not enabled, or sensor not wired Enable HSC in device configuration; check sensor supply and input LED
CPU goes to STOP with diagnostic interrupt Output short-circuit or I/O access error Read diagnostic buffer; check wiring; verify signal board is plugged correctly

FAQ

Why does PID_Compact drive the output to maximum on the first scan?

Almost always the controller is seeing a huge initial error. The two most common reasons are: (1) the input mode is set to floating-point (Input) but you are passing a raw PER value, so the block interprets 27648 as 27648% and the proportional term overflows; or (2) the process value has not yet been updated from the I/O and the controller sees zero feedback. Confirm by watching Input, Setpoint, and Input_PER in the instance DB online.

Should I use OutputPER (analog) or OutputPWM (digital) for a small DC motor?

Use OutputPWM for a single 24 V DC motor driven by an H-bridge. PWM is generated on a digital output of the S7-1200 (Q0.0 to Q0.3) at a configurable frequency between 100 Hz and 100 kHz. Use OutputPER when the motor is driven by an external analog-input driver; in that case wire a real analog output module such as SM 1232 and assign its address to the PID_Compact output.

What are good starting values for Gain and TI on a small DC motor?

Start with Gain = 0.5, TI = 10 000 ms, TD = 0 ms. Step the setpoint and halve the gain each time the output saturates. Once stable, reduce TI toward 500 to 2 000 ms. The actual values depend on motor inertia, load, and counting window. Use the pretuning mode (ModeSet = 4) for an automatic starting point.

How do I synchronize the two motors in phase, not just speed?

Add a slow outer position-correction PID that takes the time delta between the two sensor pulses and adds a small trim to the follower setpoint. Keep the position loop bandwidth at least 5x lower than the speed loop, and clamp the trim output so the integral cannot run away during long no-event periods.

Can PID_Compact auto-tune online without stopping the motor?

Yes. Set ModeSet = 4 to trigger pretuning and ModeSet = 5 to trigger fine tuning around the current operating point. The block uses a relay-feedback method and updates Gain, TI, and TD in the instance DB once tuning completes. The motor will oscillate during pretuning; run it on a bench, not on the final machine.

Back to blog