基于正交编码霍尔传感器MT测速以及PID控制开发总结

问题引入

​ 在实际应用中,有刷直流电机往往通过PWM调速控制,开环控制的问题在于固定的启动速度不能适应多种复杂的场合,使得参数整定复杂。引入PID控制解决此问题,PID控制需要反馈信号,则使用霍尔编码器对其速度进行反馈,软件上使用MT测速将霍尔信息转化为可处理的速度信息。

正交霍尔编码器

  • 输出两路PWM信号,A相和B相相位相差90度
  • 两路信号反馈得到速度信息一致,即一路即可检测速度,两路意义在于确定转动方向
  • 在某一项上升沿去检测另一相电平状态即可确定方向

MT法测速

M法测速

检测固定时间内编码器的脉冲数

其中

  • Tc:用户自定义采样周期(时间)
  • M1:在Tc时间内捕获到的编码器脉冲个数
  • 实际软件处理中出于减少计算的考虑可以不用将脉冲数转换为对应rpm

则速度计算公式如下
n = M 1 / T c (单位取决于 T c ) n=M1/Tc (单位取决于Tc) n=M1/Tc(单位取决于Tc
误差分析

  • 由上图可知,采样脉冲来临后的脉冲并不能与编码器脉冲同步,前后共同的偏差时间至多为一个编码器脉冲
  • 由公式可见,当M1数值较小时(相对于一个脉冲),这种方法计算出的n误差则会放大,故M法测速不适合低速场景,更适合高速场景

T法测速

检测一个编码器脉冲的时间

其中

  • M2:编码器一个脉冲对应的时钟计数值
  • f0:时钟计数频率
  • Tt:总计数时间
  • 实际软件处理中出于减少计算的考虑可以不用将脉冲数转换为对应rpm

则速度的计算公式如下
n = 1 / T t = f 0 / M 2 (单位取决于 T t ) n=1/Tt=f0/M2 (单位取决于Tt) n=1/Tt=f0/M2(单位取决于Tt
误差分析

  • 由上图可知,T法测速采样的触发则变为了编码器的输出脉冲,则误差来源于时钟脉冲与编码器脉冲不同步,启动是同步的,而结束最多会产生一个时钟脉冲的误差
  • 由公式可知,M2越大一个时钟脉冲带来的误差影响越小,M2越大意味着转速越慢,则T法测速更适合低速场景

MT法测速

其中

  • M1:Tc时间内捕获到的编码器脉冲数+1(为了同步T法)
  • M2:M1起始脉冲与结束脉冲的时钟计数值
  • Tc:用户自定义采样周期(时间)
  • T:M2对应的时间

则速度的计算公式
n = M 1 / T = f 0 M 1 / M 2 (单位取决于 T ) n=M1/T=f0M1/M2(单位取决于T) n=M1/T=f0M1/M2(单位取决于T
分析

  • 由于M法适合测量高速,T法适合测量低速,则综合两法,低速时M2远大于M1主要T法在奏效;高速时M1远大于M2则主要M法在奏效
  • 但实际应用中为精度要求不高的场合,T法简单且能够满足要求

该部分内容参考以下链接:http://t.csdn.cn/BC5NY

PID速度控制

公式推导

公式推导
U ( t ) = K p ( e r r ( t ) + 1 T i ∫ t 0 e r r ( t ) + T D d e r r ( t ) d t ) U(t)=Kp(err(t)+{1 \over Ti}\int {t \atop 0} err(t)+T_D{derr(t) \over dt}) Ut=Kperr(t)+Ti10terr(t)+TDdtderr(t)
其中

  • U(t)表示当前时刻输出控制量
  • Kp表示比例参数
  • Ti表示积分时间
  • Td表示微分时间
  • err(t)表示当前反馈值与输入设定值的偏差

为使其能在计算机内处理,需要对其离散化
U ( k ) = K p ( e r r ( k ) + T T i ∑ e r r ( k ) + T D e r r ( k ) − e r r ( k − 1 ) T ) U(k)=Kp(err(k)+{T \over Ti}\sum err(k)+T_D{err(k)-err(k-1) \over T}) Uk=Kperr(k)+TiTerr(k)+TDTerr(k)err(k1)
其中

  • k表示第k次采样
  • T表示采样周期
  • U(k)表示当前采样周期输出控制量
  • Kp表示比例参数
  • Ti表示积分时间
  • Td表示微分时间
  • err(k)表示当前反馈值与输入设定值的偏差

由于T以及Ti、Td为常数则可以用Ki、Kd替换上式,即可得到位置式PID离散化计算公式
U ( k ) = K p ( e r r ( k ) + K i ∑ e r r ( k ) + K D ( e r r ( k ) − e r r ( k − 1 ) )) U(k)=Kp(err(k)+Ki\sum err(k)+K_D(err(k)-err(k-1)) ) Uk=Kperr(k)+Kierr(k)+KDerr(k)err(k1)))
有了以上基础不难得到增量式PID公式:
U ( k ) = U ( k − 1 ) + △ U ( k ) U(k)=U(k-1)+\triangle U(k) Uk=Uk1+Uk

△ U ( k ) = K p ( e r r ( k ) − e r r ( k − 1 ) + K i ∗ e r r ( k ) + K D ( e r r ( k ) − 2 e r r ( k − 1 ) − e r r ( k − 2 ) )) \triangle U(k)=Kp(err(k)-err(k-1)+Ki*err(k)+K_D(err(k)-2err(k-1)-err(k-2)) ) Uk=Kperr(k)errk1+Kierr(k)+KDerr(k)2err(k1)err(k2)))

