精华内容
下载资源
问答
  • 网上有很多关于这两种控制算法的实现,但是大多基于c语言,而且用的是c语言中的结构体,看起来比较繁琐。所以我利用c++面向对象的结构以及STL中vector容器来编写两种算法,看起来简洁多了。... 上述就是位置型...

           网上有很多关于这两种控制算法的实现,但是大多基于c语言,而且用的是c语言中的结构体,看起来比较繁琐。所以我利用c++面向对象的结构以及STL中vector容器来编写两种算法,看起来简洁多了。在编写的过程中,更深刻理解了如何在实际工程中运用PID控制算法。

            话不多说,先上代码https://github.com/JackJu-HIT/PID

           关于两种算法的原理,我直接粘贴我们老师上课的课件图片了,自己打字太费劲!

          

           上述就是位置型pid算法,核心就是u(t)=kperror(t)+ki(sum(error))+kd(error(t)-error(t-1)),积分离散化就是求和,微分求和就是查分,这么理解就可以,如果你要是想理解比例、微分、积分环节对系统会产生什么影响啊,上升时间、超调量、稳定裕度等指标,建议你最好从连续系统理解,类似时域分析法、频域分析法、根轨迹之类的,具体参见自动控制原理即可。

          同样增量型的pid算法,就是从位置型推出来的,你把u(k)-u(k-1)化简一下就能得到下图那个式子。还是盗用老师课件的图:

         简单说增量型pid就是:u(t)-u(t-1)=kp*(error(t)-error(t-1))+ki*(error(t))+kd*(error(t)-2*error(t-1)+error(t-2))。增量型比位置型好在哪里?我的理解就是好就好在每次积分环节不用每次都累计的计算,每次都要求一次和,浪费计算资源。还有就是有些情况,我们只要知道当前控制量与上一次变幻多少即可。

          那么现在让我们分析分系源码吧:

          我们假设被控对象传递函数G(S)=Y(S)/U(S)=1/(2S+1),变成时间域就是 2y‘+y=u,那么我们写的是离散pid,故需要进行离散化处理,2(y(k)-y(k-1))+y(k-1)=u,整理得到,y(k)=0.5(u(k)+y(k-1))  (1).这里要注意,u是由pid输出的信号控制的。

      for (int  i = 0; i < 200; i++)
      {
      y=0.5*(y+u);//模型
      err=x_ref-y;
      pid.error=err;
      pid.PID_function(1,0.1,0);
      u=pid.u_output;
      y_output.push_back(y);
      }

         这一块是主函数了,调用pid进行控制了。里面的被控对象模型用的就是(1)式。

    //PID
    class PID
    {
    public:
        double error;
        double pre_error=0;
        double error_sum=0;
        double u_output;
        void PID_function(double kp,double ki,double kd); //位置式pid算法
        //void PID_
        PID();
        ~PID();
    };
     void PID::PID_function(double kp,double ki,double kd)
    {
       error_sum+=error;
       u_output=kp*error+ki*error_sum+kd*(error-pre_error);
       pre_error=error;
       std::cout<<"error:"<<error<<std::endl;
    }
    PID::PID()
    {
    
    }
    PID::~PID()
    {
    }

       这一部分就是代码核心的部分。位置型pid具体实现,具体算法参见代码。

    void PID::PID_function(double kp,double ki,double kd)
    { 
      
        if(i==1)
       {
            pre_error.push_back(0);
            pre_error.push_back(0);
           
            std::cout<<pre_error[0]<<std::endl;
            std::cout<<pre_error[1]<<std::endl;
            std::cout<<pre_error.size()<<std::endl;
        } 
       std::cout<<"error:"<<error<<std::endl;
       pre_error.push_back(error);
       j=pre_error.size();
       std::cout<<pre_error.size()<<std::endl;
       u_output+=kp*(pre_error[j-1]-pre_error[j-2])+ki*pre_error[j-1]+kd*(pre_error[j-1]-2*pre_error[j-2]+pre_error[j-3]);
       i=i+1;
    }

           这一部分是增量型pid的算法核心部分的代码,具体实现过程见代码,写的很清楚。最后一部分就是显示绘制出曲线的部分了。

    /*pid校正后(闭环)*/ 
     plt::subplot(2,2,1);
     plt::title("PID");
     plt::plot(y_output);
    /*****pid矫正前(开环)****/
    
     plt::subplot(2,2,2);
     plt::title("orginal");
     plt::plot(y_orgin_output);
     
    
    plt::show();

          这一部分就是绘图部分,绘制了加控制器和不加控制器两种情况,代码看起来像matlab哈,也有点像python。

         到这里,你就学完了两种经典PID控制算法啦,具体的代码,你参见开头给出我的github网址上去下载。

         如果你觉得我写的不错,就点赞、关注我吧,第一次系统介绍一个算法.后面会不定时的介绍些自动驾驶中的算法及其linux下C++工程实现。

    展开全文
  • 前面我们已经知道位置型PID和增量型PID的数学表达式,我们根据这些表达式就可以实现基本的PID的C语言编程了!下面我们开始C语言的编写。 第一步:创建一个PID各项参数的变量结构体。 第二步:PID参数...

    前面我们已经知道位置型PID和增量型PID的数学表达式,我们根据这些表达式就可以实现基本的PID的C语言编程了!下面我们开始C语言的编写。


    第一步:创建一个PID各项参数的变量结构体。



    第二步:PID参数的初始化函数。


          这里以后我们主要就是对Kp、Ki、Kd的不断调节来优化控制效果!

    第三步:PID算法的计算函数。


    注意:这里没有很严格的保证PID的算法精确,只是对公式的一种直接实现,以后我们当然要慢慢的优化!


    上面就已经结束了对PID算法的设计,下面就开始输出测试了:

    代码如下:


    下面是经过1000次PID控制之后的结果:因为数据很多,我只给出了一部分




    展开全文
  • 位置型PID的C语言实现 首先,再次给出位置型PID离散化...根据位置型PID离散化公式编写C语言代码程序: 第一步,定义PID变量结构体代码如下: struct _pid{ float SetSpeed; //定义设定值 float ActualSp...

    位置型PID的C语言实现

    首先,再次给出位置型PID离散化公式:

    根据位置型PID离散化公式编写C语言代码程序:

    第一步,定义PID变量结构体代码如下:

    struct _pid{
    	    float SetSpeed;   //定义设定值
    		float ActualSpeed;//定义实际值
    	    float err;        //定义偏差值
    	    float err_last;   //定义上一个偏差值
    		float err_past;   //定义前一个偏差值
    	    float Kp,Ki,Kd;   //定义比例、积分、微分系数
    	    float voltage;    //定义电压值(控制执行器变量)
    	    float integral;	  //定义积分值
    	
    	    int index;     // 积分分离时的变量
    	    float umax;      //积分极限
    	    float umin;
         }pid;	

    第二步,初始化变量:

    void PID_init()    //pid变量初始化
    {
      printf("PID_init begin \n");
      pid.SetSpeed = 0.0;
      pid.ActualSpeed = 0.0;
      pid.err = 0.0;
      pid.err_last = 0.0;
      pid.err_past = 0.0;
      pid.voltage = 0.0; 
      pid.integral = 0.0;
      pid.Kp = 0.4;
      pid.Ki = 0.2;
      pid.Kd = 0.2;
      pid.umax = 400;
      pid.umin = -200;
      printf("PID_init end \n");
     }	

    统一初始化变量,尤其是 Kp,Ki,Kd 三个参数,调试过程当中,对于要求的控制效果,可以通过调节这三个量直接进行调节。

    第三步,编写控制算法:

    /**********************************************************************************/
    //PID算法 驱动代码	
    //对比例、微分、积分进行离散化处理之后 
    /*********************************************************************************/ 	  
    
    //位置型PID算法 
    //PID算法最基本形式,未考虑死区问题,未定义上下限,对公式的直接实现
    float PID_realize1(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(void)
    { 
    	uart_init(115200);	//串口初始化波特率为115200
    	delay_init(168);		//初始化延时函数
    	LED_Init();		      //初始化LED端口
    	PID_init();
    	int count = 0;
      while(count<1000)
       {
    	 GPIO_ResetBits(GPIOC,GPIO_Pin_13); 
    	 delay_ms(50);  		   //延时300ms
    	 GPIO_SetBits(GPIOC,GPIO_Pin_13);	  
         delay_ms(50);        //延时300ms
    
         float speed = PID_realize1(200.0);
    	 printf("%f\n",speed);
    	 count++;
    
        }
      return 0 ;
     }
    

    测试说明:测试代码中,初始化串口,奖PID的数据通过串口发送给电脑上位机,同时每传送一次数据,LED等闪烁一次,用以提                 示程序运行状况。

    第四步,测试结果说明:

    经过1000次调节后输出单片机1000个数据,其中一部分如下所示:

    83.000001  11.555000  59.559675  28.175408  52.907421  38.944152  51.891699  46.141651
    53.339054  51.509998  55.908450  55.944631  58.970680
    
    199.999094  199.999115  199.999123  199.999135  199.999152  199.999161  199.999172
    199.999183  199.999201  199.999203  199.999224  199.999232  199.999243  199.999261
    199.999263  199.999284  199.999292  199.999304  199.999321  199.999323  199.999344
    199.999352  199.999364  199.999381  199.999390  199.999401  199.999412  199.999430
    199.999432  199.999453  199.999461  199.999473

    由输出数据可知,PID的输出在一定时间内,会逐步稳定到期望值。

    以上是我对位置型PID算法的简单代码表示,希望大家多多提出宝贵意见,我一定会及时改正。

    转载于:https://my.oschina.net/u/3955129/blog/1939131

    展开全文
  • 位置型PID的C语言实现首先,再次给出位置型PID离散化公式: 根据位置型PID离散化公式编写C语言代码程序:第一步,定义PID变量结构体代码如下:struct _pid{float SetSpeed; //定义设定值float ActualSpeed;//定义...

    位置型PID的C语言实现

    首先,再次给出位置型PID离散化公式:c555efa83b62ab0f0639c8416325805e.png

    根据位置型PID离散化公式编写C语言代码程序:

    第一步,定义PID变量结构体代码如下:

    struct _pid{

    float SetSpeed; //定义设定值

    float ActualSpeed;//定义实际值

    float err; //定义偏差值

    float err_last; //定义上一个偏差值

    float err_past; //定义前一个偏差值

    float Kp,Ki,Kd; //定义比例、积分、微分系数

    float voltage; //定义电压值(控制执行器变量)

    float integral; //定义积分值

    int index; // 积分分离时的变量

    float umax; //积分极限

    float umin;

    }pid;

    第二步,初始化变量:

    void PID_init() //pid变量初始化

    {

    printf("PID_init begin \n");

    pid.SetSpeed = 0.0;

    pid.ActualSpeed = 0.0;

    pid.err = 0.0;

    pid.err_last = 0.0;

    pid.err_past = 0.0;

    pid.voltage = 0.0;

    pid.integral = 0.0;

    pid.Kp = 0.4;

    pid.Ki = 0.2;

    pid.Kd = 0.2;

    pid.umax = 400;

    pid.umin = -200;

    printf("PID_init end \n");

    }

    统一初始化变量,尤其是 Kp,Ki,Kd 三个参数,调试过程当中,对于要求的控制效果,可以通过调节这三个量直接进行调节。

    第三步,编写控制算法:

    /**********************************************************************************/

    //PID算法 驱动代码

    //对比例、微分、积分进行离散化处理之后

    /*********************************************************************************/

    //位置型PID算法

    //PID算法最基本形式,未考虑死区问题,未定义上下限,对公式的直接实现

    float PID_realize1(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(void)

    {

    uart_init(115200);//串口初始化波特率为115200

    delay_init(168);//初始化延时函数

    LED_Init(); //初始化LED端口

    PID_init();

    int count = 0;

    while(count<1000)

    {

    GPIO_ResetBits(GPIOC,GPIO_Pin_13);

    delay_ms(50); //延时300ms

    GPIO_SetBits(GPIOC,GPIO_Pin_13);

    delay_ms(50); //延时300ms

    float speed = PID_realize1(200.0);

    printf("%f\n",speed);

    count++;

    }

    return 0 ;

    }

    测试说明:测试代码中,初始化串口,奖PID的数据通过串口发送给电脑上位机,同时每传送一次数据,LED等闪烁一次,用以提                 示程序运行状况。

    第四步,测试结果说明:

    经过1000次调节后输出单片机1000个数据,其中一部分如下所示:

    83.000001 11.555000 59.559675 28.175408 52.907421 38.944152 51.891699 46.141651

    53.339054 51.509998 55.908450 55.944631 58.970680

    199.999094 199.999115 199.999123 199.999135 199.999152 199.999161 199.999172

    199.999183 199.999201 199.999203 199.999224 199.999232 199.999243 199.999261

    199.999263 199.999284 199.999292 199.999304 199.999321 199.999323 199.999344

    199.999352 199.999364 199.999381 199.999390 199.999401 199.999412 199.999430

    199.999432 199.999453 199.999461 199.999473

    由输出数据可知,PID的输出在一定时间内,会逐步稳定到期望值。

    以上是我对位置型PID算法的简单代码表示,希望大家多多提出宝贵意见,我一定会及时改正。

    展开全文
  • c语言编写单片机技巧

    2009-04-19 12:15:17
    答:对于复杂而开发时间紧的项目时,可以采用C语言,但前提是要求对该MCU系统的C语言和C编译器非常熟悉,特别要注意该C编译系统所能支持的数据类型和算法。虽然C语言是最普遍的一种高级语言,但不同的MCU厂家其...
  • (1)利用 TruckSim 搭建了铰接式车辆垂直泊车...设计路径跟踪横向和纵向联合控制器,并基于 TruckSim 与 Simulink 联合仿真平台对牵引销置于后轴中点前端车辆,垂直泊车路径跟踪和平行泊车路径跟踪进行了仿真验证。
  • 训练,从而验证了基于 DDPG 算法控制策略的有效性。设计多组泊车泛化 性试验,在试验中调整泊车起始位置与停车位尺寸,从而进行泊车试验,验证和 分析算法的泛化性。将CarSim中的车辆接口硬件化,硬件在环平台...
  • Motion_control.rar

    2020-07-16 11:43:00
    用Verilog语言编写的步进电机加减速控制算法,可选择梯形曲线或S曲线算法,包含源码,工程等,包含初试速度设置,位置设置,正反转,位置反馈等
  • 本设计旨在制作一台十二自由度的小型电动直驱四足机器人,并探究以对角步态为主的相关步态控制算法,具体工作包括主控板设计制作、电路系统搭建、电机驱动调试、底层驱动代码编写控制算法仿真移植和应用层环境感知...
  • 易语言 茶凉专用模块

    2010-05-04 12:26:36
    子程序 窗口状态控制, 逻辑, 公开, 控制窗口状态(成功返回真,失败返回假) .参数 临时句柄, 整数, , 窗口句柄 .参数 状态, 整数, , 0 隐藏取消激活 1 还原激活 2 最小化激活 3 最大化激活 4 还原 6 最小化取消...
  • Gams用户指南

    热门讨论 2013-01-05 22:23:06
    通过排除考虑纯技术上的机器特定的问题的需要,比如地址计算,存储分配,子程序链接,和输入输出和流程控制,GAMS增加了用于概念化和运行模型,和分析结果的时间.GAMS本身构建了良好的建模习惯,通过请求简明而精确的实体和...
  •  本套试题是遵循《全国计算机技术与软件专业技术资格(水平)考试程序员考试大纲与培训指南(2009版)》中程序员考试的要求,根据最近两年的程序员考试的命题规律整理编写的,基本涵盖了所有重要考点,其难度、题型...
  • (31) 算法一般都可以用哪几种控制结构组合而成______。(D) A. 循环、分支、递归 B. 顺序、循环、嵌套 C. 循环、递归、选择 D. 顺序、选择、循环 (32) 数据的存储结构是指______。(B) A. 数据所占的存储空间量 B. ...
  • 7.3.3 编写GUI的步骤 7.4 GUI图形用户界面 7.4.1 设置GUI的大小 7.4.2 为GUI加控件 7.4.3 调整控件位置 7.4.4 设置Tab顺序 7.4.5 选择GUI选项 7.5 创建GUI界面菜单 7.5.1 编辑一般菜单 7.5.2 编辑ContextMenus菜单 ...
  • java源码包---java 源码 大量 实例

    千次下载 热门讨论 2013-04-18 23:15:26
     util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码...
  • 5.1 为什么需要循环控制 5.2 用while语句实现循环 5.3 用do…while语句实现循环 5.4 用for语句实现循环 5.5 循环的嵌套 5.6 几种循环的比较 5.7 改变循环执行的状态 5.7.1 用break语句提前终止循环 5.7.2 用continue...
  •  3.3.2 浮点数值类型  3.4 布尔类型  3.5 字符串类型  3.5.1 字符类型  3.5.2 字符串类型  3.6 数组  3.6.1 数组的声明与初始化  3.6.2 数组的使用  3.7 枚举类型  3.8 用结构体类型描述复杂的事物  ...
  • (31) 算法一般都可以用哪几种控制结构组合而成(D) 注:P3 A. 循环、分支、递归 B. 顺序、循环、嵌套 C. 循环、递归、选择 D. 顺序、选择、循环 (32) 数据的存储结构是指(B) 注:P13,要牢记 A. 数据所占的存储空间量...
  • 章讨论其他形式,包括数组(存储多个同类型的值)、结构(存储多个不同类型的值)、指针(标识内存位置) 。读者还将学习如何创建和存储文本字符串及如何使用C—风格字符数组和C抖string类来处理文本输入和 输出。最后,...
  • 章讨论其他形式,包括数组(存储多个同类型的值)、结构(存储多个不同类型的值)、指针(标识内存位置) 。读者还将学习如何创建和存储文本字符串及如何使用C—风格字符数组和C抖string类来处理文本输入和 输出。最后,...
  • 内容包括窗体与界面设计、控件应用、数据处理技术、图形技术、多媒体技术、文件系统、操作系统与window相关程序、注册表、数据库技术、sql查询...与算法、delphi语言基础、加密/安全与软件注册、实用工具、程序打包等...
  • 章讨论其他形式,包括数组(存储多个同类型的值)、结构(存储多个不同类型的值)、指针(标识内存位置) 。读者还将学习如何创建和存储文本字符串及如何使用C—风格字符数组和C抖string类来处理文本输入和 输出。最后,...
  • 章讨论其他形式,包括数组(存储多个同类型的值)、结构(存储多个不同类型的值)、指针(标识内存位置) 。读者还将学习如何创建和存储文本字符串及如何使用C—风格字符数组和C抖string类来处理文本输入和 输出。最后,...
  • 内容包括窗体与界面设计、控件应用、数据处理技术、图形技术、多媒体技术、文件系统、操作系统与window相关程序、注册表、数据库技术、sql查询...与算法、delphi语言基础、加密/安全与软件注册、实用工具、程序打包等...
  • 虚拟现实技术与应用

    热门讨论 2012-12-31 14:28:39
    本书内容较为全面且涉及面广,在编写时本着侧重于普及、推广及应用的原则,内容方面没有过多涉及有关虚拟现实技术的算法理论及程序等。本书既介绍了虚拟现实技术的必要理论,又介绍了具有代表性的虚拟现实软件的使用...
  • java源码包2

    千次下载 热门讨论 2013-04-20 11:28:17
     util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码...
  • 语音识别的MATLAB实现

    热门讨论 2009-03-03 21:39:18
    用四个c1108三极管来控制小车遥控手柄的前、后、左、右触点的通断。从计算机的并口引出四根信号线,与三极管相连,与前、后、左、右一一对应。若判断出指令信号后,则相应的信号线上输出高电平,该电路导通,发送...
  • 实例040 设置窗体在屏幕中的位置 50 实例041 始终在最上面的窗体 51 1.12 设置窗体大小 52 实例042 限制窗体大小 52 实例043 获取桌面大小 53 实例044 组件大小随窗体的改变而改变 53 实例045 在窗口间...
  • 根据快速原型法的特点,说明它特别适合于开发探索、实验的软件。 3. 如何画分层数据流图? 答: 总的原则是:至顶而下,逐层分解(画分层数据流图)。 比较复杂的系统不能画在一张纸上,逐层分解的画法可以...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 131
精华内容 52
关键字:

编写位置型控制算法