1.根据我控制算法类文章中关于PID的理论的一些描述,同时也根据网络上一些其他的PID文章,以及自己最近一个项目的实践后,总结了几套基于C语言的PID算法,由于网络中很少有人进行分享完整的PID算法实现,我这里分享下。

(1)头文件,定义pid的结构体,类的概念,包含pid的属性和方法

#ifndef __PID_H_
#define __PID_H_ #include <stdint.h> typedef struct _pid
{
int16_t set_value; // 给定值,rin(k)
int16_t actual_value; // 实际值,反馈值,rout(k)
int16_t err; // 偏差值,rin(k) - rout(k)
int16_t err_last; // 上一次偏差值,rin(k - 1) - rout(k - 1)
int16_t err_last_last; // 上一次上一次的偏差值,rin(k - 2) - rout(k - 2)
float kp; // 比例系数
float ki; // 积分系数
float kd; // 微分系数
float uk; // pid公式运算结果值
float incremental_value; // 增量值
float integral_value; // 积分值
float umax; // uk的上限值,抗积分饱和用
float umin; // uk的下限值,抗积分饱和用
int16_t err_up_value; // 偏差上限值,积分分离用
int16_t ki_k; // 积分的再次乘机系数,积分分离用 float out_value; // float(*position_type)(struct _pid *ppid); // 位置型PID算法,无积分分离、无抗积分饱和
float(*incremental_type)(struct _pid *ppid); // 增量型PID算法
float(*integral_separation_type)(struct _pid *ppid); // 积分分离PID算法
float(*int_sep_anti_sat_type)(struct _pid *ppid); // 积分分离 + 抗积分饱和PID算法
}_pid_t; _pid_t *pid_create(void); extern _pid_t *pg_pid; #endif

(2).c文件,包含头文件中4个PID算法的实现,包含位置型PID算法、增量型PID算法、积分分离PID算法、积分分离+抗饱和PID算法

