4. 速度计算与测速方法:基于霍尔脉冲的M法/T法/M-T法测速、低速与高速下的精度权衡

速度计算,说白了就是回答一个问题:电机转得有多快?

霍尔传感器每转一圈给你三个脉冲(或者更多,取决于极对数)。我们得从这些脉冲里把转速“算”出来。听起来简单,但实际做起来,你会发现低速和高速完全是两个世界。

我个人习惯把测速方法分成三类:M法、T法、M-T法。每种方法都有自己的脾气,选错了,你的控制系统就会“抖”给你看。

4.1 先搞清楚:霍尔脉冲与转速的关系

在讲方法之前,我们先统一一下基础概念。

一个霍尔传感器,每转过一个磁极,就输出一个跳变沿。对于一对极的电机,三个霍尔传感器,一圈总共产生 6 个跳变沿(上升沿+下降沿)。

所以,每个跳变沿对应的机械角度是:

Δθ = 360° / (3 × 2) = 60°

如果你用的是多对极电机,比如 4 对极,那每个跳变沿对应的电角度还是 60°,但机械角度变成了 60°/4 = 15°。

我的小习惯: 我一般直接用“电角度”来算速度,因为控制最终关心的是电频率。机械速度最后再换算。这样能少绕一圈。

4.2 M法测速:高速时的好兄弟

M法,全称是“在规定时间内数脉冲”。

做法很简单:开一个固定时间窗口(比如 10ms),数一下这个窗口内来了多少个霍尔跳变沿。

速度 = (脉冲数 × 60) / (极对数 × 3 × 2 × 时间窗口)

举个例子,1 对极电机,10ms 内数到 30 个跳变沿:

速度 = (30 × 60) / (1 × 6 × 0.01) = 30000 RPM

优点很明显: 高速时脉冲多,计数准确,分辨率高。

缺点也很致命: 低速时,一个时间窗口可能只抓到 1 个甚至 0 个脉冲。你想想看,如果只抓到 1 个脉冲,速度就是 1000 RPM;抓到 2 个,就是 2000 RPM。这跳变太大了,控制根本稳不住。

我曾经踩过的坑: 有一次做低速爬行测试,目标转速 50 RPM。我用 M 法,10ms 窗口,结果速度反馈在 0 和 1000 RPM 之间来回跳。电机像抽风一样。后来我才意识到,M 法在低速下就是“脉冲数不够,精度来凑”。

4.3 T法测速:低速时的救星

T法,思路反过来——不数脉冲,而是测量两个脉冲之间的时间。

用定时器捕获两个相邻跳变沿的时间差 ΔT,然后:

速度 = 60 / (极对数 × 3 × 2 × ΔT)

还是 1 对极电机,如果测到两个跳变沿间隔 1ms:

速度 = 60 / (1 × 6 × 0.001) = 10000 RPM

低速时,脉冲间隔很长,定时器能测得很准。比如 10 RPM 时,两个跳变沿间隔 100ms,你用高精度定时器去量,误差很小。

但高速时,T 法就露怯了。10000 RPM 时,两个跳变沿间隔只有 1ms。如果你的定时器分辨率是 1μs,那测量误差就是 0.1%。还行。但如果转速到了 100000 RPM,间隔只有 100μs,误差就变成 1% 了。

核心结论:
  • M法: 高速准,低速不准。
  • T法: 低速准,高速不准。
说白了,它们俩是互补的。

4.4 M-T法:我全都要

既然 M 法和 T 法各有短板,那能不能把两者结合起来?

M-T法 就是干这个的。它的思路是:

  1. 设定一个固定的测速周期 T0(比如 10ms)。
  2. 在这个周期内,数脉冲个数 M1(M 法的思路)。
  3. 同时,用定时器测量这个周期内最后一个完整脉冲的时间间隔 T2(T 法的思路)。
  4. 最终速度 = (M1 × 60) / (极对数 × 3 × 2 × T2)

你看,它用 M1 来保证高速时的计数精度,用 T2 来保证低速时的测量精度。两者一结合,全速域都能获得不错的精度。

实际实现时,我一般这样写:

