1. FOC电流环基础调试
任务目标
本案例驱动一台带编码器的永磁同步电机(PMSM),在FOC框架下实现d/q轴电流环PI控制。通过调节PI参数,使电机相电流实际值跟踪给定值,并借助上位机或调试器观察电流波形,验证电流环的跟随性能。
环境与依赖
- 硬件:STM32F407开发板 + 三相逆变桥(如DRV8301)+ PMSM电机(带增量式编码器或磁编码器)
- 软件:STM32CubeIDE 或 Keil MDK,配合ST Motor Control Workbench(可选)
- 关键依赖:定时器输出6路PWM(中心对齐模式)、ADC同步采样两相电流、编码器接口读取电角度
核心实现
以下代码实现FOC电流环的核心闭环:读取电角度与相电流 → Clarke/Park变换 → PI调节 → 逆Park变换 → SVPWM输出。PI参数通过外部变量Kp、Ki实时调整,便于在线调试。
// 电流环PI控制参数(可在线修改)
float Kp = 0.5f; // 比例增益
float Ki = 0.01f; // 积分增益
// 电流环状态
static float integral_d = 0.0f, integral_q = 0.0f;
static float i_alpha, i_beta, i_d, i_q;
static float v_d, v_q, v_alpha, v_beta;
// 电机电气参数
#define POLE_PAIRS 4
#define PWM_PERIOD 1000 // 对应20kHz,ARR=1000
// 读取电角度(来自编码器或观测器)
extern float get_electrical_angle(void);
// 读取两相电流(ADC采样值转换为安培)
extern void read_phase_currents(float *ia, float *ib);
// 设置PWM占空比(SVPWM结果)
extern void set_pwm_duty(float ta, float tb, float tc);
// Clarke变换
void clarke_transform(float ia, float ib) {
i_alpha = ia;
i_beta = (ia + 2.0f * ib) * 0.57735f; // 1/sqrt(3)
}
// Park变换
void park_transform(float theta) {
float sin_t = sinf(theta), cos_t = cosf(theta);
i_d = i_alpha * cos_t + i_beta * sin_t;
i_q = -i_alpha * sin_t + i_beta * cos_t;
}
// 逆Park变换
void inverse_park_transform(float theta) {
float sin_t = sinf(theta), cos_t = cosf(theta);
v_alpha = v_d * cos_t - v_q * sin_t;
v_beta = v_d * sin_t + v_q * cos_t;
}
// SVPWM实现(扇区判断与矢量作用时间)
void svpwm(float v_alpha, float v_beta) {
float v1 = v_beta;
float v2 = -0.5f * v_beta + 0.866f * v_alpha;
float v3 = -0.5f * v_beta - 0.866f * v_alpha;
int sector = 0;
if (v1 > 0) sector = 1;
if (v2 > 0) sector += 2;
if (v3 > 0) sector += 4;
float ta, tb, tc;
// 根据扇区计算各相导通时间(简化实现,假设Vdc归一化)
switch (sector) {
case 3: ta = v1; tb = v2; tc = -v3; break;
case 1: ta = -v1; tb = v3; tc = v2; break;
case 5: ta = v2; tb = -v3; tc = v1; break;
case 4: ta = -v2; tb = v1; tc = v3; break;
case 6: ta = v3; tb = -v1; tc = -v2; break;
case 2: ta = -v3; tb = -v2; tc = -v1; break;
default: ta = tb = tc = 0; break;
}
// 归一化到PWM周期并限制占空比
float max_t = fmaxf(fmaxf(ta, tb), tc);
float min_t = fminf(fminf(ta, tb), tc);
float offset = (PWM_PERIOD - max_t - min_t) * 0.5f;
ta += offset; tb += offset; tc += offset;
set_pwm_duty(ta, tb, tc);
}
// 电流环中断服务函数(PWM定时器更新中断中调用,频率20kHz)
void current_loop_isr(void) {
float ia, ib, theta;
float i_d_ref = 0.0f; // d轴电流给定(弱磁控制时为负值)
float i_q_ref = 1.0f; // q轴电流给定(转矩指令)
// 1. 采样
read_phase_currents(&ia, &ib);
theta = get_electrical_angle();
// 2. 坐标变换
clarke_transform(ia, ib);
park_transform(theta);
// 3. PI调节(带积分限幅)
float err_d = i_d_ref - i_d;
float err_q = i_q_ref - i_q;
integral_d += Ki * err_d;
integral_q += Ki * err_q;
// 积分限幅
if (integral_d > 1.0f) integral_d = 1.0f;
if (integral_d < -1.0f) integral_d = -1.0f;
if (integral_q > 1.0f) integral_q = 1.0f;
if (integral_q < -1.0f) integral_q = -1.0f;
v_d = Kp * err_d + integral_d;
v_q = Kp * err_q + integral_q;
// 4. 逆变换与SVPWM
inverse_park_transform(theta);
svpwm(v_alpha, v_beta);
}
// 初始化函数(在main中调用一次)
void current_loop_init(void) {
// 配置PWM定时器更新中断、ADC采样、编码器接口
// 使能中断:HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_ALL);
}
运行与调试
- 将上述代码集成到定时器更新中断中,确保中断频率为20kHz(PWM频率)。
- 在main函数中调用
current_loop_init(),并设置i_q_ref为期望的电流幅值(如1A)。 - 编译烧录后,通过调试器(如J-Link)在线修改
Kp、Ki值,观察电流响应。 - 使用DAC输出
i_q实际值,或通过串口以1kHz速率发送至上位机绘图。
验证方法
- 静态验证:电机堵转时,给定
i_q_ref为1A,读取实际i_q,稳态误差应小于5%。 - 动态验证:将
i_q_ref从0阶跃至1A,用示波器观察i_q波形,超调量应小于10%,调节时间小于5ms(典型PI参数下)。 - 相电流波形:电机空载旋转时,用电流探头观察U相电流,应为正弦波,频率与电转速一致,且幅值稳定。
常见问题
- 电流采样噪声大:检查ADC采样是否与PWM中心对齐,必要时增加硬件滤波电容。
- PI输出饱和:若
v_q长时间达到限幅值,说明给定电流过大或母线电压不足,需增加积分限幅或降低i_q_ref。 - 电角度不准确:编码器安装偏移会导致电流环失控,需在初始化时进行电角度对齐(如注入直流定位)。