【面试五】PID控制算法

一、 PID算法简介

        PID(Proportional-Integral-Derivative)控制算法是一种经典的反馈控制方法,广泛应用于自动控制系统,例如温度控制、速度控制、位置控制等。

        PID控制算法的核心包含三个部分:比例项(P),积分项(I),和微分项(D)。它们分别对系统的当前误差、过去误差的积累和误差的变化率进行响应。PID控制器的输出由这三部分的加权和组成。

        PID控制算法通过结合比例、积分和微分三种控制作用,对被控对象的偏差进行精确控制,以达到期望的控制效果。其基本原理可以概括为:

  1. 比例控制(P):根据偏差的大小成比例地调整输出,以减小偏差。比例控制能迅速反映偏差,但无法消除静差(即系统稳定时的偏差)。
  2. 积分控制(I):对偏差进行积分,以消除系统的稳态误差。积分控制作用与偏差的存在时间有关,只要系统存在偏差,积分控制就会不断起作用,直至偏差消除。
  3. 微分控制(D):根据偏差的变化趋势(即偏差的变化率)进行超前控制,以抑制偏差的进一步变化。微分控制有助于减小系统的超调和振荡,提高系统的动态性能。

二、两种变换公式

三、C语言算法代码

1.加入mpu6050的PID算法
        (1)主函数里的逻辑:
// 自己定义的中间参数
int Balance_Pwm, Velocity_Pwm, Turn_Pwm; // PID计算的PWM值
int Motor1, Motor2;						 // 左右电机PWM值
int Encoder_left, Encoder_right;		 // 检测速度
float Movement = 0;						 // 速度调节
int Contrl_Turn = 64;					 // 转向调节变量// mpu6050数据采集
void mpu6050_data(void)
{static struct mpu6050_data Last_Data;if (mpu_dmp_get_data() != 0)OutMpu = Last_Data;elseLast_Data = OutMpu;
}// 平衡小车PID算法
void PID_test(void)
{Encoder_left = Read_Encoder(1);	  // 读取编码器值(当作小车当前前进的速度)Encoder_right = -Read_Encoder(2); // 读取编码器值(当作小车当前前进的速度)// 1、确定直立环PWMBalance_Pwm = Vertical_Ring_PD(OutMpu.pitch, OutMpu.gyro_x);// 2、确定速度环PWMVelocity_Pwm = Vertical_speed_PI(Encoder_left, Encoder_right, OutMpu.pitch, Movement);// 3、确定转向环PWMTurn_Pwm = Vertical_turn_PD(Contrl_Turn, OutMpu.gyro_z);// 4、确定最终左右电机的PWMMotor1 = Balance_Pwm + Velocity_Pwm + Turn_Pwm;Motor2 = Balance_Pwm + Velocity_Pwm - Turn_Pwm;PWM_Limiting(&Motor1, &Motor2);	// PWM限幅函数// 5、设置电机Set_PWM(Motor1, Motor2);
}
        (2)PID算法封装:
#include "math.h"
#include "stdlib.h"
#include "stm32f4xx_hal.h"
#include "contrl.h"int Dead_Zone = 1200;  // 电机死区// PID调节参数
struct pid_arg PID = {.Balance_Kp = 200,.Balance_Kd = 1,.Velocity_Kp = -56,.Velocity_Ki = -0.28,.Turn_Kp = 18,.Turn_Kd = 0.18,
};/***************************************************************************************************************函数名:Read_Encoder()*功能:读取编码器值(当作小车当前前进的速度)*形参:(u8 TIMX):x为编码器1或者2*返回值:无*************************************************************************************************************/
int Read_Encoder(u8 TIMX)
{int Encoder_TIM;switch (TIMX){case 1:Encoder_TIM = (short)TIM1->CNT;TIM1->CNT = 0;break;case 2:Encoder_TIM = (short)TIM2->CNT;TIM2->CNT = 0;break;default:Encoder_TIM = 0;}return Encoder_TIM;
}/***************************************************************************************************************函数名:Vertical_Ring_PD()*功能:直立环PD控制*形参:(float Angle):x轴的角度/(float Gyro):x轴的角速度*返回值:经过PID转换之后的PWM值**************************************************************************************************************/
// 直立环的PDint Vertical_Ring_PD(float Angle, float Gyro)
{float Bias;int balance;Bias = Angle - Mechanical_balance;balance = PID.Balance_Kp * Bias + Gyro * PID.Balance_Kd;return balance;
}/***************************************************************************************************************函数名:Vertical_speed_PI()*功能;速度环PI控制*形参:(int encoder_left):左轮编码器值/(int encoder_right):编码器右轮的值/(float Angle):x轴角度值*返回值:**************************************************************************************************************/int Vertical_speed_PI(int encoder_left, int encoder_right, float Angle, float Movement)
{static float Velocity, Encoder_Least, Encoder;static float Encoder_Integral;Encoder_Least = (encoder_left + encoder_right) - 0; // 获取最新速度偏差=测量速度(左右编码器之和)-目标速度(此处为零)Encoder *= 0.8f;									// 一阶低通滤波器 ,上次的速度占85%Encoder += Encoder_Least * 0.2f;					// 一阶低通滤波器, 本次的速度占15%Encoder_Integral += Encoder;						// 积分出位移 积分时间:10msEncoder_Integral = Encoder_Integral - Movement;if (Encoder_Integral > 10000)Encoder_Integral = 10000; // 积分限幅if (Encoder_Integral < -10000)Encoder_Integral = -10000; // 积分限幅Velocity = Encoder * PID.Velocity_Kp + Encoder_Integral * PID.Velocity_Ki; // 速度控制if (Turn_off(Angle) == 1)Encoder_Integral = 0; // 电机关闭后清除积分return Velocity;
}/***************************************************************************************************************函数名:Vertical_turn_PD()*功能:转向环PD*形参:无  CCD小于64左转、CCD大于64右转。 yaw = z轴陀螺仪数值*返回值:无***************************************************************************************************************/
int Vertical_turn_PD(u8 CCD, short yaw)
{float Turn;float Bias;Bias = CCD - 64;Turn = -Bias * PID.Turn_Kp - yaw * PID.Turn_Kd;return Turn;
}/***************************************************************************************************************函数名:PWM_Limiting()*功能:PWM限幅函数*形参:无*返回值:无***************************************************************************************************************/
void PWM_Limiting(int *motor1, int *motor2)
{int Amplitude = 5800;if (*motor1 < -Amplitude)*motor1 = -Amplitude;if (*motor1 > Amplitude)*motor1 = Amplitude;if (*motor2 < -Amplitude)*motor2 = -Amplitude;if (*motor2 > Amplitude)*motor2 = Amplitude;
}/***************************************************************************************************************函数名:Turn_off()*功能:关闭电机*形参:(const float Angle):x轴角度值*返回值:1:小车当前处于停止状态/0:小车当前处于正常状态***************************************************************************************************************/
u8 FS_state;u8 Turn_off(const float Angle)
{u8 temp;if (fabs(Angle) > 80){FS_state = 1;temp = 1;AIN2(0), AIN1(0);BIN1(0), BIN2(0);}elsetemp = 0;FS_state = 0;return temp;
}/***************************************************************************************************************函数名:Set_PWM()*功能:输出PWM控制电机*形参;(int motor1):电机1对应的PWM值/(int motor2):电机2对应的PWM值*返回值:无*************************************************************************************************************/void Set_PWM(int motor1, int motor2)
{if (motor1 > 0)AIN2(1), AIN1(0);elseAIN2(0), AIN1(1);PWMA = Dead_Zone + (abs(motor1)) * 1.17;if (motor2 > 0)BIN1(1), BIN2(0);elseBIN1(0), BIN2(1);PWMB = Dead_Zone + (abs(motor2)) * 1.17;//	printf("PWMA = %d\n",PWMA);//	printf("PWMB = %d\n",PWMB);
}
2.纯PID算法 
        (1)PID.c
