文章目录
前言
本篇使用到的基于这个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);
}
总结
简述一下,不喜勿喷谢谢。