以STM32直流电机速度为例,深入理解PID模块化控制

文章目录

  • 前言
  • 一、相关PID源码
  • .c
  • .h
  • 二、如何使用
  • 1.创建变量
  • 2.初始化
  • 3.运算
  • 4.修改pid参数
  • 总结

  • 前言

    本篇使用到的基于这个STM32CubeMX 直流电机PID速度控制、HAL库、cubemx、PID、速度控制、增量式
    由于上次使用的pid没有模块化,当多出使用pid的时候就会很麻烦
    所以这次使用的模块化的


    一、相关PID源码

    .c

    /* 包含头文件 ----------------------------------------------------------------*/
    #include "pid.h"
    
    /* 私有类型定义 --------------------------------------------------------------*/
    /* 私有宏定义 ----------------------------------------------------------------*/
    /* 私有变量 ------------------------------------------------------------------*/
    /* 扩展变量 ------------------------------------------------------------------*/
    /* 私有函数原形 --------------------------------------------------------------*/
    /* 函数体 --------------------------------------------------------------------*/ 
    void abs_limit(float *a, float ABS_MAX)// 对输入 a 进行限制,使其在 [-ABS_MAX, ABS_MAX] 区间内
    {
      if (*a > ABS_MAX)
        *a = ABS_MAX;
      if (*a < -ABS_MAX)
        *a = -ABS_MAX;
    }
    
    // 初始化 PID 参数
    static void pid_param_init(
        pid_t*   pid,          // PID 控制器结构体
        uint32_t mode,         // PID 控制器模式
        uint32_t maxout,       // PID 控制器输出最大值
        uint32_t intergral_limit, // PID 控制器积分限制
        float    kp,           // PID 控制器 P 项系数
        float    ki,           // PID 控制器 I 项系数
        float    kd)           // PID 控制器 D 项系数
    {
    
      pid->integral_limit = intergral_limit;
      pid->max_out        = maxout;
      pid->pid_mode       = mode;
    
      pid->p = kp;
      pid->i = ki;
      pid->d = kd;
    
    }
    /**
      * @brief     modify pid parameter when code running
      * @param[in] pid: control pid struct
      * @param[in] p/i/d: pid parameter
      * @retval    none
      */
    static void pid_reset(pid_t *pid, float kp, float ki, float kd)// 重置 PID 控制器的参数
    {
      pid->p = kp;
      pid->i = ki;
      pid->d = kd;
      
      pid->pout = 0;
      pid->iout = 0;
      pid->dout = 0;
      pid->out  = 0;
      
    }
    
    /**
      * @brief     calculate delta PID and position PID
      * @param[in] pid: control pid struct
      * @param[in] get: measure feedback value
      * @param[in] set: target value
      * @retval    pid calculate output 
      */
    float pid_calc(pid_t *pid, float get, float set)// 计算 PID 控制器的输出
    {
      pid->get = get;
      pid->set = set;
      pid->err[NOW] = set - get;
    
      if ((pid->input_max_err != 0) && (pid->err[NOW] > pid->input_max_err))
          pid->err[NOW] = pid->input_max_err;
      if ((pid->input_min_err != 0) && (pid->err[NOW] < pid->input_min_err))
          pid->err[NOW] = pid->input_min_err;
      if (pid->pid_mode == POSITION_PID) //position PID// 位置式 PID 控制器
      {
          pid->pout = pid->p * pid->err[NOW];
          pid->iout += pid->i * pid->err[NOW];
          pid->dout = pid->d * (pid->err[NOW] - pid->err[LAST]);
        
          abs_limit(&(pid->iout), pid->integral_limit);
          pid->out = pid->pout + pid->iout + pid->dout;
          abs_limit(&(pid->out), pid->max_out);
      }
      else if (pid->pid_mode == DELTA_PID) //delta PID// 增量式 PID 控制器
      {
          pid->pout = pid->p * (pid->err[NOW] - pid->err[LAST]);
          pid->iout = pid->i * pid->err[NOW];
          pid->dout = pid->d * (pid->err[NOW] - 2 * pid->err[LAST] + pid->err[LLAST]);
    
          pid->out += pid->pout + pid->iout + pid->dout;
          abs_limit(&(pid->out), pid->max_out);
      }
    
      pid->err[LLAST] = pid->err[LAST];
      pid->err[LAST]  = pid->err[NOW];
      
      
      if ((pid->output_deadband != 0) && (fabs(pid->out) < pid->output_deadband))
        return 0;
      else
        return pid->out;
    
    }
    void pid_ClearIntegrals(pid_t*   pid)// 清除积分项
    {
    	pid->pout = 0;
        pid->iout = 0;
        pid->dout = 0;
        pid->out  = 0;
    }
    /**
      * @brief     initialize pid parameter
      * @retval    none
      */
    void PID_struct_init(		// 初始化 PID 结构体
        pid_t*   pid,
        uint32_t mode,
        uint32_t maxout,
        uint32_t intergral_limit,
    
        float kp,
        float ki,
        float kd)
    {
      pid->f_param_init = pid_param_init;
      pid->f_pid_reset  = pid_reset;
      pid->f_pid_calc = pid_calc;
      pid->f_pid_ClearIntegrals = pid_ClearIntegrals;
    
      pid->f_param_init(pid, mode, maxout, intergral_limit, kp, ki, kd);
      pid->f_pid_reset(pid, kp, ki, kd);
    }
    
    
    
    

    .h

    #ifndef __PID_H__
    #define __PID_H__
    
    /* 包含头文件 ----------------------------------------------------------------*/
    #include "stdint.h"
    #include "math.h"
    /* 类型定义 ------------------------------------------------------------------*/
    enum
    {
      LLAST = 0,
      LAST,
      NOW,
      POSITION_PID,
      DELTA_PID,
    };
    typedef struct pid_t
    {
      float p;
      float i;
      float d;
    
      float set;
      float get;
      float err[3];
    
      float pout;
      float iout;
      float dout;
      float out;
    
      float input_max_err;    //input max err;
      float input_min_err;    //input max err;
      float output_deadband;  //output deadband;
      
      uint32_t pid_mode;
      uint32_t max_out;
      uint32_t integral_limit;
    
      void  (*f_param_init)(struct pid_t *pid, 
                            uint32_t      pid_mode,
                            uint32_t      max_output,
                            uint32_t      inte_limit,
                            float         p,
                            float         i,
                            float         d);
      void  (*f_pid_reset)(struct pid_t *pid, float p, float i, float d);
      float (*f_pid_calc)(struct pid_t *pid, float get, float set);
      void  (*f_pid_ClearIntegrals)(struct pid_t*   pid);
    } pid_t;
    /* 宏定义 --------------------------------------------------------------------*/
    /* 扩展变量 ------------------------------------------------------------------*/
    /* 函数声明 ------------------------------------------------------------------*/
    void PID_struct_init(
        pid_t*   pid,
        uint32_t mode,
        uint32_t maxout,
        uint32_t intergral_limit,
        float kp,
        float ki,
        float kd);
    float pid_calc(pid_t *pid, float get, float set);
    #endif  // __PID_H__
    
    
    

    二、如何使用

    1.创建变量

    在main.c或者其他位置创建pid的变量

    pid_t a_moto_pid;
    pid_t b_moto_pid;
    

    2.初始化

    注意一定要在pid计算之前初始化all_moto_pid_init,不然会导致stm32硬件错误!!!!

    void all_moto_pid_init(void)
    {
        PID_struct_init(
            &a_moto_pid,              // PID 控制器对象
            DELTA_PID,      // 控制器模式
            7500,               // 输出最大值
            0,                // 积分限制
            45.0f,              // P 项系数
            25.0f,              // I 项系数
            0.0f               // D 项系数
        );
        PID_struct_init(
            &b_moto_pid,              // PID 控制器对象
            DELTA_PID,      // 控制器模式
            7500,               // 输出最大值
            0,                // 积分限制
            45.0f,              // P 项系数
            25.0f,              // I 项系数
            0.0f               // D 项系数
        );	
    
    }
    

    3.运算

    
    int a_moto_pid_calc(float current_value,float target_value)/*current_value当前值target_value目标值*/
    {
    // 使用 PID 控制器计算控制输出
    	int control_output = a_moto_pid.f_pid_calc(&a_moto_pid, current_value, target_value);	
    	return control_output;
    }
    int b_moto_pid_calc(float current_value,float target_value)/*current_value当前值target_value目标值*/
    {
    // 使用 PID 控制器计算控制输出
    	int control_output = b_moto_pid.f_pid_calc(&b_moto_pid, current_value, target_value);	
    	return control_output;
    }
    
    

    4.修改pid参数

    /*
    修改pid的值
    */
    void angle_pid_set(float  p,float i ,float d )
    {
    	angle_pid.f_pid_reset(&angle_pid, p, i, d);
    }
    

    总结

    简述一下,不喜勿喷谢谢。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 以STM32直流电机速度为例,深入理解PID模块化控制

    发表评论