公司动态
FPGA实现无刷电机高精度闭环控制:从USB通信到PWM信号生成
1. 项目概述当FPGA遇上无刷电机最近在捣鼓一个挺有意思的玩意儿用FPGA通过USB去控制一个带电子调速器ESC的无刷直流电机BLDC。这听起来像是把几个不同领域的技术硬生生揉在了一起对吧确实它融合了电机控制、数字逻辑设计和上位机通信。我之所以想这么干核心动机很简单传统的单片机方案在处理高速PWM信号生成、多路信号同步以及需要极低延迟响应的复杂控制算法时有时会显得力不从心尤其是当你想同时实现高精度速度环、电流环甚至位置环的时候。FPGA的并行处理能力和硬件定时的精确性在这里就展现出了巨大的优势。这个项目的目标很明确构建一个从电脑端上位机到电机轴的完整控制链路。用户可以在电脑上的软件界面比如用Python或LabVIEW写的设定目标转速这个指令通过USB发送给FPGA。FPGA解析指令生成相应的PWM信号输送给ESCESC再驱动BLDC电机旋转。同时FPGA还可以通过ESC反馈的某些信号比如通过捕获电机反电动势或霍尔传感器信号来估算实际转速形成一个闭环控制系统。整个系统就像一个定制化的高性能电机控制器特别适合用于需要快速原型验证、对控制时序有苛刻要求的研究或高端DIY项目比如小型无人机、机器人关节驱动或者精密仪器。2. 系统架构与核心组件选型要搭起这套系统得先搞清楚每个部分扮演什么角色以及它们之间如何“对话”。整个系统的数据流和控制流可以看作一个三层结构上位机命令与监控层、FPGA核心控制与信号处理层、ESCBLDC功率执行层。2.1 无刷电机与电子调速器动力核心无刷直流电机BLDC和它的搭档电子调速器ESC是系统的执行终端。BLDC电机没有电刷和换向器依靠外部电路来切换绕组电流方向从而驱动永磁转子旋转。它的优点很明显效率高、寿命长、扭矩特性好。ESC本质上就是一个三相逆变器加一个控制大脑。它接收来自控制器的PWM信号通常是50Hz脉宽在1ms到2ms之间变化的标准舵机信号或者更高频率的PWM然后将其解译为对六个MOSFET管的开关控制从而在电机三相绕组上产生旋转磁场。注意市面上常见的ESC有两种主要通信协议。一种是上面说的标准PWM/舵机信号另一种是数字协议如DShot、OneShot等。对于FPGA初学者或希望快速验证的项目从标准的50Hz PWM信号入手是最简单的因为其协议简单直接用FPGA的计数器就能生成。而DShot等协议速度更快、抗干扰更好但需要FPGA实现特定的串行编码复杂度稍高。在这个项目中我选择了一款支持标准PWM输入、最大电流适中的ESC并搭配了一个尺寸匹配的BLDC电机。选型时除了电压电流参数还要特别注意ESC的启动程序和进角设置这些都会影响低速平稳性和效率最好选择支持通过编程卡或信号进行配置的型号。2.2 FPGA并行化的控制大脑FPGA是这个项目的灵魂。我选用的是Xilinx Artix-7系列的一款中等规模开发板。选择它的理由有几个首先它有足够的逻辑资源和片上存储器来处理控制算法和通信协议其次它通常自带稳定的时钟源和多个通用IO方便连接最后其开发工具Vivado成熟社区资源丰富。FPGA在这里要完成几项核心任务USB通信接口实现与上位机的数据交换。协议解析与命令处理解析上位机发来的速度指令并将其转换为内部的控制设定值。PWM信号生成模块根据设定值产生精确的、死区时间可调的PWM波形输出给ESC。速度反馈处理模块如果实现闭环捕获电机霍尔传感器或反电动势信号计算实时转速。控制算法模块如PID控制器比较设定转速与实际转速计算出新的PWM占空比。FPGA的并行特性允许这些模块同时运行。例如USB接收数据、PID计算、PWM生成可以是在不同的时钟节拍下同步执行的硬件逻辑块这确保了控制的实时性和确定性这是软件顺序执行的单片机难以媲美的。2.3 USB通信桥梁FT232H vs 软核实现连接FPGA和电脑的USB链路是关键。有两种主流实现方式一是使用专用的USB转接芯片如FTDI的FT232H二是在FPGA内部用软核实现USB协议栈。对于大多数项目我强烈推荐使用FT232H这类桥接芯片方案。原因如下它把复杂的USB协议处理完全用硬件解决了对FPGA开发者来说FT232H呈现的是一个简单的异步串口UART或同步FIFO接口你只需要在FPGA端实现一个UART或FIFO读写控制器即可难度骤降。FTDI提供的驱动非常稳定在电脑上会被识别为一个COM端口上位机编程就像操作普通串口一样简单。虽然理论带宽不如原生USB2.0但对于电机速度控制这种数据量不大的应用每秒几百上千个字节的命令和状态数据完全绰绰有余。在FPGA内部用软核例如使用Xilinx的USB IP核实现USB设备功能虽然看起来更“集成”但会消耗大量逻辑资源并且需要深入理解USB协议开发调试复杂度很高除非项目对体积、成本或特定USB协议如HID有极端要求否则不建议初学者采用。我的选择是FT232H。在硬件连接上将FT232H的TX/RX引脚与FPGA的两个IO口相连同时连接好RTS/CTS硬件流控制信号如果必要。在Vivado中需要编写一个UART接收/发送模块其时钟频率需要与FT232H设置的波特率匹配例如921600 bps或更高以提高数据传输效率。3. FPGA逻辑设计与核心模块实现有了清晰的架构就可以开始在Vivado里搭建数字逻辑了。整个FPGA设计采用自顶向下的模块化设计主要包含以下几个关键部分。3.1 顶层模块与时钟管理顶层模块Top Module负责实例化所有子模块并连接它们之间的信号。首先需要解决时钟问题。开发板上的晶振提供了一个基础时钟如100MHz通过FPGA内部的时钟管理单元MMCM或PLL可以生成不同频率的时钟供各个模块使用。系统主时钟clk_100m用于大部分逻辑和UART模块。PWM生成专用时钟clk_pwm频率需要远高于PWM载波频率。例如若PWM频率为20kHz为了获得精细的占空比分辨率clk_pwm可以设为100MHz这样每个PWM周期有5000个计数点分辨率很高。速度测量时钟clk_speed用于对霍尔信号进行定时频率适中即可如10MHz。// 示例顶层模块端口定义部分 module top_bldc_control ( input wire clk_100m, // 板载100MHz时钟 input wire rst_n, // 复位信号低有效 // USB-UART 接口 input wire uart_rxd, // 来自FT232H的接收数据 output wire uart_txd, // 发送给FT232H的数据 // ESC PWM 输出 output wire pwm_out, // 输出给ESC的PWM信号 // 电机霍尔传感器输入 (可选用于闭环) input wire hall_a, input wire hall_b, input wire hall_c, // 其他IO... ); // 内部信号与模块实例化... endmodule3.2 UART通信协议解析模块这个模块负责与FT232H通信。我们需要定义一套简单的应用层协议。例如上位机发送一个包含目标转速的指令帧FPGA回复一个包含当前转速和状态的应答帧。帧格式设计示例命令帧上位机 - FPGA0xAA帧头 0x01命令字代表设置速度 Speed_H速度高字节 Speed_L速度低字节 Checksum校验和。应答帧FPGA - 上位机0xBB帧头 0x81应答命令字 CurrentSpeed_HCurrentSpeed_LStatus状态字节 Checksum。在Verilog中UART接收器是一个状态机持续监测uart_rxd线的起始位然后按位接收数据位、校验位和停止位将接收到的字节存入一个缓冲区FIFO。另一个协议解析状态机从FIFO中读取字节识别帧头0xAA然后按照预定长度接收后续字节计算校验和如果正确则提取出Speed_H和Speed_L合并成一个16位的目标速度值更新到一个寄存器中供PWM生成模块读取。发送过程类似将需要上传的数据打包成帧通过UART发送器一位一位地发送出去。实操心得在实现UART时建议将波特率生成器Baud Rate Generator做成参数化模块。例如输入系统时钟频率和所需波特率自动计算分频计数值。这样移植到不同时钟的开发板时非常方便。另外强烈建议在发送和接收路径上都加入FIFO先入先出存储器以缓冲数据避免因处理不及时导致数据丢失。Xilinx的IP Catalog里提供了非常易用的FIFO Generator IP核。3.3 高精度PWM信号生成模块这是直接驱动ESC的模块。虽然ESC期望的是50Hz的舵机信号但我们的FPGA可以产生频率和占空比都极其精确的PWM。模块的核心是一个计数器和一个比较器。计数器在clk_pwm时钟驱动下从0计数到PWM_PERIOD - 1然后归零循环往复。PWM_PERIOD决定了PWM的频率PWM_Freq clk_pwm_freq / PWM_PERIOD。例如clk_pwm100MHz想要50Hz则PWM_PERIOD 100,000,000 / 50 2,000,000。这个值很大意味着计数器需要很多位至少21位。比较器有一个duty_cycle寄存器其值由主控制逻辑根据目标速度设定。当计数器的值小于duty_cycle时pwm_out输出高电平否则输出低电平。这样duty_cycle / PWM_PERIOD就是占空比。对于标准舵机协议占空比在5%到10%之间对应1ms到2ms的脉宽。因此我们需要将上位机发来的速度设定值比如0-1000线性映射到这个脉宽区间。假设PWM_PERIOD对应20ms50Hz那么1ms脉宽对应的duty_cyclePWM_PERIOD * 0.05。module pwm_generator ( input wire clk, input wire rst_n, input wire [20:0] period, // PWM周期计数值 input wire [20:0] duty, // 占空比计数值 output reg pwm_out ); reg [20:0] counter; always (posedge clk or negedge rst_n) begin if (!rst_n) begin counter 0; pwm_out 0; end else begin if (counter period - 1) begin counter counter 1; end else begin counter 0; end // 比较生成PWM注意duty为0时全低dutyperiod时全高需钳位 pwm_out (counter duty) ? 1b1 : 1b0; end end endmodule注意事项duty值绝对不能大于或等于period否则会导致PWM输出常高可能损坏ESC。必须在数据输入到该模块前进行钳位处理确保duty值在安全范围内例如period的5%到10%。3.4 速度闭环与PID控制实现如果要让电机精确稳定在某个转速开环控制直接给固定PWM是不够的负载一变转速就飘了。因此需要引入速度闭环。这里假设我们的电机带有霍尔传感器输出三个相位差120度的方波。速度测量使用三个霍尔信号我们可以通过检测其边沿变化来知道转子何时转过一个电周期。更简单的方法是只使用其中一个霍尔信号如HALL_A测量其两个上升沿或下降沿之间的时间间隔这个时间就是电机转过一对磁极所需的时间。速度RPM 60 / (极对数 * 时间间隔)。在FPGA里我们可以用一个计数器在霍尔信号上升沿时记录下当前一个高速计时器的值并与上一次的值相减得到间隔计数再根据计时器时钟频率换算成时间。数字PID控制器这是一个在FPGA里用硬件描述语言实现的算法模块。它周期性地例如每10ms执行一次计算。输入目标速度setpoint和实测速度feedback。输出PWM的duty_cycle设定值。公式位置式PIDoutput Kp * error Ki * integral Kd * derivative。 其中error setpoint - feedback。积分项integral是历次error的累加需防饱和微分项derivative是本次error与上次error的差值。在Verilog中这需要用到乘法器和加法器。为了便于调整参数KpKiKd通常用定点数表示例如Q11.4格式16位中11位整数4位小数。整个计算过程是纯组合逻辑或流水线逻辑在一个时钟周期或几个周期内完成。闭环整合主状态机协调工作。UART解析出新的setpoint后更新PID模块的设定值寄存器。速度测量模块定期更新feedback值。PID模块以固定周期计算并输出新的duty_cycle传递给PWM生成模块。这样就形成了一个完整的数字闭环控制系统。4. 上位机软件与调试技巧FPGA是下位机还需要一个上位机来发送命令和显示状态。这里灵活性很大可以用PythonPyQt/PySide做界面pyserial库通信、LabVIEW、C#甚至简单的串口调试助手配合脚本。一个实用的上位机应该具备串口连接/断开功能。目标速度设置可以通过滑块、输入框或按钮设置。实时曲线显示绘制目标速度和实际反馈速度的曲线这是调试PID参数最直观的工具。PID参数在线调整能实时修改Kp Ki Kd并发送给FPGA观察系统响应变化。数据日志记录保存运行数据以供后续分析。调试是项目成败的关键尤其是硬件、FPGA逻辑、上位机软件联调时。分阶段调试不要试图一次性完成所有功能。第一步先确保FPGA能通过UART正确收发数据。可以写一个简单的回环测试程序FPGA把收到的数据原样发回用串口助手验证。第二步测试PWM模块。用示波器测量FPGA输出给ESC的PWM引脚调整duty_cycle寄存器观察脉宽是否精确变化。此时先不要连接电机和ESC第三步连接ESC和电机但去掉电机桨叶或负载进行开环测试。通过上位机发送速度值听电机声音是否平滑变化观察电机是否正常启动旋转。第四步实现并测试速度测量模块。让电机空载旋转通过上位机读取FPGA计算并传回的转速值看是否合理。第五步最后才集成PID闭环。先设Ki0 Kd0只调Kp让系统能有响应但不震荡然后慢慢加入Ki消除静差最后酌情加Kd改善动态性能。必备工具示波器/逻辑分析仪查看PWM波形、UART信号、霍尔信号时序不可或缺。万用表检查电源、连接。FPGA开发工具的仿真器如Vivado Simulator在烧录到板子前对各个模块尤其是UART解析和PID计算进行仿真测试可以节省大量时间。带有图形化功能的串口调试软件如SerialPlot Docklight可以实时绘制数据曲线对调试闭环控制至关重要。常见问题与排查电机不转/抽搐检查PWM信号是否正常到达ESC检查ESC的电源是否充足确认PWM脉宽是否在ESC的识别范围内通常1ms-2ms尝试给ESC重新校准油门行程。转速控制不线性/有台阶感检查PWM占空比的计算和映射是否有精度损失确保UART发送的速度指令传输正确无误可能是PID参数不合适导致系统响应迟钝或过冲。USB通信不稳定/数据错乱检查波特率设置是否一致检查硬件流控制是否启用并正确连接RTS/CTS在UART接收模块中增加帧超时和错误帧丢弃机制确保FPGA端的UART时钟频率准确累积误差小。闭环振荡电机转速来回波动这是PID参数尤其是Kp和Kd设置不当的典型表现。首先降低Kp如果振荡频率很高可能是Kd太大或测量噪声被放大可以尝试降低Kd或在速度测量环节加入低通滤波。资源占用过高如果FPGA编译报告显示资源使用接近极限可以考虑优化将一些常数计算移到上位机进行使用更节省资源的PID算法如增量式PID降低一些模块的运行频率或数据位宽。这个项目从概念到实现涉及的知识面比较广但每一步拆解开来都是可以攻克的。它的价值在于提供了一个完全自主可控的高性能电机控制平台原型。你可以基于此进一步扩展功能比如加入电流采样实现力矩控制、实现更复杂的FOC磁场定向控制算法、或者用多个FPGA IO控制多个电机同步。当看到通过自己编写的代码和设计的电路让电机精准地按照指令旋转时那种成就感正是电子系统设计的乐趣所在。