你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

foc电流环无法正确维持Iq在自己设定的数值。

[复制链接]
Lee_Corle 提问时间:2024-10-31 10:07 / 未解决
  • 代码的基本逻辑:目前只是使用了电流环,我们设定目标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和电角度,输出PWM
void 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两项的电流波形。

image.png

在调试中观察的数值变化

image.png

5fb5caa5073abbc45f224e1d8edea0e.png
收藏 评论3 发布时间:2024-10-31 10:07

举报

3个回答
Lee_Corle 回答时间:9 小时前

目前我感觉是PID函数没有在正常的工作

xmshao 回答时间:9 小时前
这里给些建议供参考:


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


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


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


4.可以参考ST的 MCSDK的相关代码;
Lee_Corle 回答时间:6 小时前

xmshao 发表于 2024-10-31 10:27
这里给些建议供参考:</p>
<p>

好的我会继续尝试不同的PI参数。目前只控制Q轴,d周我直接赋值Ud = 0,电流采样部分应该是没什么问提。

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版