关于无人机上层控制的PID算法的思考

news2024/9/26 1:27:44

一、前言

背景介绍:PID虽然出现了很多年,但是目前工业界还是把PID作为主流的控制算法(尽管学术界有很多非常时尚的控制算法,包括鲁邦控制,神经网络控制等等),PID的算法在于其不需要对系统进行复杂的建模,就可以完成比较好的控制效果。
PID算法的优势在于其非常简单,很多时候算法好不好取决于对参数的设置,所以很多时候,PID算法其实是一个体力活,主要精力都在于寻找最优参数去了。当然,对于开环系统就不用说这种PID算法了
PID算法只适合于闭合系统。对于非线性系统,时滞比较严重的系统个人也不建议使用PID,这种情况控制效果不怎么好。

二、算法介绍

  • 开环控制系统
    在这里插入图片描述
    在开环控制系统中,系统输出只受输入的控制,控制精度和抑制干扰的特性都比较差。就没有什么误差控制输入的说法,就不谈什么PID了

  • 闭环控制系统
    在这里插入图片描述

PID简介:PID控制应该算是应用非常广泛的控制算法了。小到控制一个元件的温度,大到控制无人机的飞行姿态和飞行速度等等,都可以使用PID控制。这里我们从原理上来理解PID控制。
PID(proportion integration differentiation)其实就是指比例,积分,微分控制。
在这里插入图片描述
公式描述如下:
在这里插入图片描述
其中U(t)是PID控制器的输出,PID控制器的输出是执行器的输入,如果我们知道执行器的模型,就可以实行精确控制。
这里我们引用知乎上的作者例子知乎网址为了简单说明情况和好理解,知乎这边文章里面把控制器和执行器进行了等价,就是控制器输出等于执行器输出。

2.1、P控制算法

  我们先说PID中最简单的比例控制,抛开其他两个不谈。还是用一个经典的例子吧。假设我有一个水缸,最终的控制目的是要保证水缸里的水位永远的维持在1米的高度。假设初始时刻,水缸里的水位是0.2米,那么当前时刻的水位和目标水位之间是存在一个误差的error,且error为0.8.这个时候,假设旁边站着一个人,这个人通过往缸里加水的方式来控制水位。如果单纯的用比例控制算法,就是指加入的水量u和误差error是成正比的。即
  u=kp*error  设kp=0.5
  那么t=1时(表示第1次加水,也就是第一次对系统施加控制),那么u=0.50.8=0.4,所以这一次加入的水量会使水位在0.2的基础上上升0.4,达到0.6.
  接着,t=2时刻(第2次施加控制),当前水位是0.6,所以error是0.4。u=0.5
0.4=0.2,会使水位再次上升0.2,达到0.8.
如此这么循环下去,就是比例控制算法的运行方法。
可以看到,最终水位会达到我们需要的1米。(无限下去数学上面就是一个逼近1m的求和级数,但是是永远达不到准确的1m的)
  但是,单单的比例控制存在着一些不足,其中一点就是 –稳态误差。
像上述的例子,根据kp取值不同,系统最后都会达到1米,只不过kp大了到达的快,kp小了到达的慢一些。不会有稳态误差。但是,考虑另外一种情况,假设这个水缸在加水的过程中,存在漏水的情况,假设每次加水的过程,都会漏掉0.1米高度的水。仍然假设kp取0.5,那么会存在着某种情况,假设经过几次加水,水缸中的水位到0.8时,水位将不会再变换!!!因为,水位为0.8,则误差error=0.2. 所以每次往水缸中加水的量为u=0.5*0.2=0.1.同时,每次加水,缸里又会流出去0.1米的水!!!加入的水和流出的水相抵消,水位将不再变化!!
也就是说,我的目标是1米,但是最后系统达到0.8米的水位就不再变化了,且系统已经达到稳定。由此产生的误差就是稳态误差了。
(上诉例子是一个增量PID控制算法的解释,具体什么是增量控制算法,后续会说,先有个基本概念)

2.2 I控制算法

  还是用上面的例子,如果仅仅用比例,可以发现存在暂态误差,最后的水位就卡在0.8了。于是,在控制中,我们再引入一个分量,该分量和误差的积分是正比关系。所以,比例+积分控制算法为:
  u=kp*error+ ki∗∫ error
