首页 > 其他分享 >PID学习

PID学习

时间:2024-10-10 18:53:05浏览次数:3  
标签:输出 内环 PID float pid 学习 小球

直立环PD,速度环PI,转向环PD

PID的实例

e943be3ba6e54841a4917c9ee180214d.png

对小球进行速度控制

pid目标值:需要小球达到的速度

pid反馈值:小球的实时速度

pid输出值:施加在小球上的力

对电机的转速进行控制

pid目标值:需要电机达到的转速

pid反馈值:电机的实时转速

pid输出值:电机中流过电流的大小

fbcab02a65754d048f3ed05447d9a107.png

毕竟微积分都是连续的,而我们采样得到的是离散的数据点。其实也很简单,离散状态下的积分计算其实就是把过去采样得到的所有误差加在一起,而微分计算就是把这一轮计算得到的误差与上一轮的误差相减。

最后,我们一般还会对PID的积分和输出进行限幅(规定上下限),积分限幅可以减小积分引起的超调,输出限幅可以保护执行机构或被控对象。

//首先定义一个PID结构体类型用来存放PID的数据
typedef struct
{
    float kp, ki, kd;
    float Error , LastError;
    float Integral , MaxIntegral;//积分限制
    float Output , MaxOutput;//输出,输出限幅
}PID;


//用于初始化pid
void PID_Init(PID *pid, float p, float i, float d, float MaxI, float Maxout)
{
    pid->kp = p;
    pid->ki = i;
    pid->kd = d;
    pid->MaxIntegral = MaxI;
    pid->MaxOutput = Maxout;
}

//进行一次PID运算结果放在结构体参数Out,Error里
void PID_Cala(PIDM *pid , float Reference, flaot Feedback)
{
    pid->LastError = pid->Error;//在计算之前先把上一次的误差存储起来
    pid->Error = Reference - Feedback;//计算新的error目标值-测量值
    //计算积分P
    float Pout=pid->Error*pid->kp;
    //D
    float Dout = pid->Error*pid->kd;
    //I,这个i的积分是累加的
    pid->integral += pid->Error*pid->ki;
    //对输出进行限幅
    if(pid->Output > pid->MaxOutput) pid->Output = pid->MaxOutput;
    else if(pid->Output < pid->MaxOutput) pid->Output = pid->MaxOutput;
}

PID mypid = {0};//创建结构体变量,这里创建了


int main()
{


    PID_Init(&mypid, 10 ,1 ,5 ,800 ,1000);
    while(1)
    {
        float FeedbackValue = 
        float TargetValue = 
    PID_Calc(&mypid, TargetValue, FeedbackValue);
    执行器输出大小(mypid.Output);
    Delay_ms(10)
    }
}
    

 



     

串级PID

更进一步——串级PID

从单级到串级

fe6dae60ea4b490e9c15d4aedecb2469.png

当我们在进行小球的位置控制时,我们可能经常会发现一个问题,如果小球与目标之间的距离较远的话,小球在运动过程中的速度会很快,会导致较大的超调,而且不论怎么修改参数都很难让系统的表现更好一些。

如果运动过程中的速度没这么快就好了,这样就不会冲过头了。没错,这就要用到串级PID了。

我们上面所说的算法其实就是单级PID,目标值和反馈值经过一次PID计算就得到输出值并直接作为控制量,但如果目标物理量和输出物理量之间不止差了一阶的话,中间阶次的物理量我们是无法控制的。比如:目标物理量是位置,输出物理量是加速度,则小球的速度是无法控制的。

而串级PID就可以改善这一点。串级PID其实就是两个单级PID“串”在一起组成的,它的信号框图如下:

d02efad272b743e9a03dca1816fa35d7.png

串级PID为一个整体,有三个输入一个输出而此时被控对象也需要提供两个反馈量,那么它们都应该对应些什么物理量呢?

09ec83234336449daa5e38f554e442c1.png

目标值:小球目标位置

外环反馈:小球实时位置

内环反馈:小球实时速度

输出值:施加在小球上的控制力//直接反馈的是小球实时速度

内环与小球构成了一个恒速系统,PID内环负责小球的速度控制;而如果把内环和小球看作一个整体被控对象,外环又与这个对象一起构成了一个位置控制系统,外环负责位置控制;总体来说,外环负责根据小球位置误差计算出小球需要达到的速度,而内环负责计算出控制力使小球达到这个目标速度,两个环协同工作,就可以完成任务了。对应的位置有对应的速度

目标值:需要电机达到的角度

外环反馈值:电机的实时角度

内环反馈值:电机的实时速度

输出值:电机电流大小

分析:外环负责电机角度控制,根据电机目标角度和反馈角度计算出目标转速;内环负责转速控制,根据速度反馈和目标转速计算出电流

其实就是对外环PID的输出进行限幅,因为外环PID输出的是目标速度,限制外环输出就相当于限制了小球目标速度的最大值,内环也就会维持小球的速度不超过这个最大值了。

可以看到,使用串级PID后小球不再像之前那样“着急”地奔着目标而去,而是以近似匀速运动到达目标点。由于位置误差很大,外环输出在大部分时间内都处于限幅的最大值,因此小球在运动中接近匀速,这个速度就是所设定的外环输出限幅。而且由于运动速度变慢了,超调也几乎消失了。这就是我们想要的“控制位置的同时还能控制速度”的效果。

