问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

PID算法在电机速度控制上的应用

创作时间:
作者:
@小白创作中心

PID算法在电机速度控制上的应用

引用
CSDN
1.
https://blog.csdn.net/mftang/article/details/139266992

本文详细介绍了如何使用PID算法实现电机速度控制。通过光电编码器进行速度检测,结合STM32F103RC主控芯片和LN298N电机驱动模块,实现了基于PID算法的电机闭环控制。文章从硬件框架、软件配置到PID算法的具体实现,再到实际测试案例,内容详尽且具有很高的实用性。

概述

本文主要介绍使用PID算法实现电机速度的控制。通过光电编码器检测电机转速,利用STM32F103RC微控制器处理信号,结合PID算法调节PWM占空比,从而实现对电机速度的精准控制。

系统硬件框架

框架介绍

  1. 光电编码器:用于速度检测,具体实现可参考相关资料。
  2. TIMER7:配置为10us定时中断,为系统提供基准时钟。
  3. TIMER8:用于生成PWM信号,通过调节PWM占空比实现电机速度控制。

硬件实物图

使用STM32F103RC作为主控芯片,LN298N用于驱动电机,光电码盘用于测试电机转速。具体的测试实物图如下:

STM32Cube工程生成

软件版本信息

软件名称
版本信息
STM32Cube
STM32CubeMX 6.11
STM32 HAL
STM32Cube_FW_F1_V1.8.5

配置参数

  1. EXTI IO中断:使用PC0接口监测编码器脉冲,使能外部中断函数。
  2. Timer7配置:中断间隔为10us,具体配置参数如下:

  1. PWM相关配置:计数周期为10ms,各通道对应的IO接口配置如下:

生成项目

配置完成后生成项目,项目结构如下:

PID算法实现

概念

PID算法是一种常用的控制算法,全称为比例-积分-微分控制算法(Proportional-Integral-Derivative Control)。它通过对系统的误差进行比例、积分和微分运算,从而对系统进行控制。

  • 比例项(Proportional):根据误差的大小与比例系数的乘积来计算,决定了控制量与误差之间的直接关系。
  • 积分项(Integral):根据误差的累积进行计算,可以消除系统存在的静态误差,对系统的稳定性有影响。
  • 微分项(Derivative):根据误差的变化率进行计算,可以预测误差的未来变化趋势,提前调整控制量。

PID算法的最终控制量是比例项、积分项和微分项的加权叠加,其中比例系数、积分系数和微分系数可以根据实际需求进行调整,以达到最佳的控制效果。

代码实现

typedef struct
{
    float target_val;       //目标值
    float actual_val;       //实际值
    float err;              //定义偏差值
    float err_last;         //定义上一个偏差值
    float Kp,Ki,Kd;         //定义比例、积分、微分系数
    float integral;         //定义积分值
}_pid;

/**
  * @brief  速度PID算法实现
  * @param  actual_val:实际值
    @note   无
  * @retval 通过PID计算后的输出
  */
float pid_speed_realize(_pid *pid, float actual_val)
{
    /*计算目标值与实际值的误差*/
    pid->err = pid->target_val - actual_val;
    if((pid->err<0.2f )&& (pid->err>-0.2f))
    {
        pid->err = 0.0f;
    }
    pid->integral += pid->err;    // 误差累积
    /*PID算法实现*/
    pid->actual_val = pid->Kp*pid->err+pid->Ki*pid->integral+pid->Kd*(pid->err-pid->err_last);
    /*误差传递*/
    pid->err_last=pid->err;
    /*返回当前实际值*/
    return pid->actual_val;
}

其他功能实现

设置电机速度

void set_motor_speed( uint16_t actual_speed )
{
    HAL_TIM_SetPWM_Pulse( actual_speed, TIM_CHANNEL_1);
    HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_2);
}

PID算法控制电机

void motor_pid_control(void)
{
    float actual_speed, cal_speed ;
    uint8_t value;
    bool is_match;
    uint8_t buff[16];
    uint32_t delta_value;
    
    actual_speed = get_motor_speed();
    cal_speed = pid_get_target(&pid_speed);
    
    is_match = abs((int)((actual_speed- cal_speed)*10)) > 10 ? false : true;
    if( !is_match )
    {
        cal_speed = pid_speed_realize( &pid_speed,actual_speed);    // 进行 PID 计算
        cal_speed = convet_speed( cal_speed );
        cal_speed = (cal_speed > PWM_PERIOD_MAX_COUNT) ? PWM_PERIOD_MAX_COUNT : cal_speed;    // 速度上限处理
        set_motor_speed(cal_speed);                                 // 设置 PWM 占空比
    }
    
    #if defined(PID_ASSISTANT_EN)
        value = (uint8_t)actual_speed;
        buff[0] =  value;
        protocol_computer_value(SEND_FACT_CMD, CURVES_CH1, buff, 1);               // 给通道 1 发送实际值
    #else
        printf("实际值:%.02f 目标值:%.0f\n", actual_speed, pid_get_target(&pid_speed));      // 打印实际值和目标值
    #endif
}

功能函数的调用

void motor_pid_control(void)
{
    float actual_speed, cal_speed ;
    uint8_t value;
    bool is_match;
    uint8_t buff[16];
    uint32_t delta_value;
    
    actual_speed = get_motor_speed();
    cal_speed = pid_get_target(&pid_speed);
    
    is_match = abs((int)((actual_speed- cal_speed)*10)) > 10 ? false : true;
    if( !is_match )
    {
        cal_speed = pid_speed_realize( &pid_speed,actual_speed);    // 进行 PID 计算
        cal_speed = convet_speed( cal_speed );
        cal_speed = (cal_speed > PWM_PERIOD_MAX_COUNT) ? PWM_PERIOD_MAX_COUNT : cal_speed;    // 速度上限处理
        set_motor_speed(cal_speed);                                 // 设置 PWM 占空比
    }
    
    #if defined(PID_ASSISTANT_EN)
        value = (uint8_t)actual_speed;
        buff[0] =  value;
        protocol_computer_value(SEND_FACT_CMD, CURVES_CH1, buff, 1);               // 给通道 1 发送实际值
    #else
        printf("实际值:%.02f 目标值:%.0f\n", actual_speed, pid_get_target(&pid_speed));      // 打印实际值和目标值
    #endif
}

测试

测试案例1

PID参数设置如下类型,观察速度值的变化(Expect value: speed = 50

pid_speed.Kp = 7.0;
pid_speed.Ki = 20.0;
pid_speed.Kd = 14.0;

串口log如下,在5s左右就完成速度定速功能

测试案例2

PID参数设置如下类型,观察速度值的变化(Expect value: speed = 50

pid_speed.Kp = 7.0;
pid_speed.Ki = 2.0;
pid_speed.Kd = 4.0;

串口log如下,在2min左右才完成速度定速功能

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号