还是用上面的例子来说明,第一次的误差error是0.8,第二次的误差是0.4,至此,误差的积分(离散情况下积分其实就是做累加),∫error=0.8+0.4=1.2. 这个时候的控制量,除了比例的那一部分,还有一部分就是一个系数ki乘以这个积分项。由于这个积分项会将前面若干次的误差进行累计,所以可以很好的消除稳态误差(假设在仅有比例项的情况下,系统卡在稳态误差了,即上例中的0.8,由于加入了积分项的存在,会让输入增大,从而使得水缸的水位可以大于0.8,渐渐到达目标的1.0.)这就是积分项的作用。

2.3 D控制算法

  换一个另外的例子,考虑刹车情况。平稳的驾驶车辆,当发现前面有红灯时,为了使得行车平稳,基本上提前几十米就放松油门并踩刹车了。当车辆离停车线非常近的时候,则使劲踩刹车,使车辆停下来。整个过程可以看做一个加入微分的控制策略。
微分,说白了在离散情况下,就是error的差值,就是t时刻和t-1时刻error的差,即u=kd*(error(t)-error(t-1)),其中的kd是一个系数项。可以看到,在刹车过程中,因为error是越来越小的,所以这个微分控制项一定是负数,在控制中加入一个负数项,他存在的作用就是为了防止汽车由于刹车不及时而闯过了线。从常识上可以理解,越是靠近停车线,越是应该注意踩刹车,不能让车过线,所以这个微分项的作用,就可以理解为刹车,当车离停车线很近并且车速还很快时,这个微分项的绝对值(实际上是一个负数)就会很大,从而表示应该用力踩刹车才能让车停下来。
切换到上面给水缸加水的例子,就是当发现水缸里的水快要接近1的时候,加入微分项,可以防止给水缸里的水加到超过1米的高度,说白了就是减少控制过程中的震荡。

3、PID控制算法的变形

3.1连续PID

在这里插入图片描述

虽然在教程和文献中有各种时间常数,比如TI TD这种,但是由于其本质也是一个参数,所以很多人为了方便,最后统一成了Kp,KI,Kd
在这里插入图片描述
在这里插入图片描述

3.2(位置型)数字PID

在这里插入图片描述
数字也是一样,可以简化为,
在这里插入图片描述
在这里插入图片描述
C++代码

#include <iostream>

class PositionPID {
private:
    double kp;  // 比例增益
    double ki;  // 积分增益
    double kd;  // 微分增益
    double prevError;  // 上一次误差
    double integral;   // 积分项累加值

public:
    PositionPID(double kp, double ki, double kd) : kp(kp), ki(ki), kd(kd), prevError(0), integral(0) {}

    double calculate(double setpoint, double current) {
        double error = setpoint - current;
        integral += error;
        
        double output = kp * error + ki * integral + kd * (error - prevError);
        
        prevError = error;
        return output;
    }
};

int main() {
    // 示例使用
    double setpoint = 50.0;  // 目标值
    double current = 0.0;   // 当前值

    PositionPID positionPID(0.1, 0.01, 0.05);  // 用具体的参数值初始化PID控制器

    for (int i = 0; i < 100; ++i) {
        double output = positionPID.calculate(setpoint, current);
        // 在实际系统中应用输出值,更新当前值 current
        // 这里仅简单输出控制器的输出值
        std::cout << "Iteration " << i << ": Output = " << output << std::endl;
    }

    return 0;
}

3.2增量型数字PID

在这里插入图片描述

C++代码

#include <iostream>

class IncrementalPID {
private:
    double kp;  // 比例增益
    double ki;  // 积分增益
    double kd;  // 微分增益
    double prevOutput;  // 上一次的输出
    double prevError;   // 上一次误差

public:
    IncrementalPID(double kp, double ki, double kd) : kp(kp), ki(ki), kd(kd), prevOutput(0), prevError(0) {}

    double calculate(double setpoint, double current) {
        double error = setpoint - current;
        
        double pTerm = kp * error;
        double iTerm = ki * (error + prevError);
        double dTerm = kd * (error - prevError);
        
        double output = prevOutput + pTerm + iTerm + dTerm;

        prevOutput = output;
        prevError = error;

        return output;
    }
};

int main() {
    // 示例使用
    double setpoint = 50.0;  // 目标值
    double current = 0.0;   // 当前值

    IncrementalPID incrementalPID(0.1, 0.01, 0.05);  // 用具体的参数值初始化PID控制器

    for (int i = 0; i < 100; ++i) {
        double output = incrementalPID.calculate(setpoint, current);
        // 在实际系统中应用输出值,更新当前值 current
        // 这里仅简单输出控制器的输出值
        std::cout << "Iteration " << i << ": Output = " << output << std::endl;
    }

    return 0;
}

