STM32—PID结构体使用讲解
1、这篇文章的目的
由于本人之前做过的很多项目中,基本上都用到了pid算法,发现pid用起来是真香,不仅算法简单,控制的效果也是很不错的,基本上都能够达到要求。但是随着我做过的项目多了,发现每次做一个新的项目后,总是又回过头来找寻以前写的pid函数,然后又重复的写pid函数调节pid的参数,一次又一次在宏定义上修改这么多参数,真是太麻烦了(本人太懒了)。
既然我们不是学过c语言中的结构体和函数指针吗,能不能用pid结构体保存于pid运算有关的参数数据,用结构体直接保存函数指针,然后在调pid参数和使用函数时直接修改这个结构体,这样多方便啊。
2、整理出来的可以直接使用的函数
(1) pid.c函数
#include "pid.h"//绝对值函数
#define ABS(x) ((x>0)? x: -x) /*参数初始化--------------------------------------------------------------*/
static void pid_param_init(PID_TypeDef * pid, PID_ID id,uint16_t maxout,uint16_t intergral_limit,float deadband,uint16_t period,int16_t max_err,int16_t target,float kp, float ki, float kd)
{pid->id = id; pid->ControlPeriod = period; //没用到pid->DeadBand = deadband;pid->IntegralLimit = intergral_limit;pid->MaxOutput = maxout;pid->Max_Err = max_err;pid->target = target;pid->kp = kp;pid->ki = ki;pid->kd = kd;pid->output = 0;
}/*中途更改参数设定--------------------------------------------------------------*/
static void pid_reset(PID_TypeDef * pid, float kp, float ki, float kd)
{pid->kp = kp;pid->ki = ki;pid->kd = kd;
}/*pid计算-----------------------------------------------------------------------*/
static float pid_calculate(PID_TypeDef* pid, float measure,int16_t target)
{
// uint32_t time,lasttime;pid->lasttime = pid->thistime;pid->thistime = HAL_GetTick();pid->dtime = pid->thistime-pid->lasttime;pid->measure = measure;pid->target = target;pid->last_err = pid->err;pid->last_output = pid->output;pid->err = pid->target - pid->measure;//是否进入死区if((ABS(pid->err) > pid->DeadBand)){pid->pout = pid->kp * pid->err;pid->iout += (pid->ki * pid->err);pid->dout = pid->kd * (pid->err - pid->last_err); //积分是否超出限制if(pid->iout > pid->IntegralLimit)pid->iout = pid->IntegralLimit;if(pid->iout < - pid->IntegralLimit)pid->iout = - pid->IntegralLimit;//pid输出和pid->output = pid->pout + pid->iout + pid->dout;//选择是否滤波?//pid->output = pid->output*0.7f + pid->last_output*0.3f;//输出限幅if(pid->output>pid->MaxOutput) {pid->output = pid->MaxOutput;}if(pid->output < -(pid->MaxOutput)){pid->output = -(pid->MaxOutput);}}return pid->output;
}/*pid结构体初始化,每一个pid参数需要调用一次--------------------------------------*/
void pid_init(PID_TypeDef* pid)
{pid->f_param_init = pid_param_init;pid->f_pid_reset = pid_reset;pid->f_cal_pid = pid_calculate;
}
(2)pid.h函数
#ifndef _PID_H
#define _PID_H#include "stdint.h"//PID优化功能枚举
typedef enum
{PID_Position,PID_Speed
}PID_ID;typedef struct _PID_TypeDef
{PID_ID id;float target; //目标值float lastNoneZeroTarget;float kp;float ki;float kd;float measure; //测量值float err; //误差float last_err; //上次误差float pout;float iout;float dout;float output; //本次输出float last_output; //上次输出float MaxOutput; //输出限幅float IntegralLimit; //积分限幅float DeadBand; //死区(绝对值)float ControlPeriod; //控制周期float Max_Err; //最大误差uint32_t thistime;uint32_t lasttime;uint8_t dtime; void (*f_param_init)(struct _PID_TypeDef *pid, //PID参数初始化PID_ID id,uint16_t maxOutput,uint16_t integralLimit,float deadband,uint16_t controlPeriod,int16_t max_err, int16_t target,float kp,float ki,float kd
);
//pid三个参数修改
void (*f_pid_reset)(struct _PID_TypeDef *pid, float kp,float ki, float kd);
//pid计算
float (*f_cal_pid)(struct _PID_TypeDef *pid, float measure);
}PID_TypeDef;void pid_init(PID_TypeDef* pid);#endif
(3)pid函数的使用
#include "pid.h"//有几个电机就用几个pid结构体
PID_TypeDef motor_pid[4];//初始化PID参数
static void motor_init(void)
{for(int i=0; i<4; i++){ pid_init(&motor_pid[i]);motor_pid[i].f_param_init(&motor_pid[i],PID_Speed,16384,5000,10,0,8000,0,1.5,0.1,0);//类型id,输出限幅,积分限幅,绝对值,控制周期,最大误差,目标值, p, i, d}
}//对四个电机同时进行pid计算
static void motor_control(int32_t set_spd1,int32_t set_spd2,int32_t set_spd3,int32_t set_spd4)
{//motor_pid[0].target = set_spd1; motor_pid[0].f_cal_pid(&motor_pid[0],now_speed_1,set_spd1);//PID计算 motor_pid[1].f_cal_pid(&motor_pid[1],now_speed_2,set_spd2);//PID计算 motor_pid[2].f_cal_pid(&motor_pid[2],now_speed_3,set_spd3);//PID计算 motor_pid[3].f_cal_pid(&motor_pid[3],now_speed_4,set_spd4);//PID计算//将PID的计算结果 motor_pid[0].output 控制电机osDelay(10); //PID控制频率100HZ
}
STM32—PID结构体使用讲解相关推荐
- Linux网络编程之sockaddr与sockaddr_in,sockaddr_un结构体详细讲解
Linux网络编程之sockaddr与sockaddr_in,sockaddr_un结构体详细讲解 (1)sockaddr struct sockaddr { unsigned short sa_ ...
- c语言sockaddr_in结构体,转:sockaddr与sockaddr_in结构体详细讲解
sockaddr与sockaddr_in结构体详细讲解 二者区别 struct sockaddr { unsigned short sa_family; /* address family, ...
- STM32 把结构体存入Flash,并读取(微薄之力,已验证)
结构体对齐原则:点击浏览 在网上有看到把结构体存入数组的说法,于是自己尝试一下,确实可以. 不过也遇到问题,就是存入数据到Flash,里面有填充0x00的情况 经过分析应该是这种情况,就是结构体对齐的 ...
- (摘录)sockaddr与sockaddr_in,sockaddr_un结构体详细讲解
struct sockaddr { unsigned short sa_family; /* address family, AF_xxx */ char sa_data[14]; ...
- 看了这篇c语言结构体精讲解,你难道还怕你不会吗?
本文主要介绍结构体入门,结构体指针的教学,请读者讲此段代码复制在Devc++,以便更好阅读体验.谢谢. #include<stdio.h> //结构体教学 首先,结构体的格式是在主函数前先 ...
- sockaddr,sockaddr_in,sockaddr_un结构体详细讲解
struct sockaddr {unsigned short sa_family; /* address family, AF_xxx */char sa_data[14]; /* 14 bytes ...
- 【Linux 内核】进程管理 task_struct 结构体 ② ( state 字段 | stack 字段 | pid 字段 | tgid 字段 | pid_links 字段 )
文章目录 一.task_struct 结构体字段分析 1.state 字段 2.stack 字段 3.pid字段 4.tgid 字段 5.pid_links 字段 在 Linux 内核 中 , &qu ...
- 串口初始化结构体和固件库讲解
串口初始化结构体和固件库讲解 常用的6个函数,结构体: USART 初始化结构体(USART_InitTypeDef) USART 时钟初始化结构体(USART_ClockInitTypeDef) 串 ...
- 驱动下通过进程PID获得进程名 (动态获取ImageFileName在EPROCESS结构体中的相对偏移)...
思路 进程EPROCESS结构体中含有进程名ImageFileName(需求处ImageFileName在EPROCESS结构体中的相对偏移)-->获得进程EPROCESS-->通过进程句 ...
最新文章
- 从简单工厂到工厂方法
- 最聪明女生集结清华,挑战人工智能
- Daily Scrum - 11/24
- ArrayList、LinkedList、Vector的区别。
- tomcat 禁用access.log
- 运用shell,python自动下载linux系统运维
- 【Linux系统编程】进程介绍
- DE连接,创建数据集,数据导入以及数据导出(转载)
- python sqlite3
- 超越自我 — 实现人生价值之路
- 浅谈聊天机器人 ChatBot 涉及到的技术点 以及词性标注和关键字提取
- 【Unity3D开发小游戏】《青蛙过河》Unity开发教程
- Forever young
- Ubuntu16.04安装NVIDIA Titan Xp显卡驱动
- bzoj 4008 亚瑟王 - 动态规划 - 概率与期望
- 学习云计算前景如何?云计算成为获取人工智能主要途径
- 模拟键盘按键 自动输入文字
- 【DBCA -SILENT】静默安装之rac数据库安装
- Java 面试 :乐观锁 悲观锁
- 摘自《大长今励志启示》
热门文章
- 现在的杀毒软件真是无语的没话说
- 情感脑机接口研究综述
- 构建私有云,需要考虑哪些要点?
- spark sql 出现 java.lang.RuntimeException: serious problem
- syslog-ng详解——syslog-ng配置语法
- 霹雳巴拉卷积神经网络+图像分类篇
- linux安装mt7601网卡固件,上网本Debian下装无线网卡7601的驱动过程
- CODING 敏捷实战系列课第五讲:敏捷中国史
- 蓝桥杯之单片机设计与开发(34)——第十届省赛前最后总结与程序封装
- 图像质量评价学习笔记01:IQA的基本概念及分类