ST意法半导体
直播中

李骏鹏

8年用户 1287经验值
私信 关注
[问答]

foc电流环无法正确维持Iq在自己设定的数值怎么解决?


  • 代码的基本逻辑:目前只是使用了电流环,我们设定目标Iq_set = 0.3,然后调用PID控制函数,返回值传给Uq
  • 目前存在的问题:肉眼观察下电机可以正常的转动,但是高负载的情况下转不动。目前通过调试观察 Iq 的值,发现Iq根本无法稳定在 0.3 附近,而且无规律的跳动。使用上位机观察UWV其中两项的电流值,电流曲线有点正弦波的样子,但是很杂。搞了很长时间找不出问题在哪里,求指导。
typedef struct{    float error;       // 当前误差    float errorLast;   // 上一次误差    float feedforward; // 前馈    float integral;    // 积分    float saturation;  // 饱和    float differ;      // 差值    float kp;          // 比例增益    float ki;          // 积分增益    float kd;          // 微分增益    float ns;          // 速度限制    float ka;          // 加速度限制    float limit;       // 限制} PID_LocTypeDef;/* 初始化PID参数 */PID_Init(&PID_Iq, 0.65, 0.12, 0, 10, 0.01);foc.Uq = PID_Loc(0.3, cur.Iq, &PID_Iq);void PID_Init(PID_LocTypeDef* pidHandle, float kp, float ki, float kd, float limit, float ns){  pidHandle->kp = kp;  pidHandle->ki = ki;  pidHandle->kd = kd;  pidHandle->limit = limit;  pidHandle->ns = ns;}foc.Uq = PID_Loc(0.3, cur.Iq, &PID_Iq);setPhaseVoltage(&foc, angle.Eangle);这是foc的SVPWM代码
// FOC核心函数:输入Ud、Uq和电角度,输出PWMvoid setPhaseVoltage(sfoc *foc, float angle){    foc->angle_el = angle;    foc->angle_el = _normalizeAngle(foc->angle_el);    float cos_angle = arm_cos_f32(foc->angle_el);    float sin_angle = arm_sin_f32(foc->angle_el);    // 反park变换    foc->U_alpha = foc->Ud * cos_angle - foc->Uq * sin_angle;    foc->U_beta  = foc->Ud * sin_angle + foc->Uq * cos_angle;    foc->Uref    = _sqrtf(foc->U_alpha * foc->U_alpha + foc->U_beta * foc->U_beta) / voltage_power_supply;    // 限制最大参考电压    if (foc->Uref > 0.577f)        foc->Uref = 0.577f;    if (foc->Uref < -0.577f)        foc->Uref = -0.577f;    // 标准化电角度值,并根据Uq确定扇区    if (foc->Uq > 0)        foc->angle_el = _normalizeAngle(foc->angle_el + _PI_2);    else        foc->angle_el = _normalizeAngle(foc->angle_el - _PI_2);    foc->sector = (foc->angle_el / _PI_3) + 1;    // 计算作用时间    foc->T1 = SQRT_3 * arm_sin_f32(foc->sector * _PI_3 - foc->angle_el) * foc->Uref;    foc->T2 = SQRT_3 * arm_sin_f32(foc->angle_el - (foc->sector - 1.0f) * _PI_3) * foc->Uref;    foc->T0 = 1 - foc->T1 - foc->T2;    // 根据扇区计算占空比    switch (foc->sector) {        case 1:            foc->Ta = foc->T1 + foc->T2 + foc->T0 / 2;            foc->Tb = foc->T2 + foc->T0 / 2;            foc->Tc = foc->T0 / 2;            break;        case 2:            foc->Ta = foc->T1 + foc->T0 / 2;            foc->Tb = foc->T1 + foc->T2 + foc->T0 / 2;            foc->Tc = foc->T0 / 2;            break;        case 3:            foc->Ta = foc->T0 / 2;            foc->Tb = foc->T1 + foc->T2 + foc->T0 / 2;            foc->Tc = foc->T2 + foc->T0 / 2;            break;        case 4:            foc->Ta = foc->T0 / 2;            foc->Tb = foc->T1 + foc->T0 / 2;            foc->Tc = foc->T1 + foc->T2 + foc->T0 / 2;            break;        case 5:            foc->Ta = foc->T2 + foc->T0 / 2;            foc->Tb = foc->T0 / 2;            foc->Tc = foc->T1 + foc->T2 + foc->T0 / 2;            break;        case 6:            foc->Ta = foc->T1 + foc->T2 + foc->T0 / 2;            foc->Tb = foc->T0 / 2;            foc->Tc = foc->T1 + foc->T0 / 2;            break;        default: // 错误情况            foc->Ta = 0;            foc->Tb = 0;            foc->Tc = 0;            break;    }    // 输出PWM信号    TIM1->CCR1 = foc->Ta * PWM_PERIOD;    TIM1->CCR2 = foc->Tb * PWM_PERIOD;    TIM1->CCR3 = foc->Tc * PWM_PERIOD;}这是PID控制的代码
float PID_Loc(float SetValue, float ActualValue, PID_LocTypeDef* pidHandle){pidHandle->error = SetValue - ActualValue;/* Proportional Item */float p = pidHandle->kp * pidHandle->error;/* Integral Item */float i = pidHandle->ki * (pidHandle->error - pidHandle->ka * pidHandle->saturation) + pidHandle->integral;// i = _constrain(i, MIN(0.f, -pidHandle->limit), MAX(0.f, pidHandle->limit));i = _constrain(i, -pidHandle->limit, pidHandle->limit);pidHandle->integral = i;/* Differential Item */float d = pidHandle->kd * pidHandle->ns * (pidHandle->error - pidHandle->errorLast) -pidHandle->differ * (pidHandle->ns - 1.0f);pidHandle->errorLast = pidHandle->error;pidHandle->differ = d;/* Output value update and saturation value calculation */float val = p + i + d + pidHandle->feedforward;float out = _constrain(val, -pidHandle->limit, pidHandle->limit);pidHandle->saturation = val - out;return out;}这是计算Iq和Id的值部分
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef *hadc){GetCurrent(&cur);float I_alpha = cur.CurA;float I_beta = (cur.CurB - cur.CurC) * SQRT_3 / 2;cur.Id = I_alpha * arm_cos_f32(foc.angle_el) + I_beta * arm_sin_f32(foc.angle_el);cur.Iq = I_beta * arm_cos_f32(foc.angle_el) - I_alpha * arm_sin_f32(foc.angle_el);/* 低通滤波 */cur.Id = LowPassFilter_Update(&LPF_Id, cur.Id);cur.Iq = LowPassFilter_Update(&LPF_Iq, cur.Iq);}这是使用上位机观察到了UV两项的电流波形。

在调试中观察的数值变化



回帖(2)

王若鸿

2025-3-13 09:49:59
这里给些建议供参考:


1.检测电流环PI参数是否合适;


2.电流环控制是否只控制了Q轴,而没有控制D轴电流,如果是话,请把D轴也加上;


3、检查采样电流是否正确;


4.可以参考ST的 MCSDK的相关代码;
举报

陶醉了的猫

2025-3-17 18:05:02

根据你的描述,问题可能出在以下几个方面:电流环控制、PID参数、硬件限制、传感器噪声等。以下是一些可能的解决方案和调试步骤:




1. 检查PID参数



  • 问题:PID参数(比例、积分、微分系数)不合适可能导致Iq无法稳定在目标值。

  • 解决方案

    • 确保比例系数(Kp)足够大,以便快速响应误差。

    • 检查积分系数(Ki)是否合适,避免积分饱和或响应过慢。

    • 微分系数(Kd)可以帮助抑制振荡,但过大会引入噪声。

    • 逐步调整PID参数,观察Iq的响应情况,找到最佳组合。





2. 检查电流采样和滤波



  • 问题:电流采样噪声或干扰可能导致Iq值跳动。

  • 解决方案

    • 检查电流采样电路,确保硬件设计合理(如采样电阻、放大器、ADC等)。

    • 在软件中对电流采样值进行滤波(如低通滤波或移动平均滤波),以减少噪声影响。

    • 确保采样频率足够高,避免混叠效应。





3. 检查电机负载和硬件限制



  • 问题:高负载下电机转不动,可能是硬件能力不足或电流环输出受限。

  • 解决方案

    • 检查电机驱动器的电流限制,确保其能够提供足够的电流。

    • 检查电源电压是否足够,避免因电压不足导致电流无法达到目标值。

    • 如果电机负载过大,可能需要更换更大功率的电机或驱动器。





4. 检查控制频率



  • 问题:控制频率过低可能导致电流环响应慢,无法稳定控制Iq。

  • 解决方案

    • 确保控制频率足够高(通常建议在10kHz以上)。

    • 检查控制周期是否稳定,避免因任务调度问题导致控制延迟。





5. 检查电流环逻辑



  • 问题:电流环逻辑可能存在问题,导致Iq无法稳定。

  • 解决方案

    • 确保电流环的输入(Iq_set和实际Iq)正确。

    • 检查PID输出(Uq)是否合理,避免输出饱和或异常。

    • 在调试中打印关键变量(如Iq_set、Iq、Uq等),分析其变化规律。





6. 检查电机参数



  • 问题:电机参数(如电感、电阻等)不准确可能导致电流环控制失效。

  • 解决方案

    • 重新测量电机参数,确保其在控制算法中使用正确的值。

    • 如果电机参数未知,可以使用电机参数辨识方法进行测量。





7. 检查死区时间和PWM输出



  • 问题:死区时间设置不当或PWM输出异常可能导致电流控制失效。

  • 解决方案

    • 检查PWM输出的死区时间,确保其合理(避免上下桥臂短路)。

    • 使用示波器观察PWM波形,确保其与预期一致。





8. 检查电流环与速度环的耦合



  • 问题:如果同时使用了速度环和电流环,两者可能相互影响。

  • 解决方案

    • 确保速度环和电流环的控制频率和参数匹配。

    • 如果速度环输出作为电流环的输入,确保其范围合理。





9. 调试建议



  • 逐步调试:从简单的控制逻辑开始,逐步增加复杂性,确保每一步都正确。

  • 分段测试:将问题分段,分别测试电流采样、PID控制、PWM输出等部分。

  • 使用工具:使用示波器、逻辑分析仪等工具,观察关键信号的变化。




示例代码改进


以下是一个简单的PID控制逻辑示例,供参考:


typedef struct {
    float Kp, Ki, Kd; // PID参数
    float error, errorLast, integral; // 误差、上一次误差、积分项
} PIDController;

float PID_Update(PIDController *pid, float setpoint, float measurement) {
    // 计算误差
    pid->error = setpoint - measurement;

    // 计算积分项(避免积分饱和)
    pid->integral += pid->error;

    // 计算微分项
    float derivative = pid->error - pid->errorLast;

    // 更新上一次误差
    pid->errorLast = pid->error;

    // 计算PID输出
    return pid->Kp * pid->error + pid->Ki * pid->integral + pid->Kd * derivative;
}



通过以上步骤,你应该能够找到问题的根源并解决Iq无法稳定的问题。如果问题仍然存在,可以进一步提供更多细节(如硬件配置、控制逻辑等),以便更深入地分析。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分