#include <stdlib.h>
#include <string.h> #include "pid.h" #include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "portmacro.h"
#include "semphr.h" #include "Debug.h" /*************************************
*
* Funciton Name : pid_position_type
* Function :位置型PID算法,无积分分离、无抗积分饱和
* @note : 积分分离:能解决初期系统偏差值大,累加到积分项中,引起系统超调、振荡问题。积分是为了消除静态误差的,应在误差在小范围时引入积分
* : 抗积分饱和:能解决执行器到达极限值时,但uk还在增大,使得系统进入饱和,进入饱和区的时间越长,当系统出现反向偏差,解决这个反向偏差的时间就会越长,此时系统会像失控一样。
* :进入抗积分饱和,当uk超过上限时,积分向只累加负偏差,当uk超过下限时,积分项只累加正偏差。
*
× @param :pid
*
*
* @return : uk
*************************************/
static float pid_position_type_f(struct _pid *ppid)
{
ppid->err = ppid->set_value - ppid->actual_value; // 偏差 ppid->integral_value += ppid->err; // 积分累加 ppid->uk = ppid->kp * ppid->err + ppid->ki * ppid->integral_value + ppid->kd * (ppid->err - ppid->err_last); ppid->err_last = ppid->err; return (ppid->uk);
} /*************************************
*
* Funciton Name : pid_incremental_type_f
* Function :增量型PID算法
* @note : 相较于位置型,因为与3个偏差相关,增强了系统稳定性
*
× @param :pid
*
*
* @return : uk + 增量值
*************************************/
static float pid_incremental_type_f(struct _pid *ppid)
{
ppid->err = ppid->set_value - ppid->actual_value; // 偏差 //ppid->integral_value += ppid->err; // 积分累加 ppid->incremental_value = ppid->kp * ( ppid->err - ppid->err_last) + ppid->ki * ppid->err + ppid->kd * (ppid->err - 2 * ppid->err_last + ppid->err_last_last); ppid->uk += ppid->incremental_value; ppid->err_last_last = ppid->err_last;
ppid->err_last = ppid->err; return (ppid->uk);
} /*************************************
*
* Funciton Name : pid_integral_separation_type_f
* Function :积分分离PID算法
* @note : 能解决初期系统偏差值大,累加到积分项中,引起系统超调、振荡问题。积分是为了消除静态误差的,应在误差在小范围时引入积分
*
× @param :pid
*
*
* @return : uk
*************************************/
static float pid_integral_separation_type_f(struct _pid *ppid)
{
ppid->err = ppid->set_value - ppid->actual_value; // 偏差 // 误差过大去除积分效果
if ( abs(ppid->err) > ppid->err_up_value )
{
ppid->ki_k = 0;
}
else
{
ppid->ki_k = 1;
ppid->integral_value += ppid->err; // 积分累加
} ppid->uk = ppid->kp * ppid->err + ppid->ki_k * ppid->ki * ppid->integral_value + ppid->kd * (ppid->err - ppid->err_last); ppid->err_last = ppid->err; return (ppid->uk);
} /*************************************
*
* Funciton Name : pid_int_sep_anti_sat_type_f
* Function :积分分离 + 抗积分饱和PID算法
* @note : 能解决初期系统偏差值大,累加到积分项中,引起系统超调、振荡问题。积分是为了消除静态误差的,应在误差在小范围时引入积分
* : 抗积分饱和:能解决执行器到达极限值时,但uk还在增大,使得系统进入饱和,进入饱和区的时间越长,当系统出现反向偏差,解决这个反向偏差的时间就会越长,此时系统会像失控一样。
* :进入抗积分饱和,当uk超过上限时,积分向只累加负偏差,当uk超过下限时,积分项只累加正偏差。
*
× @param :pid
*
*
* @return : uk
*************************************/
static float pid_int_sep_anti_sat_type_f(struct _pid *ppid)
{
ppid->err = ppid->set_value - ppid->actual_value; // 偏差 Debug("ppid->err = %d\r\n", ppid->err); if ( ppid->out_value > ppid->umax ) // 抗积分饱和
{
// 误差过大去除积分效果
if ( abs(ppid->err) > ppid->err_up_value ) // 积分分离
{
ppid->ki_k = 0;
}
else
{
ppid->ki_k = 1; if ( ppid->err < 0 )
{
ppid->integral_value += ppid->err; // 积分累加
} }
}
else if ( ppid->out_value < ppid->umin ) // 抗积分饱和
{
// 误差过大去除积分效果
if ( abs(ppid->err) > ppid->err_up_value ) // 积分分离
{
ppid->ki_k = 0;
}
else
{
ppid->ki_k = 1; if ( ppid->err > 0 )
{
ppid->integral_value += ppid->err; // 积分累加
} }
}
else
{
// 误差过大去除积分效果
if ( abs(ppid->err) > ppid->err_up_value )
{
ppid->ki_k = 0;
}
else
{
ppid->ki_k = 1;
ppid->integral_value += ppid->err; // 积分累加
}
} ppid->uk = ppid->kp * ppid->err + ppid->ki_k * ppid->ki * ppid->integral_value + ppid->kd * (ppid->err - ppid->err_last); ppid->err_last = ppid->err; // if ( ppid->uk >= 0.07 && ppid->uk <= 1 )
// {
// ppid->uk = 1;
// }
//
// if ( ppid->uk <= -0.07 && ppid->uk >= -1 )
// {
// ppid->uk = -1;
// } return (ppid->uk);
} /*************************************
*
* Funciton Name : pid_init
* Function : pid实例构造
*
*
*************************************/
static void pid_init(_pid_t *ppid)
{
ppid->kp = 0.2;
ppid->ki = 0.05;
ppid->kd = 0; ppid->umax = 4000;
ppid->umin = 0; ppid->position_type = pid_position_type_f;
ppid->incremental_type = pid_incremental_type_f;
ppid->integral_separation_type = pid_integral_separation_type_f;
ppid->int_sep_anti_sat_type = pid_int_sep_anti_sat_type_f;
} /*************************************
*
* Funciton Name : pid_create
* Function : pid实例创建
* @author :
*
* @return : 返回pid实例
*
*************************************/
_pid_t *pid_create(void)
{
_pid_t *ppid = (_pid_t *)pvPortMalloc(sizeof(_pid_t)); memset(ppid, 0, sizeof(_pid_t)); pid_init(ppid); return ppid;
}

(3)PID的实现算法有了,但还是要根据实际情况进行调试选取最适合的PID算法以及修改可能存在的不恰当的位置。