总结

位置型PID控制器的基本特点:

  • 位置型PID控制的输出与整个过去的状态有关,用到了偏差的累加值,容易产生累积偏差。

  • 位置型PID适用于执行机构不带积分部件的对象。

  • 位置型的输出直接对应对象的输出,对系统的影响比较大。

增量型PID控制器的基本特点:

  • 增量型PID算法不需要做累加,控制量增量的确定仅与最近几次偏差值有关,计算偏差的影响较小。
  • 增量型PID算法得出的是控制量的增量,对系统的影响相对较小。
  • 采用增量型PID算法易于实现手动到自动的无扰动切换

该部分内容主要参考以下链接:https://blog.csdn.net/foxclever/article/details/80250994

c代码实现

PID结构体定义

typedef struct
{
    uint8_t mode;
    //PID 三参数
    fp32 Kp;
    fp32 Ki;
    fp32 Kd;

    fp32 max_out;  //最大输出
    fp32 max_iout; //最大积分输出

    fp32 set;
    fp32 fdb;

    fp32 out;
    fp32 Pout;
    fp32 Iout;
    fp32 Dout;
    fp32 Dbuf[3];  //微分项 0最新 1上一次 2上上次
    fp32 error[3]; //误差项 0最新 1上一次 2上上次
} pid_type_def;

PID控制器实现

fp32 PID_calc(pid_type_def *pid, fp32 ref, fp32 set)
{
    if (pid == NULL)
    {
        return 0.0f;
    }
    pid->error[2] = pid->error[1];
    pid->error[1] = pid->error[0];
    pid->set = set;
    pid->fdb = ref;
    pid->error[0] = set - ref;
    if (pid->mode == PID_POSITION)
    {
        pid->Pout = pid->Kp * pid->error[0];
        pid->Iout += pid->Ki * pid->error[0];
        pid->Dbuf[2] = pid->Dbuf[1];
        pid->Dbuf[1] = pid->Dbuf[0];
        pid->Dbuf[0] = (pid->error[0] - pid->error[1]);
        pid->Dout = pid->Kd * pid->Dbuf[0];
        LimitMax(pid->Iout, pid->max_iout);
        pid->out = pid->Pout + pid->Iout + pid->Dout;
        LimitMax(pid->out, pid->max_out);
    }
    else if (pid->mode == PID_DELTA)
    {
        pid->Pout = pid->Kp * (pid->error[0] - pid->error[1]);
        pid->Iout = pid->Ki * pid->error[0];
        pid->Dbuf[2] = pid->Dbuf[1];
        pid->Dbuf[1] = pid->Dbuf[0];
        pid->Dbuf[0] = (pid->error[0] - 2.0f * pid->error[1] + pid->error[2]);
        pid->Dout = pid->Kd * pid->Dbuf[0];
        pid->out += pid->Pout + pid->Iout + pid->Dout;
        LimitMax(pid->out, pid->max_out);
    }
    return pid->out;
}

总结

本文为个人学习总结,主要面向于在于应用,存在诸多问题没有深入讨论,若存在不当之处,望指正。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