【面试05】PID控制算法

news2024/9/22 21:35:35

一、 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;
	else
		Last_Data = OutMpu;
}

// 平衡小车PID算法
void PID_test(void)
{

	Encoder_left = Read_Encoder(1);	  // 读取编码器值(当作小车当前前进的速度)
	Encoder_right = -Read_Encoder(2); // 读取编码器值(当作小车当前前进的速度)

	// 1、确定直立环PWM

	Balance_Pwm = Vertical_Ring_PD(OutMpu.pitch, OutMpu.gyro_x);

	// 2、确定速度环PWM

	Velocity_Pwm = Vertical_speed_PI(Encoder_left, Encoder_right, OutMpu.pitch, Movement);

	// 3、确定转向环PWM

	Turn_Pwm = Vertical_turn_PD(Contrl_Turn, OutMpu.gyro_z);

	// 4、确定最终左右电机的PWM
	Motor1 = 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值
 **************************************************************************************************************/
// 直立环的PD

int 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;						// 积分出位移 积分时间:10ms
	Encoder_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);
	}
	else
		temp = 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);
	else
		AIN2(0), AIN1(1);
	PWMA = Dead_Zone + (abs(motor1)) * 1.17;

	if (motor2 > 0)
		BIN1(1), BIN2(0);
	else
		BIN1(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.coloradmin.cn/o/2101505.html

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

相关文章

一键掌控园区运营,数字化管理平台如何实现?

在当今数字化时代&#xff0c;高效的管理是企业成功的关键。对于各类园区而言&#xff0c;如何实现一键掌控园区运营&#xff0c;成为了提升竞争力的重要课题。幸运的是&#xff0c;数字化管理平台的出现如同一把智慧钥匙&#xff0c;为实现园区运营提供了完美的解决方案。 数字…

<Rust>egui学习之小部件(九):如何在窗口中添加下拉列表combobox部件?

前言 本专栏是关于Rust的GUI库egui的部件讲解及应用实例分析&#xff0c;主要讲解egui的源代码、部件属性、如何应用。 环境配置 系统&#xff1a;windows 平台&#xff1a;visual studio code 语言&#xff1a;rust 库&#xff1a;egui、eframe 概述 本文是本专栏的第九篇博…

系统编程-数据库

数据库 目录 数据库 引入 1、先安装数据库 2、数据库设置密码 3、数据库的进入和退出(前提 你的密码更改过了) 数据库的基本操作 1、显示所有的数据库 2、创建数据库 3、删除数据库 4、选择数据库 在数据库中对表进行操作 1、查看当前数据库中的表 2、在数据库中…

Spring框架——springweb(一篇包会)

目录 一、Springweb概述 1.SpringWeb特点 2.SpringWeb组件 3.SpringWeb运行流程 二、搭建Springweb 1.导入框架所需的包 2.配置 DispatcherServlet 3.开启SpringWeb注解 4.处理器类搭建 5.请求处理 &#xff08;1&#xff09;接收请求RequestMapping &#xff08;2&…

大疆上云API基于源码部署

文章目录 大疆上云API基于源码部署1、学习官网2、环境准备注意事项3、注册成为DJI开发者4、下载前后端运行所需要的包/依赖前端依赖下载后端所需要的Maven依赖包 用到的软件可以在这里下载5、MySQL数据库安装安装MySQL启动MySQL服务在IDEA中配置MySQL的连接信息 6、Redis的安装…

Visual Studio Code大大提升工作效率小技巧~~~

Visual Studio Code &#xff08; VS Code &#xff09;是一个知名且评价很高的代码编辑器&#xff0c;具有大量功能和扩展以增强开发体验。使用 VS Code 的主要好处之一是它的灵活性&#xff0c;允许开发人员根据他们的特定需求对其进行自定义。 此外&#xff0c;VS Code 轻巧…

(十五)SpringCloudAlibaba-Sentinel持久化到Nacos

前言 在前面我们已经将Sentinel配置的规则持久化到系统的文件中。本章节我们将Sentinel持久化到Nacos中; 传送门(Sentinel数据持久化到文件)https://blog.csdn.net/weixin_45876411/article/details/140742963 默认情况下 Sentinel 只能接收到 Nacos 推送的消息&#xff0c;但…

JNPF低代码:可视化如何赋能企业的转型之路

在数字化转型的浪潮中&#xff0c;企业面临着前所未有的挑战与机遇。传统的软件开发方式往往耗时长、成本高&#xff0c;且难以快速适应市场变化。低代码开发平台的出现&#xff0c;为企业的数字化转型提供了新的思路和工具。其中&#xff0c;JNPF低代码平台以其独特的可视化特…

LDR6023:革新手机转接器体验,快充与OTG并存的科技杰作

在智能设备日益普及的今天&#xff0c;手机已经成为我们日常生活中不可或缺的一部分。然而&#xff0c;随着功能的不断增加&#xff0c;手机对于电力和数据传输的需求也日益提升。为了应对这一挑战&#xff0c;深圳市乐得瑞科技有限公司凭借其深厚的科技积累和创新精神&#xf…

嵌入式系统------ARM

目录 一.c语言回顾 1.特殊符号 &#xff08;1&#xff09;const &#xff08;2&#xff09;static &#xff08;3&#xff09;extern 2.内存的结构 &#xff08;1&#xff09;kernel&#xff1a;内核 &#xff08;2&#xff09;栈区 &#xff08;3&#xff09;堆区 &#xff08…

Java 入门指南:Java 并发编程 —— 并发容器 ConcurrentSkipListMap

ConcurrentMap ConcurrentMap 是 Java 并发包中提供的一个接口&#xff0c;它继承了 java.util.Map 接口&#xff0c;专门用于支持高并发环境下的线程安全操作。ConcurrentMap 提供了一系列线程安全的方法&#xff0c;旨在解决在多线程环境下使用普通 Map 类型&#xff08;如 …

用ChatGPT三分钟写一个完美的PPT,彻底告别繁琐的制作过程

用AI或ChatGPT来制作PPT的方式多得很&#xff01; 下面就用超级简单的语言&#xff0c;一步步教你怎么搞定&#xff0c;三分钟内保准搞定你的PPT。 所有需要的方法和工具都在这里&#xff01; 很简单&#xff0c;只要你输入一个标题&#xff0c;AI就能完成PPT的制作。 如果…

文件 fd

目录 1. 建立共识原理2. 回忆 C 文件接口2.1 当前工作路径2.2 w / a 方式写入2.3 默认打开的三个文件流 3. 认识文件系统调用3.1 O_WRONLY|O_CREAT 写时创建3.2 O_TRUNC 截断长度&#xff08;也即全覆盖式写入&#xff09;3.3 O_APPEND 追加 4. 浅谈文件访问的本质4.1 简证 1. …

高级算法设计与分析 学习笔记 2 希尔排序 线性时间内的排序——计数排序,基数排序,桶排序

希尔排序&#xff08;比较排序&#xff09; 要选定一个步长&#xff08;比如4&#xff09;&#xff0c;那么0&#xff0c;4&#xff0c;8……它们是一组&#xff0c;1&#xff0c;5&#xff0c;9……他们是一组。分组排完之后再换成2步长&#xff0c;最后改成1&#xff0c;就行…

牛心包瓣类医用生物瓣膜厚度无损检测

关键字&#xff1a;牛心包瓣膜&#xff0c;牛心包瓣叶&#xff0c;生物瓣膜&#xff0c;生物心脏膜&#xff0c;测厚仪&#xff0c;瓣膜生产&#xff0c;瓣膜检测设备&#xff0c; 牛心包瓣叶的厚度和轮廓所需的高精度取决于多个因素&#xff0c;包括瓣膜的制造标准、临床应用需…

百度飞将 paddle ,实现贝叶斯神经网络 bayesue neure network bnn,aistudio公开项目 复现效果不好

论文复现赛&#xff1a;贝叶斯神经网络 - 飞桨AI Studio星河社区 https://github.com/hrdwsong/BayesianCNN-Paddle 论文复现&#xff1a;Weight Uncertainty in Neural Networks 本项目复现时遇到一个比较大的问题&#xff0c;用pytorch顺利跑通源代码后&#xff0c;修改至pad…

【每日一练】python之tkinter的Label标签基础用法

""" 什么是tkinter窗口&#xff1f;tkinter是python中一个标准的库&#xff0c;用于创建图形界面&#xff08;GUI&#xff09;应用程序&#xff0c;它提供了一组工具和组件&#xff0c;使开发者能够在Python中创建窗口、按钮、标签、文本框、菜单等各种界面元素…

基于协同过滤的电影推荐系统

推荐系统已经成为当今互联网平台不可或缺的一部分&#xff0c;尤其是在电影、音乐和电子商务等领域。本文将带您深入探讨如何利用协同过滤算法&#xff0c;构建一个功能齐全的电影推荐系统。我们将结合Python、Django框架以及协同过滤算法&#xff0c;逐步实现这一目标。 完整…

Go父类调用子类方法(虚函数调用)

前言 在Go语言中&#xff0c;支持组合而不是继承。网上都说可以通过接口和结构体内嵌来模拟面向对象编程中的子类和父类关系。但给的例子或写法感觉都不是很好&#xff0c;难以达到我的目的&#xff08;比如通过模板模式实现代码的重用等&#xff09;。因此调查了一下实现方式…

内裤洗衣机需要一人一台吗?快来围观2024年五大好货集合

随着市面上的内衣抑菌产品越来越多&#xff0c;内衣洗衣机的质量也是参差不齐&#xff0c;一些网红跨界品牌内衣洗衣机的用料和做工品质较差&#xff0c;使用过程中出现清洗不干净和稳定性不足等问题。那么选购内衣洗衣机需要注意什么呢&#xff1f;我作为一名小家电测评博主&a…