PID控制算法的C语言实现

1、PID算法简介

  PID(proportion integration differentiation)其实就是指比例,积分,微分控制。目前来说,PID控制算法是一种使用非常广泛的算法。比在平衡车、无人机等方面的应用。PID算法是简单,又能体现反馈思想的控制算法,可谓经典中的经典。在这里插入图片描述
  PID控制流程简单,通过误差信号控制被测量,并且控制器本身就是比例、积分、微分3个环节的加和。通过这三个的组合可有效地纠正被控制对象的偏差,从而使其达到一个稳定的状态。
PID控制规律:

在这里插入图片描述

kp——比例增益,kp与比例度成倒数关系;
T——积分时间常数; 
TD——微分时间常数; 
u(x)——PID控制器的输出信号; 
e(t)——给定值r(t)与测量值之差。 

1.1、各个环节的作用

1、PID控制其实是对偏差的控制。
2、如果偏差为0,则比例环节不起作用,只有存在偏差时,比例环节才起作用。
3、积分环节主要是来消除静差,所谓静差,就是系统稳定后输出值和和设定值之间的差值,积分环节实际上就是偏差累计的过程,把累计的误差加到原来的所有系统上以抵消系统的静差。
4、微分信号则反应了偏差信号的变换规律,或者说变化趋势,根据偏差信号变化趋势来经行超前调节,增加系统的快速性。

2、位置型PID算法

2.1、离散表达形式:

在这里插入图片描述

2.2、位置型代码

核心算法部分。
在这里插入图片描述

main函数,按下开发板的KEY0,程序开始测试。

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "pid.h"
#include "usart.h"
#include "key.h"

//PID算法测试
 int main(void)
 {	
		int count;
	  u8 key;
		delay_init();	    	 //延时函数初始化	  
		LED_Init();		  	//初始化与LED连接的硬件接口
	  KEY_Init();
		PID_init();
	  uart_init(9600);
		printf("System begin \r\n");
		
	 
		while(1)
		{
			key = KEY_Scan(0);
			while(count<1000)
			{
			float speed = PID_realize(200.0);
			printf("%f \r\r",speed);
			count++;
			}
			delay_ms(10);
			if(key == KEY0_PRES)
			{
				count =0;
			}
		}
 }

pid.c 文件
  统一初始化变量,尤其是Kp、Ki、Kd3个参数,对于要求的控制效果调试过程中,通过调试这个3个变量直接进行调参。

#include "pid.h"
#include "usart.h"

struct _pid
	{
		float SetSpeed;   //定义设定值
		float ActualSpeed; //定义实际值
		float err ;        // 定义偏差值
		float err_last;    //定义上一个偏差值
		float Kp,Ki,Kd;    //定义比例、积分、微分系数
		float voltage;     //定义电压值 控制器执行的变量
		float integral;    //定义积分值
  }pid;

void PID_init()
{
	printf("Pid_init begin\r\n");
	pid.SetSpeed = 0.0;
	pid.ActualSpeed = 0.0;
	pid.err = 0.0;
	pid.err_last = 0.0;
	pid.voltage = 0.0;
	pid.integral = 0.0;
	pid.Kp = 0.2;
	pid.Ki = 0.015;
	pid.Kd =0.2;
	printf("PID_init end \r\n");
}

float PID_realize(float speed)
{
	pid.SetSpeed = speed;
	pid.err = pid.SetSpeed - pid.ActualSpeed ;
	pid.integral += pid.err ;
	// 算法基本公式  没有考虑死区问题和上下限
	pid.voltage = pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);
	pid.err_last  = pid.err;
	pid.ActualSpeed = pid.voltage*1.0;
	return pid.ActualSpeed;
	
}

pid.h 文件

#ifndef __PID_H
#define __PID_H	

void PID_init(void);
float PID_realize(float speed);

#endif

2.3、测试效果

emsp; 一部分数据,可以看到,逐渐的趋近了200,设定值200,但是这个过程相对比较长。
在这里插入图片描述

3、增量型PID算法

3.1 、离散表达式:

在这里插入图片描述

3.2 增量型代码

核心算法部分。
在这里插入图片描述

main函数代码如下:

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "pid.h"
#include "usart.h"
#include "key.h"

//PID算法测试
 int main(void)
 {	
		int count;
	  u8 key;
		delay_init();	    	 //延时函数初始化	  
		LED_Init();		  	//初始化与LED连接的硬件接口
	  KEY_Init();
		PID_init();
	  uart_init(9600);
		printf("System begin \r\n");
		
	 
		while(1)
		{
			key = KEY_Scan(0);
			while(count<1000)
			{
			float speed = PID_realize(200.0);
			printf("%f \r\r",speed);
			count++;
			}
			delay_ms(10);
			if(key == KEY0_PRES)
			{
				count =0;
			}
		}
 }


