问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

毕设项目分享 经典单片机控制算法:PID

创作时间:
作者:
@小白创作中心

毕设项目分享 经典单片机控制算法:PID

引用
CSDN
1.
https://m.blog.csdn.net/MDC_sir/article/details/139956580

PID控制算法是单片机控制领域中一种经典且重要的控制算法,广泛应用于温度控制、电机转速控制、平衡车控制等多个领域。本文将从PID算法的基本概念出发,详细介绍其原理和实现方法,并通过三个具体的代码示例帮助读者深入理解。

1 简介

PID控制算法是一种闭环控制算法,通过比例(P)、积分(I)和微分(D)三个部分的组合来实现对系统的精确控制。这种算法在工业控制、机器人控制等领域有着广泛的应用。

2 什么是PID

2.1 P:比例

比例部分成比例地反映控制系统的偏差信号e(t)。当系统输出与设定值存在偏差时,比例部分会立即产生控制作用,以减小偏差。但是,仅使用比例控制时系统输出通常存在稳态误差。

2.2 I:积分

积分部分用于消除静差,提高系统的无差度。积分作用的强弱取决于积分时间常数T,T越大,积分作用越弱,反之则越强。

2.3 D:微分

微分部分反映偏差信号的变化趋势,并能在偏差信号变得太大之前,在系统中引入一个有效的早期修正信号,从而加快系统的动作速度,减少调节时间。

3 PID算法能做什么

PID算法主要用于单片机对某种器件的控制,常见的控制对象包括:

  • 温控(烤箱,冰箱等)
  • 电机转速控制
  • 平衡车控制
  • 飞行器控制
  • 压力、温度、流量、液位控制器

4 PID算法实现

PID算法有多种实现方式,以下是三种常用的实现方法:

4.1 位置式PID算法实现

位置式PID算法通过对积分的持续累加来实现控制,但容易造成积分饱和,导致系统过调。

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 \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 \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;
}

int main(){
    printf("System begin \n");
    PID_init();
    int count=0;
    while(count<1000)
    {
        float speed=PID_realize(200.0);
        printf("%f\n",speed);
        count++;
    }
    return 0;
}

4.2 增量式PID实现

增量式PID算法只与前后三次的误差值有关,计算更简单,避免了积分饱和的问题。

#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(){
    pid.SetSpeed=0.0;
    pid.ActualSpeed=0.0;
    pid.err=0.0;
    pid.err_last=0.0;
    pid.err_next=0.0;
    pid.Kp=0.2;
    pid.Ki=0.015;
    pid.Kd=0.2;
}

float PID_realize(float speed){
    pid.SetSpeed=speed;
    pid.err=pid.SetSpeed-pid.ActualSpeed;
    float 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;
}

int main(){
    PID_init();
    int count=0;
    while(count<1000)
    {
        float speed=PID_realize(200.0);
        printf("%f\n",speed);
        count++;
    }
    return 0;
}

4.3 抗积分饱和的PID算法实现

抗积分饱和PID算法通过判断实际输出是否超出上下限来决定是否进行积分计算,避免了积分饱和的问题。

float PID_realize(float speed){
    int index;
    pid.SetSpeed=speed;
    pid.err=pid.SetSpeed-pid.ActualSpeed;
    if(pid.ActualSpeed>pid.umax)
    {
        if(abs(pid.err)>200)
        {
            index=0;
        }else{
            index=1;
            if(pid.err<0)
            {
                pid.integral+=pid.err;
            }
        }
    }else if(pid.ActualSpeed<pid.umin){
        if(abs(pid.err)>200)
        {
            index=0;
        }else{
            index=1;
            if(pid.err>0)
            {
                pid.integral+=pid.err;
            }
        }
    }else{
        if(abs(pid.err)>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;
}
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号