// 伪代码:M-T法测速
void Speed_MT_Calc(void)
{
    static uint32_t last_capture = 0;
    static uint32_t pulse_count = 0;
    uint32_t current_capture;
    uint32_t delta_t;
    float speed;

    // 霍尔中断服务函数中调用
    current_capture = TIM_GetCapture(TIM2);
    delta_t = current_capture - last_capture;
    last_capture = current_capture;
    pulse_count++;

    // 每 10ms 计算一次速度
    if (TIM_GetFlag(TIM3, TIM_FLAG_UPDATE))
    {
        if (delta_t > 0)
        {
            // M-T法核心公式
            speed = (float)(pulse_count * 60) / (POLE_PAIRS * 6 * delta_t * TIMER_RESOLUTION);
        }
        pulse_count = 0;
        TIM_ClearFlag(TIM3, TIM_FLAG_UPDATE);
    }
}
我的经验: M-T 法虽然好,但实现起来比 M 法和 T 法复杂一点。你需要一个定时器专门做捕获,另一个定时器做周期中断。而且要注意,在极低速下(比如 1 RPM 以下),delta_t 可能会溢出,需要做防溢出处理。

4.5 三种方法对比:一张表说清楚

方法 原理 低速精度 高速精度 实现复杂度 适用场景
M法 固定时间数脉冲 差 好 低 高速电机、风机、泵
T法 测量脉冲间隔 好 差 低 低速伺服、位置控制
M-T法 两者结合 好 好 中 全速域通用、高性能驱动

4.6 精度权衡:你到底需要多准?

你可能会问:我是不是无脑选 M-T 法就行了?

不一定。精度是有代价的。

  • M法 实现最简单,代码量最少,适合对成本敏感、高速运行的场景(比如吸尘器、电风扇)。
  • T法 在低速下精度极高,适合需要低速平稳运行的场景(比如机器人关节、转台)。
  • M-T法 精度最好,但需要更多的定时器资源和更复杂的逻辑。如果你的 MCU 资源紧张,可能得不偿失。

我个人的选择原则是:

  1. 如果电机主要工作在额定转速的 30% 以上,用 M 法就够了。
  2. 如果电机经常工作在 10% 以下,必须用 T 法或 M-T 法。
  3. 如果全速域都需要高精度,别犹豫,上 M-T 法。
注意: 无论你用哪种方法,霍尔传感器的安装精度都会直接影响测速结果。如果三个霍尔传感器安装不对称,你测出来的速度会带有周期性波动。我曾经遇到过,换了传感器位置,速度波动直接降了一半。

4.7 一张图看懂三种方法

下面这张图,我画了 M 法、T 法和 M-T 法的核心逻辑对比。你看一眼就能明白它们的区别。

M法 / T法 / M-T法 核心逻辑对比 M法:固定时间窗口 数脉冲个数 M 速度 = M / ΔT 高速:脉冲多,精度高 低速:脉冲少,精度差 T法:测量脉冲间隔 测量时间差 ΔT 速度 = 1 / ΔT 低速:间隔长,测量准 高速:间隔短,误差大 M-T法:两者结合 数脉冲 M + 测间隔 ΔT 速度 = M / ΔT 全速域:精度均衡 实现稍复杂,但最通用 选型建议 • 高速电机(>3000 RPM):优先 M 法,简单可靠 • 低速伺服(<100 RPM):必须 T 法或 M-T 法 • 全速域高性能:M-T 法,虽然复杂但值得 • 资源受限 MCU:M 法 + 低速时切换 T 法

4.8 实际调参中的几个坑

最后,分享几个我在实际项目中踩过的坑,希望能帮你少走弯路。

  • 定时器分辨率不够: 有一次我用 72MHz 的定时器做 T 法测速,觉得够用了。结果电机在 100000 RPM 时,两个脉冲间隔只有 100μs,定时器只能数到 7200 个 tick。误差 0.014%,还行。但如果你的定时器只有 1MHz,那误差就大了。所以,高速时一定要用高分辨率定时器。
  • 滤波不能少: 霍尔信号本身有抖动,尤其是电机振动大的时候。我一般会在速度计算后面加一个一阶低通滤波器,截止频率设在 10-20Hz。这样速度反馈会平滑很多。
  • 启动时的特殊处理: 电机刚启动时,霍尔脉冲还没稳定。这时候用 M 法或 T 法都会算出离谱的速度。我的做法是:启动后的前 3 个脉冲不参与速度计算,等信号稳定了再开始算。
  • 注意溢出: T 法测速时,如果电机停了,两个脉冲间隔会无限大。定时器会溢出。一定要做溢出判断,否则速度会突然跳到一个很大的值。
一句话总结:

M 法适合高速,T 法适合低速,M-T 法全都要。选哪个,取决于你的电机跑多快、你的 MCU 有多强、你的控制精度要求有多高。没有最好的方法,只有最合适的方法。