pid.c 代码如下:
  统一初始化变量,尤其是Kp、Ki、Kd3个参数,对于要求的控制效果调试过程中,通过调试这个3个变量直接进行调参。

#include "pid.h"
#include "usart.h"
#include <stdio.h>
#include <stdlib.h>

struct _pid
	{
		float SetSpeed;   //定义设定值
		float ActualSpeed; //定义实际值
		float err ;        // 定义偏差值
		float err_next;    //定义上一个偏差值
		float err_last;    //定义上上一个偏差值
		float Kp,Ki,Kd;    //定义比例、积分、微分系数
  }pid;

void PID_init()
{
	printf("Pid_init begin\r\n");
	pid.SetSpeed = 0.0;
	pid.ActualSpeed = 0.0;
	pid.err = 0.0;
	pid.err_next = 0.0;
	pid.err_last = 0.0;
	pid.Kp = 0.2;
	pid.Ki = 0.015;
	pid.Kd =0.2;
	printf("PID_init end \r\n");
}

float PID_realize(float speed)
{
	float incrementSpeed;
	pid.SetSpeed = speed;
	pid.err = pid.SetSpeed - pid.ActualSpeed ;
	// 算法基本公式 
	incrementSpeed = pid.Kp*(pid.err-pid.err_next)+pid.Ki *pid.err+pid.Kd*(pid.err-2*pid.err_next+pid.err_last);
	pid.ActualSpeed += incrementSpeed;
	pid.err_last = pid.err_next ;
	pid.err_next = pid.err ;
	return pid.ActualSpeed ;
}

pid.h 文件如下:

#ifndef __PID_H
#define __PID_H	

void PID_init(void);
float PID_realize(float speed);

#endif

3.3、效果展示

在这里插入图片描述

4、积分分离的PID控制算法

  基本思路是,当被控制量与设定的值偏差较大时,取消积分作用,当被控量接近给定值时,引入积分控制,以消除静差,提高精度。
在这里插入图片描述

4.1、代码实现

main函数:

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "pid.h"
#include "usart.h"
#include "key.h"

//PID算法测试
 int main(void)
 {	
		int count;
	  u8 key;
		delay_init();	    	 //延时函数初始化	  
		LED_Init();		  	//初始化与LED连接的硬件接口
	  KEY_Init();
		PID_init();
	  uart_init(9600);
		printf("System begin \r\n");
		
	 
		while(1)
		{
			key = KEY_Scan(0);
			while(count<1000)
			{
			float speed = PID_realize(200.0);
			printf("%f \r\r",speed);
			count++;
			}
			delay_ms(10);
			if(key == KEY0_PRES)
			{
				count =0;
			}
		}
 }


pid.c 文件
#include “pid.h”
#include “usart.h”
#include <stdio.h>
#include <stdlib.h>

struct _pid
{
float SetSpeed; //定义设定值
float ActualSpeed; //定义实际值
float err ; // 定义偏差值
float err_last; //定义上一个偏差值
float Kp,Ki,Kd; //定义比例、积分、微分系数
float voltage; //定义电压值 控制器执行的变量
float integral; //定义积分值
}pid;

void PID_init()
{
printf(“Pid_init begin\r\n”);
pid.SetSpeed = 0.0;
pid.ActualSpeed = 0.0;
pid.err = 0.0;
pid.err_last = 0.0;
pid.voltage = 0.0;
pid.integral = 0.0;
pid.Kp = 0.2; //比例
pid.Ki = 0.04; //积分
pid.Kd =0.2; //微分
printf(“PID_init end \r\n”);
}

float PID_realize(float speed)
{
int index;
pid.SetSpeed = speed;
pid.err = pid.SetSpeed - pid.ActualSpeed ;
pid.integral += pid.err ;
// 算法实现过程
if(abs(pid.err)>200) //设定值 200
{
index = 0;
}
else
{
index = 1;
pid.integral += pid.err ;

}
pid.voltage = pid.Kp*pid.err+index*pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);
pid.err_last  = pid.err;
pid.ActualSpeed = pid.voltage*1.0;
return pid.ActualSpeed;

}

4.2、效果图

  通过测试,系统数据达到199所用的时间为原来的1/2,系统的快速性得到提升。

在这里插入图片描述

5、工程文件下载

在这里插入图片描述

工程文件链接https://download.csdn.net/download/weixin_45488643/12647479有需要自己下载吧。

  • 20
    点赞
  • 149
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值