I'm trying to understand the CMSIS PID Motor Control. Obvisouly it is a PID controller in parallel structure (instead of in series stucture or some sophisticated structure). It seems like there is no standardized way of how the "gains" are defined w.r.t. naming as well as valid value ranges. The derived gains A0, A1 and A2 may be calculated from the gains Kp, Ki, Kd. The state array is not documented at all.


It's an incremental form of PID, therefore the Ki shall not be zero (disabled integrator).

"series" as you call it:

$$u=K_p (\varepsilon + \dfrac{1}{T_i}\int\varepsilon\cdot dt \ + T_d\dfrac{d\varepsilon}{dt}) $$


$$u=K_p \cdot \varepsilon + \dfrac{K_p}{T_i}\int\varepsilon\cdot dt \ + K_p\cdot T_d\dfrac{d\varepsilon}{dt} $$

$$u=K_p \cdot \varepsilon + K_i\int\varepsilon\cdot dt \ + K_d\dfrac{d\varepsilon}{dt} $$

incremental series:

$$u=K_p\int (\dfrac{d\varepsilon}{dt} + \dfrac{1}{T_i}\varepsilon\ + T_d\dfrac{d^2\varepsilon}{dt^2}) dt+C $$

Where C is the integration constant, actually the previous value of the function. The whole integral is the increment value. If the value hits the min/max constraints then in next cycle starts from there, so that's why disabling the integrator would remain biased at max or min.

You can compute the constans as:

$$K_i=K_p\dfrac{T_s}{T_i}$$ $$K_d=K_p\dfrac{T_d}{T_s}$$

See Chapter 4.1 how the PID algorithm is derived and you'll understand that CMSIS can be easily translated.



If you substitute ki, kd you can notice that the CMSIS PID is the same as Vladimír Bobál's Ziegler-Nichols BRM PID. You have all the needed theory in there + there is a Matlab library STCSL on Mathwork's webpage somewhere.

Vladimír Bobál :

enter image description here


enter image description here


Source code

  static __INLINE float32_t arm_pid_f32(
  arm_pid_instance_f32 * S,
  float32_t in)
    float32_t out;

    /* y[n] = y[n-1] + A0 * x[n] + A1 * x[n-1] + A2 * x[n-2]  */
    out = (S->A0 * in) +
      (S->A1 * S->state[0]) + (S->A2 * S->state[1]) + (S->state[2]);

    /* Update state */
    S->state[1] = S->state[0];
    S->state[0] = in;
    S->state[2] = out;

    /* return to application */
    return (out);

  • \$\begingroup\$ Thanks for the hint. As far as I know in practice Kp, Ki and Kd are determined experimentally or via autotune algorithms. \$\endgroup\$ – thinwybk May 4 at 13:05
  • \$\begingroup\$ One of those heuristic algorithms for manual, incremental optimization is e.g. Ziegler–Nichols method. To what algorithm does match the equations for Ki and Kd you've provided above? \$\endgroup\$ – thinwybk May 4 at 13:22
  • 1
    \$\begingroup\$ @thinwybk To Ziegler-Nichols PID, see table 7.1 : 1), 2), 3) or Table 4.1. It think the CMSIS is the same as BRM = Backward Rectangular Method of discretization. \$\endgroup\$ – Marko Buršič May 4 at 15:38
  • \$\begingroup\$ Great. Thanks a lot for the hint. \$\endgroup\$ – thinwybk May 4 at 15:47
  • 1
    \$\begingroup\$ @thinwybk I agree. The code misses the min/max limits ,so you have to write your own limit func. and in turn overwrite the S->state[2], if you want a correct functionality like anti-windup. Every actuator or DAC,PWM has a min/max limit constraint, if this is not taken into account, it will saturate the PID and very poor working. It takes a PhD to use this library, comprehensive user manual would be needed. \$\endgroup\$ – Marko Buršič May 5 at 9:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.