BLDC电机开发之二-----测速方式和误差讨论
在基于hall或反电动势测速时,不同的测速方法会导致导致测速的反馈速度和精度都不一样,本文通过三种测试方法的对比,讨论不同测速方法的优劣和误差,本文中所使用代码来自本人开源项目 https://gitee.com/cyytx/bldc_-pid_-control
在PWM更新中断里测速
通常,控制BLDC电机的pwm频率在20KHZ左右,也就是pwm更新中断最多可达50us,这个就是测速时间的最小刻度,50us虽然看起啦比较短,但是在高速时可能会造成较大的测速误差,实际上我们可以通过公式来推导不同转速下的测速误差。
测速误差的公式推导
首先是根据电机和测试方法来推导公式,我的电机是2极对(四电极),测量方法是单hall_u变化检测(u/v/w都行), 二极对代表机械角度转一圈(360度),则电角度要转两圈,也就是720度,而hall_u 在一个电气周期(电角度360度)变化两次。所以机械角度转一圈,则hall_u变化四次。假设两次hall_u之间间隔的的中断次数为tick_diff,那么可以推导:
1、转一个机械圈的时间为4*tick_diff*50us = 200us*tick_diff
2、既然知道转一圈的时间,那么可以计算每秒转多少圈PRS = 1s/(200us*tick_diff)= (1s/200us) * (1/tick_diff) = 5000 /tick_diff,
3、电机的速度不是用PRS 而是用PRM,每分钟转多少圈来表示,所以RRM= PRS *60 = 300000 /tick_diff
4、由此可得公式RRM = 300000 /tick_diff 同时也可以根据转速推测需要多少个中断次数,也就是 tick_diff = 300000 / RPM
比如如果我预设速度为2800,那么根据公式可知 tick_diff = 300000 /2800 =107.142 857 1 ,但是tick_diff必须是整数,因为它是pwm中断的次数,也就是代表无论如何都无法得到一个准确的2800的测速值,那么在PID调控中,它就会在周围波动,极有可能测速时的tick_diff 是106 107 108 三个值。另外既然有了公式,那么实际上我们可让ai给我们编写一个网页用来将所有RPM下的误差计算出来,并绘制出误差曲线,这样我们就可以较为直观的看到不同转速下的误差情况。
测速误差的现象理论推导
1、总体看,从曲线可以看到,随着速度越来越大,那么测试误差的总趋势越来越大,但存在周期性震荡

2,从细节看,具体误差可具体推导,并且由于50us 精度的限制,某些


测速误差的实测
如图,红线是速度,黄线是预设速度 ,从红线的毛刺就可以看到确实是速度大误差越大

从细节上看,可以看到在3000RPM误差在±60RPM,比预测的要大一倍左右,为什么会这样呢?按理说tick_diff 在±1也就是在3000RPM时大概在±30左右才对。其实原因在于转子的机械误差,比如我的四电极转子有四个磁极,它们不可能是完全准确的90°均匀分布的,肯定会有些误差的,这个就导致了问题,我会在下面的定时器测速中讨论到这个问题。

单定时器捕获测速
pwm中断之所以测速不准的一个原因是时间刻度为50us ,时间间隔太大了导致测速不准,那么如果使用定时器捕获呢,我目前主频为128mhz,定时器不分频,那那么定时器捕获的精度为1/128mhz = 7.8125ns是非常 精确的
测试误差公式推导
1、转一圈时间为 4*7.8125ns * tick_diff = 31.25ns * tick_diff,
2、每秒转的圈数为 PRS=1s/(31.25ns * tick_diff) = 32,000,000 / tick_diff
3、每分钟转的圈数为RPM = PRS * 60 = 32,000,000 * 60 / tick_diff = 1,920,000,000 / tick_diff
4、由此可得公式:RPM = 1,920,000,000 / tick_diff同时也可得到:tick_diff = 1,920,000,000 / RPM
那么同样是对于2800 RPM,tick_diff =1,920,000,000 / 2800 = 685 714.2857
那么可以计算误差为 :
1920000000/685713 = 2800.005 250
1920000000/685714 = 2800.001 167
1920000000/685715 = 2799.997 083
可以看到测量误差小于0.01RPM,可以忽略不计了。
实测速度
非常奇怪 ,速度跳动还是比较大,虽然比前面的小了一点。前面的能够用测速误差来解释的话,下面的显然不能,因为精度够了,所以不得不找别的解释,另外还有一点可以看到的是,速度跳动时,在预测值上方的多,在下方的少,这一点也和上面在pwm中断里的不一样。

