PID 多环控制

        速度环的后级,再串上一个电流环,以前级的输出 (这里指速度环的输出),作为后级的输入 (这里指作为电流环的输入),最终后级 (电流环) 的输出最终实现在执行机构上, 以形成双反馈控 制的效果。

        在串级 PID 控制中,最外环一般选择期望控制的参数的环节例如对应速度快慢的速度环、位置的位置环、电流大小的电流环大小,本代码的选择位置环作为最外环,位置作为控制量,期望控电机实际位置。

/**
  * @brief  电机位置式 PID 控制实现(定时调用)
  * @param  无
  * @retval 无
  * 电机的输出位置作为控制目标,所以就以位置环作为外环
  */
void motor_pid_control(void)
{
    static uint32_t louter_ring_timer = 0;   // 外环环周期(电流环计算周期为定时器周期T,速度环为2T,位置环为3T)
    int32_t actual_current = get_curr_val(); // 读取当前电流值
    if (actual_current > TARGET_CURRENT_MAX)
    {
        actual_current = TARGET_CURRENT_MAX;
    }
    if (is_motor_en == 1) // 电机在使能状态下才进行控制处理
    {
        static int32_t Capture_Count = 0; // 当前时刻总计数值
        static int32_t Last_Count = 0;    // 上一时刻总计数值
        float cont_val = 0;               // 当前控制值

        /* 当前时刻总计数值 = 计数器值 + 计数溢出次数 * ENCODER_TIM_PERIOD  */
        Capture_Count = __HAL_TIM_GET_COUNTER(&TIM_EncoderHandle) + (Encoder_Overflow_Count * ENCODER_TIM_PERIOD);

        /* 位置环计算 */
        if (louter_ring_timer++ % 3 == 0)
        {
            cont_val = location_pid_realize(&pid_location, Capture_Count); // 进行 PID 计算

            /* 目标速度上限处理 */
            if (cont_val > TARGET_SPEED_MAX)
            {
                cont_val = TARGET_SPEED_MAX;
            }
            else if (cont_val < -TARGET_SPEED_MAX)
            {
                cont_val = -TARGET_SPEED_MAX;
            }
            /*******************************
            将位置环的输出给速度环
            ********************************/
            set_pid_target(&pid_speed, cont_val); // 设定速度的目标值

#if defined(PID_ASSISTANT_EN)
            int32_t temp = cont_val;
            set_computer_value(SEND_TARGET_CMD, CURVES_CH2, &temp, 1); // 给通道 2 发送目标值
#endif
        }

        /* 速度环计算 */
        static int32_t actual_speed = 0; // 实际测得速度
        if (louter_ring_timer % 2 == 0)
        {
            /* 转轴转速 = 单位时间内的计数值 / 编码器总分辨率 * 时间系数  */
            actual_speed = ((float)(Capture_Count - Last_Count) / ENCODER_TOTAL_RESOLUTION / REDUCTION_RATIO) / (GET_BASIC_TIM_PERIOD() * 2 / 1000.0 / 60.0);

            /* 记录当前总计数值,供下一时刻计算使用 */
            Last_Count = Capture_Count;

            cont_val = speed_pid_realize(&pid_speed, actual_speed); // 进行 PID 计算

            if (cont_val > 0) // 判断电机方向
            {
                set_motor_direction(MOTOR_FWD);
            }
            else
            {
                cont_val = -cont_val;
                set_motor_direction(MOTOR_REV);
            }

            cont_val = (cont_val > TARGET_CURRENT_MAX) ? TARGET_CURRENT_MAX : cont_val; // 电流上限处理
            /*******************************
            将 速度 环的输出给 电流 环
            ********************************/
            set_pid_target(&pid_curr, cont_val); // 设定电流的目标值

#if defined(PID_ASSISTANT_EN)
            int32_t temp = cont_val;
            set_computer_value(SEND_TARGET_CMD, CURVES_CH3, &temp, 1); // 给通道 3 发送目标值
#endif
        }

        /* 电流环计算 */
        cont_val = curr_pid_realize(&pid_curr, actual_current); // 进行 PID 计算

        if (cont_val < 0)
        {
            cont_val = 0; // 下限处理
        }
        else if (cont_val > PWM_MAX_PERIOD_COUNT)
        {
            cont_val = PWM_MAX_PERIOD_COUNT; // 速度上限处理
        }
        /*******************************
            将 电流 环的输出直接作用给 被控对象
        ********************************/
        set_motor_speed(cont_val); // 设置 PWM 占空比

#if defined(PID_ASSISTANT_EN)
        set_computer_value(SEND_FACT_CMD, CURVES_CH1, &Capture_Count, 1); // 给通道 1 发送实际值
                                                                          //    set_computer_value(SEND_FACT_CMD, CURVES_CH2, &actual_speed,   1);         // 给通道 2 发送实际值
                                                                          //    set_computer_value(SEND_FACT_CMD, CURVES_CH3, &actual_current, 1);         // 给通道 3 发送实际值
#else
        printf("1.电流:实际值:%d. 目标值:%.0f.\n", Capture_Count, get_pid_target(&pid_location)); // 打印实际值和目标值
#endif
    }
}

闭环死区,是指执行机构的最小控制量,无法满足控制需求产生的

积分饱和的处理。积分饱和,就是执行机构达到极限输出能力了,仍无法到达目标值,在很长一
段时间内无法消除静差造成的。简单举例,就是电机满功率运行,仍达不到期望转速,在一段时
间内没有到达目标值,这时候 PID 的积分项累计了很大的数值,如果这时候到达了目标值或者重
新设定了目标值,由于积分由于累计的误差很大,系统并不能马上稳定到目标值,并会造成严重
的超调或失调的现象。解决办法有很多,代码中使用了积分分离的方法,在累计误差大于一定值
后去掉积分项的作用。
由于编码器精度原因,当实际值和目标值的偏差小于编码区能测量得到的最小精度时,就认为目
标值与实际值没有偏差

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Car12

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值