PID算法的C语言实现的更多相关文章

  1. PID算法(c 语言)(转)

    PID算法(c 语言)(来自老外) #include <stdio.h> #include<math.h> //定义PID 的结构体 struct _pid { int pv; ...

  2. PID算法(c 语言)(来自老外)

    #include <stdio.h> #include<math.h> //定义PID 的结构体 struct _pid { int pv; // integer that c ...

  3. PID控制算法的C语言实现三 位置型PID的C语言实现

    上一节中已经抽象出了位置性PID和增量型PID的数学表达式,这一节,重点讲解C语言代码的实现过程,算法的C语言实现过程具有一般性,通过PID算法的C语言实现,可以以此类推,设计其它算法的C语言实现. ...

  4. PID控制算法的C语言实现

    参考: PID控制器开发笔 浅谈位置式PID 专家PID控制在快速系统中的仿真及应用(这篇了论文介绍的积分分离PID.专家PID(脚本实现和simulink实现)很详细) PID控制算法的C语言实现一 ...

  5. 【转】位置式、增量式PID算法C语言实现

    位置式.增量式PID算法C语言实现 芯片:STM32F107VC 编译器:KEIL4 作者:SY 日期:2017-9-21 15:29:19 概述 PID 算法是一种工控领域常见的控制算法,用于闭环反 ...

  6. PID算法(C语言)

    /************ PID算法(C语言) ************/ #include <stdio.h> #include<math.h> struct _pid { ...

  7. PID控制算法的C语言实现十一  模糊算法简介

    在PID控制算法的C语言实现九中,文章已经对模糊PID的实质做了一个简要说明.本来打算等到完成毕业设计,工作稳定了再着力完成剩下的部分.鉴于网友的要求和信任,抽出时间来,对模糊PID做一个较为详细的论 ...

  8. PID控制算法的C语言实现二 PID算法的离散化

    上一节中,我论述了PID算法的基本形式,并对其控制过程的实现有了一个简要的说明,通过上一节的总结,基本已经可以明白PID控制的过程.这一节中先继续上一节内容补充说明一下. 1.说明一下反馈控制的原理, ...

  9. PID控制算法的C语言实现一 PID算法原理

    本系列是转载............. 全部的程序有一个共同点:就是我没认真去调pid的参数 在工业应用中PID及其衍生算法是应用最广泛的算法之一,是当之无愧的万能算法,如果能够熟练掌握PID算法的设 ...

随机推荐

  1. shell脚本在后台运行以及日志重定向输出

    后台运行命令 在命令行后加上 &,表示进程到后台中执行,如:cmd & 日志输出重定向 如:cmd > out.log & Linux默认定义两个变量:1和2: 1 表示 ...

  2. Mac安装stf

    1.brew install rethinkdb graphicsmagick zeromq protobuf yasm pkg-config 2.node版本8.x我的是8.15.0 3.npm i ...

  3. 后羿:我射箭了快上—用MotionLayout实现王者荣耀团战

    前言 昨晚跟往常一样,饭后开了一局王者荣耀,前中期基本焦灼,到了后期一波决定胜负的时候,我果断射箭,射中对面,配合队友直接秒杀,打赢团战一波推完基地.那叫一个精彩,队友都发出了666666的称赞,我酷 ...

  4. CentOS 网卡固定地址配置

    修改4个文件后重启网卡 vim /etc/default/grub GRUB_CMDLINE_LINUX="resume=UUID=05dbb36b-dbba-40a3-ba99-1b044 ...

  5. 两分钟搞定VS下第三方库的配置(以GNU Regex Library库为例)

    写C的朋友大概知道导入一个库的痛苦,特别是在宇宙第一IDE--VS下更是无从下手,生怕一不小心就把VS搞崩了,而VS的卸载过程又是一个十分头疼的过程.所以,这里特此开了一篇如何在VS下配置第三方库的博 ...

  6. 去重想到set,排序想到Arrays.sort

    package test; import java.util.Arrays; import java.util.Scanner; import java.util.Set; import java.u ...

  7. git同步源码到gitee和github

    如何把我们的源码同步到gitee或github远程仓库中 同步方式分以下几种: 1.命令同步    先查看下我们是否有远程仓库:git remote -v 如有就要删除远程仓库或是同命令覆盖,如全新安 ...

  8. 如何快速在windows上创建你的第一个odoo项目

    一.什么是Odoo Odoo 是一系列开源商业应用程序套装(ERP企业管理系统),此套装可满足贵公司的一切应用需求,例如,企业基本的进销存.采购.销售.MRP生产制造.品保质量保障.企业招聘.员工合同 ...

  9. python数据类型之set(集合)

    set集合 关注公众号"轻松学编程"了解更多. 1.概述 set与dict类似,但set是一组key的集合,与dict的区别在于set不存储value. 本质:无序且无重复元素的集 ...

  10. 循序渐进VUE+Element 前端应用开发(26)--- 各种界面组件的使用(2)

    在我们使用Vue+Element开发前端的时候,往往涉及到很多界面组件的使用,其中很多直接采用Element官方的案例即可,有些则是在这个基础上封装更好利用.更少代码的组件:另外有些则是直接采用第三方 ...