电机控制器,FPGA 硬件电流环 基于FPGA的永磁同步伺服控制系统的设计,在FPGA实现了伺服电机的矢量控制。 有坐标变换,电流环,速度环,位置环,电机反馈接口,SVPWM。 Verilog
最近在折腾工业伺服控制器的FPGA实现,发现这玩意儿真是把数学和硬件完美融合的典型。传统的DSP方案虽然灵活,但面对高精度电流环时总显得力不从心。这次咱们直接上FPGA硬刚,用Verilog把整个矢量控制系统搬进芯片里,实测效果比预期还要带劲。
先看核心的坐标变换模块。Clarke变换的Verilog实现其实挺有意思的,这里直接用定点数运算避免浮点消耗资源:
module clarke_transform ( input [15:0] ia, ib, ic, output [15:0] alpha, beta ); // 1/sqrt(3) ≈ 0.57735 转换为Q2.14格式 parameter INV_SQRT3 = 16'h4A9B; wire [31:0] alpha_tmp = ia; wire [31:0] beta_tmp = (ib - ic) * INV_SQRT3 >>> 14; assign alpha = alpha_tmp[23:8]; // 保留有效位 assign beta = beta_tmp[23:8]; endmodule这里有个坑:三相电流本来应该满足ia+ib+ic=0,但实际硬件采样可能会有偏差。我们专门在ADC接口模块里加了实时校验逻辑,用组合电路自动修正零点漂移,比软件滤波快了两个数量级。
电流环是真正的性能杀手,传统的PI调节器在FPGA里得改头换面。来看这个并行计算的PI核:
always @(posedge clk_10M) begin if(current_loop_en) begin // 误差计算 err_d <= (i_ref_q - i_fb_q); err_q <= (i_ref_d - i_fb_d); // 并行计算比例项和积分项 p_term_d <= err_d * Kp_current; i_term_d <= i_term_d + (err_d * Ki_current); p_term_q <= err_q * Kp_current; i_term_q <= i_term_q + (err_q * Ki_current); // 饱和处理 if(i_term_d > MAX_INTEGRAL) i_term_d <= MAX_INTEGRAL; if(i_term_q < -MAX_INTEGRAL) i_term_q <= -MAX_INTEGRAL; end end注意这里用10MHz时钟驱动,每个周期同时处理d/q轴数据。实测从采样到输出控制仅0.3μs延迟,比传统方案快20倍不止。不过积分项容易溢出,我们搞了个动态积分限幅机制:当输出电压达到80%PWM幅值时自动缩小积分系数,防止windup现象。
SVPWM模块是调制的关键,这里用状态机实现七段式调制。重点在扇区判断和矢量作用时间计算:
// 扇区判断逻辑 wire [2:0] sector = {vbeta[15], valpha[15], (valpha_abs > vbeta_abs)}; // 作用时间计算 always @(*) begin case(sector) 3'b000: begin t1 = (vbeta * Tpwm) / Vdc; t2 = (valpha * Tpwm) / Vdc; end // 其他扇区计算类似... endcase // 过调制处理 if((t1 + t2) > Tpwm) begin t1 = t1 * Tpwm / (t1 + t2); t2 = t2 * Tpwm / (t1 + t2); end end这里用组合逻辑生成PWM占空比,配合FPGA内部的高速PWM发生器,波形畸变率控制在0.5%以内。有个骚操作是把死区时间生成直接做在比较器硬件里,省去了软件插入延迟的麻烦。
位置环的编码器接口值得一提,我们设计了硬件正交解码器:
always @(posedge clk) begin case({A_sync, B_sync}) 2'b00: pos_cnt <= pos_cnt; 2'b01: pos_cnt <= dir ? pos_cnt + 1 : pos_cnt -1; 2'b10: pos_cnt <= dir ? pos_cnt -1 : pos_cnt +1; 2'b11: pos_cnt <= pos_cnt; endcase // 自动检测方向 dir <= (A_prev ^ B_sync); end这玩意儿直接挂在AXI总线上,主控CPU随时能读取位置计数值。实测在20000rpm转速下,位置检测误差不超过1个脉冲,比专用解码芯片还准。
最后说说资源优化。整个系统吃掉了约15K逻辑单元,电流环模块用了68个DSP Slice。为了省资源,把Park变换的正弦表改成了CORDIC迭代计算,虽然多花3个时钟周期,但节省了2.5KB的Block RAM。现在整个系统能在Xilinx Artix-7上跑到200MHz主频,控制周期压到5ns,对付万转以上的伺服电机完全没压力。
调试时发现个玄学问题:电机启动时偶尔会抖振。后来发现是SVPWM的载波同步没做好,在PWM周期开始瞬间强制重置积分器才解决。果然硬件世界里,时序就是上帝。