串级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,最大输出1000
    PID_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,最大输出1000
    PID_Init(&mypid.inner, 10, 0, 0, 0, 1000);
    // 初始化外环参数:比例系数5,积分系数0,微分系数5,最大积分0,最大输出100
    PID_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.mfbz.cn/a/769909.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

自然语言处理与Transformer模型:革新语言理解的新时代

引言 自然语言处理&#xff08;NLP&#xff09;是人工智能和计算机科学的一个重要分支&#xff0c;旨在使计算机能够理解、生成和处理人类语言。随着互联网和数字化信息的爆炸性增长&#xff0c;NLP在许多领域中的应用变得越来越重要&#xff0c;包括&#xff1a; 搜索引擎&am…

SCI丨一篇待投2区,计算机结合复合材料

题目:基于空间状态xxxx智能复合材料板的声辐射控制 期刊&#xff1a;2区 状态&#xff1a;准备提交 摘要&#xff1a;研究了xxxxx无限流体介质相互作用的有源声辐射的影响。

JAVA实现二分查找,斐波那契数列,深度优先搜索详情教程【包含代码】

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

计算机网络 | 期末复习

物理层&#xff1a; 奈氏准则&#xff1a;带宽&#xff08;w Hz&#xff09;&#xff0c;在不考虑噪音的情况下&#xff0c;最大速率&#xff08;2W&#xff09;码元/秒 信噪比S/N&#xff1a;以分贝&#xff08;dB&#xff09;为度量单位。信噪比&#xff08;dB&#xff09;…

ueditor集成秀米编辑器

ueditor集成秀米编辑器 一、背景二、集成秀米编辑器流程2.1、新增秀米插件的按钮&#xff0c;显示在我们的富文本编辑器上2.2、点击该按钮&#xff0c;可以呼出一个iframe&#xff0c;这个iframe引用的是秀米自己的编辑器页面2.3、要是有图片&#xff0c;需要再修改配置哈2.4、…

react ts 封装3D柱状图,支持渐变

留档&#xff0c;以防忘记 bar3D.tsx import React, { useEffect, useRef, useState } from react; import * as echarts from echarts; import echarts/lib/chart/bar; import echarts/lib/chart/pictorialBar; import echarts/lib/component/grid; import echarts/lib/comp…

HTML总结2

什么是HTML HTML&#xff08;Hypertext Markup Language&#xff09;&#xff0c;超文本标记语言&#xff0c;&#xff08;是一套标记标签&#xff0c;一般用来描述网页&#xff09;。 HTML标签 HTML标记标签&#xff0c;通常被称为HTML标签&#xff0c;或者HTML标记。 标签…

VScode使用ssh连接服务器

VScode是一款有丰富插件的编译器&#xff0c;非常好用&#xff01;除非你不会用&#xff0c;因为太过繁琐或着频繁出错导致想把电脑砸了&#xff1b; 插件选择 ssh 配置文件 Host myblablaHostName xxx.xx.xxx.xxxUser username用户名一般是服务器上创建有什么用户名&#xf…

【STM32】在标准库中使用DMA

1.MDA简介 DMA全称Direct Memory Access,直接存储区访问。 DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作&#xff0c;传输动作本身是由DMA控制器来实现和完成的。DMA传输方式无需CPU直接控制传输&#xff0c;也没有中断处理方式那样保留现场和…

seq2seq+Attention机制原理介绍

一、Seq2seq的局限性 Seq2seq&#xff08;序列到序列&#xff09;模型我们在前面讲了它的原理&#xff0c;是一种广泛用于处理序列转换任务的深度学习架构&#xff0c;特别是在机器翻译、文本摘要、对话生成等应用中。然而&#xff0c;尽管seq2seq模型在某些领域取得了显著的成…

使用 Python2.7 抓取 systrace 文件

为了排查安卓终端系统底层问题&#xff0c;需要抓取终端的systrace文件分析&#xff0c;下面是操作步骤&#xff1a; 1、安装python 2.7 2、打开cmd执行命令安装python包&#xff1a;pip install pypiwin32 3、解压six-1.16.0.tar.gz&#xff0c;进入目录用命令安装six&#xf…

《UDS协议从入门到精通》系列——图解0x84:安全数据传输

《UDS协议从入门到精通》系列——图解0x84&#xff1a;安全数据传输 一、简介二、数据包格式2.1 服务请求格式2.2 服务响应格式2.2.1 肯定响应2.2.2 否定响应 Tip&#x1f4cc;&#xff1a;本文描述中但凡涉及到其他UDS服务的&#xff0c;均提供专栏内文章链接跳转方式以便快速…

Stable Diffusion最强功能—— 图片背景完美替换

今天分享 Stable Diffusion 图片背景完美替换 功能&#xff0c;通过 Stable Diffusion 图生图重绘蒙版进行背景图的二次重绘。 在广告产品图、头像背景替换、图片后期处理等场景下用到的都很频繁。 整体步骤&#xff1a; 通过 removebg 插件实现图片主体蒙版的抠图 结合图生…

提升研发效能的67个技术点丨IDCF

在当今快速变化的市场环境中&#xff0c;企业要想保持竞争力&#xff0c;就必须不断提高研发效率。高效的研发不仅能够帮助企业快速响应市场需求&#xff0c;还能降低成本、提高产品质量。本文让我们一起来看一下&#xff0c;作为微软18年MVP的技术大咖徐磊老师&#xff0c;梳理…

HTML CSS 基础复习笔记 - 列表使用

用于自己复习 自定义列表 示例代码 <!DOCTYPE html> <html> <head><title>Definition List Example</title> </head> <body><h1>古诗</h1><dl><dt>静夜思</dt><dd>床前明月光&#xff0c;疑…

使用dot来画流程图

Dot是一种图形描述语言&#xff0c;属于Graphviz软件的一部分。Graphviz是一个用于可视化图形&#xff08;图表、网络图等&#xff09;的开源工具集。使用Dot语言&#xff0c;你可以创建并描述节点和边&#xff0c;从而生成图形。以下是如何使用Dot语言画图的基本步骤&#xff…

修复 OpenSSH 爆出极其严重的安全漏洞!

最近几天OpenSSH爆出了一个高危漏洞&#xff1a;CVE-2024-6387&#xff0c;影响到了很多的Linux服务器系统。明月第一时间给所有的代维客户服务器进行了排查和漏洞修复&#xff0c;因此耽搁了一些时间。直到今天才算抽出空来给大家分享一下。严格上来说这个漏洞的危险性还是极高…

Beyond Compare 解锁版下载及安装教程 (文件和文件夹比较工具)

前言 Beyond Compare 是一款功能强大的文件和文件夹比较工具。它支持文件夹比较、文件夹合并与同步、文本比较、表格比较、图片比较、16进制比较、注册表比较、版本比较等多种功能。通过 Beyond Compare&#xff0c;您可以轻松调查文件和文件夹之间的不同之处&#xff0c;并使…

MySQL篇-SQL优化实战-减少子查询

回顾 上一篇了解了分析SQL使用的explain&#xff0c;可以点击查看MySQL篇-SQL优化实战了解我在写sql的注意事项还有explain的说明&#xff0c;这次拿一段生产使用的sql进行优化说明。从14s优化到2.6s 待优化的SQL SELECT DISTINCTswpe.tag_number,hca.ACCOUNT_NAME customer…

ELFK简介

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;CSDN博客专家   &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01…