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.

- 125
- 5
1 Answers
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}) $$
Parallel:
$$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.
EDIT:
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 :
CMSIS:
EDIT 2:
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);
}

- 23,562
- 2
- 20
- 33
-
Thanks for the hint. As far as I know in practice `Kp`, `Ki` and `Kd` are determined experimentally or via autotune algorithms. – thinwybk May 04 '21 at 13:05
-
One of those heuristic algorithms for manual, incremental optimization is e.g. [Ziegler–Nichols method](https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method). To what algorithm does match the equations for `Ki` and `Kd` you've provided above? – thinwybk May 04 '21 at 13:22
-
1@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. – Marko Buršič May 04 '21 at 15:38
-
Great. Thanks a lot for the hint. – thinwybk May 04 '21 at 15:47
-
@thinwybk I that solves your question, please mark it as accepted. – Marko Buršič May 04 '21 at 16:01
-
One last open point: The state array defines `x[n]`, `x[n-1]` and `x[n-2]` I guess... – thinwybk May 04 '21 at 16:05
-
@thinwybk As well as y[n-1] or maybe not, since it is computed from y[n], but any x[...] and y[..] would be a discrete state, different algo could have more than just those used for this PID. Isn't the source code avalable for CMSIS lib? – Marko Buršič May 04 '21 at 16:14
-
@thinwybk https://www.keil.com/pack/doc/CMSIS/DSP/html/structarm__pid__instance__f32.html#afd394e1e52fb1d526aa472c83b8f2464 3 elements so x[n-1], x[n-2] , y[n] – Marko Buršič May 04 '21 at 16:17
-
@thinwybk If you would like to use it as P.controller only (ki,kd=0), then IMO you should 1st call arm_pid_reset_ to clear all states before calling the PID function, so that y[n]=kp*x[n]. Then you're able to to do ZN tuning to find ultimate gain and period, compute the kp, ki, kd , update params. and stop calling arm_pid_reset_ . Keep in mind that this algo needs the integrator fully working. – Marko Buršič May 04 '21 at 16:38
-
That's exactly the point this question is all about. Given a good API documentation you don't have to look into the sources to know how to use ist :D – thinwybk May 05 '21 at 07:09
-
1@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. – Marko Buršič May 05 '21 at 09:12
-
Thankfully I've just a M.Eng. ... good argument for not beeing blamed if something goes wrong :D – thinwybk May 05 '21 at 09:48