形象解释PID算法+PID算法源代码

合集下载

C语言实现PID算法

C语言实现PID算法

C语言实现PID算法PID算法是一种常用的控制算法,在工控系统中广泛应用。

下面将详细介绍C语言实现PID算法的步骤和代码。

PID算法是基于反馈的控制算法,通过对系统输出与期望输出之间的差异进行处理,生成一个控制器的输出信号,从而实现对系统状态的调节。

PID算法由比例(P)、积分(I)和微分(D)三个部分组成。

具体的计算公式为:输出值=Kp*(误差+1/Ti*积分项+Td*微分项)其中,Kp为比例系数,Ti为积分时间常数,Td为微分时间常数。

积分项为历史误差的累积,微分项为误差变化率的反馈。

下面是C语言实现PID算法的代码:```c//PID算法的数据结构typedef structdouble Kp; // 比例系数double Ti; // 积分时间常数double Td; // 微分时间常数double lastError; // 上一次的误差double integral; // 积分项}PID;void initPID(PID* pid, double Kp, double Ti, double Td)pid->Kp = Kp;pid->Ti = Ti;pid->Td = Td;pid->lastError = 0;pid->integral = 0;//更新PID算法的参数void updatePID(PID* pid, double error, double dt)double proportional, integral, derivative;//比例项proportional = pid->Kp * error;//积分项pid->integral += error * dt;integral = pid->Kp / pid->Ti * pid->integral;//微分项derivative = pid->Kp * pid->Td * (error - pid->lastError) / dt;//更新上一次的误差pid->lastError = error;//计算输出值double output = proportional + integral + derivative;//进行输出处理(例如对输出进行限幅)//...//输出控制信号//...```使用上述代码,可以通过调用`initPID`函数进行PID算法的初始化,并通过调用`updatePID`函数更新PID算法的参数和计算控制器的输出。

pid工作原理代码

pid工作原理代码

pid工作原理代码PID(Proportional-Integral-Derivative)是一种常用的控制算法,用于自动控制系统中的反馈控制。

它的工作原理是通过不断调整控制器的输出来维持被控对象的状态,使其达到期望值。

PID控制器的工作原理可以简单描述为:根据被控对象的当前状态与期望值的差异,计算出一个控制量,然后根据该控制量对被控对象进行调节,使其逐渐接近期望值。

我们来看一下PID控制器的三个组成部分:比例(Proportional)、积分(Integral)和微分(Derivative)。

比例控制是根据被控对象当前状态与期望值的差异,按照一定的比例系数来计算控制量。

当被控对象偏离期望值较大时,比例控制器会给出一个较大的控制量,以快速调整被控对象的状态。

积分控制是根据被控对象状态与期望值的历史差异,按照一定的积分时间来计算控制量。

积分控制器会累积被控对象状态与期望值之间的偏差,如果被控对象长时间偏离期望值,则积分控制器会给出一个较大的控制量,以更好地消除系统的静态误差。

微分控制是根据被控对象状态的变化速率来计算控制量。

微分控制器会根据被控对象状态与期望值之间的变化率,预测被控对象未来的状态变化趋势,并根据这个趋势给出一个控制量,以抑制被控对象快速变化的趋势。

PID控制器通过将比例、积分和微分控制相结合,综合考虑被控对象的当前状态、历史状态和状态变化趋势,从而实现对被控对象的精确控制。

在实际应用中,PID控制器的参数需要根据被控对象的特性进行调整。

通常可以通过试验和经验来确定最佳的参数配置,以达到最优的控制效果。

除了基本的PID控制器,还有一些改进的算法,如增量式PID控制、自适应PID控制等。

这些算法在特定的应用场景中可以提供更好的控制性能。

总结起来,PID控制器是一种常用的控制算法,通过比例、积分和微分控制相结合的方式,实现对被控对象的精确控制。

在实际应用中,根据被控对象的特性进行参数调整,可以达到更好的控制效果。

PID算法通俗讲解

PID算法通俗讲解

#include <>typedef unsigned char uChar8;typedef unsigned int uInt16;typedef unsigned long int uInt32;sbit ConOut = P1^1; //加热丝接到口typedef struct PID_Value{uInt32 liEkVal[3]; //差值保存,给定和反馈的差值uChar8 uEkFlag[3]; //符号,1则对应的为负数,0为对应的为正数uChar8 uKP_Coe; //比例系数uChar8 uKI_Coe; //积分常数uChar8 uKD_Coe; //微分常数uInt16 iPriVal; //上一时刻值uInt16 iSetVal; //设定值uInt16 iCurVal; //实际值}PID_ValueStr;PID_ValueStr PID; //定义一个结构体,这个结构体用来存算法中要用到的各种数据bit g_bPIDRunFlag = 0; //PID运行标志位,PID算法不是一直在运算。

而是每隔一定时间,算一次。