从细节看,比如在3000转时 ,跳动在+50 和-30之间,并且往上跳动的多,往下跳动的少。为什么会这样呢?我猜测是和转子的机械误差有关

转子机械偏差证明
首先如下图,我电机是四电极的电机,也就是转子有四个极性,我目前测速度方式是单HALL测速,在转子转动时,N和S极会轮流扫过HALL_U位置,没变化四次就是一圈,每变化一次就是90度,但是实际上无法做到精准的刚好90度就触发hall变化,因为工艺等问题总是会有写细微的差距。那么在下面我将证明这种差距

前面说BLDC (无刷直流电机) 的四电极转子不可能完全精准地以 90 度均匀分布,会存在机械偏差,但是怎么证明呢,之前我们有pid调整,引入了变量,那么我以固定PWM占空比,也就是固定的定时器CCR值来驱动空载的电机,然后将每次中断捕获的值列出来,用曲线展示,同时做滑动窗口平均 ,因为我们是四电极和单HALL测量,所以窗口=4
如图绿际测得到tick_diff,可以看到非常明显周期性,四个为一周期,的有红色线是做了滑动窗口平均,窗口为4,可以看到它的波动非常的小,由此也就证明了确实存在机械偏差,

同理也对速度做滑动窗口平均,可以看到原来速度在2040~1900之间跳动,速度变化有50,进过滑动窗口平均后,速度变化只有±1左右.
**另外其实另一个疑惑也可以得到解释,就是为什么在timer 捕获测试时,上误差比下无法大,正如下图,是因为我手头上的这个电机的器械误差刚好造成了这种特性。

使用整圈测速法
那既然机械误差的存在,改怎么准确测速呢,其实道理非常简单就是整圈测速,虽然四个转子无法均匀90°,但是四个的和加起来一定是360度,使用滑动窗口平均的方法测速,每次测的都是一整圈的,但同时速度又能保持每次hall 变化都能更新速度,比如下面这样
capture_num++; //记录hall 变化次数也就是捕获次数
capture_diff_buff_sum += g_speed_capture.capture_diff; //将新的值加到总和
capture_diff_buff_sum -= capture_diff_buff[capture_diff_buff_index]; //将旧的值清除
capture_diff_buff[capture_diff_buff_index] = g_speed_capture.capture_diff; //更新新的值更新到buffer中
capture_diff_buff_index++; //窗口序列滑动
if (capture_diff_buff_index >= 4) //循环滑动
{
capture_diff_buff_index = 0;
}
if(capture_num < 4) //为了解决前几次窗口没满是不返回速度,导致pid积分时间过长,所以即使不完全准确也先更新速度
{
g_bldc_motor1.speed = RPM_CALC_CONSTANT/(capture_diff_buff_sum/capture_num);
} else {
g_bldc_motor1.speed = RPM_CALC_CONSTANT/(capture_diff_buff_sum/4); //窗口是满的,是实际的整圈测速。
}
所以经过滑动窗口平均后,速度误差基本在±1(注意下图左侧的刻度),相比于之前得到了极大的提升

三定时器捕获测速法
单定时器捕获测速实际上已经能够把速度测的很准了,多定时器我觉得大部分情况下其实不需要,不过我之前写代码的时候,当时PID 调试时,发现一个问题,就是在低速时单HALL测速速度反馈太慢了,导致PID积分时间过长导致超调.所以当时为了提高速度更新速度使用了三个Halll测速,也就是多定时器测速法。它的本质和单定时器也是一致的,只不过他的测速度更新速度是单定时器捕获的三倍。不过低速时PID导致PID积分时间过长导致超调的问题其实可以通过PID自适应积分增益算法来解决。具体可参考本人开源项目 https://gitee.com/cyytx/bldc_-pid_-control 同理,因为是三定时器,也就是三hall 测速,一整圈我的hall会变化12次,所以滑动窗口就变成12了,如下图。

结语
经过上面的讨论,本文的观点如下:在PWM中断测速会因为精度的问题导致测速存在误差,在条件允许下使用定时器捕获的方法会更好,另外由于转子存在机械误差,所以要想精准测速,需要使用滑动窗口平均的方法进行整圈测速,既能保证速度点更新节奏,也能保证高精度