上一篇文章讨论了永磁无刷电机电流环、速度环的建模和控制器的参数整定,这篇文章会讨论前馈、滤波、抗饱和算法以及其他一些要注意的细节,且包含了大量工程经验。结合这两篇文章的内容,我们可以完整地使用经典 PI 控制器实现电机转速的控制。
一. 前馈
不考虑功率变换器和纯延时环节,系统双环传递函数如下:
永磁无刷电机的 DQ 轴电压方程如下:
{ u d = R i d + L d d i d d t − ω e L q i q u q = R i q + L q d i q d t + ω e ( L d i d + ϕ f ) \begin{cases} u_d=Ri_d+L_d\frac{di_d}{dt}-\omega_eL_qi_q\\ u_q=Ri_q+L_q\frac{di_q}{dt}+\omega_e\left( L_di_d+\phi _f \right)\\ \end{cases} {ud=Rid+Lddtdid−ωeLqiquq=Riq+Lqdtdiq+ωe(Ldid+ϕf)
可以看到, u d u_d ud 不仅和 i d i_d id 有关,同时还和 i q i_q iq 有关; u q u_q uq 不仅和 i q i_q iq 有关,还和 i d i_d id 有关。换句话说,DQ 轴之间存在耦合。如果我们简单地使用两个 PI 控制器去分别控制 DQ 轴,那么耦合一定会影响控制器的性能,但幸运的是,在任何一个时刻 − ω e L q i q -\omega_eL_qi_q −ωeLqiq 以及 ω e ( L d i d + ϕ f ) \omega_e(L_di_d+\phi_f) ωe(Ldid+ϕf) 是确定的,与偏差无关,故我们可以使用前馈进行直接补偿,在 Q 轴控制器的输出上加上 ω e ( L d i d + ϕ f ) \omega_e(L_di_d+\phi_f) ωe(Ldid+ϕf),在 D 轴控制器的输出上加上 − ω e L q i q -\omega_eL_qi_q −ωeLqiq 。
理想情况下,通过这样的方法,我们可以完美地补偿掉反电动势带来的影响,实现 DQ 轴的完全解耦。但事实上却并不是这样,一方面,我们在进行前馈补偿时需要用到 i q , i d , ω e i_q,\,i_d,\,\omega_e iq,id,ωe,但采样得到的电流和转速通常有比较大的噪声;而另一方面,前馈中还包含 L d , L q , ϕ f L_d,\,L_q,\,\phi_f Ld,Lq,ϕf 等电机参数,我们获取到的电机参数很可能不准确,并且电机在高速旋转时,自身的参数也会发生摄动。
把一个没有那么准确且包含噪声的前馈直接加到控制器的输出上作为 DQ 轴电压的一部分,带来的负面作用很可能高于 DQ 轴解耦的正面作用,严重时甚至可能导致系统失稳。
所以,是否使用前馈需要根据典型工况、性能指标、软硬件性能等因素综合考虑。如果引入前馈会带来正面效果,那么就使用前馈。
前馈的使用在工程上非常灵活。在大部分情况下,采样得到的 i d , i q i_d,\,i_q id,iq 中包含的噪声要大于 ω e \omega_e ωe 中的噪声,那么我们完全可以只补偿 ω e ϕ f \omega_e\phi_f ωeϕf,实现 DQ 轴的部分解耦。
除此之外,在工程上还可以使用各种低通滤波器滤除掉 i q , i d , ω e i_q,\,i_d,\,\omega_e iq,id,ωe 中的噪声,再进行前馈补偿,但滤波器也会引入滞后,实际效果的好坏需要权衡。
最后,就算不存在模型摄动,我们获取到的电机参数以及电流转速都 100% 准确,我们仍然不可能进行 DQ 轴的完全解耦,因为系统中存在很多延时环节,这些延时环节导致我们的前馈作用到被控对象上时,被控对象的状态已经发生了变化,我们补偿的其实是系统之前的状态。
如果能准确预测到延时之后系统的状态,我们可以直接使用该状态进行前馈补偿,而这通常是很难做到的,所以在工程上我们可以引入前馈系数 K f ∈ ( 0 , 1 ) K_f\in(0,1) Kf∈(0,1),将前馈乘以 K f K_f Kf 再加入到控制器中,通过调节 K f K_f Kf 的大小,可以有效地降低前馈带来的负面影响,同时尽可能保留前馈解耦的正面作用。
二. 滤波
电流环使用一个一阶低通滤波器进行反馈滤波和指令滤波,其传递函数为一个一阶惯性环节:
G
f
(
s
)
=
Y
(
s
)
R
(
s
)
=
1
1
+
1
w
b
s
G_f\left( s \right) =\frac{Y\left( s \right)}{R\left( s \right)}=\frac{1}{1+\frac{1}{w_b}s}
Gf(s)=R(s)Y(s)=1+wb1s1
其中
w
b
w_b
wb 为低通滤波器的截止频率。我们用后向积分法进行 Z 变换,有:
s
=
z
−
1
T
z
G
f
(
z
)
=
Y
(
z
)
R
(
z
)
=
w
b
T
w
b
T
+
1
−
z
−
1
R
(
z
)
w
b
T
=
Y
(
z
)
(
w
b
T
+
1
)
−
Y
(
z
)
z
−
1
Y
(
n
)
=
T
w
b
T
w
b
+
1
R
(
n
)
+
1
T
w
b
+
1
Y
(
n
−
1
)
s=\frac{z-1}{Tz} \\ G_f\left( z \right) =\frac{Y\left( z \right)}{R\left( z \right)}=\frac{w_bT}{w_bT+1-z^{-1}} \\ R\left( z \right) w_bT=Y\left( z \right) \left( w_bT+1 \right) -Y\left( z \right) z^{-1} \\ Y\left( n \right) =\frac{Tw_b}{Tw_b+1}R\left( n \right) +\frac{1}{Tw_b+1}Y\left( n-1 \right)
s=Tzz−1Gf(z)=R(z)Y(z)=wbT+1−z−1wbTR(z)wbT=Y(z)(wbT+1)−Y(z)z−1Y(n)=Twb+1TwbR(n)+Twb+11Y(n−1)
得到离散后的时域表达式我们就可以在程序中实现滤波器了。
我们在上一篇文章的建模中考虑了速度环使用的一阶低通滤波器,故其参数可以通过电流环带宽 w b c r t w_{b}^{crt} wbcrt 和电流环帧率 f f f 计算得到。而速度环的滤波器并没有在建模时考虑,相反,我们把它视为一种扰动,它的参数是需要手动整定的。我们希望它在滤除掉噪声的同时,给系统带来的相位滞后最小,即滤波器对系统带来的扰动最小。
为了减小滤波器对速度环产生的扰动,我们使用二阶巴特沃斯滤波器进行滤波,使用高阶滤波器可以在保证滤波效果的同时引入更小的相位滞后。在这篇文章中我简单对比过不同滤波器的性能:【ADRC】一. 线性跟踪微分器,这里就不详细地对滤波器进行介绍了。
二阶巴特沃斯滤波器的核心代码如下,详细的代码可以查看 PX4 飞控源码中的 LowPassFilter2p.hpp
文件,滤波器的推导可以参考这篇文章。
// init
const float fr = _sample_freq / _cutoff_freq;
const float ohm = tanf(M_PI_F / fr);
const float c = 1.f + 2.f * cosf(M_PI_F / 4.f) * ohm + ohm * ohm;
_b0 = ohm * ohm / c;
_b1 = 2.f * _b0;
_b2 = _b0;
_a1 = 2.f * (ohm * ohm - 1.f) / c;
_a2 = (1.f - 2.f * cosf(M_PI_F / 4.f) * ohm + ohm * ohm) / c;
// apply
T delay_element_0{sample - _delay_element_1 *_a1 - _delay_element_2 * _a2};
const T output{delay_element_0 *_b0 + _delay_element_1 *_b1 + _delay_element_2 * _b2};
_delay_element_2 = _delay_element_1;
_delay_element_1 = delay_element_0;
值得一提的是,速度环的帧率要显著低于电流环,在速度环运行计算量稍大的二阶滤波器不会占用太多算力。
三. 抗饱和(Anti-Windup)
在实际的控制系统中,电机和驱动器都有最大功率限制。比如,电流环的输出为 Q 轴和 D 轴的相电压,其最大值受到调制方法和母线电压的限制,对于 SVPWM 来说, U q m a x = U d m a x = 3 / 3 ∗ U b u s max U_{q}^{max}=U_{d}^{max}=\sqrt{3}/3*U_{bus}^{\max} Uqmax=Udmax=3/3∗Ubusmax。速度环的输出为 Q 轴电流,其最大值为电机最大电流和驱动器最大电流中的最小值,即 U v e l t _ l o o p m a x = min { I m o t o r m a x , I e s c m a x } U^{max}_{velt\_loop} = \min \left\{ I_{motor}^{max},\, I_{esc}^{max} \right\} Uvelt_loopmax=min{Imotormax,Iescmax}。
当控制器的输出达到执行器的极限时,反馈回路失效,系统将运行于开环状态,此时我们说执行器处于饱和状态,系统长时间饱和很可能造成系统失稳,故我们在进行控制器设计时要做抗饱和(Anti-Windup)处理,考虑执行器的物理约束。
设 PI 控制器中比例项的输出为 U p U_p Up,积分项的输出为 U i U_i Ui,总输出为 U U U,其最大值为 U m a x U^{max} Umax。
我们可以简单的令 U i m a x = U m a x = − U i m a x {U_i}^{max}=U^{max}=-{U_i}^{max} Uimax=Umax=−Uimax,这是最简单的抗饱和处理。除此之外,我们还可以用积分分离、变速积分等方法进行抗饱和,不过这两种方法在电流环控制中都存在局限性:积分分离法在偏差较小时不使用积分控制,在偏差大于某个值时启用积分控制,其不适合应用在扭矩不断变化的场合,因为积分反复开关可能会造成电流的突变。变速积分法通过引入一个变化的增益,做到大偏差时积分较慢,小偏差时积分较快,其本质上是通过引入非线性环节来获得更好的控制效果,但这样做会影响到我们前面的建模分析,即通过带宽整定 K p c r t , K i c r t K_{p}^{crt},\, K_{i}^{crt} Kpcrt,Kicrt 的公式可能不再适用,且变积分的参数整定也较为困难,所以我们接下来还是在最简单的抗饱和方法之上进行拓展。
回到 U i m a x = U m a x = − U i m a x {U_i}^{max}=U^{max}=-{U_i}^{max} Uimax=Umax=−Uimax 上,当 U p U_p Up 较大时,积分效应仍然可能导致控制器的总输出 U U U 达到饱和,即 U = U i + U p > U m a x U=U_{i}+U_p>U^{max} U=Ui+Up>Umax。我们抗饱和的根本目标是通过限制积分器的输出来保证控制器不饱和且拥有最大输出能力,即通过限制 U i m a x U_{i}^{max} Uimax 和 U i m i n U_{i}^{min} Uimin 来保证 − U m i n < U < U m a x -U^{min}<U<U^{max} −Umin<U<Umax 。
所以,考虑到比例项的输出,我们可以使用积分器的动态限幅,即 U i m a x = U m a x − U p , U i m i n = − U m a x − U p U_{i}^{max}=U^{max}-U_p,\, U_{i}^{min}=-U^{max}-U_p Uimax=Umax−Up,Uimin=−Umax−Up,每个时刻的积分限幅是动态变化的,和当前比例项的输出有关。这样可以保证总输出限幅一定,在偏差较大时可以起到类似变速积分的效果。
考虑到前馈项,我们还需要对前馈的输出进行处理,由于前馈项的形式比较灵活,在这里就不举例了,我们只需要保证积分项 U i U_i Ui 不会使得控制器输出 U U U 的绝对值超过 U m a x U^{max} Umax 即可。
四. 其他细节
1. 单位
两篇文章中提到的所有频率,如 w b , w c , w n w_b,\,w_c,\,w_n wb,wc,wn 等,单位都为 r a d / s rad/s rad/s。其余物理量的单位均为国际单位制,如电流单位为安培 (A),电压单位为伏特 (V),等等。
2. Z 变换中的时间
很多人使用 PID 时,都没有考虑代码的执行周期
T
T
T ,积分项直接使用 Ui += error * Ki
,如果是手动调节参数的话这样做并没有什么问题,但我们直接使用理论计算出的 PI 参数,就必须在所有的环节都符合公式推导,代码中应该使用 Ui += error * Ki * dt
。dt
对应 Z 变换
s
=
(
z
−
1
)
/
T
z
s=(z-1)/Tz
s=(z−1)/Tz 中的
T
T
T。
3. 放缩
虽然现在大部分微处理器中都集成了浮点计算单元(FPU,floating-point unit),但浮点数的计算还是比定点数的计算要慢得多,为了提高运算速度,我们可以把所有浮点数放缩为定点数进行计算,在最后使用的时候再放缩回来,这通常是使用数学库来实现的,比如 TI 的 IQmath Library,CMSIS 的 DSP Software Library 等。
在通信中也要考虑数据溢出的问题,为了在有限长的字节内传递全部信息,通常也要对数据进行放缩处理。
4. 指令预处理
在程序中需要根据物理约束对输入控制器的指令进行限幅,比如速度环的目标值不应超过电机的最高转速,电流环的目标值不应该超过电机和驱动器所允许的最大电流。
其次根据驱动系统的性能,可能还需要对指令的变化率进行限制,直接给电流环非常大的电流阶跃会给控制带来较大压力,可以对指令额外进行低通滤波,或者简单地使用斜坡信号代替阶跃。
5. 运行速率
电流环的帧率对控制器的性能有显著影响,至少要保证电流环帧率在 10K 以上,一般 10K~40K 之间比较合适,帧率超过 40K 之后,再提高帧率所带来的收益较小。
使能 FPU、使用定点数运算、使用查表法计算
sin
\sin
sin 和
cos
\cos
cos、开启编译器 -O1/-O2
优化可以显著提高运行速率,除此之外,将反复调用的函数定义为内联函数、将浮点数除法改为浮点数乘法等方法也可以帮助提高代码的执行速度。