/* ********************************************************/* 函数名称:PID_Operation()/* 函数功能:PID运算/* 入口参数:无(隐形输入,系数、设定值等)/* 出口参数:无(隐形输出,U(k))/* 函数说明:U(k)+KP*[E(k)-E(k-1)]+KI*E(k)+KD*[E(k)-2E(k-1)+E(k-2)] ******************************************************** */void PID_Operation(void){uInt32 Temp[3] = {0}; //中间临时变量uInt32 PostSum = 0; //正数和uInt32 NegSum = 0; //负数和if > //设定值大于实际值否?{if - > 10) //偏差大于10否?= 100; //偏差大于10为上限幅值输出(全速加热)else //否则慢慢来{Temp[0] = - ; //偏差<=10,计算E(k)[1] = 0; //E(k)为正数,因为设定值大于实际值/* 数值进行移位,注意顺序,否则会覆盖掉前面的数值 */[2] = [1];[1] = [0];[0] = Temp[0];/*=================================================================== */if[0] > [1]) //E(k)>E(k-1)否?{Temp[0] = [0] - [1]; //E(k)>E(k-1)[0] = 0; //E(k)-E(k-1)为正数}else{Temp[0] = [1] - [0]; //E(k)<E(k-1)[0] = 1; //E(k)-E(k-1)为负数}/*=================================================================== */Temp[2] = [1] * 2; //2E(k-1)if([0] + [2]) > Temp[2]) //E(k-2)+E(k)>2E(k-1)否?{Temp[2] = [0] + [2]) - Temp[2];[2]=0; //E(k-2)+E(k)-2E(k-1)为正数 }else//E(k-2)+E(k)<2E(k-1){Temp[2] = Temp[2] - [0] + [2]);[2] = 1; //E(k-2)+E(k)-2E(k-1)为负数 }/*=================================================================== */Temp[0] = (uInt32) * Temp[0]; //KP*[E(k)-E(k-1)]Temp[1] = (uInt32) * [0]; //KI*E(k)Temp[2] = (uInt32) * Temp[2]; //KD*[E(k-2)+E(k)-2E(k-1)] /* 以下部分代码是讲所有的正数项叠加,负数项叠加 *//* ========= 计算KP*[E(k)-E(k-1)]的值 ========= */if[0] == 0)PostSum += Temp[0]; //正数和elseNegSum += Temp[0]; //负数和/* ========= 计算KI*E(k)的值 ========= */if[1] == 0)PostSum += Temp[1]; //正数和else; /* 空操作。

c语言pid算法

c语言pid算法

c语言pid算法PID(Proportional-Integral-Derivative)控制器是一种非常常见且有效的控制系统算法,主要用于调节一个过程或者系统的输出,使其尽可能接近期望的设定值。

PID控制器的名字来源于它的三个主要组成部分:比例(Proportional)、积分(Integral)和微分(Derivative)。

在C语言中,一个简单的PID控制器可以如下实现:c复制代码#include<stdio.h>typedef struct {double kp; // 比例系数double ki; // 积分系数double kd; // 微分系数double last_error; // 上一次的误差double integral; // 误差的积分} PIDController;double calculatePID(PIDController* pid, double setpoint, double actual_value, double dt) {double error = setpoint - actual_value;// Proportional termdouble pout = pid->kp * error;// Integral termpid->integral += error * dt;double iout = pid->ki * pid->integral;// Derivative termdouble derivative = (error - pid->last_error) / dt;double dout = pid->kd * derivative;// Save error for next timepid->last_error = error;// Return total outputreturn pout + iout + dout;}int main() {PIDController pid;pid.kp = 1.0;pid.ki = 0.1;pid.kd = 0.01;st_error = 0;pid.integral = 0;double setpoint = 100.0; // 目标值double actual_value = 0.0; // 实际值double dt = 0.1; // 时间间隔for (int i = 0; i < 100; i++) {double output = calculatePID(&pid, setpoint, actual_value, dt);actual_value += output * dt; // 更新实际值printf("Setpoint: %f, Actual Value: %f, Output: %f\n", setpoint, actual_value, output);}return0;}在这个示例中,我们定义了一个PIDController结构体,它包含了PID控制器的所有参数。

PID算法的C语言实现

PID算法的C语言实现

PID算法的C语言实现PID(Proportional-Integral-Derivative)算法是一种常用的控制算法,被广泛应用于自动控制系统中。

它是通过计算系统当前的误差,来调整控制器的输出值,从而使得系统的输出与期望输出之间达到期望的关系。

以下是一个简单的PID算法的C语言实现示例:```c#include <stdio.h>//PID控制器参数float Kp = 1.0; // 比例系数float Ki = 0.5; // 积分系数float Kd = 0.2; // 微分系数//预设值float setpoint = 100.0;//PID控制器输出限制float outMin = 0.0;float outMax = 255.0;//PID控制器变量float integral = 0.0;float lastError = 0.0;//PID控制器计算函数//计算误差float error = setpoint - input;//计算比例项float proportional = Kp * error;//计算积分项integral += Ki * error;//计算微分项float derivative = Kd * (error - lastError);//保存上一次的误差lastError = error;//计算PID输出float output = proportional + integral + derivative; //限制输出值在指定范围内if (output > outMax)output = outMax;} else if (output < outMin)output = outMin;}return output;int maifloat processVariable = 0.0; // 进程变量,即被控制物理系统的输出值//模拟控制循环for (int i = 0; i < 100; i++)//获取控制器输出值//模拟物理系统processVariable += (output * 0.1);printf("Iteration: %d\tOutput: %.2f\tProcessVariable: %.2f\n", i, output, processVariable);}return 0;```上述代码中,首先定义了PID控制器的参数(比例系数Kp、积分系数Ki和微分系数Kd)、预设值(setpoint)以及PID控制器的输出限制(outMin和outMax)。

PID控制算法的C语言实现

PID控制算法的C语言实现

PID控制算法的C语言实现PID控制算法是一种经典的控制算法,用于调节系统输出和期望值之间的差异,以达到控制系统稳定的目的。

该算法由比例(P)、积分(I)、微分(D)三个部分组成,通过调节这三个部分的权重系数,可以实现对系统的精准控制。

以下是PID控制算法的C语言实现示例代码。

```c#include <stdio.h>//定义PID控制参数结构体typedef structdouble Kp; // 比例系数double Ki; // 积分系数double Kd; // 微分系数double setpoint; // 期望值double integral; // 积分项double prev_error; // 前一次误差}PID;//初始化PID控制器void PID_init(PID* pid, double Kp, double Ki, double Kd, double setpoint)pid->Kp = Kp;pid->Ki = Ki;pid->Kd = Kd;pid->setpoint = setpoint;pid->integral = 0;pid->prev_error = 0;//更新PID控制器的输出值double PID_update(PID* pid, double input, double dt)//计算误差double error = pid->setpoint - input;//比例项double p_term = pid->Kp * error;//积分项pid->integral += pid->Ki * error * dt;//微分项double d_term = pid->Kd * (error - pid->prev_error) / dt; //更新前一次误差pid->prev_error = error;//计算总输出值double output = p_term + pid->integral + d_term;return output;int mai//初始化PID控制器PID pid;PID_init(&pid, 0.5, 0.2, 0.1, 10.0); // 设置Kp=0.5, Ki=0.2, Kd=0.1, setpoint=10.0//模拟系统输入double input = 5.0;//模拟系统运行for (int i = 0; i < 100; i++)//计算PID控制器输出double output = PID_update(&pid, input, 1.0); // 假设采样时间为1.0s//更新系统输入input += output;printf("Output: %lf\n", output);}return 0;```以上代码中,我们定义了一个`PID`结构体,用于存储PID控制器的参数和状态。

PID算法原理,PID源码,自整定,及工具

PID算法原理,PID源码,自整定,及工具

专家系统、模糊算法,需要参数整定就一定要有整定的依据,也就是说什么情 况下整定什么值是要有依据的,这个依据是一些逻辑的组合,只要找出其中的 逻辑组合关系来,这些依据就再明显不过了。下面先说一下专家 PID 的 C 语言 实现。正如前面所说,需要找到一些依据,还得从 PID 系数本身说起。
三、PID 算法参数整定方法 1.临界比例度法 (1)将调节器的积分时间置于最大,微分时间置零,比例度 δ 适当,平衡操 作一段时间,把系统投入自动运行。 (2)将比例度 δ 逐渐减小,得到等幅振荡过程,记下临界比例度和临界振荡 周期值。 (3)根据和值,采用经验公式,计算出调节器各个参数,即 δ、、的值。 (4)按“先 P 后 I 最后 D”的操作程序将调节器整定参数调到计算值上。若还 不够满意,可再作进一步调整。
上一节中介绍了最简单的位置型 PID 的实现手段,这一节讲解增量式 PID 的实 现方法。 #include<stdio.h> #include<stdlib.h>
struct t_pid{ float SetSpeed; float ActualSpeed; float err; float err_next; float err_last; float Kp,Ki,Kd;
临界振荡整定计算公式
2.衰减曲线法 在纯比例作用下,由大到小调整比例度以得到具有衰减比(4:1)的过渡过 程,记下此时的比例度及振荡周期,根据经验公式,求出相应的积分时间和微 分时间。
衰减曲线法控制器参数计算表
3.经验法 根据经验先将控制器参数放在某些数值上,直接在闭合的控制系统中通过改变 给定值以施加干扰,看输出曲线的形状,以 δ、、,对控制过程的规律为指 导,调整相应的参数进行凑试,直到合适为止。

PID控制算法通俗讲解(转)

PID控制算法通俗讲解(转)

抛弃公式,从原理上真正理解PID控制PID控制应该算是应用非常广泛的控制算法了。

小到控制一个元件的温度,大到控制无人机的飞行姿态和飞行速度等等,都可以使用PID控制。

这里我们从原理上来理解PID控制。

PID(proportion integration differentiation)其实就是指比例,积分,微分控制。

先把图片和公式摆出来,看不懂没关系。

(一开始看这个算法,公式能看懂,具体怎么用怎么写代码也知道,但是就是不知道原理,不知道为什么要用比例,微分,积分这3个项才能实现最好的控制,用其中两个为什么不行,用了3个项能好在哪里,每一个项各有什么作用)总的来说,当得到系统的输出后,将输出经过比例,积分,微分3种运算方式,叠加到输入中,从而控制系统的行为,下面用一个简单的实例来说明。

比例控制算法我们先说PID中最简单的比例控制,抛开其他两个不谈。

还是用一个经典的例子吧。

假设我有一个水缸,最终的控制目的是要保证水缸里的水位永远的维持在1米的高度。

假设初试时刻,水缸里的水位是0.2米,那么当前时刻的水位和目标水位之间是存在一个误差的error,且error为0.8.这个时候,假设旁边站着一个人,这个人通过往缸里加水的方式来控制水位。

如果单纯的用比例控制算法,就是指加入的水量u和误差error是成正比的。

即u=kp*error假设kp取0.5,那么t=1时(表示第1次加水,也就是第一次对系统施加控制),那么u=0.5*0.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米。

但是,单单的比例控制存在着一些不足,其中一点就是–稳态误差!(我也是看了很多,并且想了好久才想通什么是稳态误差以及为什么有稳态误差)。

最全PID控制算法的C语言实现

最全PID控制算法的C语言实现

最全PID控制算法的C语言实现PID控制算法是一种在控制系统中常用的反馈控制算法,用于根据实际测量值来调节输出来实现对系统状态的控制。

PID算法包含三个控制参数:比例常数(Kp)、积分常数(Ki)和微分常数(Kd)。

这三个参数分别调节了比例控制、积分控制和微分控制的比例,用于实现不同的控制效果。

下面是一个最全的PID控制算法的C语言实现示例:```c#include <stdio.h>//定义PID控制算法的参数float Kp = 1.0; // 比例常数float Ki = 0.5; // 积分常数float Kd = 0.2; // 微分常数//定义全局变量用于记录控制过程中的误差与累积误差float error = 0.0;float lastError = 0.0;float integral = 0.0;//定义PID控制函数float pidControl(float target, float current, float dt)//计算误差error = target - current;//计算累积误差integral += error * dt;//计算微分误差float derivative = (error - lastError) / dt;//计算PID输出float output = Kp * error + Ki * integral + Kd * derivative; //更新上一次误差lastError = error;return output;int mai//模拟控制过程float target = 100.0; // 目标值float current = 0.0; // 当前值float dt = 0.1; // 控制周期for(int i = 0; i < 100; i++)//调用PID控制函数float output = pidControl(target, current, dt);//更新当前值,模拟实际过程中的测量误差current += output * dt + 0.2;printf("Target: %.2f, Current: %.2f, Output: %.2f\n", target, current, output);}return 0;```上述代码通过定义全局变量来记录控制过程中的误差与累积误差,并在PID控制函数中进行计算和更新。

PID算法的通俗讲解及调节口诀

PID算法的通俗讲解及调节口诀

PID算法的通俗讲解及调节口诀PID算法是一种常用的控制算法,用于控制系统中的反馈回路,以使系统的输出能够接近所需值。

PID算法的基本原理是通过不断调节控制器的输出信号,使系统的实际输出与期望输出之间的误差最小化。

在这篇文章中,我们将用通俗的语言来解释PID算法的原理,并提供一些调节的口诀。

首先,让我们来了解一下比例控制部分。

比例控制的作用是根据当前的误差值,产生一个与之成比例的输出信号。

比例控制的公式为:输出信号=比例系数*误差值比例系数是一个常数,用于确定比例控制的权重。

当误差值较大时,比例控制会产生较大的输出信号,从而加大纠正的力度。

但是,如果比例系数设置得过大,可能会导致系统产生过冲或震荡的现象。

接下来是积分控制部分。

积分控制的作用是根据误差值的累积量,产生一个与之成比例的输出信号。

积分控制的公式为:输出信号=积分系数*误差值的累积量积分系数也是一个常数,用于确定积分控制的权重。

积分控制的作用是消除系统的稳态误差,即系统输出值与期望输出值之间的偏差。

当误差值较大时,积分控制会逐渐增加输出信号,直到误差值降至接近于零为止。

然而,如果积分系数设置得过大,可能会导致系统产生震荡的现象。

最后是微分控制部分。

微分控制的作用是根据误差值的变化率,产生一个与之成比例的输出信号。

微分控制的公式为:输出信号=微分系数*误差值的变化率微分系数也是一个常数,用于确定微分控制的权重。

微分控制的作用是抑制系统的瞬态响应,即系统输出值发生变化时的过渡过程。

当误差值的变化率较大时,微分控制会产生较大的输出信号,从而减小系统的瞬态响应。

但是,如果微分系数设置得过大,可能会导致系统产生过冲或震荡的现象。

综上所述,PID控制的输出信号等于比例控制、积分控制和微分控制三个部分的加权和:输出信号=比例系数*误差值+积分系数*误差值的累积量+微分系数*误差值的变化率现在我们来看一下PID算法的调节口诀。

根据经验和实践,我们总结了以下的调节口诀:1.比例系数:首先调节比例系数,使系统能够快速响应。

通俗易懂的PID控制算法讲解

通俗易懂的PID控制算法讲解

最优控制旨在寻找一种最优的控制策 略,使得系统性能达到最优。与PID 控制相比,最优控制具有更高的性能 指标和更好的全局优化能力。然而, 最优控制的实现需要精确的数学模型 和大量的计算资源,且对系统参数变 化较为敏感。
05
PID控制算法的应用实例
工业自动化领域的应用
要点一
温度控制
在工业生产过程中,PID控制算法被 广泛应用于温度控制系统中,如熔炼 炉、热处理炉等设备的温度控制。通 过实时采集温度数据,与设定值进行 比较,PID控制器能够自动调节加热 元件的功率,使温度稳定在设定值附 近。
该传递函数描述了PID控制器在频域中的特性,可用于分析系统的稳定性、动态性能和 稳态精度等。
通过调整Kp、Ki和Kd三个参数,可以实现对系统性能的优化。在实际应用中,常采用 试凑法、经验法或优化算法等方法来确定PID参数。
03
PID控制算法的参数整定
参数整定的意义
提高系统性能
通过调整PID控制器的参数,可以优化系统 的动态响应和稳态精度,从而提高系统的整 体性能。
适应不同应用场景
不同的被控对象和不同的应用场景需要不同的PID 参数配置,参数整定可以使PID控制器适应各种应 用场景。
保证系统稳定性
合理的参数配置可以保证系统的稳定性,避 免系统出现振荡或失控等不稳定现象。
参数整定的方法
试凑法
根据经验或实验数据,逐步调整 PID控制器的参数,观察系统的响 应情况,直到满足性能指标要求 。
PID控制算法由比例(P)、积分(I) 和微分(D)三个部分组成,每个部 分都有不同的作用,通过调整三个部 分的参数可以实现对系统的精确控制 。
PID控制算法的应用领域
01
02
03

PID控制算法通俗讲解

PID控制算法通俗讲解

PID控制算法通俗讲解PID控制算法是一种经典的反馈控制算法,其全称为“比例-积分-微分控制算法”,是目前工业领域使用最广泛的一种控制方法。

它通过调整输出信号和目标值之间的差异来实现系统的稳定和精确控制。

PID控制算法的原理非常复杂,但可以用一种通俗易懂的方式来解释。

我们可以把PID控制算法类比为一个小孩子学习骑自行车的过程。

小孩子第一次骑自行车时,会感到不稳定,容易摔倒。

这时,父母可能会帮助他们保持平衡,通过把手握住自行车后座来保持稳定。

这个过程就相当于PID控制算法中的“比例”部分。

“比例”部分是PID控制算法的基础,它通过调整输出信号和目标值之间的差值,来决定控制量的大小。

比如说,当小孩子离平衡点很远时,父母会用力拉住自行车,让他尽快回到平衡点。

而当离平衡点很近时,父母会放松控制,让他能够自主控制。

这就是“比例”部分的作用,根据偏差的大小来调整控制量,使系统向目标值靠近。

然而,只有“比例”部分还不足以保持稳定。

因为当小孩子骑自行车时,即便靠近平衡点,也有可能因为一些突发因素而失去平衡。

这时,父母可能会及时给他支撑,保持平衡。

这个过程就相当于PID控制算法中的“积分”部分。

“积分”部分的作用是累积系统在长时间内的偏差,并根据累积值来调整控制量。

当系统出现长时间的偏差时,积分部分会逐渐增加,产生补偿作用,使系统更加稳定。

比如说,当小孩子长时间无法保持平衡时,父母可能会给予更多的支撑力,帮助他恢复平衡。

不过,积分部分也有一个缺点,就是会导致系统的响应速度较慢。

因此,PID控制算法引入了“微分”部分来解决这个问题。

我们可以把微分部分类比为小孩子骑自行车时,父母根据自行车的倾斜程度来给予支撑的力度。

“微分”部分通过测量系统的变化速率来调整控制量。

当系统变化速率很快时,微分部分会增加控制量,使系统迅速做出反应。

比如说,当小孩子在转弯时,系统的变化速率会加大,父母就会给予更多的支撑力,以避免摔倒。

综上所述,PID控制算法通过比例、积分和微分三部分的组合来实现系统的稳定和精确控制。

PID控制算法C源码

PID控制算法C源码

PID控制算法C源码感觉代码不错,以后肯定会⽤到,侵删#include <reg52.h>#include <string.h> //C语⾔中memset函数头⽂件#define unsigned int uinttypedef struct PID {double SetPoint; // 设定⽬标Desired valuedouble Proportion; // ⽐例常数Proportional Constdouble Integral; // 积分常数Integral Constdouble Derivative; // 微分常数Derivative Constdouble LastError; // Error[-1]double PrevError; // Error[-2]double SumError; // Sums of Errors}PID;/*====================================================================================================PID计算部分 =====================================================================================================*/double PIDCalc( PID *pp, double NextPoint ){double dError, Error;Error = pp->SetPoint - NextPoint; // 偏差pp->SumError += Error; // 积分dError = Error - pp->LastError; // 当前微分pp->PrevError = pp->LastError;pp->LastError = Error;return (pp->Proportion * Error // ⽐例项+ pp->Integral * pp->SumError // 积分项+ pp->Derivative * dError // 微分项);}/*==================================================================================================== Initialize PID Structure PID参数初始化 ============= ========================================================================================*/ void PIDInit (PID *pp){memset ( pp,0,sizeof(PID));}/*==================================================================================================== Main Program 主程序 =====================================================================================================*/ double sensor (void) // Dummy Sensor Function{return100.0;} //void actuator(double rDelta) // Dummy Actuator Function //{}void main(void) {PID sPID; // PID Control Structuredouble rOut; // PID Response (Output)double rIn; // PID Feedback (Input)PIDInit ( &sPID ); // Initialize StructuresPID.Proportion = 0.5; // Set PID CoefficientssPID.Integral = 0.5;sPID.Derivative = 0.0;sPID.SetPoint = 100.0; // Set PID Setpointfor (;;) { //Mock Up of PID ProcessingrIn = sensor (); // Read InputrOut = PIDCalc ( &sPID,rIn ); // Perform PID Interation//actuator ( rOut ); // Effect Needed Changes}}。

pid基础介绍(包含代码)

pid基础介绍(包含代码)

pid基础介绍总所周知,PID算法是个很经典的东西。

而做自平衡小车,飞行器PID是一个必须翻过的坎。

因此本节我们来好好讲解一下PID,根据我在学习中的体会,力求通俗易懂。

并举出PID的形象例子来帮助理解PID。

一、首先介绍一下PID名字的由来:P:Proportion(比例),就是输入偏差乘以一个常数。

I:Integral(积分),就是对输入偏差进行积分运算。

D:Derivative(微分),对输入偏差进行微分运算。

注:输入偏差=读出的被控制对象的值-设定值。

比如说我要把温度控制在26度,但是现在我从温度传感器上读出温度为28度。

则这个26度就是”设定值“,28度就是“读出的被控制对象的值”。

然后来看一下,这三个元素对PID算法的作用,了解一下即可,不懂不用勉强。

P:打个比方,如果现在的输出是1,目标输出是100,那么P的作用是以最快的速度达到100,把P理解为一个系数即可;而I呢?大家学过高数的,0的积分才能是一个常数,I就是使误差为0而起调和作用;D呢?大家都知道微分是求导数,导数代表切线是吧,切线的方向就是最快到至高点的方向。

这样理解,最快获得最优解,那么微分就是加快调节过程的作用了。

二、然后要知道PID算法具体分两种:一种是位置式的,一种是增量式的。

在小车里一般用增量式,为什么呢?位置式PID的输出与过去的所有状态有关,计算时要对e(每一次的控制误差)进行累加,这个计算量非常大,而明显没有必要。

而且小车的PID控制器的输出并不是绝对数值,而是一个△,代表增多少,减多少。

换句话说,通过增量PID算法,每次输出是PWM要增加多少或者减小多少,而不是PWM的实际值。

所以明白增量式PID就行了。

三、接着讲PID参数的整定,也就是PID公式中,那几个常数系数Kp,Ti,Td等是怎么被确定下来然后带入PID算法中的。

如果要运用PID,则PID参数是必须由自己调出来适合自己的项目的。

通常四旋翼,自平衡车的参数都是由自己一个调节出来的,这是一个繁琐的过程。

PID控制算法的C语言实现完整版精编版

PID控制算法的C语言实现完整版精编版

PID控制算法的C语言实现完整版精编版以下是PID控制算法的C语言实现完整版代码。

```#include <stdio.h>#include <stdlib.h>//定义PID参数#define KP 0.5#define KI 0.2#define KD 0.1//PID结构体typedef structfloat setpoint; // 设定值float error; // 误差float integral; // 积分float derivative; // 微分float prev_error; // 上一次误差float output; // 输出}PID;//初始化PIDvoid initializePID(PID *pid, float setpoint)pid->setpoint = setpoint;pid->error = 0;pid->integral = 0;pid->derivative = 0;pid->prev_error = 0;pid->output = 0;//更新PIDfloat updatePID(PID *pid, float input, float dt)//计算误差pid->error = pid->setpoint - input;//计算积分pid->integral += pid->error * dt;//计算微分pid->derivative = (pid->error - pid->prev_error) / dt;//计算输出pid->output = KP * pid->error + KI * pid->integral + KD * pid->derivative;//保存当前误差作为上一次误差pid->prev_error = pid->error;return pid->output;int mai//创建PID对象PID pid;//初始化PIDinitializePID(&pid, 50);//模拟控制过程for (int step = 0; step < 100; step++)//模拟获取输入值float input = input_value(step); // 自定义获取输入值的函数,根据实际应用进行修改//更新PID并获取输出float output = updatePID(&pid, input, 0.1); // 假设采样时间间隔为0.1秒//输出控制信号printf("Step: %d, Output: %.2f\n", step, output);}return 0;```上述代码实现了一个简单的PID控制算法。

PID最形象解释及其算法代码

PID最形象解释及其算法代码

小明接到这样一个任务:有一个水缸点漏水(而且漏水的速度还不一定固定不变),要求水面高度维持在某个位置,一旦发现水面高度低于要求位置,就要往水缸里加水。

小明接到任务后就一直守在水缸旁边,时间长就觉得无聊,就跑到房里看小说了,每30分钟来检查一次水面高度。

水漏得太快,每次小明来检查时,水都快漏完了,离要求的高度相差很远,小明改为每3分钟来检查一次,结果每次来水都没怎么漏,不需要加水,来得太频繁做的是无用功。

几次试验后,确定每10分钟来检查一次。

这个检查时间就称为采样周期。

开始小明用瓢加水,水龙头离水缸有十几米的距离,经常要跑好几趟才加够水,于是小明又改为用桶加,一加就是一桶,跑的次数少了,加水的速度也快了,但好几次将缸给加溢出了,不小心弄湿了几次鞋,小明又动脑筋,我不用瓢也不用桶,老子用盆,几次下来,发现刚刚好,不用跑太多次,也不会让水溢出。

这个加水工具的大小就称为比例系数。

小明又发现水虽然不会加过量溢出了,有时会高过要求位置比较多,还是有打湿鞋的危险。

他又想了个办法,在水缸上装一个漏斗,每次加水不直接倒进水缸,而是倒进漏斗让它慢慢加。

这样溢出的问题解决了,但加水的速度又慢了,有时还赶不上漏水的速度。

于是他试着变换不同大小口径的漏斗来控制加水的速度,最后终于找到了满意的漏斗。

漏斗的时间就称为积分时间。

小明终于喘了一口,但任务的要求突然严了,水位控制的及时性要求大大提高,一旦水位过低,必须立即将水加到要求位置,而且不能高出太多,否则不给工钱。

小明又为难了!于是他又开努脑筋,终于让它想到一个办法,常放一盆备用水在旁边,一发现水位低了,不经过漏斗就是一盆水下去,这样及时性是保证了,但水位有时会高多了。

他又在要求水面位置上面一点将水凿一孔,再接一根管子到下面的备用桶里这样多出的水会从上面的孔里漏出来。

这个水漏出的快慢就称为微分时间。

大学时代做机器人时用的PID算法源代码:#define PID_Uint struct pid_uintPID_Uint{int U_kk;int ekk;int ekkk;int Ur; //限幅输出值,需初始化int Un; //不灵敏区//int multiple; //PID系数的放大倍数,用整形数据的情况下,提高PID参数的设置精度固定为256int Kp; //比例,从小往大调int Ti; //积分,从大往小调int Td; //微分,用巡线板时设为0int k1; //int k2;int k3;};/********************************************************************函数名:void Init_PID_uint(PID_uint *p)功能:初始化PID参数说明:调用本函数之前,应该先对Kp,Ti,Td做设置,简化了公式入口参数:PID单元的参数结构体地址返回值:无***********************************************************************/void Init_PID_uint(PID_Uint *p){p->k1=(p->Kp)+(p->Kp)*1024/(p->Ti)+(p->Kp)*(p->Td)/1024;p->k2=(p->Kp)+2*(p->Kp)*(p->Td)/1024;p->k3=(p->Kp)*(p->Td)/1024;}/********************************************************************函数名:void reset_Uk(PID_Uint *p)功能:初始化U_kk,ekk,ekkk说明:在初始化时调用,改变PID参数时有可能需要调用入口参数:PID单元的参数结构体地址返回值:无***********************************************************************/void reset_Uk(PID_Uint *p){p->U_kk=0;p->ekk=0;p->ekkk=0;}/********************************************************************函数名:int PID_commen(int set,int jiance,PID_Uint *p)功能:通用PID函数说明:求任意单个PID的控制量入口参数:期望值,实测值,PID单元结构体返回值:PID控制量***********************************************************************/ int PID_common(int set,int jiance,PID_Uint *p){int ek,U_k=0;ek=jiance-set;if((ek>(p->Un))||(ek<-(p->Un))) //积分不灵敏区U_k=(p->U_kk)+(p->k1)*ek-(p->k2)*(p->ekk)+(p->k3)*(p->ekkk);p->U_kk=U_k;p->ekkk=p->ekk;p->ekk=ek;if(U_k>(p->Ur)) //限制最大输出量,U_k=p->Ur;if(U_k<-(p->Ur))U_k=-(p->Ur);return U_k/1024;}。

PID算法(源代码+调试方法)

PID算法(源代码+调试方法)

PID算法(源代码+调试方法)3。

PID代码//定义变量float Kp; //PI调节的比例常数float Ti; //PI调节的积分常数float T; //采样周期float Ki;float ek; //偏差e[k]float ek1; //偏差e[k-1]float ek2; //偏差e[k-2]float uk; //u[k]signed int uk1; //对u[k]四舍五入取整signed int adjust; //调节器输出调整量//变量初始化Kp="4";Ti="0"。

005;T="0".001;// Ki="KpT/Ti"=0.8,微分系数Kd=KpTd/T=0.8,Td=0.0002,根据实验调得的结果确定这些参数ek="0";ek1=0;ek2=0;uk="0";uk1=0;adjust="0";int piadjust(float ek) //PI调节算法if( gabs(ek)<0.1 ){adjust="0";}else{uk="Kp"*(ek-ek1)+Ki*ek; //计算控制增量ek1=ek;uk1=(signed int)uk;if(uk>0){if(uk-uk1>=0.5){uk1=uk1+1;}}if(uk<0){if(uk1-uk>=0.5){uk1=uk1-1;}}adjust="uk1";}return adjust;下面是在AD中断程序中调用的代码。

else //退出软启动后,PID调节,20ms调节一次{EvaRegs.CMPR3=EvaRegs.CMPR3+piadjust(ek);//误差较小PID调节稳住if(EvaRegs.CMPR3>=890){EvaRegs.CMPR3=890; //限制PWM占空比}}。

PID源码讲解

PID源码讲解

PID源码讲解有人让我解释一下我程序里面PID计算的过程,这里就插一节吧,就是介绍下我的PID,当然,还很不完善,后期肯定还要经过很多改动才行,这里就先介绍下现在的"初级版"吧.void PID_CAL(void) PID计算函数{static float thr=0,rool=0,pitch=0,yaw=0; 控制量static float rool_i=0,pitch_i=0; 积分int16_t Motor1,Motor2,Motor3,Motor4; 四个电机输出IMU_TEST(); 计算姿态GET_EXPRAD(); 获得控制量////////////////////////////////////////////////////////////////////////////////rool = PID_RP.P * DIF_ANGLE.X; roll方向的P计算if(Q_ANGLE.Rool>-0.1 && Q_ANGLE.Rool<0.1) 判断I是否需要清零{rool_i = 0;}rool_i -= PID_RP.I * Q_ANGLE.Rool; I计算PID_RP.IMAX = DIF_ANGLE.X * 10; 积分限幅if(PID_RP.IMAX<0){PID_RP.IMAX = (-PID_RP.IMAX) + 100;}else{PID_RP.IMAX += 100;}if(rool_i>PID_RP.IMAX) rool_i = PID_RP.IMAX;if(rool_i<-PID_RP.IMAX) rool_i = -PID_RP.IMAX;rool += rool_i; 积分rool -= PID_RP.D * GYRO_F.X; D计算///////////pitch = PID_RP.P * DIF_ANGLE.Y; 同上if(Q_ANGLE.Pitch>-0.1 && Q_ANGLE.Pitch<0.1){pitch_i = 0;}pitch_i -= PID_RP.I * Q_ANGLE.Pitch;if(PID_RP.IMAX<0){PID_RP.IMAX = (-PID_RP.IMAX) + 100;}else{PID_RP.IMAX += 100;}if(PID_RP.IMAX<0) PID_RP.IMAX = -PID_RP.IMAX;if(pitch_i>PID_RP.IMAX) pitch_i = PID_RP.IMAX;if(pitch_i<-PID_RP.IMAX) pitch_i = -PID_RP.IMAX;pitch += pitch_i;pitch -= PID_RP.D * GYRO_F.Y;/////////////GYRO_I[0].Z += EXP_ANGLE.Z/3000; yaw方向就简单的用了陀螺的积分PDyaw = -10 * GYRO_I[0].Z;yaw -= 3 * GYRO_F.Z;//thr = RC_DATA.THROTTLE+400;////////////////////////////////////////////////////////////////////////////////将控制量输出给电机Motor1=(int16_t)(thr + rool - pitch + yaw);Motor2=(int16_t)(thr + rool + pitch - yaw);Motor3=(int16_t)(thr - rool + pitch + yaw);Motor4=(int16_t)(thr - rool - pitch - yaw);if(FLY_ENABLE && (RC_DATA.THROTTLE>-400)) 和解锁有关,未解锁或油门太低电机禁止转动MOTO_PWMRFLASH(Motor1,Motor2,Motor3,Motor4);elseMOTO_PWMRFLASH(0,0,0,0);}程序就这么简单,当然还需要很多改进,PID参数也需要慢慢调试才行。

PID源代码

PID源代码

电机PID控制算法// 闭环控制算法// 功能:// 输入:*p PID控制结构体// 输出:电机控制输出值——PWM波脉冲宽度int count=0;unsigned int speed_PID_Calc( struct PID *p ){int ek;int tmpValue = p->ControlValue;int deltaValue = 0;ek = p->Reference - p->FeedBack; // 本次误差 = 参考值 - 反馈值//将PID公式离散化后,采用增量式PID控制,更新电机控制输出值// 遇限削弱积分法,如果进入饱和区,并且积分增加,则不进行积分运算,尽快离开饱和。

// 增量的范围(0~10)*(1+10+10)*256=53760)线性转换为(0~550),移位数, 在4~7之间为好if ( ( p->ControlValue >=550 && ek>0 ) || ( p->ControlValue <= 0 && ek<0 ))//进入饱和区则不再进行积分运算deltaValue = ((int)( p->Ka * ((ek - p->ek_1) + p->Kc * ( (ek - p->ek_1)- (p->ek_1 - p->ek_2) ))))>>5 ;else//不在饱和区,则按正常离散的PID公式计算deltaValue = ((int)( p->Ka * ((ek - p->ek_1) + p->Kb * ek + p->Kc * ( (ek - p->ek_1) - (p->ek_1 - p->ek_2) ))))>>5 ;// 更新前两次误差p->ek_2 = p->ek_1;p->ek_1 = ek;tmpValue = p->ControlValue + deltaValue;// 返回值if ( tmpValue >= 551 )return 550;elseif ( tmpValue <= 0 )return 1;else return tmpValue;}主要原理是上面的,如果需要和实际应用结合起来,那就依据所留I/O口进行适当的修改参数。

PID公式的推导过程及实现代码

PID公式的推导过程及实现代码

PID公式的推导过程及实现代码一、PID 框图:n0(t)是要稳定的值n(t)是当前输出值e(t) = n0(t) - n(t)一、模拟PID 控制原理这个公式网络上很好找:二、数字PID 控制由于模拟的微积分运算对应计算机来说是不太好写代码的,所以要利用采样将数据离散化于是公式就可以转换为:其中T 为采样时间,由于T 之类的参数是常量,所以将Kp 乘入公式中可以转换成另一种写法这个公式叫位置式算法由于要不断的累加ej,增加了计算量,所以这个公式又可以转换为增量式算法:然后u(k) = u(k-1) + u 三、参数的整定先将Ti 设置为无穷大,Td 设置为0,调节Kp 然后再调节Ti,最后是Td 四、实现代码typedef struct PID{ int SetPoint; //设定目标Desired ValuelongSumError; //误差累计double Proportion; // 比例常数Proportional Cons double Integral; //积分常数Integral Constdouble Derivative; //微分常数Derivative Const int LastError; //Error[-1] int PrevError; //Error[-2]}PID;/******************************************************************************** 函数名称: IncPIDCalc* 函数描述: 增量式PID 控制计算* 函数输入: int 当前位置* 函数输出: 无*函数返回: 增量式PID 结果*******************************************************************************/int IncPIDCalc(int NextPoint){ int iError, iIncpid; //当前误差iError =sptr->SetPoint - NextPoint; //增量计算iIncpid = sptr->Proportion * iError //E[k]项- sptr->Integral * sptr->LastError //E[k-1]项+ sptr->Derivative * sptr->PrevError; //E[k-2]项//存储误差,用于下次计算sptr->PrevError = sptr->LastError; sptr- >LastError = iError; //返回增量值return(iIncpid);}/******************************************************************************** 函数名称: LocPIDCalc* 函数描述: 位置式PID 控制计算* 函数输入: int 当前位置* 函数输出: 无*函数返回: 位置式PID 结果*******************************************************************************/int LocPIDCalc(int NextPoint){ int iError,dError; iError = sptr->SetPoint - NextPoint; //偏差sptr->SumError += iError; //积分dError = iError - sptr->LastError; //微分sptr->LastError = iError; return(sptr->Proportion * iError // 比例项+ sptr->Integral * sptr->SumError //积分项+ sptr->Derivative * dError); // 微分项}tips:感谢大家的阅读,本文由我司收集整编。

相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

小明接到这样一个任务:
有一个水缸点漏水(而且漏水的速度还不一定固定不变),
要求水面高度维持在某个位置,
一旦发现水面高度低于要求位置,就要往水缸里加水。

小明接到任务后就一直守在水缸旁边,
时间长就觉得无聊,就跑到房里看小说了,
每30分钟来检查一次水面高度。

水漏得太快,
每次小明来检查时,水都快漏完了,离要求的高度相差很远
,小明改为每3分钟来检查一次,结果每次来水都没怎么漏
,不需要加水,来得太频繁做的是无用功。

几次试验后,
确定每10分钟来检查一次。

这个检查时间就称为采样周期。

开始小明用瓢加水,水龙头离水缸有十几米的距离,
经常要跑好几趟才加够水,于是小明又改为用桶加,
一加就是一桶,跑的次数少了,加水的速度也快了,
但好几次将缸给加溢出了,不小心弄湿了几次鞋,小明又动脑筋,
我不用瓢也不用桶,老子用盆,几次下来,发现刚刚好,不用跑太多次,
也不会让水溢出。

这个加水工具的大小就称为比例系数。

小明又发现水虽然不会加过量溢出了,有时会高过要求位置比较多
,还是有打湿鞋的危险。

他又想了个办法,在水缸上装一个漏斗,
每次加水不直接倒进水缸,而是倒进漏斗让它慢慢加。

这样溢出的问题解决了,
但加水的速度又慢了,有时还赶不上漏水的速度。

于是他试着变换不同大小口径的漏斗来控制加水的速度
,最后终于找到了满意的漏斗。

漏斗的时间就称为积分时间。

小明终于喘了一口,但任务的要求突然严了,
水位控制的及时性要求大大提高,一旦水位过低,
必须立即将水加到要求位置,而且不能高出太多,否则不给工钱。

小明又为难了!于是他又开努脑筋,终于让它想到一个办法,常放一盆备用水在旁边,
一发现水位低了,不经过漏斗就是一盆水下去,这样及时性是保证了,但水位有时会高多了。

他又在要求水面位置上面一点将水凿一孔,再接一根管子到下面的备用桶里这样多出的水会从上面的孔里漏出来。

这个水漏出的快慢就称为微分时间。

大学时代做机器人时用的PID算法源代码:
#define PID_Uint struct pid_uint
PID_Uint
{
int U_kk;
int ekk;
int ekkk;
int Ur; //限幅输出值,需初始化
int Un; //不灵敏区
//int multiple; //PID系数的放大倍数,用整形数据的情况下,提高PID参数的设置精度固定为256 int Kp; //比例,从小往大调
int Ti; //积分,从大往小调
int Td; //微分,用巡线板时设为0
int k1; //
int k2;
int k3;
};
/********************************************************************
函数名:void Init_PID_uint(PID_uint *p)
功能:初始化PID参数
说明:调用本函数之前,应该先对Kp,Ti,Td做设置,简化了公式
入口参数:PID单元的参数结构体地址
返回值:无
***********************************************************************/
void Init_PID_uint(PID_Uint *p)
{
p->k1=(p->Kp)+(p->Kp)*1024/(p->Ti)+(p->Kp)*(p->Td)/1024;
p->k2=(p->Kp)+2*(p->Kp)*(p->Td)/1024;
p->k3=(p->Kp)*(p->Td)/1024;
}
/********************************************************************
函数名:void reset_Uk(PID_Uint *p)
功能:初始化U_kk,ekk,ekkk
说明:在初始化时调用,改变PID参数时有可能需要调用
入口参数:PID单元的参数结构体地址
返回值:无
***********************************************************************/
void reset_Uk(PID_Uint *p)
{
p->U_kk=0;
p->ekk=0;
p->ekkk=0;
}
/********************************************************************
函数名:int PID_commen(int set,int jiance,PID_Uint *p)
功能:通用PID函数
说明:求任意单个PID的控制量
入口参数:期望值,实测值,PID单元结构体
返回值:PID控制量
***********************************************************************/
int PID_common(int set,int jiance,PID_Uint *p)
{
int ek,U_k=0;
ek=jiance-set;
if((ek>(p->Un))||(ek<-(p->Un))) //积分不灵敏区
U_k=(p->U_kk)+(p->k1)*ek-(p->k2)*(p->ekk)+(p->k3)*(p->ekkk); p->U_kk=U_k;
p->ekkk=p->ekk;
p->ekk=ek;
if(U_k>(p->Ur)) //限制最大输出量,
U_k=p->Ur;
if(U_k<-(p->Ur))
U_k=-(p->Ur);
return U_k/1024;
}。

相关文档
最新文档