笔者近日在做有感foc,对于一些过程有感悟,看到网上资料没有整理出来,特此记录一下。

一、六步换相、spwm开环驱动

可以先开环驱动一下,例如六步换相、spwm开环驱动。

二、foc函数

首先把相关foc的坐标变换写好,这里特别说一下,svpwm生成马鞍波有两种方法,一种是网上经常能看到的七段式svpwm(几何方法),还有一种就是笔者做foc发现的一种叫做均值零序分量(三次谐波)注入SPWM等效为SVPWM,也叫中点平移法(代数方法),这也能生成马鞍波,并且不需要七段式svpwm庞大的逻辑,减少计算量。

马鞍波

马鞍波、递增的电角度、Ialpha与Ibeta

三、Vf拖动(开环)

这一般是验证自己的svpwm写的有没有问题。

步骤就是自己设定一个电角度,定义一个变量在0-6.28自增即可,调用先前写的foc函数,给定Uq,将Ud设为0,即可让电机开环转起来啦。改变电角度增量大小,即可改变电机转速。同时,这种情况下给Ud在一定值,Uq为0,电机同样会转动,原因是没做电流闭环,给定Ud的同时影响到了Uq。

(注意,这种方式下观察adc采回来的三相电流,是三个相位相差120度的正弦波,并且这种情况下不能转太久,因为没做电流环,电机发热严重)

adc采回来的三相波形

clark变换后的波形(静止坐标系)

四、If拖动(电流环)

void Iq_PID(void)
{
    static double Last_Bias = 0, Bias = 0, LPF_Bias = 0;
    LPF_Bias = pid.T_iq - foc.Iq;
//    FirstOrderRC_LPF(LPF_Bias, Bias, 0.3);
    foc.Uq += pid.Iqkp*(LPF_Bias-Last_Bias) + pid.Iqki*(LPF_Bias);
    LIMIT_OUT(foc.Uq, 1000, -1000);
    Last_Bias = LPF_Bias;
}

void Id_PID(void)
{
    static double Last_Bias = 0, Bias = 0, LPF_Bias = 0;
    LPF_Bias = pid.T_id - foc.Id;
//    FirstOrderRC_LPF(LPF_Bias, Bias, 0.3);
    foc.Ud += pid.Idkp*(LPF_Bias-Last_Bias) + pid.Idki*(LPF_Bias);
    LIMIT_OUT(foc.Ud, 1000, -1000);
    Last_Bias = LPF_Bias;
}

这个情况,我们是做了q轴与d轴的电流闭环(考虑到电流环PID积分饱和问题,采用增量式PI),角度仍然像Vf一样给定电角度,调试参数时,先调d轴参数,这时候需要把角度增量设置为0,否则调试d轴时电机会转起来。调试完d后,把参数复制一份给q轴即可。

另外注意这里电流环不要加入滤波,因为pid本身就是一个低通滤波器。

Id跟踪波形

注意:这时我们给定目标Iq,发现Iq直接就跟踪上iq_ref,这跟网上不一样,网上资料说的是控制的是堵转电流,笔者在这也很疑惑,后面加上编码器,并校准(这里校准是因为编码器0点与电机转子,即电角度0点不重合),发现现象就和网上资料一样了,控制Iq,电机速度会一直上升,直到满速,但是观察Iq波形发现,Iq并没有到达设定值,这时候用手去捏住(注意不要在电机转的很快的时候一下子猛地捏住,这样子电流一下子会上升的很高,容易烧mos和电源,因此建议调试时使用航模电池调试),就会发现Iq慢慢收敛到达设定Iq。

用手捏住后Iq变化

这个图其实可以看到,Iq变化的过程中,Id也会有震荡,这是因为iq和id之间是耦合的,但是电流环响应快的话就能很快稳定控制下来。

这里Iq目标值是100,可以看到堵转时电流就会收敛

笔者这里用的都是id=0控制,弱磁控制相关设计电机极限圆以及电机方程的考虑,这里暂时不讨论这个问题。

五、速度环

增量式PI即可,注意限制一下堵转电流大小,防止烧驱动。

void Speed_PID(void) //增量式PI
{
    static double Last_Bias = 0, Bias = 0;
    Bias = pid.T_speed - pid.LPF_R_speed;
    pid.T_iq += pid.Vkp*(Bias-Last_Bias) + pid.Vki*Bias;
    LIMIT_OUT(pid.T_iq, 600, -600); //给大给1000,防止烧驱动
    Last_Bias = Bias;
}

六、位置环

位置式PD,网上资料有说单P即可,笔者这里认为D项必须引入,因为单P项结果会震荡,需要引入D项,并且这个D需要的参数还会比较大,笔者这里Kp是-15,Kd是-3000,仅供参考。

void Position_PID(void)
{
    static double Last_Bias = 0, Bias = 0;
    Bias = (pid.T_position - pid.R_position)/1000.0;
    if(Bias > 8.192)  Bias-=16.384;
    if(Bias < -8.192) Bias+=16.384;
    if(fabs(pid.Pki) > EPSILON)
        pid.Integral_bias_Position+=Bias;
    pid.Result_Integral_bias_Position = pid.Pki*pid.Integral_bias_Position;
    LIMIT_OUT(pid.Result_Integral_bias_Position, 5, -5);
    pid.T_speed = pid.Pkp*Bias + pid.Result_Integral_bias_Position + pid.Pkd*(Bias-Last_Bias);
    LIMIT_OUT(pid.T_speed, 20, -20); //最大给45
    Last_Bias = Bias;
}

位置环PD效果图

笔者这里位置上升是比较平缓的,如需响应更快,对应加大P项即可,不过带来的超调不可避免。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