资讯详情

STM32 FOC速度模式实战:编码器反馈与速度环调参

📅 2026/10/15 1:12:25 | 华诺云谱 👁 阅读
STM32 FOC速度模式实战:编码器反馈与速度环调参
简介面向电机控制应用开发者提供基于ST MCSDK V5.4.4与编码器反馈的FOC速度模式控制完整工程。资源围绕编码器驱动解析覆盖带OS与无OS两种运行环境以及接口1、接口2等不同硬件接口实现适合正在学习FOC控制原理或调试速度环的工程师参考。包内共2000个文件以C源文件1266个.c与头文件671个.h为主同时包含少量txt说明文档、cpp扩展文件和工程配置压缩包约53.6MB文件按功能模块组织编码器解码、速度计算、FOC核心算法等代码层次清晰便于按需查阅。已有132人学习下载。通过阅读分析可系统掌握编码器信号解码、速度环PI调节、FOC坐标变换与电流控制等关键实现理解带OS与无OS任务调度差异并能基于接口1/2的驱动框架适配实际硬件缩短FOC电机控制项目的开发调试周期具有较强的工程参考价值。1. FOC 速度模式控制编码器驱动的正确打开方式前阵子帮人调一台移动底盘的无刷电机空载转速正常一上负载就咔咔响速度直接垮掉一半。当时用的还是霍尔换相的六步方波负载一变换相点跟着飘速度环根本拉不住。后来把整套控制改成 ST MCSDK 的 FOC 速度模式用增量式编码器做转速反馈低速扭矩、带载刚性完全是两个维度。这份资源就是围绕这个场景整理的工程参考编码器怎么接进 STM32、速度环 PI 怎么从电流环派生、调完之后用什么手段验证它扛得住负载。适合两类人一是刚把电机转起来、想从开环切闭环的二是已经在跑霍尔换相但速度一高就发飘的。把它当一份照着接线、照着调参的底稿比从头翻手册省事得多。2. 速度模式先看懂电流环、速度环与编码器的三角关系2.1 FOC 双环结构为什么速度模式必须建立在电流环之上FOC 全称磁场定向控制核心是把定子电流分解成励磁分量 d 轴和转矩分量 q 轴。永磁同步电机里d 轴电流主要负责建立磁场q 轴电流真正产生转矩所以经典的 id0 控制就是让励磁分量归零集中力量控制 q 轴。速度模式在此基础上多套了一层速度环目标转速经过斜坡模块先送给速度 PI速度 PI 计算出一个 iq 参考值然后电流环把实际 iq 拉向这个参考值最后由 SVPWM 生成三相电压。整个链条从目标到 PWM 是一层压一层的。为什么速度环必须建立在电流环之上因为速度环的输出本质上是转矩请求而转矩请求最终要落在电流上。没有电流环时速度环直接去控电压母线上的压降、电机的反电动势、换向过渡过程全都会干扰结果尤其是高速带载时速度环等于在打一个看不见的靶子。有了电流环之后速度环面对的是一个相对线性的被控对象给多少 iq 参考就出多少转矩电流中间的非线性大多被电流环消化掉了。在 ST MCSDK 的工程框架里速度模式天然就是双环结构。电流环跑在 PWM 定时器中断里速度快通常 10kHz 甚至更高速度环则跑在慢得多的调节周期里先由速度斜坡限制加速度再由 PI 输出 iq 参考。很多初次接触的人上来就调速度环参数发现怎么调都震荡原因往往在电流环iq 实际值根本没跟上参考值速度环看到的转矩是滞后的、抖动的。所以调速度模式的第一步不是动速度环 Kp而是先确认电流环正常工作。编码器在这个结构里的角色比较特殊FOC 需要转子位置来计算 Park 变换的角度速度环需要转速作为反馈而一个增量式编码器能同时提供这两样。位置由计数器累加给出速度由位置差分得到。也就是说编码器既是电流环的眼睛也是速度环的眼睛它的分辨率直接决定速度环能看到多精细的变化。回到前面那个移动底盘案例六步方波只靠霍尔换相霍尔分辨率低位置误差大而编码器的每圈脉冲数高出一个数量级速度环才能稳定运行在重载工况下。2.2 编码器接口ABI 正交信号与 Z 脉冲在 FOC 里的分工常见增量式编码器是三路输出A 相、B 相和 Z 相。A 和 B 相位差 90 度靠这两个信号的边沿组合可以判断方向。Z 相每圈输出一个脉冲通常用来标定电气原点。这里的第一个关键操作是四倍频定时器在 A/B 的每个上升沿和下降沿都计数一个 1024 线的编码器等效成每圈 4096 个计数分辨率翻四倍。A/B 的相位关系直接决定计数方向。电机正转时 A 相超前 B 相 90 度反转时 B 相超前 A 相。如果接线接反了计数器方向就反了速度反馈变成负值闭环一启动就往反方向加速飞车。这是新手最容易踩的坑后面避坑部分会详细说。Z 脉冲则负责每圈校准因为增量编码器没有绝对位置上电后的第一次计数只是相对位置FOC 需要知道转子电角度Z 信号可以用来消除累计误差。传感器选型上霍尔、编码器、无传感器三种方案各有边界。我习惯用一个简单表格来对比方便项目初期决策反馈方案低速表现带载刚性成本与接线适用场景无传感器观测器差零速基本失效一般最低不用额外接线风机、泵类负载霍尔传感器一般分辨率低中等低三根开关信号电动工具、简单调速增量式编码器好零速可保持高较高A/B/Z 差分线伺服、移动底盘、机械臂速度模式要想稳定反馈分辨率是很现实的约束。霍尔在低速下换相位置误差大速度环看到的转速噪声也大编码器则几乎没有这个问题。另一个信号质量问题是传输编码器线长超过一二十厘米建议用差分输出版本不然 A/B 信号上的毛刺会让定时器多计数速度反馈会无故跳变。2.3 PWM 采样同步编码器读数与电流采样的时序约束FOC 的电流采样不是一个随便的时刻抓一次的。ST MCSDK 的典型做法是在 PWM 下桥开通的中间时刻采样这时候电流波形最平稳采到的值最接近相电流平均值。单电阻采样还需要在特定的开关状态组合下补采三分流则相对宽松。这个时机窗口随占空比变化高速大扭矩时窗口会变窄采样噪声也会变大。所以在 MCSDK 工程里看到电流环频率和 PWM 频率绑定是有物理原因的。速度环的反馈则来自编码器。速度环周期通常比电流环慢我常用的配置是电流环 16kHz、速度环 1kHz。这里有一个容易被忽略的计算设速度环周期 T1ms编码器等效每圈计数 N4096那么最低稳定转速 10rpm 时一个速度环周期内的平均脉冲数就是p N × n / 60 × T 4096 × 10 / 60 × 0.001 ≈ 0.68也就是说1ms 里只能等来不到一个脉冲。此时速度反馈要么是 0要么是一个整数的跳变速度环在这种反馈下天生抖动。要解决要么换更高线数的编码器要么把速度环周期拉长到 5ms、10ms要么用 M/T 测速法在低速时同时测量脉冲计数和测速时间。MCSDK 自带的速度测量模块综合考虑了这些因素但如果你是自己外挂编码器这条计算一定要先做否则后面调参全是在玄学里打转。3. MCSDK 工程配置把编码器驱动接进速度闭环3.1 MC Workbench 配置从电机参数到编码器传感器ST MCSDK 的工程项目一般由 MC Workbench 生成Workbench 里做的事情其实就是把电机参数、控制板拓扑、传感器类型和调节周期映射成一套底层驱动代码。我拿到一块板子第一件事是在 Workbench 里新建工程先填电机侧的额定电压、额定电流、极对数再填 PWM 频率和电流采样方式。这里最容易出错的是极对数有些用户直接抄电机铭牌上的极数比如 8 极但 FOC 里要填的是极对数也就是 4。填错之后电角度换算全错电机根本转不起来。传感器配置界面里选 EncoderABI需要给出每圈脉冲数和方向。每圈脉冲数要与实际编码器一致MCSDK 内部会用它换算速度方向则决定电角度增长的顺序。如果这里的方向配置反了后面闭环一定反向飞车。Workbench 生成工程后会输出 mc_config 等配置文件速度环、电流环的参数都在里面。我把常用的几个关键参数列出来方便对照配置项含义常见取值PWM 频率决定电流环执行频率16kHz ~ 20kHz电流采样方式单电阻 / 三分流三分流更稳速度调节周期速度环执行间隔1ms ~ 5ms编码器每圈脉冲数换算速度的位置基准1000 ~ 4096传感器方向正反方向修正根据实测翻转生成工程之后不要急着改 PI先把传感器接口打通。MCSDK 会生成速度测量和位置计算的代码但编码器的硬件初始化和中断处理还是由 STM32 的定时器外设承担。我一般先在生成的工程里做一个小验证手动转动电机轴观察 Workbench 的实时变量里位置和速度是否有变化、方向是否正确。这一步跑通了后面才有意义。3.2 编码器外设初始化TIM 正交编码器模式的正确姿势STM32 的定时器大部分带编码器模式也就是将 A/B 两路信号接到定时器的两个输入引脚定时器自动完成差频计数和方向判断。以通用定时器 TIM2 为例使用时序大致是这样先使能时钟配置 GPIO 为复用输入然后用定时器的 Slave 模式启动编码器接口再把计数周期设为最大让计数器工作在自由溢出模式。下面这段是我在项目里常用的编码器初始化片段去掉具体引脚后可以直接套用static void Encoder_TIM_Init(TIM_HandleTypeDef *htim) { TIM_Encoder_InitTypeDef enc {0}; // A 相和 B 相都作为输入TI1FP1 与 TI2FP2 组合计数 enc.EncoderMode TIM_ENCODER_MODE_TI12; enc.IC1Polarity TIM_ICPOLARITY_RISING; // A 相上升沿和下降沿都计入 enc.IC1Selection TIM_ICSELECTION_DIRECTTI; enc.IC1Prescaler 0; enc.IC1Filter 0x0F; // 输入滤波抗毛刺 enc.IC2Polarity TIM_ICPOLARITY_RISING; enc.IC2Selection TIM_ICSELECTION_DIRECTTI; enc.IC2Prescaler 0; enc.IC2Filter 0x0F; if (HAL_TIM_Encoder_Init(htim, enc) ! HAL_OK) { // 编码器初始化失败检查 GPIO 与 TIM 时钟 } HAL_TIM_Encoder_Start(htim, TIM_CHANNEL_ALL); }这段代码的要点有三个。第一EncoderMode 选 TI12即 A/B 同时参与计数才能得到四倍频效果。第二输入滤波不是越大越好滤波系数 0x0F 在大多数电机环境下够用但编码器线特别长、干扰大的时候我会先试 0x3F代价是延迟变大高速时反而会丢脉冲。第三这个定时器的计数器必须保留给编码器专用不要和任何 PWM 输出共用否则计数器被触发事件清零位置数据就全乱了。初始化完成后在空闲中断里读取计数器前老手会先做一个方向校准实验用手缓慢正转电机轴看计数值是否增加。如果减少有两种补救方法一是交换 A/B 接线二是在 Workbench 里翻转传感器方向。我一般先改接线因为这样代码逻辑与物理接线一致后续排查时更直观。3.3 速度换算从编码器计数增量到 RPM编码器计数的原始值是 16 位或 32 位整型速度环需要的是转速数值。换算思路很简单周期性读取计数器值与上一次读数相减得到时间间隔内的脉冲增量再除以编码器每圈计数和间隔时间得到转速。方向则由增量的正负体现。这里最关键的是溢出处理。定时器计数器到达上限会回绕到 0如果直接用当前值减上次值会得到巨大的错误数值。正确做法是用无符号减法让回绕特性自己抵消。我的速度读取函数大致是这样#define ENCODER_PULSES_PER_REV 4096 // 四倍频后的等效线数 #define SPEED_LOOP_PERIOD_MS 1 // 速度环周期 1ms float Encoder_GetSpeedRPM(uint16_t cnt_now, uint16_t cnt_last) { int16_t delta; float rpm; // 无符号回绕减法cnt_now 比 cnt_last 小时得到补数等价于正确差值 delta (int16_t)(cnt_now - cnt_last); // 每秒计数增量 / 每圈计数 每秒转数再乘 60 转成 rpm rpm (float)delta * 1000.0f / SPEED_LOOP_PERIOD_MS / ENCODER_PULSES_PER_REV * 60.0f; return rpm; }这个函数看起来简单但有三个细节决定了它能不能直接用。首先是 cnt_last 的更新时机必须在读取 cnt_now 之后立刻更新如果漏了下一次调用时算出来的增量就是两倍间隔速度会偏低一半。其次是转速正负delta 是带符号的速度环直接拿这个带符号反馈值和目标值比较天然支持正反转。最后是换算系数1000 是 1 秒除以 1ms 得到的只要改了速度环周期这个系数就要同步改否则实际转速与反馈值差一个倍数PI 输出会很怪。在 MCSDK 框架里位置和速度测量模块通常已经封装好了但我自己写这个函数的意义在于能独立验证编码器是否工作正常。手转电机轴时串口打印转速正转正数、反转负数、数值稳定这一步通过再启用闭环省掉很多后面查问题的烦恼。4. 速度环调参先从电流环把编码器反馈喂稳4.1 速度环与电流环的带宽匹配默认参数为什么经常不顺手速度环调参的前提是电流环可靠。FOC 里面电流环的响应速度远快于速度环通常电流环带宽做到 1kHz 甚至更高速度环只做到几十赫兹。为什么要差这么多因为速度环采样的是电机转速转动惯量让转速变化天然比较慢速度环带宽太高反而会把编码器噪声放大成扭矩脉动。我在实际项目里常用的匹配关系如下电流环带宽速度环带宽适用工况1kHz10 ~ 20Hz大惯量、重负载2kHz30 ~ 50Hz通用伺服、移动底盘3kHz 以上50 ~ 100Hz高动态、小惯量如果电流环带宽不足速度环提上去之后高速运行时电流环相位滞后明显整个系统表现为「速度震荡、电流削顶」。所以只要发现速度环怎么调都带着电流噪声就先停下来查电流环。ST MCSDK 的电流环 PI 在 Workbench 里会按电机参数给出初始值但真正落地时受采样电阻误差和死区时间影响几乎都要手动修。电流环 PI 的理论初值一般按电感和电阻估算Kp 与定子电感成正比Ki 与定子电阻相关。MCSDK 采用归一化格式Kp 的数值含义和裸工程不一样直接看代码里的注释确认单位更稳妥。调电流环时我用示波器看 iq 的阶跃响应想要的是电流快速跟上且略微有一点超调完全没有超调说明 Kp 偏低带载时会觉得肉。4.2 测速滤波与感知延迟不要迷信一阶低通编码器速度反馈天生带量化噪声尤其是低速段速度环周期内只有几个脉冲反馈值在 0 和某正整数之间跳。很多人第一反应是上一阶低通滤波器结果速度环确实平了但延迟大了一加载就震荡。血泪经验是速度环带宽 20Hz 时一阶低通截止频率如果设在 50Hz反馈上的相位滞后就足以让 PI 失控。我更倾向用滑动平均滤波或者中值滤波。滑动平均的实现简单但窗口长度要跟速度环周期匹配。以 1ms 速度环周期为例我常用 8 点滑动平均约 8ms 延迟对 20Hz 速度环来说可以接受。示例代码#define SPEED_FILTER_LEN 8 static float speed_buf[SPEED_FILTER_LEN]; static uint8_t speed_idx 0; static float speed_sum 0.0f; float Speed_Filter_Update(float raw_speed) { // 移出最旧值移入最新值用累加和求平均 speed_sum - speed_buf[speed_idx]; speed_buf[speed_idx] raw_speed; speed_sum raw_speed; speed_idx (speed_idx 1) % SPEED_FILTER_LEN; return speed_sum / SPEED_FILTER_LEN; }滑动平均的问题在于编码器毛刺如果出现在某个采样点上它会对接下来 8 个周期都产生影响看起来像一个小平台。中值滤波对脉冲式毛刺更友好但排序开销稍大1ms 周期下用冒泡或插入排序完全来得及。我的习惯是先看原始速度波形的噪声形态表现为单点毛刺就用中值表现为周期波动就用滑动平均。另外滤波输出加入速度环之前一定要把原始值和滤波值同时留一份给调试串口方便判断问题到底是来自编码器还是来自 PI。关于感知延迟还有一个容易被忽略的点编码器信号本身的电气延迟。长线传输、光耦隔离、输入滤波都会让 A/B 信号的沿滞后滞后时间折算成角度就相当于位置误差进而影响电流环的 Park 变换。位置误差在低速时影响小高速时直接削弱输出转矩。如果高速带载能力不足不一定是 PI 问题先测一下编码器 A 相信号和实际转子位置的对齐关系。4.3 斜坡、限幅与零速调好边界再谈 PI速度环的 PI 参数只能在合理边界内起作用。第一层边界是加速度斜坡MCSDK 的速度模式里有一个斜坡模块它的作用是把阶跃目标速度转换成连续升高或降低的参考速度。很多现场调试遇到的情况是速度环参数明明没错给定 1000rpm电机要 2 秒才爬到那是因为斜坡限定了加速度PI 再强也追不上参考值。想测试真实动态性能时我会把斜坡加速度暂时调大看速度环本身的跟踪能力。第二层边界是 iq 限幅。速度环输出的 iq 参考必须限制在安全电流以内否则母线过流、驱动器炸管。调参时要时刻盯着 iq如果加载后速度跌落iq 已经顶到限幅那属于转矩不足调速度环 Kp 没有意义要么提高限幅在硬件允许范围内要么减小负载要么换更大扭矩的电机。反过来说iq 远没到限幅但速度一直上不去才需要加 Kp 或 Ki。零速工况是速度模式的特殊难题。编码器在零速附近几乎没有脉冲速度反馈大概率是 0此时速度 PI 的输出会慢慢积到一个较大值电机突然一抖。我的处理方式是把速度环的积分分离或加死区速度误差小于阈值时积分项保持不继续累加。ST MCSDK 的工程里也提供了相关的保护机制但现场调的时候把零速抖动和正常低速运行分开来看如果只是启动瞬间抖一下主要由 I 项初始冲击造成给速度环输出加一个限幅斜率如果是长期低速爬行抖动那问题在测速分辨率回到第 2 章的脉冲数计算去解决。5. 常见问题排查编码器方向反、堵转与低速抖动的现场处理5.1 现象一电机正转速度反馈却是负的闭环直接反向飞车现象手动转电机位置和速度变量都在变化但方向相反。速度环一启动给定正转速电机反而加速往反方向冲直到撞上限幅。原因A/B 相接线接反或者 Workbench 里的传感器方向配置与真实电机相反。FOC 里电角度方向和速度方向必须一致方向反了等于速度环在负反馈状态下变成正反馈。解决先切换闭环为开环或手动模式用手转动电机轴观察编码器计数方向。若计数方向不对直接交换 A/B 两根线这是最彻底的做法。如果接线已经固定不方便改再到 Workbench 的传感器配置里翻转 Encoder Direction 选项。改完后重新上电手动转轴确认计数方向与电机实际转向一致再恢复闭环。注意改完方向后位置零点也变了需要重新做一次电角度对齐。5.2 现象二低速抖速度读数在目标值上下跳电流毛刺乱现象目标转速 30rpm实际转速在 15 到 45 之间来回晃电流波形上叠加明显的高频毛刺声音也嗡嗡响。原因多数是测速分辨率不足和编码器信号毛刺两件事叠加。30rpm 低速下1ms 速度环周期内可能只有 2 到 3 个脉冲量化台阶大PI 输入就在台阶之间跳。另一个原因是输入滤波太弱A/B 信号上的毛刺被当成有效边沿多计了数。解决先看原始计数值确认是否存在单方向上反复多计如果是提高输入滤波系数或者检查编码器屏蔽层接地。再看速度环周期内脉冲数是否够不够就把速度环周期从 1ms 拉到 5ms相当于提高了每次采样的脉冲数量。最后给速度反馈加 8 点滑动平均让 PI 看到更平滑的输入。调完之后目标 30rpm 的波动应能压到 ±2rpm 以内否则继续找机械或信号源的问题。5.3 现象三一加载转速就掉Kp 加大后反而震荡现象空载运行良好加载后转速明显跌落恢复很慢。调大速度环 Kp 后跌落变快但转速开始震荡甚至出现周期性啸叫。原因速度跌落本质是转矩不足或速度环抗扰动能力弱而抗扰动能力与速度环带宽相关。无脑加大 Kp带宽提上去的同时把编码器噪声也放大了形成限幅震荡。另一个隐蔽原因是电流环 iq 已到限幅速度环再大也没用。解决先记录加载后的 iq 实际值看是否触及限幅。如果触及检查限幅设置和负载匹配。如果没有触及再按顺序调先小幅增加速度环带宽同时把测速滤波窗口缩短一点以减小延迟然后增加 Ki 消除稳态误差最后验证加载后转速恢复时间。每一步都要做阶跃测试对比不要同时改两个量否则永远不知道是谁起的作用。5.4 现象四Z 信号引起过零跳变位置和转速同时异常现象每次转到某一位置附近位置值突然跳一个很大台阶转速显示瞬间飙升随后又恢复。有时还会伴随偶发堵转。原因Z 脉冲触发的位置复位与编码器计数方向不匹配或者 Z 信号带毛刺在非零位附近误触发。还有一种情况是 Z 信号布线靠近功率线干扰耦合进定时器触发引脚。解决先用示波器抓 Z 和 A/B 波形确认 Z 是否每圈只有一包脉冲且与 A/B 有确定的相位关系。若 Z 毛刺多给 Z 输入加硬件 RC 滤波或软件消抖。若 Z 位置正常但复位方向反了把 Z 对齐的触发条件反过来。最后排查布线上 Z 是否与其他信号共用线束至少要做到双绞并避开功率器件散热区域。6. 验证方法速度阶跃、负载跌落与编码器校准6.1 速度阶跃测试怎么判断调参到底成没成速度环调完我习惯先跑一组三档阶跃300rpm、1000rpm、1500rpm。每一档都要记录转速反馈、iq 电流和母线电压三路数据。转速看超调量与稳定时间iq 看峰值电流和稳态脉动。如果 1000rpm 阶跃时超调超过 10%就把 Kp 小幅下调如果到达目标转速前出现明显爬行则增加 Ki。判断标准就两条转速一两次过冲内稳定iq 不顶限幅。数据记录用串口导出再配合一段小脚本提取指标import re data [] for line in open(speed_log.txt): m re.search(rt(\d)ms, rpm(\S), line) if m: data.append((int(m.group(1)), float(m.group(2)))) target 1000.0 peak max(rpm for _, rpm in data) steady [rpm for _, rpm in data[-50:]] overshoot (peak - target) / target * 100 settle_ms next((t for t, rpm in data if abs(rpm - target) 10), -1) print(f超调量: {overshoot:.1f}%) print(f稳态偏差: {abs(sum(steady)/len(steady) - target):.1f} rpm)这个脚本很简单但能把「手感」量化。超调量小于 10%、稳态偏差小于 1% 是我验收的及格线。另外要对比阶跃前后的 iq 曲线如果 iq 在阶跃瞬间出现很深的负向尖峰说明电流环动态偏慢先别动速度环回去处理电流环。6.2 加载测试与编码器校准把「能转」升级成「扛得住」空载阶跃通过只说明速度环能跟踪目标真正考验是突加负载。我用磁粉制动器或给电机轴上直接挂负载在 1000rpm 稳定运行状态下瞬间加载到额定转矩观察转速跌落和恢复时间。转速跌落小于 5%、恢复时间小于 300ms基本就能交付。如果跌落明显需要确认 iq 是否冲到限幅这直接决定了系统还剩多少转矩余量。编码器校准也要纳入验证流程。上电后手动转动电机一圈确认 Z 信号到位后位置值归零一次。然后在低速 10rpm 下连续运行十分钟观察位置累计误差是否一直在小范围内。如果位置漂移持续增大说明编码器脉冲有丢失检查机械连接是否有松动、联轴器是否打滑。从那以后我每次调完速度环都强制走一遍从空载阶跃到加载跌落的整套测试宁愿多花一个小时也不在现场翻车。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