//串级PID的结构体,包含两个单级PID
typedef struct
{
    PID Inner; //内环
    PID Outer; //外环
    float Output; //串级输出,等于inner.output
}CascadePID;


//串级PID的计算函数
void PID_CascadeCalc(CascadeCalc *pid, float OuterRef, float OuterFdb, float InnerFdb)
{
    PID_Calc(&pid->Outer, OuterRef, OuterFdb);//计算外环
    PID_Calc(&pid->Inner, pid->Outer.Output, InnerFdb);//计算内环
    pid-Output = pid->Inner.Output;//内环输出就是串级PID的输出
}


CascadePID myoid = {0};

int main()
{

    PID_Init(&mypid.Inner, 10, 0, 0, 0, 1000);初始化内环
    PID_Init(&mypid.Outer, 5, 0, 5, 0, 100);初始化外环
    while(1)
    {
    float OuterTarget = //内环目标值
    float OutFeedback = //外环反馈值
    float InnerFeedback = //内环反馈值
    PID_CascadeCalc(&mypid, OutTarget, OutFeedback, InnerFeedback);
    执行机构输出大小(mypid.Output);
    Delay_ms(10);
    }
}
    

    

 

 

 

标签:输出,内环,PID,float,pid,学习,小球
From: https://blog.csdn.net/2301_77871040/article/details/141472666

相关文章

  • 学习python2.0
    这两天白天都满课,傍晚才有私人时间。今天学习了5.2字符串和编码:(1)ASCII,可以编码的是英文字母,数字和一些符号。GB2312编码,可以编码中文。Unicode把所有语言都统一到一套编码里,比较方便,但是占用的存储空间大。UTF-8编码可以省空间。(2)ord()函数获取字符的整数表示,chr()......
  • 基于Java语言的医学生在线交流学习平台设计与实现(源码+论文+远程安装)
    文章目录1.前言2.详细视频演示3.文档参考3.1论文参考3.2流程设计图3.3数据库表结构设计3.4系统测试部分4.项目运行截图5.技术框架5.1后端采用SpringBoot框架5.2前端框架Vue6.选题推荐毕设案例8.系统测试8.1系统测试的目的8.2系统功能测试9.代码参考10......
  • ThinkPHP5&bootstrap&MySQL开发学习平台(包括后台管理功能、PC端网页、移动端网页)手把
    一、项目预览(全部源码链接在最下面)功能及页面持续优化中......二、本地运行方式1、下载源码包进行解压(源码在最下面)2、下载phpstudy_pro,并运行Apache&......
  • php学习片段
    目录1.$2.->3.EOF4.数组5.in_array6.=>7.as8.unset1.$$i是一个变量名,在PHP中以$符号开头表示一个变量。1.$i=0;这里将变量$i初始化为0。2.->PHP代码中,->是用于访问对象的属性和方法的操作符。例如:$res->fields["job_number"]表示访问$res这个对象的fi......
  • javascript学习——鼠标事件详解
    鼠标事件鼠标事件的种类鼠标事件主要有下面这些,所有事件都继承了MouseEvent接口(详见后文)。(1)点击事件鼠标点击相关的有四个事件。click:按下鼠标(通常是按下主按钮)时触发。dblclick:在同一个元素上双击鼠标时触发。mousedown:按下鼠标键时触发。mouseup:释放按下的鼠标键时触......
  • javascript学习——事件模型
    事件模型监听函数浏览器的事件模型,就是通过监听函数(listener)对事件做出反应。事件发生后,浏览器监听到了这个事件,就会执行对应的监听函数。这是事件驱动编程模式(event-driven)的主要编程方式。JavaScript有三种方法,可以为事件绑定监听函数。HTML的on-属性HTML语言允......
  • Spring是什么?我们为什么要学习它?
    环境jdk1.8ideamaven-3.6.1spring-5.2.3.RELEASE整个spring系列使用官方最新版本5.2.3.RELEASE,会有大量案例,都是通过maven来管理的,所以maven是必备技能,对这块不熟悉的可以去看一下:Maven系列为什么需要学习spring?最大程度的简化了开发spring是一个非常优秀的java框架,其目......
  • 'FK_StudentEducation_Student_StudentTrackSignupId' 不是约束。 未能删除约束。请参
    Student主表StudentEducation从表建表的时候外键约束名写错了,不能数据库直接改通过映射文件想要删掉外键重新生成protectedoverridevoidUp(MigrationBuildermigrationBuilder){migrationBuilder.DropForeignKey("FK_StudentEducation_Student_StudentTrackSignupId",......
  • prometheus学习笔记之进程监控process_exporter
    项目地址:https://github.com/ncabatoff/process-exporter一、安装process-exporterhttps://github.com/ncabatoff/process-exporter/releases/download/v0.8.3/process-exporter-0.8.3.linux-amd64.tar.gztarxfprocess-exporter-0.8.3.linux-amd64.tar.gzmvprocess-expo......
  • 知识四:无模型强化学习
    知识四:强化学习-无模型强化学习4.1介绍Model-free方法蒙特卡罗学习(A方法)时序差分学习(B方法)TD(λ\lambdaλ)(A+B混合)、为了评估......