#include "pid.h"//定义一个结构体类型变量
tPid pidMotor1Speed;
//给结构体类型变量赋初值
void PID_init()
{pidMotor1Speed.actual_val=0.0;pidMotor1Speed.target_val=0.00;pidMotor1Speed.err=0.0;pidMotor1Speed.err_last=0.0;pidMotor1Speed.err_sum=0.0;pidMotor1Speed.Kp=0;pidMotor1Speed.Ki=0;pidMotor1Speed.Kd=0;
}
//比例p调节控制函数
float P_realize(tPid * pid,float actual_val)
{pid->actual_val = actual_val;//传递真实值pid->err = pid->target_val - pid->actual_val;//当前误差=目标值-真实值//比例控制调节   输出=Kp*当前误差pid->actual_val = pid->Kp*pid->err;return pid->actual_val;
}
//比例P 积分I 控制函数
float PI_realize(tPid * pid,float actual_val)
{pid->actual_val = actual_val;//传递真实值pid->err = pid->target_val - pid->actual_val;//当前误差=目标值-真实值pid->err_sum += pid->err;//误差累计值 = 当前误差累计和//使用PI控制 输出=Kp*当前误差+Ki*误差累计值pid->actual_val = pid->Kp*pid->err + pid->Ki*pid->err_sum;return pid->actual_val;
}
// PID控制函数
float PID_realize(tPid * pid,float actual_val)
{pid->actual_val = actual_val;//传递真实值pid->err = pid->target_val - pid->actual_val;当前误差=目标值-真实值pid->err_sum += pid->err;//误差累计值 = 当前误差累计和//使用PID控制 输出 = Kp*当前误差  +  Ki*误差累计值 + Kd*(当前误差-上次误差)pid->actual_val = pid->Kp*pid->err + pid->Ki*pid->err_sum + pid->Kd*(pid->err - pid->err_last);//保存上次误差: 这次误差赋值给上次误差pid->err_last = pid->err;return pid->actual_val;
}
        (2)PID.h 
