基于正交编码霍尔传感器MT测速以及PID控制开发总结
在实际应用中,有刷直流电机往往通过PWM调速控制,开环控制的问题在于固定的启动速度不能适应多种复杂的场合,使得参数整定复杂。引入PID控制解决此问题,PID控制需要反馈信号,则使用霍尔编码器对其速度进行反馈,软件上使用MT测速将霍尔信息转化为可处理的速度信息。本文为个人学习总结,主要面向于在于应用,存在诸多问题没有深入讨论,若存在不当之处,望指正。
基于正交编码霍尔传感器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}) U(t)=Kp(err(t)+Ti1∫0terr(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}) U(k)=Kp(err(k)+TiT∑err(k)+TDTerr(k)−err(k−1))
其中
- 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)) ) U(k)=Kp(err(k)+Ki∑err(k)+KD(err(k)−err(k−1)))
有了以上基础不难得到增量式PID公式:
U ( k ) = U ( k − 1 ) + △ U ( k ) U(k)=U(k-1)+\triangle U(k) U(k)=U(k−1)+△U(k)
△ 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)) ) △U(k)=Kp(err(k)−err(k−1)+Ki∗err(k)+KD(err(k)−2err(k−1)−err(k−2)))
总结
位置型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;
}
总结
本文为个人学习总结,主要面向于在于应用,存在诸多问题没有深入讨论,若存在不当之处,望指正。
更多推荐



所有评论(0)