个人总结

在无人机项目中,我为了迫使无人机姿态一直处于目标中央,通过调整无人机yaw角度来使用水平方向使得识别的目标一直处于无人机中央,但是给出的代码确实直接假设了控制输出等于执行器输入这里绝对是错误的,PID控制器的输出是图像目标中心位置640,但是不能简单的将这个输出等价于偏航角。


Command_Now.Reference_State.yaw_ref =incrementalPID.calculate(set_target_x , now_target_x); ;//PID角度控制


实际情况是对控制器的输出的目标位置量与角度调整量进行建模,而不是将二者简单相等。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

跟着小德学C++之安全模块

嗨&#xff0c;大家好&#xff0c;我是出生在达纳苏斯的一名德鲁伊&#xff0c;我是要立志成为海贼王&#xff0c;啊不&#xff0c;是立志成为科学家的德鲁伊。最近&#xff0c;我发现我们所处的世界是一个虚拟的世界&#xff0c;并由此开始&#xff0c;我展开了对我们这个世界…

Spring Security 6.x 系列(15)—— 会话管理之源码分析

一、前言 在上篇 Spring Security 6.x 系列(13)—— 会话管理之会话概念及常用配置 Spring Security 6.x 系列(14)—— 会话管理之会话固定攻击防护及Session共享 中了清晰了协议和会话的概念、对 Spring Security 中的常用会话配置进行了说明,并了解会话固定攻击防护…

WorkPlus完备的企业级功能堆栈,打造高效的企业移动平台

在如今的数字化时代&#xff0c;企业需要一个完备的功能堆栈来满足复杂的业务需求。WorkPlus作为一个完整的企业级移动平台&#xff0c;拥有完备的企业级功能&#xff0c;如IM、通讯录、内部群、模板群、工作台、权限管控、应用中心、日程管理、邮箱、同事圈、服务号、智能表单…

【Docker-Dev】Mac M2 搭建docker的redis环境

Redis的dev环境docker搭建 1、前言2、官方文档重点信息提取2.1、创建redis实例2.2、使用自己的redis.conf文件。 3、单机版redis搭建4、redis集群版4.1、一些验证4.2、一些问题 结语 1、前言 本文主要针对M2下&#xff0c;相应进行开发环境搭建&#xff0c;然后做一个文档记录…

FreeRTOS学习第6篇–任务状态挂起恢复删除等操作

目录 FreeRTOS学习第6篇--任务状态挂起恢复删除等操作任务的状态设计实验IRReceiver_Task任务相关代码片段实验现象本文中使用的测试工程 FreeRTOS学习第6篇–任务状态挂起恢复删除等操作 本文目标&#xff1a;学习与使用FreeRTOS中的几项操作&#xff0c;有挂起恢复删除等操作…

自动驾驶apollo9.0 Dreamview Debug方法

Apollo 9.0 安装&编译方法 # 拉取源码 git clone gitgithub.com:ApolloAuto/apollo.git git checkout v9.0.0# 启动docker bash docker/scripts/dev_start.sh bash docker/scripts/dev_into.sh# 编译project ./apollo.sh build默认启动方式 default mode wget https:…

MybatisPlus—自定义SQL

目录 1. 自定义SQL介绍 2. 自定义SQL使用步骤 3. 自定义SQL实例 4.总结 1. 自定义SQL介绍 介绍&#xff1a;自定义SQL并不是由我们来编写全部SQL语句&#xff0c;而是通过利用MyBatisPlus的Wrapper来构建复杂的Where条件&#xff0c;然后自己定义SQL语句中剩下的部分。 使…

详细全面的postman接口测试实战教程

基本介绍 postman是一款流程的接口调试工具&#xff0c;其特点就是使用简单&#xff0c;功能强大。使用角色也非常广泛&#xff0c;后端开发&#xff0c;前端人员&#xff0c;测试人员都可以使用它进行接口调试或测试。 基本框架 如果把postman去其内容只保留框架的话&#…

WorkPlus安全专属的即时通讯解决方案,助力企业高效沟通协作