#ifndef __PID_H
#define __PID_H//声明一个结构体类型
typedef struct 
{float target_val;//目标值float actual_val;//实际值float err;//当前偏差float err_last;//上次偏差float err_sum;//误差累计值float Kp,Ki,Kd;//比例,积分,微分系数} tPid;//声明函数
float P_realize(tPid * pid,float actual_val);
void PID_init(void);
float PI_realize(tPid * pid,float actual_val);
float PID_realize(tPid * pid,float actual_val);
#endif

四、PID控制算法的应用和优化

1.PID控制算法的应用

        PID控制算法因其结构简单、易于实现、鲁棒性好等特点,被广泛应用于各种工业控制系统中。具体来说,其应用领域包括但不限于:

        (1)温度控制:在温度控制系统中,PID控制器通过调节加热或制冷设备的功率,使系统温度稳定在设定值附近。例如,在塑料加工、食品加工等行业中,精确的温度控制对于保证产品质量至关重要。

        (2)压力控制:在液压、气压等系统中,PID控制器用于维持系统压力的稳定。通过调节阀门开度或泵的输出功率,PID控制器能够迅速响应压力变化,保持系统压力在设定范围内。

        (3)流量控制:在液体或气体流量控制系统中,PID控制器通过调节阀门的开度或泵的转速,实现对流量的精确控制。这对于化工、水处理等行业中的流体传输和分配具有重要意义。

        (4)电机控制:在电机控制系统中,PID控制器用于调节电机的转速和转矩。通过实时监测电机的运行状态和负载情况,PID控制器能够调整电机的输入电压或电流,以实现电机的稳定运行和精确控制。

        (5)飞行控制:在无人机、飞机等飞行器的控制系统中,PID控制器用于实现飞行器的姿态、速度和位置等参数的精确控制。通过调整飞行器的舵面偏角或发动机推力等参数,PID控制器能够确保飞行器按照预定的轨迹和姿态飞行。

2.PID控制算法的优化

        尽管PID控制算法具有广泛的应用价值,但在实际应用中仍需要根据系统的具体特性和控制要求进行优化,以提高控制性能。以下是一些常用的PID控制算法优化方法:

        (1)参数整定:PID控制器的性能很大程度上取决于比例、积分和微分系数的选择。因此,需要根据实际系统的特性进行参数整定,以找到最优的参数组合。常用的参数整定方法有试凑法、临界比例度法、衰减曲线法和人工智能优化算法等。

        (2)积分饱和限制:为了避免积分饱和现象对系统性能的影响,可以采取积分分离或积分限幅等措施。积分分离是指在偏差较大时暂时取消积分环节,以避免积分过量;积分限幅则是对积分项的输出进行限制,防止其过大导致系统失稳。

        (3)微分先行与滤波:微分环节对噪声敏感,容易导致控制器输出波动。为了解决这个问题,可以采取微分先行或滤波措施。微分先行是将微分环节提前到比例和积分环节之前进行计算,以减少噪声对微分环节的影响;滤波则是通过对偏差进行平滑处理来消除噪声干扰。

        (4)智能PID控制器:随着人工智能技术的发展,越来越多的研究者将智能算法与PID控制器相结合,形成了智能PID控制器。例如,模糊PID控制器、神经网络PID控制器等。这些智能PID控制器可以根据系统的实时状态自动调整参数,以适应不同的工作条件和环境变化,从而提高系统的自适应性和鲁棒性。

        (5)数字PID控制:随着计算机技术的发展,数字PID控制已成为PID控制算法的主要实现方式。数字PID控制通过将连续函数进行离散化,并利用计算机程序实现PID控制和校正。常用的数字PID控制方法有位置式PID、增量式PID以及步进式PID等。其中,增量式PID因其计算量小、稳定性好等优点,在实际应用中得到了广泛应用。

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

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

相关文章

Linux基础(包括centos7安装、linux基础命令、vi编辑器)

一、安装CentOS7 需要&#xff1a;1、VMware Workstation&#xff1b;2、CentOS7镜像 1、安装镜像 2、虚拟机配置 开启虚拟机&#xff0c;鼠标从vm中移出来用快捷键ctrlalt 点击开始安装&#xff0c;设置密码&#xff0c;等待安装完成,&#xff0c;重启。 3、注意事项 如果没…

CAN总线简介

CAN 是 Controller Area Network 的缩写&#xff08;以下称为 CAN&#xff09;&#xff0c;是 ISO国际标准化的串行通信协议。 历史背景 CAN 最初出现在80年代末的汽车工业中&#xff0c;由德国 Bosch 公司最先提出。当时&#xff0c;由于消费者对于汽车功能的要求越来越多&a…

android仿assistivetouch悬浮窗实现(带功能实现)

一、悬浮窗点击后的界面&#xff1a; 主要有四个功能&#xff0c;返回、应用程序、退出和主界面。其他功能也可以类似添加。 界面布局代码就不贴出来了&#xff0c;源码&#xff08;切记需要签名才能让功能实现&#xff09;&#xff1a;下载地址 二、主要是检测系统启动或者a…

动态规划法例题

第一个空&#xff0c;用手工计算&#xff0c;可以用贪心法 先选择价值最大的物品&#xff0c;有两个价值是6的物品&#xff0c;重量合计246 剩余4个空间&#xff0c;只能放重量为2的物品&#xff0c;一共是66315 第二个空&#xff0c;需要将所有物品都放进背包舱室&#xff…

基于Python的量化交易回测框架Backtrader初识记录(一)

版权声明&#xff1a;本文为博主原创文章&#xff0c;如需转载请贴上原博文链接&#xff1a;基于Python的量化交易回测框架Backtrader初识记录&#xff08;一&#xff09;-CSDN博客 前言&#xff1a;近期以来&#xff0c;对股市数据获取及预处理算是告一段落&#xff0c;下一步…

OpenCV绘图函数(5)绘制标记函数drawMarker()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::drawMarker 函数在 OpenCV 中用于在一个给定的位置上绘制标记。目前支持几种不同的标记类型&#xff0c;具体信息可以参考 MarkerTypes 函数…

【C++ | 设计模式】观察者模式的详解与实现

1.概念 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为型设计模式&#xff0c;它的核心思想是定义对象间的一对多依赖关系&#xff0c;当一个对象的状态发生变化时&#xff0c;所有依赖于它的对象都会收到通知并自动更新。这个模式在现实生活中非常常见&#…

Selenium的四种部署方式详解

关于selenium 的部署&#xff0c;我在网上找了很多&#xff0c;基本上都没有提到或是说的比较清晰的。当时我一直有个困惑&#xff1a;测试的脚本代码&#xff0c;是放在跟浏览器同一台机器上呢&#xff0c;还是放在Application Server上&#xff1f; 在官方开发文档中&#x…

从0开始深度学习(2)——自动微分

1 微积分 1.1 导数和微分 略 1.2 偏导数 略 1.3 梯度&#xff08;gradient&#xff09; 1.3.1 定义 对于一个多变量函数 f ( x 1 , x 2 , … , x n ) f\left(x_{1}, x_{2}, \ldots, x_{n}\right) f(x1​,x2​,…,xn​)其中点 a ( a 1 , a 2 , … , a n ) \mathbf{a}(a_…

YGG深海传奇,创造财富无限可能!

随著区块链技术的创新与游戏产业的深度融合&#xff0c;GameFi赛道迅速崛起&#xff0c;成为全球投资者与玩家瞩目的新兴领域。 成立于2020年的Yield Guild Games(YGG)&#xff0c;作为全球区块链游戏领域的先锋公会之一&#xff0c;也加入到向去中心化经济模式的转型浪潮当中。…

E. Sheep Eat Wolves

https://codeforces.com/gym/104869/problem/E 赛时队友想贪心&#xff0c;贪不了一点&#xff0c;我想了数学办法每次都送固定的发现送过去就不满足了 赛后补&#xff0c;暴力做O&#xff08;n4) 至少要几次才能把安全所有羊送到对岸去 考虑最短路,bfs,用数组存下所有状态 …

17:4层板层叠设置

层叠设置参考PCB专栏 设置平面内缩 GND内缩设置20mil0.508mm 电源层内缩设置要比GND内缩大&#xff0c;设置40mil1mm

米家商城主题 html 页面源码分享,可用于网页设计作业

使用技术&#xff1a; HTML, CSS , Javascript 项目亮点&#xff1a; 1. 仿照米家商城页面布局所做的页面样式结构 2. 首页放置了可自动切换的轮播图 3. 登录页有表单结构&#xff0c;并且有切换的动画效果 4. 包含实时的动态时间&#xff0c;使用 js 实现 5. 页面布局清…

Datawhale X 李宏毅苹果书AI夏令营深度学习详解入门Task02

本文了解深度学习详解中的线性模型 本文了解深度学习详解中的线性模型将围绕梯度下降优化、线性模型的局限性、改进模型以及深度学习模型等关键要点展开讨论。 一、梯度下降优化 梯度下降是深度学习中常用的优化算法&#xff0c;它通过不断调整模型的参数&#xff0c;使得损失函…

axios发送post请求实例

在body中的数据格式又有两种&#xff0c;一种是 json 数据格式&#xff0c;另一种是 字符串。具体要用哪种格式取决于后端入参的格式。 如果后端接收json数据类型&#xff0c;post 的 headers 需要设置 { ‘content-type’: ’application/json’ }&#xff0c;传给后端的数…

【王树森】BERT:预训练Transformer模型(个人向笔记)

前言 BERT&#xff1a;Bidirectional Encoder Representations from TransformerBERT是用来预训练Transformer模型的encoder的本节课只讲述主要思想BERT用两个主要思想来训练Transformer的encoder网络&#xff1a;①随机遮挡单词&#xff0c;让encoder根据上下文来预测被遮挡的…

Fine-Grained Egocentric Hand-Object(中文翻译)

精细化自我中心手-物体分割&#xff1a; 数据集、模型&#xff08;model&#xff09;与应用 灵芝张1, 盛昊周1, 西蒙斯滕特 $ {}^{2} $, 和健博石 $ {}^{1} $ 摘要。 自我中心视频提供了高保真度建模人类行为的细粒度信息。手和交互对象是理解观众行为和意图的一个关键方面。…

掌握 JavaScript 解构赋值的指南

JavaScript 的解构赋值是一种从数组 or 对象中提取值并将其赋给变量的语法。这种语法让我们从复杂的数据结构中提取数据变得简洁和易读。解构赋值可以用在数组、对象以及嵌套结构中。 解构是&#xff1a;使用 ES6 的一种语法规则&#xff0c;将一个对象或数组的某个属性提取到…

JavaSE-递归法解决二分查找、快速排序

704. 二分查找https://leetcode.cn/problems/binary-search/ package demo;public class BinarySearch {public static void main(String[] args) {BinarySearch brnew BinarySearch();System.out.println(br.search(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}, 8));}public int s…

[Tools: LoRA] Diffusers中Stable Diffusion的实现

实现底层原理 Diffusers中的Attention操作实现在AttnProcessor类&#xff08;diffusers.models.attention_processor.py&#xff09;&#xff0c;里面定义了单次Attention操作。添加LoRA&#xff0c;本质上是用LoRAAttnProcessor类替换AttnProcessor类。LoRAAttnProcessor中新…