极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 2704|回复: 14

PID详细总结

[复制链接]
发表于 2017-8-5 19:30:33 | 显示全部楼层 |阅读模式
经过很久的战争,终于PID被我拿下,下面我将就增量式PID介绍,位置式的就是公式不一样,套一下就可以了
PID控制算法的C语言,增量型PID的C语言实现
这里直接给出代码了。
#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;
}

这个只是c语言程序,还要修改一下成为单片机的,但是我们可以参考她的公式及思路,




下面是我窜眼很久写出来的pid代码,虽然不好,但大致可以实现控制电机,加了限幅滤波算法
废话不多说,直接上代码,不足之处望大佬指正

采用298驱动的,板子型号是Arduino UNO,以下是接线(为了省事,298的IN1和IN2我没有通过程序给出高低电平,直接接在arduino UNO的5v和gnd,)
/*
        IN1-----+5V;
        IN2------GND;
        ENA-----D9;
        光耦测速模块D0-----2;
*/

#include <MsTimer2.h>   
int pwm = 9;
float kp = 8,ki = 4,kd = 2;
float e,e1,e2;
int cnt;  //存储电机触发的脉冲次数
int m;  //记录进入定时器中断的次数
int v;  //存储电机500ms内触发的脉冲次数
int uk,uk1,duk,out=20;
int SpeedSet = 200;
int v1;//用于滤波记录当前值

void setup()
{
  Serial.begin(9600);
  pinMode(9,OUTPUT);
  pinMode(2,INPUT);
  attachInterrupt(0, blink, CHANGE);
  MsTimer2::set(2, flash);
  MsTimer2::start();           //开始计时
}

void PIDControl()        
{
  e=SpeedSet-v;   
  duk=(kp*(e-e1)+ki*e+kd*(e-2*e1+e2))/50;    //增量式PID输出   
  uk=uk1+duk;     
  out=(int)uk;
  if(out>1000)
  {
    out=1000;
  }
  else if(out<0)
  {
    out=0;
  }
  uk1=uk;         
  e2=e1;
  e1=e;         
}

// 限幅滤波法(又称程序判断滤波法)
int Filter()
{
  int NewV;
  NewV = v;
  if(abs(NewV - v) > 10)
    return v;
  else
    return NewV;
}

void loop()
{
  v1 = Filter();
  v = v1;
  Serial.println(v1);
  analogWrite(pwm,out);
}

void blink()
{
    cnt++;
  }

void flash()
{
    m++;
    if(m>100)
    {
        v = 2.5*cnt;//计算500ms内的脉冲数
        PIDControl();   
        cnt = 0;
        m = 0;
      }
  }

电机通过L298N驱动,这里为了省事,298的IN1和IN2我没有通过程序给出高低电平,直接接在arduino UNO的5v和gnd,298的ENA接在D9脚,才用光藕计脉冲,接在2脚

把程序上传到你的板子上,通过串口监视器就可以看到变化啦,当然pid参数需要根据你的实际情况调整。

希望能帮到大家!
回复

使用道具 举报

发表于 2017-8-5 22:30:23 | 显示全部楼层
那个MsTimer2的库,能不能打个包发一下
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-8-6 13:00:55 | 显示全部楼层
这个是Arduino UNO 的定时器库文件,稍候上传Arduino 2560的库文件

MsTimer2.rar

1.45 KB, 下载次数: 36

这个库文件Arduino UNO适用

回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-8-6 22:13:51 | 显示全部楼层
zjz5717 发表于 2017-8-5 22:30
那个MsTimer2的库,能不能打个包发一下

这个是Arduino 2560板子适用的定时器的库,UNO的已经上传了

FlexiTimer2.rar

8.84 KB, 下载次数: 25

回复 支持 反对

使用道具 举报

发表于 2017-8-7 08:13:26 | 显示全部楼层
收藏了,谢谢分享!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-8-8 09:50:40 | 显示全部楼层
leisd 发表于 2017-8-7 08:13
收藏了,谢谢分享!

哈哈,第一次发帖,感谢支持
回复 支持 反对

使用道具 举报

发表于 2017-8-9 18:31:54 | 显示全部楼层
PID对新人来说还是挺复杂的,而且在很多地方都有用到,继续加油!

ps:我记得有标准PID库,可以看一下。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-8-10 00:32:58 | 显示全部楼层
Damn_intuition 发表于 2017-8-9 18:31
PID对新人来说还是挺复杂的,而且在很多地方都有用到,继续加油!

ps:我记得有标准PID库,可以看一下。

库我也使用过,可能会我还没完全弄会把,测出来的实际转速和设定值总是误差很大
回复 支持 反对

使用道具 举报

发表于 2017-8-16 09:24:45 | 显示全部楼层
多谢分享哦
回复 支持 反对

使用道具 举报

发表于 2017-8-16 18:57:50 | 显示全部楼层
nt Filter()
{
  int NewV;
  NewV = v;
  if(abs(NewV - v) > 10)
    return v;
  else
    return NewV;
这里有点问题把,一直是返回 NewV;


还有 void flash()
{
    m++;
    if(m>100)
    {
        v = 2.5*cnt;//计算500ms内的脉冲数
        PIDControl();   
        cnt = 0;
        m = 0;
      }
  }
应该是200毫秒吧
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-8-18 17:31:11 | 显示全部楼层
neebourne 发表于 2017-8-16 18:57
nt Filter()
{
  int NewV;

随着程序的不断改进,注释还是一开始的,也懒得改了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-8-23 10:53:10 | 显示全部楼层
neebourne 发表于 2017-8-16 18:57
nt Filter()
{
  int NewV;

测试过程中,程序一直在修改,那些注释还是一开始的,后面改好了,也就没有改过来了,比较懒
回复 支持 反对

使用道具 举报

发表于 2017-8-28 17:00:03 | 显示全部楼层
亲,我也是被pid困扰好久好久的人了。有个问题想请教,
 就是你在pid控制电机是选用带编码器的吗?能发个图片看看吗?
回复 支持 反对

使用道具 举报

发表于 2017-9-2 16:25:00 | 显示全部楼层
问问。这个2560定时库文件该怎么使用呢?我 的想法是升温到设定温度在恒温。到设定的时间后循环升温恒温。
回复 支持 反对

使用道具 举报

发表于 2017-9-7 12:54:31 | 显示全部楼层
戳戳戳 发表于 2017-8-23 10:53
测试过程中,程序一直在修改,那些注释还是一开始的,后面改好了,也就没有改过来了,比较懒

觉得你已经很厉害啦,我搞啦几天pid又放下啦
回复 支持 反对

使用道具 举报

高级模式  
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2018-6-21 21:49 , Processed in 0.045158 second(s), 7 queries , File On.

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表