PID模块化__以stm32直流电机速度为例

文章目录


前言

本篇使用到的基于这个STM32CubeMX 直流电机PID速度控制、HAL库、cubemx、PID、速度控制、增量式

由于上次使用的pid没有模块化,当多出使用pid的时候就会很麻烦
所以这次使用的模块化的


一、相关PID源码

.c

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

c 复制代码
#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的变量

c 复制代码
pid_t a_moto_pid;
pid_t b_moto_pid;

2.初始化

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

c 复制代码
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.运算

c 复制代码
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参数

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

总结

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

相关推荐
ZZZ_O^O24 分钟前
二分查找算法——寻找旋转排序数组中的最小值&点名
数据结构·c++·学习·算法·二叉树
CV-King1 小时前
opencv实战项目(三十):使用傅里叶变换进行图像边缘检测
人工智能·opencv·算法·计算机视觉
代码雕刻家1 小时前
数据结构-3.9.栈在递归中的应用
c语言·数据结构·算法
雨中rain1 小时前
算法 | 位运算(哈希思想)
算法
Kalika0-03 小时前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法
sp_fyf_20243 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-02
人工智能·神经网络·算法·计算机视觉·语言模型·自然语言处理·数据挖掘
我是哈哈hh5 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
EVERSPIN5 小时前
分享国产32位单片机的电机控制方案
单片机·嵌入式硬件
每天一杯冰美式oh5 小时前
51单片机的家用煤气报警系统【proteus仿真+程序+报告+原理图+演示视频】
嵌入式硬件·51单片机·proteus
Tisfy5 小时前
LeetCode 2187.完成旅途的最少时间:二分查找
算法·leetcode·二分查找·题解·二分