串级PID控制算原理及法详解

文章目录

1. PID

2. 串级PID

3. 串级PID的物理量

4. C语言实现单极PID

5. C语言实现串极PID

6. 模拟仿真


1. PID

PID是应用最广泛的闭环控制方法之一,是一种常用的反馈控制方法,对于每个PID控制器由三个部分组成:比例控制(Proportional)、积分控制(Integral)和微分控制(Derivative)。

PID三个环节的作用

由控制无人机案例我们可以总结出PID三个环节各自的主要作用和效应:

  • 比例环节:起主要控制作用,使反馈量向目标值靠拢,但可能导致振荡。

  • 积分环节:消除稳态误差,但会增加超调量。

  • 微分环节:产生阻尼效果,抑制振荡和超调,但会降低响应速度。

对于单环PID的控制算原理及法详解可以看下面这篇文章:

PID原理及控制算法详解-CSDN博客

2. 串级PID

串级PID控制是一种高级控制策略,通过使用两个(或更多)PID控制器来提高系统的稳定性和抗干扰能力。在串级控制中,外环控制器的输出作为内环控制器的设定值。图片中的示例详细解释了这种控制策略在四轴飞行器中的应用。

为什么要用串级PID?

表面上看,单一的PID控制器好像已经足够了,只要能够给出反馈,控制相应的物理量就可以了。但是,在一些复杂的系统中,单一的PID控制器可能无法满足控制需求。这时,就需要使用串级PID控制器来提高控制性能。

当进行无人机的调试时,可能会发现一个问题,如果无人机的高度与目标高度之间的距离较远的话,无人机在运动过程中的速度会很快,会导致较大的超调,而且不论怎么修改参数都很难让系统稳定。

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

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

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

图中的外环和内环就分别是一个单级PID,每个单级PID就如我们之前所说,需要获取一个目标值和一个反馈值,然后产生一个输出值。串级PID中两个环相“串”的方式就是将外环的输出作为内环的目标值。 

小车上坡的类比

  • 单环PID的输出速度V不一定是真实的速度V,因此需要在内环再加上速度环PID,构成串级PID控制。
  • 外环控制位置,输出值是小车的理论速度,内环控制速度,输入是小车的理论速度,希望尽可能的使输出为理论速度。

四轴飞行器的控制

  • 外环为角度环,输出的是期望达到该角度所需的PWM(也可以理解为角速度和PWM的映射)。
  • 内环为角速度环,输入是期望的角速度和自身真实的角速度,输出为最终的PWM(角速度)。

串级PID控制的具体实现

  • 角度环PID控制器

    • 目标是控制四轴飞行器的角度。
    • 输入:期望角度和当前角度。
    • 输出:期望角速度(角度环PID输出值)。
  • 角速度环PID控制器

    • 目标是实现期望的角速度。
    • 输入:期望角速度和当前角速度。
    • 输出:控制电机的PWM信号。

3. 串级PID的物理量

在串级PID控制系统中,有三个输入和一个输出,且被控对象需要提供两个反馈量。我们以小球控制为例,来解释这些物理量的设置。

无人机控制案例中的串级PID设计

  1. 目标值:目标值是我们希望无人机达到的位置高度。

  2. 外环反馈:外环反馈量是无人机的实时高度位置。

  3. 内环反馈:内环反馈量是无人机的实时上升速度。

  4. 输出值:输出值是施加在无人机上的推力。

外环PID控制器

  • 输入:目标高度位置和当前实际高度位置的差值(位置误差)。
  • 输出:目标上升速度。

内环PID控制器

  • 输入:目标上升速度和当前实际上升速度的差值(速度误差)。
  • 输出:控制推力。

被控对象(无人机)

  • 输入:推力。
  • 输出:无人机的上升速度和高度位置。

具体流程

目标位置

  • 系统的目标是让无人机达到指定的高度位置。

外环PID控制器

  • 外环PID控制器接收目标高度位置和当前实际高度位置,计算出位置误差。
  • 根据位置误差,外环PID控制器计算出目标上升速度。

内环PID控制器

  • 内环PID控制器接收目标上升速度和当前实际上升速度,计算出速度误差。
  • 根据速度误差,内环PID控制器计算出需要施加的推力。

无人机

  • 施加推力后,无人机的上升速度和高度位置发生变化。
  • 实际上升速度和高度位置反馈回内环和外环控制器,形成闭环控制。

在无人机控制中,内环与无人机的速度控制形成一个闭环系统,PID内环负责无人机的速度控制;而外环与内环和无人机一起构成了一个位置控制系统,外环负责位置控制。总的来说,外环根据无人机位置误差计算出无人机需要达到的速度,而内环负责计算控制推力使无人机达到这个目标速度,两个环协同工作,就可以完成任务。

之前我们说到,使用串级PID控制后,我们可以对无人机的上升速度进行控制。那么,如何进行控制呢?其实就是对外环PID的输出进行限幅。因为外环PID输出的是目标速度,限制外环输出相当于限制了无人机目标速度的最大值,内环也就会维持无人机的上升速度不超过这个最大值。

在使用串级PID后,无人机的表现会有以下改变:

平稳的上升过程

  • 无人机不再像之前那样“着急”地向目标高度冲去,而是以近似匀速的方式上升,最终平稳地到达目标高度。

限幅作用

  • 由于高度误差较大,外环输出在大部分时间都处于限幅的最大值,这意味着无人机的上升速度被限制在一个安全的范围内,不会过快导致超调。
  • 内环PID则根据这个限幅的目标速度调整推力,使无人机平稳上升。

减少超调

  • 由于外环限制了目标速度,内环使无人机的速度变化缓慢,因此几乎没有超调。无人机的速度变化慢了,控制更加平稳。

控制位置和速度

  • 通过串级PID控制,我们不仅能精确控制无人机的高度位置,还能控制其上升速度,达到双重控制的效果。

4. C语言实现单极PID

这段代码实现了一个简单的单极PID控制器。PID控制器由三个部分组成:比例(P)、积分(I)和微分(D)。

#include <stdio.h>// 定义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->error = 0;pid->lastError = 0;pid->integral = 0;pid->output = 0;
}// 进行一次PID计算
// 参数为(pid结构体, 目标值, 反馈值),计算结果放在pid结构体的output成员中
void PID_Calc(PID *pid, float reference, float feedback)
{// 更新数据pid->lastError = pid->error;  // 将旧error存起来pid->error = reference - feedback;  // 计算新error// 计算微分项float dout = (pid->error - pid->lastError) * pid->kd;// 计算比例项float pout = pid->error * pid->kp;// 计算积分项pid->integral += pid->error * pid->ki;// 积分限幅if (pid->integral > pid->maxIntegral) pid->integral = pid->maxIntegral;else if (pid->integral < -pid->maxIntegral) pid->integral = -pid->maxIntegral;// 计算输出pid->output = pout + dout + pid->integral;// 输出限幅if (pid->output > pid->maxOutput) pid->output = pid->maxOutput;else if (pid->output < -pid->maxOutput) pid->output = -pid->maxOutput;
}// 模拟设定执行器输出大小的函数
void setActuatorOutput(float output)
{// 这里是将PID的输出值应用到执行器上的代码// 在实际应用中,这可能是一个控制电机速度、阀门开度等的函数printf("Actuator Output: %f\n", output);
}// 模拟获取反馈值的函数
float getFeedbackValue()
{// 这里是获取系统当前反馈值的代码// 在实际应用中,这可能是从传感器读取的值// 这里暂时返回一个模拟值static float feedback = 0;feedback += 1;  // 模拟反馈值增加return feedback;
}// 模拟获取目标值的函数
float getTargetValue()
{// 这里是获取系统目标值的代码// 在实际应用中,这可能是从用户输入或者其他系统计算得到的// 这里暂时返回一个固定目标值return 100;
}int main()
{PID mypid = {0};  // 创建一个PID结构体变量// 初始化PID参数:比例系数10,积分系数1,微分系数5,最大积分800,最大输出1000PID_Init(&mypid, 10, 1, 5, 800, 1000);while (1) // 进入循环运行{float feedbackValue = getFeedbackValue();  // 获取被控对象的反馈值float targetValue = getTargetValue();  // 获取目标值PID_Calc(&mypid, targetValue, feedbackValue);  // 进行PID计算,结果在output成员变量中setActuatorOutput(mypid.output);  // 将PID输出应用到执行器// 模拟延时,这里使用sleep函数,单位为秒// 在实际应用中,这个值根据系统需求调整sleep(1);  // 等待1秒再开始下一次循环}return 0;
}

定义PID结构体

  • 存放PID控制器的参数和状态,包括比例、积分、微分系数,当前和上次误差,积分值和积分限幅,输出值和输出限幅。

初始化PID参数的函数

  • 初始化PID结构体的参数。

进行一次PID计算的函数

  • 计算比例、积分和微分项,并对积分和输出进行限幅,更新PID输出值。

模拟设定执行器输出大小的函数

  • 打印PID控制器的输出值。在实际应用中,这将是控制执行器的代码。

模拟获取反馈值的函数

  • 返回一个模拟的反馈值。在实际应用中,这将是从传感器获取的反馈值。

模拟获取目标值的函数

  • 返回一个模拟的目标值。在实际应用中,这将是用户输入或其他系统计算得到的目标值。

主程序

  • 初始化PID参数,进入一个无限循环,获取反馈值和目标值,进行PID计算,将PID输出应用到执行器,并等待一段时间再进行下一次循环。

5. C语言实现串极PID

串级PID的调试

在编写代码时,PID的调参的顺序是先调整内环参数,内环控制效果达到理想效果后,再调整外环参数。

下面的代码实现了一个串级PID控制系统,通过两个单级PID控制器分别控制系统的不同部分(内环和外环)。

外环PID控制器计算出目标速度,内环PID控制器根据目标速度计算出实际控制量。

这种结构可以提高系统的稳定性和响应速度,适用于复杂控制系统,如无人机高度和速度控制。

#include <stdio.h>// 定义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->error = 0;pid->lastError = 0;pid->integral = 0;pid->output = 0;
}// 进行一次PID计算
// 参数为(pid结构体, 目标值, 反馈值),计算结果放在pid结构体的output成员中
void PID_Calc(PID *pid, float reference, float feedback)
{// 更新数据pid->lastError = pid->error;  // 将旧error存起来pid->error = reference - feedback;  // 计算新error// 计算微分项float dout = (pid->error - pid->lastError) * pid->kd;// 计算比例项float pout = pid->error * pid->kp;// 计算积分项pid->integral += pid->error * pid->ki;// 积分限幅if (pid->integral > pid->maxIntegral) pid->integral = pid->maxIntegral;else if (pid->integral < -pid->maxIntegral) pid->integral = -pid->maxIntegral;// 计算输出pid->output = pout + dout + pid->integral;// 输出限幅if (pid->output > pid->maxOutput) pid->output = pid->maxOutput;else if (pid->output < -pid->maxOutput) pid->output = -pid->maxOutput;
}// 一直到这里,前面的都是单极PID的代码// 串级PID的结构体,包含两个单级PID
typedef struct
{PID inner; // 内环PID outer; // 外环float output; // 串级输出,等于inner.output
} CascadePID;// 串级PID的计算函数
// 参数(PID结构体, 外环目标值, 外环反馈值, 内环反馈值)
void PID_CascadeCalc(CascadePID *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的输出
}// 模拟设定执行器输出大小的函数
void setActuatorOutput(float output)
{// 这里是将PID的输出值应用到执行器上的代码// 在实际应用中,这可能是一个控制电机速度、阀门开度等的函数printf("Actuator Output: %f\n", output);
}// 模拟获取反馈值的函数
float getFeedbackValue()
{// 这里是获取系统当前反馈值的代码// 在实际应用中,这可能是从传感器读取的值// 这里暂时返回一个模拟值static float feedback = 0;feedback += 1;  // 模拟反馈值增加return feedback;
}// 模拟获取目标值的函数
float getTargetValue()
{// 这里是获取系统目标值的代码// 在实际应用中,这可能是从用户输入或者其他系统计算得到的// 这里暂时返回一个固定目标值return 100;
}CascadePID mypid = {0}; // 创建串级PID结构体变量int main()
{// ...其他初始化代码// 初始化内环参数:比例系数10,积分系数0,微分系数0,最大积分0,最大输出1000PID_Init(&mypid.inner, 10, 0, 0, 0, 1000);// 初始化外环参数:比例系数5,积分系数0,微分系数5,最大积分0,最大输出100PID_Init(&mypid.outer, 5, 0, 5, 0, 100);while (1) // 进入循环运行{float outerTarget = getTargetValue(); // 获取外环目标值float outerFeedback = getFeedbackValue(); // 获取外环反馈值float innerFeedback = getFeedbackValue(); // 获取内环反馈值PID_CascadeCalc(&mypid, outerTarget, outerFeedback, innerFeedback); // 进行PID计算setActuatorOutput(mypid.output); // 设定执行器输出大小// 模拟延时,这里使用sleep函数,单位为秒// 在实际应用中,这个值根据系统需求调整sleep(1); // 等待1秒再开始下一次循环}return 0;
}

6. 模拟仿真

下面这个网站可以模拟调节PID参数来控制无人机

Webpack App

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/367556.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024中国西安科博会暨硬科技产业博览会11月召开

2024第18届中国西安国际科学技术产业博览会暨硬科技产业博览会 时间&#xff1a;2024年11月3日-5日 地点&#xff1a;西安国际会展中心 主办单位&#xff1a;中国国际科学技术合作协会 陕西省科技资源统筹中心 协办单位&#xff1a;西安市科学技术协会 西安市中小企业协会、…

Hadoop3:Yarn容量调度器配置多队列案例

一、情景描述 需求1&#xff1a; default队列占总内存的40%&#xff0c;最大资源容量占总资源60%&#xff0c;hive队列占总内存的60%&#xff0c;最大资源容量占总资源80%。 二、多队列优点 &#xff08;1&#xff09;因为担心员工不小心&#xff0c;写递归死循环代码&#…

科研与英文学术论文写作指南——于静老师课程

看到了一个特别棒的科研与英文学术论文写作指南&#xff0c;理论框架实例。主讲人是中科院信息工程研究所的于静老师。推荐理由&#xff1a;写论文和读论文或者讲论文是完全不一样的&#xff0c;即使现在还没有发过论文&#xff0c;但是通过于老师的课程&#xff0c;会给后续再…

Unity之创建与导出PDF

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity之创建与导出PDF TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不断探索 TechX —— 心探索、心进取&#xff01; 助力快速…

订单服务-提交订单业务立即购买业务

文章目录 1、提交订单 业务2、在 OrderController 创建 submitOrder 方法3、 在 OrderServiceImpl 中实现 submitOrder 方法4、根据id查询sku详情&#xff08;service-product"&#xff09;5、查询用户地址保存到订单项中&#xff08;service-user&#xff09;6、删除购物…

udp发送数据如果超过1个mtu时,抓包所遇到的问题记录说明

最近在测试Syslog udp发送相关功能&#xff0c;测试环境是centos udp头部的数据长度是2个字节&#xff0c;最大传输长度理论上是65535&#xff0c;除去头部这些字节&#xff0c;可以大概的说是64k。 写了一个超过64k的数据(随便用了一个7w字节的buffer)发送demo&#xff0c;打…

USB-SC-09编程电缆使用手册

USB-SC-09编程电缆是通过电脑的USB口仿真成传统串口&#xff08;俗称COM口&#xff09;&#xff0c;从而使用现有的各种编程软件、通信软件和监控软件等&#xff0c;转换盒上的发光二极管指示数据的收发状态&#xff0c;本电缆适用于三菱FX全系列PLC USB-SC-09电缆外观&#xf…

【AIGC评测体系】大模型评测指标集

大模型评测指标集 &#xff08;☆&#xff09;SuperCLUE&#xff08;1&#xff09;SuperCLUE-V&#xff08;中文原生多模态理解测评基准&#xff09;&#xff08;2&#xff09;SuperCLUE-Auto&#xff08;汽车大模型测评基准&#xff09;&#xff08;3&#xff09;AIGVBench-T2…

【python - 数据】

一、序列 序列&#xff08;sequence&#xff09;是一组有顺序的值的集合&#xff0c;是计算机科学中的一个强大且基本的抽象概念。序列并不是特定内置类型或抽象数据表示的实例&#xff0c;而是一个包含不同类型数据间共享行为的集合。也就是说&#xff0c;序列有很多种类&…

Python数据可视化书籍推荐:利用Python进行数据分析

《利用Python进行数据分析》 这本书几乎是数据分析入门必读书了 主要介绍了python 3个库numpy&#xff08;数组&#xff09;&#xff0c;pandas&#xff08;数据分析&#xff09;和matplotlib&#xff08;绘图&#xff09;的学习 阅读本书可以获得一份关于在Python下操作、处…

2024“国培“来也UiBot6.0 RPA数字机器人开发综合应用

前言 (本博客中会有部分课程ppt截屏,如有侵权请及请及时与小北我取得联系~) 国培笔记: 依次读取数组中每个元素 输出调试信息 [ value=[ "vivian", value[0] "老师", "上午好,O(∩_∩)O哈哈~" ], v…

Ozon、美客多补单测评黑科技:打造无懈可击的自养号补单环境

不管哪个跨境平台的风控都会做升级&#xff0c;相对的补单技术也需要进行相应的做升级&#xff0c;风控升级后&#xff0c;自己养号补单需要注意以下技术问题&#xff0c;以确保补单的稳定性和安全性&#xff1a; 一、物理环境 1. 硬件参数伪装&#xff1a;平台已经开始通过I…

在手机上也能开发软件?而且只需要用几句话就可以自动生成一个应用!

随着人工智能技术的飞速发展&#xff0c;软件开发的门槛正在迅速降低。 曾几何时&#xff0c;开发一款软件需要精通编程语言和掌握复杂的开发工具&#xff0c;而如今&#xff0c;只需几句话的描述&#xff0c;便能在手机上轻松开发出功能齐全的软件。 这一切的背后&#xff0…

Steam夏促怎么注册 Steam夏促账号注册教程

随着夏日的炙热渐渐充斥着每一个角落&#xff0c;Steam平台也赶来添热闹&#xff0c;推出了一系列让人眼前一亮的夏季促销活动。如果你也是游戏爱好者&#xff0c;我们肯定不能错过这次的steam夏促。正直本次夏日促销有着很多的游戏迎来史低和新史低&#xff0c;有各种各样的游…

VSCode里python代码不扩展/级联了的解决办法

如图 解决办法&#xff1a;重新下载新的扩展工具 步骤如下 1、在左边工具栏打开Extensions 2、搜索框输入python&#xff0c;选择别的扩展工具&#xff0c;点击Install - 3在扩展工具所在的目录下&#xff0c;新建一个文件&#xff0c;就可以用了

如何通过指纹浏览器使用代理IP?

1.指纹浏览器定义 指纹浏览器是 一种浏览器技术&#xff0c;它根据用户设备的硬件、软件和配置等特征生成唯一标识符&#xff08;称为“指纹”&#xff09;。此指纹用于识别和追踪用户身份&#xff0c;即使用户更改其 IP 地址或清除浏览器数据&#xff08;如缓存和 Cookie&…

PyCharm远程开发

PyCharm远程开发 1- 远程环境说明 每个人的本地电脑环境差别很大。各自在自己电脑上开发功能&#xff0c;测试/运行正常。但是将多个人的代码功能合并&#xff0c;运行服务器上&#xff0c;会出现各种版本兼容性问题。 在实际企业中&#xff0c;一般会有两套环境。第一套是测…

Jenkins教程-13-参数化任务构建

上一小节我们学习了发送html邮件测试报告的方法&#xff0c;本小节我们讲解一下Jenkins参数化任务构建的方法。 很多时候我们需要根据不同的条件去执行构建&#xff0c;如自动化测试中执行test、stg、prod环境的构建&#xff0c;Jenkins是支持参数化构建的。 以下是Jenkins官…

【C++】using namespace std 到底什么意思

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文作为 JohnKi 的学习笔记&#xff0c;引用了部分大佬的案例 &#x1f4e2;未来很长&a…

【C++】多态详解

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 一、多态概念 二、多态的定义及实现 1. 多态的构成条件 2. 虚函数 2.1 什么是虚函数 2.2 虚函数的重写 2.3 虚函数重写的两个…