在当今快节奏的商业环境中&#xff0c;高效的即时通讯是企业成功的关键。而WorkPlus作为一种领先的即时通讯工具&#xff0c;以其卓越的性能和创新的功能&#xff0c;助力企业高效沟通和协作。 WorkPlus作为即时通讯的新选择&#xff0c;为何备受企业的青睐&#xff1f;首先&am…

【JaveWeb教程】(7)Web前端基础:Vue组件库Element介绍与快速入门程序编写并运行 示例

目录 Element介绍快速入门示例 Element介绍 不知道同学们还否记得我们之前讲解的前端开发模式MVVM&#xff0c;我们之前学习的vue是侧重于VM开发的&#xff0c;主要用于数据绑定到视图的&#xff0c;那么接下来我们学习的ElementUI就是一款侧重于V开发的前端框架&#xff0c;主…

使用ChatGPT生成i项目需求文档模板

前言 我们在工作中需要编写的技术文档有多种形式&#xff0c;包括Word、Excel、PDF及一些在线形式。我们可以借助ChatGPT生成文本&#xff0c;然而&#xff0c;它不能直接生成Word、Excel、PDF等格式的文档。因此&#xff0c;我们需要利用其他工具来帮助我们生成一些模板&…

linux反汇编工具: ida pro、rizinorg/cutter; ubuntu 22 flameshot延迟截图 以应对下拉菜单

rizinorg/cutter rizinorg/cutter 是 命令行反汇编工具 rizinorg/rizin 的图形化界面, 这比 ida pro跑在kvm虚拟机中方便多了, ubuntu22.04下直接下载Cutter-v2.3.2-Linux-x86_64.AppImage后即可运行,如下图: 注意 有个同名的报废品: radare2/Cutter 即 radare2的图形化界…

软件测试|Linux三剑客之grep命令详解

简介 grep是一款在 Linux 和类 Unix 系统中广泛使用的文本搜索工具。它的名字来源于 Global Regular Expression Print&#xff08;全局正则表达式打印&#xff09;&#xff0c;它的主要功能是根据指定的模式&#xff08;正则表达式&#xff09;在文本文件中搜索并打印匹配的行…

JavaScript异常处理实战

前言 之前在对公司的前端代码脚本错误进行排查&#xff0c;试图降低 JS Error 的错误量&#xff0c;结合自己之前的经验对这方面内容进行了实践并总结&#xff0c;下面就此谈谈我对前端代码异常监控的一些见解。 本文大致围绕下面几点展开讨论&#xff1a; JS 处理异常的方式…

抖音在线查权重系统源码,附带查询接口

抖音权重在线查询只需输入抖音主页链接&#xff0c;即可查询作品情况。 搭建教程 上传源码并解压 修改数据库“bygoukai.sql” 修改“config.php” 如需修改水印请修改第40行 如需修改限制次数&#xff0c;请修改第156行 访问域名user.php即可查看访问用户&#xff0c;停…

学习笔记——C++运算符之赋值运算符

上次我们说到C的运算符共有四种&#xff0c;分别是算术运算符&#xff0c;赋值运算符&#xff0c;比较运算符和逻辑运算符 &#xff0c;下面介绍赋值运算符&#xff0c;赋值运算符主要的种类及作用如下表所示。 #include<bits/stdc.h> using namespace std; int main(){…

MediaPipeUnityPlugin(最新版)摇摆拳人脸识别

1、从https://github.com/homuler/MediaPipeUnityPlugin 下载Release Package 目前是MediaPipeUnity.0.12.0.unitypackage 2、导入Unity工程 3、打开Face Detection场景&#xff0c;做一些设置修改 1、打开Bootstrap&#xff0c;图像源改成Video&#xff0c;把Solution拖拽到…

车辆运动学方程推导和代码实现

文章目录 1. 运动学方程2. 模型实现 1. 运动学方程 自行车模型&#xff08;Bicycle Model&#xff09;是车辆数字化模型中最常见的一种运动学模型。其除了可以反映车辆的一些基础特性外&#xff0c;更重要的是简单易用。通常情况下我们会把车辆模型简化为二自由度的自行车模型…

Vue 中的 ref 与 reactive:让你的应用更具响应性(中)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

SD点击扩展的可用 想下载其他插件的时候报错

这个错误通常是由于命令行标志禁用了扩展访问所导致的。 您可以尝试在启动WebUI的时候添加一个参数–enable-insecure-extension-access&#xff0c;或者在webui-user.sh的export COMMANDLINE_ARGS参数中增加以下参数 --enable-insecure-extension-access。