电流环PID算法及例程
电流环PID算法及例程
1 什么是电流环PID算法
电流环PID算法是一种常用的控制算法,用于控制电机或其他设备中的电流。PID算法基于三个控制参数:比例(Proportional)、积分(Integral)或微分(Derivative),通过对当前误差、累计误差和误差变化率进行计算,来生成相应的控制输出。
下面是电流环PID算法的基本原理和步骤:
- 错误计算:首先需要计算电流环的误差,即期望电流与实际电流之间的差异。这通常通过将期望电流值减去实际电流值得到。
- 比例项计算:根据比例参数(Kp),将误差乘以一个比例增益,得到比例项的输出。比例项直接反映了误差的大小,控制输出与误差成正比。
- 积分项计算:根据积分参数(Ki),对误差进行累加,并乘以一个积分增益,得到积分项的输出。积分项可以消除静态误差,逐渐减小系统的稳态误差。
- 微分项计算:根据微分参数(Kd),计算误差的变化率,并乘以一个微分增益,得到微分项的输出。微分项可以预测误差的未来变化趋势,用于抑制系统的过冲和振荡。
- 控制输出计算:将比例项、积分项和微分项的输出相加,得到最终的控制输出。这个控制输出可以作为电流环的控制信号,用于调节电流到期望值。
要注意的是,比例、积分和微分参数的选择对PID控制效果有很大影响。合适的参数调节可以使系统响应快速、稳定,并达到较小的稳态误差。一般情况下,参数的选择需要通过实际系统测试和调试来确定,可以使用试探法或自整定方法进行参数调优。
此外,在实际应用中,还需要考虑采样时间、输出限幅、饱和处理等因素,以确保系统的稳定性和可靠性。
1 | float32 LOCATION_PID_realize(LOCATION_PID* pid, float32 temp_val) { |
1 | // PI控制代码 |
2 电流环的作用
前文不断强调,进行磁场定向控制需要控制的是电流而非电压,只是因为我们没有办法直接去控制电流才暂时退而求其次地去控制电压。虽然电压控制的效果也还不错,但由于电机不是单纯的阻性负载,所以控制电压并不能得到一个完美的效果。终极目标是控制电流,没有电流控制的foc不能叫foc,所以电流环最本质的作用是什么就不用多说了。
注:虽然框图中含有编码器,但它并不是电压控制的反馈环节,仅用来获取转子电角度,所以称其为开环控制。
2.1 让id尽可能接近0,提高效率
使用电压开环控制时,由于种种原因,id并不是一直为0,可能存在偏移或跳动,转速越高这种情况就越厉害,而使用电流闭环可以较好的遏制这种现象。
下面两张图显示了在20V供电下,某台电机空载全速转动下的id和iq波形,其中蓝色的是id。第一张图使用电压开环控制,第二张图使用电流闭环控制。
2.2 起到一个限流保护的作用
当电机堵转的时候,电流等于电压除以电阻。假如电压是12V,电机内阻是0.1欧姆,那么此时流过电机的电流就是120安培。如果电机的额定电流只有10安培,那么它很有可能在1秒钟之内冒烟烧掉,同时120安培的大电流对于小型驱动板而言也是致命的。我们可以在硬件上增加过流保护的功能,当触发过流保护时直接关断三相全桥。但我们想要的是限流,尽可能地将电机流过的电流限制在给定值之下,而不是达到阈值就关断电机,因此硬件上的过流保护只是作为最后一道保护措施,真正的限流通常是由软件上的电流环来实现。将电机的电流限死在额定电流之下,这样即使电机堵转也不用担心烧毁电机或是驱动器。
2.3 力矩控制
电机的输出转矩和电流基本上是成正比的,因此控制了电流也就相当于控制了电机的输出转矩。(这里也再强调一下,要让电机输出转矩是需要给它添加负载的。如果电机空载,那么它的输出转矩只需要克服摩擦力和空气阻力等,此时的输出转矩是非常小的。所以这里说的控制电机的输出转矩,其实是控制电机的最大输出转矩,也就是堵转时的转矩。)
3 电流环的实现
由前文的控制框图可知,实现电流环需要做这么几件事情:①电机三相电流采集②克拉克变换③帕克变换④电流环PID运算
3.1 电流采样
电流采样的方案大致有电流互感和电阻采样两种,而电阻采样又分为低端采样、母线采样和高端采样。对于电阻采样而言无论是哪一种,其原理都是一样的,根据欧姆定律可得电流等于电压除以电阻。由于电阻阻值是我们给定的,所以只要采集了电阻两端的电压就可以算出流过电阻的电流。为了尽可能不影响电路正常工作,我们选用的采样电阻的阻值一般都会很小(毫欧级),所以电阻两端的电压往往会比较小,比如10豪欧的电阻,流过10安培的电流,其两端电压仅为100毫伏,因此我们需要运算放大器来放大这个电压信号,最后送给单片机的ADC。
最终的换算公式如下:(3.3V的参考电压,12位的ADC,电流单位安培,电阻单位欧姆)
电流 = ADC原始值 / 4096 ∗ 3.3 / 采样电阻阻值 / 运放放大倍数
这里也提几个关键的地方:①对于低端采样,一定要在采样电阻对应的下桥臂开启的时候采样,否则下桥臂关断的时候几乎不会有电流流过采样电阻(高端采样也类似)。②对于母线采样,任何时候都有电流流过采样电阻,但这并不意味着任何时间点都可以采样,一定要避开mos管开启或关断的瞬间,否则会采集到非常严重的尖峰噪音(这个原则对于高端和低端采样也适用)。③电流采样的效果会直接影响到电流环的控制效果,因此不可马虎。
3.2 克拉克变换和帕克变换
两个变换加起来就四句代码:
1 | void Clarke_Park(struct MOTO_Type * moto, int32_t currA, int32_t currC) { |
为什么只需要两相电流而不是三相呢?因为三相电流之和等于0,知道两相可以倒推出第三相。为什么我这里用的是A相和C相的电流呢?一方面是有时候要方便板子布线,另一方面是用AB相的很多,这里介绍一下其他的,希望大家学会灵活运用。如果对具体的推导过程有兴趣的可以观看硬石专题8第6第7小节,链接已放在底部。
3.3 PI运算
首先明确一点,对于电流环而言一般是不会使用微分项D的,这个不是我说的,而是查阅了一些相关资料(包括ti的公开课,一些开源方案的源码)找到的结论。
经过克拉克变换以及帕克变换,我们的三相交流电流量已经变成了两个直流的电流量,因此可以很容易的使用PID去控制它。PID相信大家都非常熟悉,而去掉了D就更简单了:
1 | void Curr_PI_Cal(struct PI_Type *PI_Control, float32_t target, float32_t resultMax) { |
这里有一个地方可能和大家以往用的不太一样:
1 | PI_Control->result = PI_Control->kp * PI_Control->error + PI_Control->errSum; |
用下面这种的应该会多一些,但这种形式有个缺点就是它的积分限幅值是会随着ki的调整而变化,并且不直观,你也不知道限幅了多少。因此推荐使用上面这种形式,先将整个积分项不停地累加起来,再对其限幅。因为电流环的输入是电流id、iq,输出是电压ud、uq,而我们的ud、uq是受限于供电电压的,你不可能给你的驱动板供电12V却让它输出20V,过大的积分限幅是完全没有意义的,只会让你的电流环严重超调,而过小的限幅会让你的电机发挥不出力量,比如你的驱动板是12V供电,却只能达到6V的效果。那么多大的限幅是合适的呢?还记得前文介绍svpwm说的最大不失真电压Uref吗?
积分限幅就可以通过这个公式算出来,比方说12V供电,那么积分限幅值就可以取6.93。同样的,代码最下边的resultMax也取这个数。
这里也温馨提示一下,Uref是通过ud和uq两个矢量合成的,所以要让Uref小于限幅值,并非仅让ud、uq分别小于限幅值就够了。
4 电流环的调试
同样先明确几点:①对于普通的无刷电机,id给定值为零。②调试时先调D轴的PI参数,如果效果满意,就把D轴的PI参数原封不动的赋给Q轴。
4.1 参数整定方法
电流环的PI参数是可以算出来的,只要知道了电机的电阻和电感,就能得到这台电机的电流环PI参数。具体的推导过程可以参考下面链接的第一个视频。这里只说结论。
对于串联型的PI控制器:
Kp = L × bandwidth × 2π
Ki = R / L
对于并联型的PI控制器:
Kp = L × bandwidth × 2π
Ki = R × bandwidth × 2π
解释:
- 这里的 L 和 R 的单位是 H 和 Ω
- 如果你不清楚串联型和并联型PI控制器的区别,那么你用的百分之99就是并联型的PI控制器。前面的代码就是并联型的。
- 这里的带宽是自己给定的,带宽越小系统越稳定,响应越慢;带宽越大系统越不稳定,但响应越快
- 根据ti的资料,带宽取电流采样频率的 1/20 ;根据视频中那位大佬的回复,电流环带宽从100Hz到1000Hz的都有。
- 有些资料把 2π 放进带宽里面,而有些则是分开计算,这就产生了一个误区,两种计算方法会使PI参数相差6.28倍。个人两种方法都尝试过,不乘6.28的PI参数的阶跃响应波形更平滑,而乘以6.28的波形会略有超调,但电机并未产生震荡且能够正常工作。这里我更加偏向要乘6.28的说法,各位看着办。
4.2 调试实例
使用5208云台电机,通过万用表等仪器测得电阻为 11.4Ω,电感由于没有专业仪器,只好参考相似型号电机,估测为 3mH 左右(由于电机是闲鱼买的,没有详细参数,后面可以通过细调Kp参数来解决)。使用并联型PI,带宽这里取300Hz,可得:
Kp = 0.003 × 300 × 2π = 5.625
Ki = 11.4 × 300 × 2π = 21477.6
但由于我使用ADC的原始值作为反馈信号,因此PI参数也要相应的改变一下。由前面的公式计算得到: 电流 = ADC原始值 / 500,因此PI参数也要除以500。还有一点也要注意,算出来的Ki参数是不包含积分时间的,因此要补上,我这里的积分时间是 1 / 8000 秒。所以最终的PI参数为:
Kp = 5.625 / 500 = 0.01125
Ki = 21477.6 / 500 / 8000 = 0.00537
下面把调好的参数下载到单片机里,看一下D轴电流的阶跃响应如何(这里暂时先不给Q轴赋值)
这里给定的目标值是200,也就是0.4A,可以看到响应波形是很漂亮的,除了上升和下降的终点处有一些毛刺。
下面将D轴的PI参数原封不动的赋给Q轴试试:
这里D轴给定值为0,Q轴给定值仅为50(0.1A),但由于电机空载电流达不到0.1A,因此Q轴电流环积分项迅速饱和,此时电机正全速旋转。
我们将D轴设定值设为0,Q轴设定值设为200,然后用手反复堵转电机看一看响应波形:
当电机堵转时,Q轴电流被限制在200(0.4A)附近;当松开电机时,电机迅速地恢复全速转动,且Q轴电流仅为空载电流。并且当Q轴的设定值越大,堵转时电机的输出转矩越大。
至此,电流环的调试基本完成,大家可以参考这三张图来判断电流环的调试是否正确。第三张图的Q轴电流存在超调是因为之前全速转动的时候积分项已完全饱和,突然的堵转使积分项来不及释放干净而导致过冲,解决的办法是使用抗饱和的PI控制器,如动态积分限幅等。但如果是要求不高的场合,正确的静态积分限幅已经足够了。
解释:
先调D轴是因为如果调Q轴会使电机转起来,而电机空载下的电流非常小,如果达不到我们的给定值,积分器会迅速饱和,使电机全速转动。
串联型的PI控制器和并联型的本质上是一样的,只是Ki参数会不同。并联型的Ki相当于串联型的Kp*Ki,因此对于串联型的来说,调节Kp会使积分项的增益也随之改变。但是串联型的好处就在于使用Ki实现零极点对消,然后通过调节Kp来调整带宽。并联型的如果要调整带宽,则PI参数需要一起调。
参考资料:









