PID 算法详细介绍

这篇具有很好参考价值的文章主要介绍了PID 算法详细介绍。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 介绍

1.1 概述

比例(Proportion)积分(Integral)微分(Differential)控制器(PID控制器或三项控制器)是一种采用反馈的控制回路机制,广泛应用于工业控制系统和需要连续调制控制的各种其他应用。PID控制器连续计算误差值 e ( t ) e(t) e(t) 作为所需设定点(SP) 和测量过程变量(PV)之间的差值,并应用基于比例、积分和导数项(分别表示为P、I和D)的校正,因此得名。
PID 算法详细介绍,机器人,算法,算法
PID 算法详细介绍,机器人,算法,算法
r ( t ) r(t) r(t) 是期望的过程值或设定点 ( S P ) (SP) (SP) y ( t ) y(t) y(t) 是测量的过程值 ( P V ) (PV) (PV)

1.2 历史发展

  • 1911年,第一个PID控制器是由Elmer Sperry开发的。
  • 1922 年,俄裔美国工程师尼古拉斯·米诺斯基 ( Nicolas Minorsky)才首次利用理论分析制定了我们现在所说的 PID 或三项控制的正式控制律。米诺斯基当时正在为美国海军研究和设计自动船舶转向系统,他的分析基于对舵手的观察。他指出,舵手不仅根据当前航向误差,还根据过去的误差以及当前的变化率来驾驶船舶;然后 Minorsky 对此进行了数学处理。他的目标是稳定,而不是一般控制,这大大简化了问题。
  • 1933年,TIC(泰勒仪器公司)实现了完全可调节的前气动控制器。几年后,控制工程师通过将末端返回到一些假值,直到误差不为零,消除了比例控制器中发现的稳态误差。这个返回包含了误差,这被称为比例积分控制器。
  • 1940年,第一个气动PID控制器通过导数动作开发,以减少超调问题。
  • 1942年,Ziegler & Nichols引入了调谐规则,由工程师发现和设置PID控制器的合适参数。
  • 20世纪50年代中期,自动PID控制器在工业上得到了广泛的应用。工业中大多数现代 PID 控制都是作为DCS、PLC 或单片机程序来实现的。

1.3 应用

  • 火箭的姿态控制
  • 无人机悬停控制等
  • 相机稳定器、相机云台
  • 平衡小车
  • 汽车的定速巡航控制、转向控制
  • 发动机转速控制
  • 3D打印机上的温度控制器
  • 工业自动化领域,大约95%的闭环操作使用PID控制器。

1.4 优缺点

1.5 与 ON/OFF 型控制器对比

像PID控制器这样的闭环系统包括一个反馈控制系统。该系统利用一个固定点对反馈变量进行评估,从而产生误差信号。在此基础上,它改变系统输出。这个过程将继续,直到误差达到零,否则反馈变量的值就等于一个固定点。

与ON/OFF型控制器相比,该控制器提供了良好的效果。在开/关型控制器中,只需两个条件即可管理系统。大多数暖通空调系统、冰箱都采用这种方法。例如,在冰箱中,它会冷却内部直到达到所需温度,然后关闭冷却器,直到达到高于所需温度的设定值。一旦工艺值低于固定点,则开启。类似地,一旦该值高于固定值,它将关闭。这种控制器的输出不稳定,在不动点的区域内振荡频繁。然而,与ON/OFF型控制器相比,PID 控制器更加稳定和准确。
PID 算法详细介绍,机器人,算法,算法

1.6 响应类型

Introduction to PID

由PID控制器驱动的系统通常具有三种类型的响应:欠阻尼、过阻尼和临界阻尼。
PID 算法详细介绍,机器人,算法,算法
PID 算法详细介绍,机器人,算法,算法

  • 欠阻尼响应在稳定之前围绕参考值振荡。
  • 过阻尼响应上升缓慢并且不会超过参考值。
  • 临界阻尼响应具有最快的上升时间,且不会超过参考值。

2 公式

2.1 PID 系统定义与公式

PID 算法详细介绍,机器人,算法,算法

r ( t ) r(t) r(t) setpoint, reference,是期望的过程值或设定值 ( S P ) (SP) (SP)
y ( t ) y(t) y(t) output, process variable,是测量的过程值,输出值 ( P V ) (PV) (PV)
e ( t ) e(t) e(t) error,是偏差;
u ( t ) u(t) u(t) control effort,是控制量;

PID控制器的显着特点是能够利用比例、积分和微分这三个控制项对控制器输出的影响来进行精确和最优的控制。

PID 控制器,不断计算误差值 e ( t ) e(t) e(t) 作为所需设定点之间的差异 S P = r ( t ) SP=r(t) SP=r(t) 和测量的过程变量 P V = y ( t ) : e ( t ) = r ( t ) − y ( t ) PV=y(t):e(t)=r(t)-y(t) PV=y(t):e(t)=r(t)y(t) ,并应用基于比例、积分和导数项的修正。控制器尝试通过调整控制变量来最小化随时间变化的误差 u ( t ) u(t) u(t)。manipulated variable (MV)。

u ( t ) = M V ( t ) = K p e ( t ) + K i ∫ 0 t e ( τ ) d τ + K d d e ( t ) d t (1-1) u(t)=MV(t)=K_pe(t)+K_i \int_{0}^{t}e(τ)dτ+K_d \dfrac{de(t)}{dt}\tag{1-1} u(t)=MV(t)=Kpe(t)+Ki0te(τ)dτ+Kddtde(t)(1-1)
u ( t ) = P ∗ 偏差 + I ∗ 面积 + D ∗ 斜率 u(t)=P*偏差 + I*面积 + D*斜率 u(t)=P偏差+I面积+D斜率

K p K_p Kp 是比例增益,该参数能产生较大变化,加快系统的响应,可能导致系统超调和振荡;
K i K_i Ki 是积分增益,加速过程向设定点的移动;
K d K_d Kd 是导数增益,有助于减小系统的超调幅度和振荡次数;
t 是时间或瞬时时间(现在);
τ \tau τ 是积分变量(取值从时间 0 到现在 t)。

K p K_p Kp, K i K_i Ki, K d K_d Kd 均为非负数,分别表示比例项、积分项和导数项的系数(有时表示为P、I和D)。

From PID Controllers:Theory, Design and Tuning

u ( t ) = M V ( t ) = K p ( e ( t ) + 1 T i ∫ 0 t e ( τ ) d τ + T d d e ( t ) d t ) (1-2) u(t)=MV(t)=K_p \Bigl(e(t)+ \dfrac1{T_i} \int_{0}^{t}e(τ)dτ + T_d \dfrac{de(t)}{dt} \Bigl) \tag{1-2} u(t)=MV(t)=Kp(e(t)+Ti10te(τ)dτ+Tddtde(t))(1-2)

在方程的标准形式中, K i K_i Ki K d K_d Kd 分别替换为 K p T i \dfrac{K_p}{T_i} TiKp K p T d K_pT_d KpTd;这样做的好处是 T i , T d T_i, T_d Ti,Td 具有一些可以理解的物理意义,因为它们分别代表积分时间和微分时间。 K p T i \dfrac{K_p}{T_i} TiKp 确定控制器能够容忍输出持续高于或低于设定点的时间。 K p T d K_pT_d KpTd 是控制器尝试接近设定点的时间常数。

2.2 PID 数字公式

由于计算机控制是一种采样控制,它只能根据采样时刻的偏差计算控制量,而不能像模拟控制那样连续输出控制量,进行连续控制。由于这一特点,(式 1-1)中的积分项和微分项不能直接使用,必须进行离散化处理。
离散化处理的方法为:以 τ \tau τ 作为采样周期,k 作为采样序号,则离散采样时间 k τ k\tau kτ 对应着连续时间 t,用矩形法数值积分近似代替积分,用一阶后向差分近似代替微分,可作如下近似变换:
t ≈ k τ ( k = 0 , 1 , 2 , . . . ) u ( t ) ≈ u ( k ) e ( t ) ≈ e ( k ) ∫ 0 t e ( τ ) d τ ≈ τ ∑ j = 0 k e ( j τ ) = τ ∑ j = 0 k e j d e ( t ) d t ≈ e ( k τ ) − e ( ( k − 1 ) τ ) τ = e k − e k − 1 τ \begin{align} t & ≈ k \tau (k=0,1,2,...) \notag\\ u(t) & ≈ u(k) \notag\\ e(t) & ≈ e(k) \notag\\ \int_{0}^{t}e(τ)dτ & ≈ \tau \sum_{j=0}^k e(j \tau) = \tau \sum_{j=0}^k e_j \tag{2-1}\\ \dfrac{de(t)}{dt} & ≈ \dfrac{e(k\tau)-e((k-1)\tau)}{\tau} = \dfrac{e_k-e_{k-1}}{\tau} \notag \end{align} tu(t)e(t)0te(τ)dτdtde(t)kτ(k=0,1,2,...)u(k)e(k)τj=0ke(jτ)=τj=0kejτe(kτ)e((k1)τ)=τekek1(2-1)

偏差值 e ( i τ ) e(i\tau) e(iτ),简记为 e ( i ) e(i) e(i) 或者 e i e_i ei;
控制量 u ( i τ ) u(i\tau) u(iτ),简记为 u ( i ) u(i) u(i) 或者 u i u_i ui;

2.3 位置式 PID 算法

将(式 2-1)代入(式 1-1),就可以得到离散的 PID 表达式为
u ( k ) = K p e ( k ) + K i τ ∑ j = 0 k e ( j ) + K d e ( k ) − e ( k − 1 ) τ (2-2) u(k)=K_pe(k)+K_i \tau \sum_{j=0}^{k}e(j) + K_d \dfrac{e(k)-e(k-1)}{\tau}\tag{2-2} u(k)=Kpe(k)+Kiτj=0ke(j)+Kdτe(k)e(k1)(2-2)
将(式 2-1)代入(式 1-2),就可以得到离散的 PID 表达式为
u ( k ) = K p ( e ( k ) + τ T i ∑ j = 0 k e ( j ) + T d e ( k ) − e ( k − 1 ) τ ) (2-3) u(k)=K_p \Bigl(e(k)+ \dfrac{\tau}{T_i} \sum_{j=0}^{k}e(j) + T_d \dfrac{e(k)-e(k-1)}{\tau} \Bigl) \tag{2-3} u(k)=Kp(e(k)+Tiτj=0ke(j)+Tdτe(k)e(k1))(2-3)

积分系数、微分系数做如下替换:
注意:必须使 τ \tau τ 为定值,或者变化小到可以忽略,这样P、I、D才是固定常数,才可能调节
K i = K p T i K d = K p T d K I = K p ∗ τ T i = K i τ K D = K p T d τ = K D τ \begin{align} K_i & = \dfrac{K_p}{T_i} \notag\\ K_d & = K_pT_d \notag\\ K_I & = \dfrac{K_p*\tau}{T_i} = K_i \tau \tag{2-4}\\ K_D & = K_p\dfrac{T_d}{\tau} = \dfrac{K_D}{\tau} \notag\\ \end{align} KiKdKIKD=TiKp=KpTd=TiKpτ=Kiτ=KpτTd=τKD(2-4)

这样做的好处是 T i , T d T_i, T_d Ti,Td 具有一些可以理解的物理意义。
T i T_i Ti 代表积分时间常数;
T d T_d Td 代表微分时间常数。

K I K_I KI K D K_D KD 代入(式 2-2),就可以得到离散的 PID 表达式为
u ( k ) = K p e ( k ) + K I ∑ j = 0 k e ( j ) + K D [ e ( k ) − e ( k − 1 ) ] (2-5) u(k) = K_pe(k)+K_I \sum_{j=0}^{k}e(j) + K_D [e(k)-e(k-1)]\tag{2-5} u(k)=Kpe(k)+KIj=0ke(j)+KD[e(k)e(k1)](2-5)

k k k 为采样序列号, k = 0 , 1 , 2 , . . . k=0,1,2,... k=0,1,2,...
u k u_k uk 为第 k 次采样时刻的计算机输出值;
e k e_k ek 为第 k 次采样时刻输入的偏差值;
e k − 1 e_{k-1} ek1 为第 k-1 次采样时刻输入的偏差值;

2.4 增量式 PID 算法

所谓增量式 PID 是指数字控制器的输出只是控制量的增量 Δ u k \Delta u_k Δuk。当执行机构需要的控制量是增量,而不是位置量的绝对数值时,可以使用增量式 PID 控制算法进行控制。

增量式 PID 控制算法可以通过(式 2-2)推导出。由(式 2-2)可以得到控制器的第 k-1 个采样时刻的输出值为:

u ( k − 1 ) = K p e ( k − 1 ) + K i τ ∑ j = 0 k − 1 e ( j ) + K d e ( k − 1 ) − e ( k − 2 ) τ (2-6) u(k-1) = K_pe(k-1)+K_i \tau \sum_{j=0}^{k-1}e(j) + K_d \dfrac{e(k-1)-e(k-2)}{\tau}\tag{2-6} u(k1)=Kpe(k1)+Kiτj=0k1e(j)+Kdτe(k1)e(k2)(2-6)

由(式 2-3)可以得到控制器的第 k-1 个采样时刻的输出值为:
u ( k − 1 ) = K p ( e ( k − 1 ) + τ T i ∑ j = 0 k − 1 e ( j ) + T d e ( k − 1 ) − e ( k − 2 ) τ ) (2-7) u(k-1)=K_p \Bigl(e(k-1)+ \dfrac{\tau}{T_i} \sum_{j=0}^{k-1}e(j) + T_d \dfrac{e(k-1)-e(k-2)}{\tau} \Bigl) \tag{2-7} u(k1)=Kp(e(k1)+Tiτj=0k1e(j)+Tdτe(k1)e(k2))(2-7)

用(式 2-3)减去(式 2-7)相减并整理,就可以得到增量式 PID 控制算法公式:
Δ u k = u ( k ) − u ( k − 1 ) = K p ( e ( k ) − e ( k − 1 ) + τ T i e ( k ) + T d e ( k ) − 2 e ( k − 1 ) + e ( k − 2 ) τ ) = K p ( 1 + τ T i + T d τ ) e ( k ) − K p ( 1 + 2 T d τ ) e ( k − 1 ) + K p T d τ e ( k − 2 ) = A e ( k ) + B e ( k − 1 ) + C e ( k − 2 ) \begin{align} \Delta u_k = u(k) - u(k-1) & = K_p \Bigl(e(k)-e(k-1)+ \dfrac{\tau}{T_i} e(k) + T_d \dfrac{e(k)-2e(k-1)+e(k-2)}{\tau} \Bigl) \notag \\ & = K_p(1+\dfrac{\tau}{T_i}+\dfrac{T_d}{\tau})e(k) - K_p(1+\dfrac{2T_d}{\tau})e(k-1)+K_p\dfrac{T_d}{\tau}e(k-2) \tag{2-8} \\ & = Ae(k) + Be(k-1) + Ce(k-2) \notag \end{align} Δuk=u(k)u(k1)=Kp(e(k)e(k1)+Tiτe(k)+Tdτe(k)2e(k1)+e(k2))=Kp(1+Tiτ+τTd)e(k)Kp(1+τ2Td)e(k1)+KpτTde(k2)=Ae(k)+Be(k1)+Ce(k2)(2-8)

由(式 2-8)可以看出,如果计算机控制系统采用恒定的采样周期 τ \tau τ ,一旦确定 A、 B、 C,只要使用前后三次测量的偏差值,就可以由(式 2-8)求出控制量。

增量式 PID 控制算法与位置式 PID 算法(式 2-3)相比,只需要保持当前时刻以前三个时刻的偏差值即可,累计误差较小,计算量小的多,因此在实际中得到广泛的应用。

而位置式 PID 控制算法也可以通过增量式控制算法推出递推计算公式:
u ( k ) = u ( k − 1 ) + Δ u ( k ) (2-9) u(k) = u(k-1) + \Delta u(k) \tag{2-9} u(k)=u(k1)+Δu(k)(2-9)
(式 2-9)就是目前在计算机控制中广泛应用的数字递推 PID 控制算法。

3 调试技巧

PID 算法详细介绍,机器人,算法,算法

4 代码实现

python

From 使用python模拟实现PID控制算法

import numpy as np
import matplotlib.pyplot as plt

class PositionPID(object):
    """位置式PID算法实现"""

    def __init__(self, target, cur_val, dt, max, min, p, i, d) -> None:
        self.dt = dt  # 循环时间间隔
        self._max = max  # 最大输出限制,规避过冲
        self._min = min  # 最小输出限制
        self.k_p = p  # 比例系数
        self.k_i = i  # 积分系数
        self.k_d = d  # 微分系数

        self.target = target  # 目标值
        self.cur_val = cur_val  # 算法当前PID位置值,第一次为设定的初始位置
        self._pre_error = 0  # t-1 时刻误差值
        self._integral = 0  # 误差积分值


    def calculate(self):
        """
        计算t时刻PID输出值cur_val
        """
        error = self.target - self.cur_val  # 计算当前误差
        # 比例项
        p_out = self.k_p * error  
        # 积分项
        self._integral += (error * self.dt)
        i_out = self.k_i * self._integral
        # 微分项
        derivative = (error - self._pre_error) / self.dt
        d_out = self.k_d * derivative

        # t 时刻pid输出
        output = p_out + i_out + d_out

        # 限制输出值
        if output > self._max:
            output = self._max
        elif output < self._min:
            output = self._min
        
        self._pre_error = error
        self.cur_val = output
        return self.cur_val

    def fit_and_plot(self, count = 200):
        """
        使用PID拟合setPoint
        """
        counts = np.arange(count)
        outputs = []

        for i in counts:
            outputs.append(self.calculate())
            print('Count %3d: output: %f' % (i, outputs[-1]))

        print('Done')
        # print(outputs)
        
        plt.figure()
        plt.axhline(self.target, c='red')
        plt.plot(counts, np.array(outputs), 'b.')
        plt.ylim(min(outputs) - 0.1 * min(outputs), max(outputs) + 0.1 * max(outputs))
        plt.plot(outputs)
        plt.show()

pid = PositionPID(10, -5, 0.5, 100, -100, 0.2, 0.1, 0.01)
pid.fit_and_plot(150)

PID 算法详细介绍,机器人,算法,算法

c/c++

From PID超详细教程——PID原理+串级PID+C代码+在线仿真调参

//首先定义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计算
//参数为(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 mypid;//创建一个PID结构体变量
 
int main()
{
    //...这里有些其他初始化代码
    PID_Init(&mypid,10,1,5,800,1000);//初始化PID参数
    while(1)//进入循环运行
    {
        float feedbackValue=...;//这里获取到被控对象的反馈值
        float targetValue=...;//这里获取到目标值
        PID_Calc(&mypid,targetValue,feedbackValue);//进行PID计算,结果在output成员变量中
        设定执行器输出大小(mypid.output);
        delay(10);//等待一定时间再开始下一次循环
    }
}

单环效果
PID 算法详细介绍,机器人,算法,算法
PID 算法详细介绍,机器人,算法,算法

串级PID的C语言代码

//此处需要插入上面的单级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的输出
}
 
CascadePID mypid;//创建串级PID结构体变量
 
int main()
{
    //...其他初始化代码
    PID_Init(&mypid.inner,10,0,0,0,1000);//初始化内环参数
    PID_Init(&mypid.outer,5,0,5,0,100);//初始化外环参数
    while(1)//进入循环运行
    {
        float outerTarget=...;//获取外环目标值
        float outerFeedback=...;//获取外环反馈值
        float innerFeedback=...;//获取内环反馈值
        PID_CascadeCalc(&mypid,outerTarget,outerFeedback,innerFeedback);//进行PID计算
        设定执行机构输出大小(mypid.output);
        delay(10);//延时一段时间
    }
}

双环效果
PID 算法详细介绍,机器人,算法,算法

5 双环控制

串联

from 嵌入式软件算法之PID闭环控制原理

如果电机控制既要控制速度又要控制位置,因为速度和位置相关,所以需要串联。
PID 算法详细介绍,机器人,算法,算法

并联

from 嵌入式软件算法之PID闭环控制原理

姿态角度与速度间无相关性,各自单独算一路控制
PID 算法详细介绍,机器人,算法,算法

6 示例

循迹小车

一文搞懂PID控制算法

可见小车的循迹效果。

野火中步进电机位置速度双环控制

11. 步进电机位置速度双环控制实现

9. 步进电机速度环控制实现 和 10. 步进电机位置环控制实现 介绍了单环控制已经能很好地提高电机的性能了,但是仍有其局限性。

使用速度环精确控制了电机的转速,但是停止的位置难以精确控制;
使用位置环精确控制了电机转过的角度,却不得不人为限制速度来防止堵转。

位置环和速度环双环控制,既实现位置的精确调节又实现速度的自动控制。
PID 算法详细介绍,机器人,算法,算法

该控制下,编码器不仅起到了反馈位置的作用,也起到了反馈速度的作用。

调参技巧:在PID参数整定时,采取先内环再外环的方法,也就是先单独使用速度环控制,得到满意的参数后, 再把位置环套在外面,整定位置环参数,最后根据整体效果对速度环参数进行微调。

bsp_pid.h

/*pid*/
typedef struct
{
  float target_val;     //目标值
  float actual_val;     //实际值
  float err;            //定义当前偏差值
  float err_next;       //定义下一个偏差值
  float err_last;       //定义上一个偏差值
  float Kp, Ki, Kd;     //定义比例、积分、微分系数
}_pid;

bsp_stepper_ctrl.h

/*宏定义*/
/*******************************************************/
#define TIM_STEP_FREQ     (SystemCoreClock/TIM_PRESCALER) // 频率ft值

/*电机单圈参数*/
#define STEP_ANGLE                          1.8f                 //步进电机的步距角 单位:度
#define FSPR              (360.0f/STEP_ANGLE)  //步进电机的一圈所需脉冲数

#define MICRO_STEP        32                                         //细分器细分数
#define SPR               (FSPR*MICRO_STEP)    //细分后一圈所需脉冲数

#define PULSE_RATIO       (float)(SPR/ENCODER_TOTAL_RESOLUTION)//步进电机单圈脉冲数与编码器单圈脉冲的比值
#define SAMPLING_PERIOD   50                   //PID采样频率,单位Hz

#define MOVE_CTRL         0.1f                   //启用速度环控制量
#define TARGET_DISP       20                   //步进电机运动时的目标圈数,单位:转
#define TARGET_SPEED_MAX  800                 // 目标速度的最大值

typedef struct {
  unsigned char stepper_dir : 1;               //步进电机方向
  unsigned char stepper_running : 1;           //步进电机运行状态
  unsigned char MSD_ENA : 1;                   //驱动器使能状态
}__SYS_STATUS;

bsp_stepper_ctrl.c-增量式PID算法实现-增量式PID

/**
   * @brief  增量式PID算法实现
   * @param  val:当前实际值
   * @note   无
   * @retval 通过PID计算后的输出
   */
 float PID_realize(_pid *pid, float temp_val)
 {
   /*传入实际值*/
   pid->actual_val = temp_val;
   /*计算目标值与实际值的误差*/
   pid->err=pid->target_val-pid->actual_val;

   /*PID算法实现*/
   float increment_val = pid->Kp*(pid->err - pid->err_next) + pid->Ki*pid->err + pid->Kd*(pid->err - 2 * pid->err_next + pid->err_last);
   /*传递误差*/
   pid->err_last = pid->err_next;
   pid->err_next = pid->err;
   /*返回增量值*/
   return increment_val;
 }

bsp_stepper_ctrl.c-步进电机位置速度双闭环控制

 /**
   * @brief  步进电机位置速度双闭环控制
   * @retval 无
   * @note   基本定时器中断内调用
   */
 void Stepper_Ctrl(void)
 {
   /* 编码器相关变量 */
   static __IO float last_count = 0;
   __IO float capture_count = 0;
   __IO float capture_per_unit = 0;
   /* 经过pid计算后的期望值 */
   static __IO float speed_cont_val = 0.0f;
   static __IO float move_cont_val = 0.0f;
   static int cont_val = 0;

   /* 当电机运动时才启动pid计算 */
   if((sys_status.MSD_ENA == 1) && (sys_status.stepper_running == 1))
   {
     /* 计算编码器脉冲数 */
     capture_count = (int)__HAL_TIM_GET_COUNTER(&TIM_EncoderHandle) + (encoder_overflow_count * ENCODER_TIM_PERIOD);
     /* 计算速度环的传入值 */
     capture_per_unit = capture_count - last_count;
     last_count = capture_count;

     /* 编码器脉冲累计值作为实际值传入位置环pid控制器 */
     move_cont_val += PID_realize_move(&move_pid, (float)capture_count);// 进行 PID 计算
     /* 判断运动方向 */
     move_cont_val > 0 ? (MOTOR_DIR(CW)) : (MOTOR_DIR(CCW));
     /* 判断是否启用速度环 */
     if (fabsf(move_cont_val) >= MOVE_CTRL)
     {
       /* 传递位置环计算值,便于计算*/
       cont_val = move_cont_val;

       /* 目标速度上限处理 */
       if (cont_val > TARGET_SPEED_MAX)
       {
         cont_val = TARGET_SPEED_MAX;
       }
       else if (cont_val < -TARGET_SPEED_MAX)
       {
         cont_val = -TARGET_SPEED_MAX;
       }

 #if defined(PID_ASSISTANT_EN)
       int32_t temp = cont_val;
       set_computer_value(SEED_TARGET_CMD, CURVES_CH2, &temp, 1);     // 给通道 2 发送目标值
 #endif
       /* 设定速度的目标值 */
       set_pid_target(&speed_pid, cont_val);
       /* 单位时间内的编码器脉冲数作为实际值传入速度环pid控制器 */
       speed_cont_val += PID_realize_speed(&speed_pid, (float)capture_per_unit);// 进行 PID 计算
       /* 由于OC_Pulse_num为uint16_t变量,取速度环输出值的绝对值进行后续计算*/
       cont_val = fabsf(speed_cont_val);
       /* 计算比较计数器的值 */
       OC_Pulse_num = ((uint16_t)(TIM_STEP_FREQ / (cont_val * PULSE_RATIO * SAMPLING_PERIOD))) >> 1;
     }
     else
     {
       /* 计算比较计数器的值 */
       OC_Pulse_num = ((uint16_t)(TIM_STEP_FREQ / ((float)move_cont_val * PULSE_RATIO))) >> 1;
     }
 #if PID_ASSISTANT_EN
     int Temp_ch2 = capture_per_unit;    // 上位机需要整数参数,转换一下
     int Temp_ch1 = capture_count;
     set_computer_value(SEED_FACT_CMD, CURVES_CH2, &Temp_ch2, 1);  // 给通道 1 发送实际值     // 给通道 2 发送实际值
     set_computer_value(SEED_FACT_CMD, CURVES_CH1, &Temp_ch1, 1);     // 给通道 1 发送实际值

 #else
     printf("实际值:%d,目标值:%.0f\r\n", capture_per_unit, pid.target_val);// 打印实际值和目标值
 #endif
   }
   else
   {
     /*停机状态所有参数清零*/
     last_count = 0;
     speed_cont_val = 0;
     move_cont_val = 0;
     speed_pid.actual_val = 0;
     speed_pid.err = 0;
     speed_pid.err_last = 0;
     speed_pid.err_next = 0;
     move_pid.actual_val = 0;
     move_pid.err = 0;
     move_pid.err_last = 0;
     move_pid.err_next = 0;
   }
 }

main

 /**
   * @brief  主函数
   * @param  无
   * @retval 无
   */
 int main(void)
 {
   /* 初始化系统时钟为168MHz */
   SystemClock_Config();
   /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
   DEBUG_USART_Config();
   printf("欢迎使用野火 电机开发板 步进电机位置速度双环控制 例程\r\n");
   printf("按下按键3启动和停止电机\r\n");
   /* 初始化时间戳 */
   HAL_InitTick(5);
   /*按键中断初始化*/
   Key_GPIO_Config();
   /*led初始化*/
   LED_GPIO_Config();
   /* 初始化基本定时器定时,20ms产生一次中断 */
   TIMx_Configuration();
   /* 编码器接口初始化 */
   Encoder_Init();
   /*步进电机初始化*/
   stepper_Init();
   /* 上电默认停止电机 */
   Set_Stepper_Stop();
   /* PID算法参数初始化 */
   PID_param_init();
 //  MOTOR_DIR(CW);

   /* 目标位置转换为编码器的脉冲数作为pid目标值 */
   move_pid.target_val = TARGET_DISP * ENCODER_TOTAL_RESOLUTION;
   int32_t Temp = TARGET_DISP * ENCODER_TOTAL_RESOLUTION;
 #if PID_ASSISTANT_EN
   set_computer_value(SEED_STOP_CMD, CURVES_CH1, NULL, 0);    // 同步上位机的启动按钮状态
   set_computer_value(SEED_TARGET_CMD, CURVES_CH1, &Temp, 1);// 给通道 1 发送目标值
 #endif

   while(1)
   {
     /* 扫描KEY1,启动电机 */
     if( Key_Scan(KEY1_GPIO_PORT,KEY1_PIN) == KEY_ON  )
     {
     #if PID_ASSISTANT_EN
       Set_Stepper_Start();
       set_computer_value(SEED_START_CMD, CURVES_CH1, NULL, 0);// 同步上位机的启动按钮状态
     #else
       Set_Stepper_Start();
     #endif
     }
     /* 扫描KEY2,停止电机 */
     if( Key_Scan(KEY2_GPIO_PORT,KEY2_PIN) == KEY_ON  )
     {
     #if PID_ASSISTANT_EN
       Set_Stepper_Stop();
       set_computer_value(SEED_STOP_CMD, CURVES_CH1, NULL, 0);// 同步上位机的启动按钮状态
     #else
       Set_Stepper_Stop();
     #endif
     }
     /* 扫描KEY3,增大目标位置*/
     if( Key_Scan(KEY3_GPIO_PORT,KEY3_PIN) == KEY_ON  )
     {
       /* 目标位置增加48000,对应电机位置增加20圈 */
       move_pid.target_val += 48000;

     #if PID_ASSISTANT_EN
       int temp = move_pid.target_val;
       set_computer_value(SEED_TARGET_CMD, CURVES_CH1, &temp, 1);// 给通道 1 发送目标值
     #endif
     }
     /* 扫描KEY4,减小目标位置 */
     if( Key_Scan(KEY4_GPIO_PORT,KEY4_PIN) == KEY_ON  )
     {
       /* 目标位置减小48000,对应电机位置减少20圈 */
       move_pid.target_val -= 48000;

     #if PID_ASSISTANT_EN
       int temp = move_pid.target_val;
       set_computer_value(SEED_TARGET_CMD, CURVES_CH1, &temp, 1);// 给通道 1 发送目标值
     #endif
     }
   }
 }

其他

  • PID双闭环在吸盘机械手位置控制系统中的应用

  • Control of double-loop permanent magnet synchronous motor drives by optimized fractional and distributed-order PID controllers

  • Position and speed tracking control of inverted pendulum based on double PID controllers

  • Double-Loop PID-Type Neural Network Sliding Mode Control of an Uncertain Autonomous Underwater Vehicle Model Based on a Nonlinear High-Order Observer with Unknown Disturbance

  • Restaurant Serving Robot with Double Line Sensors Following Approach

  • Research on AGV trajectory tracking control based on double closed-loop and PID control

  • AMB Vibration Control for Structural Resonance of Double-Gimbal Control Moment Gyro With High-Speed Magnetically Suspended Rotor

  • Double Closed Loop Sliding Mode PID Control System for BLDCM of Pure Electric Vehicle

  • SPEED CONTROL OF DC MOTOR USING OPTIMIZATION TECHNIQUES BASED PID CONTROLLER

补充知识点

模拟量数字化

实际数字化应用中,PID 系统中的积分项和微分项需要进行离散化处理。类似的典型应用有数字示波器。对于数字示波器来说它无法直接量化模拟信号,替代的办法就是持续周期性采样,然后将得到的一系列采样点显示出来,当采样速率越高,显示的图像越真实,这就是数学中极限的与微分的思想。
PID 算法详细介绍,机器人,算法,算法

香农(Shannon) 采样定律

  • 取样
    连续变量函数f(x)不能直接用计算机处理,选取 f ( x ) f(x) f(x) 在离散点的值 f ( x n ) f(x_n) f(xn),这个过程称为取样。
  • 定理内容
    香农取样定理是针对有限带宽函数的。
    为了不失真地恢复模拟信号,采样频率应该不小于模拟信号频谱中最高频率的2倍。

参考

1、wiki–PID controller
2、What is a PID Controller : Working & Its Applications
3、PID Controllers:Theory, Design and Tuning
4、11. 步进电机位置速度双环控制实现
5、嵌入式软件算法之PID闭环控制原理
6、PID控制算法详解
7、小圆滚滚–PID算法的数学推导
8、什么是PID?故事+动图,通俗易懂!精彩讲解!
9、PID Control
10、PID算法推导与解析
11、PID控制
12、Proportional Integral Derivative (PID)
13、串讲:控制理论:PID控制(经典控制理论)
14、深入浅出PID控制算法
https://blog.csdn.net/kilotwo/article/details/79828201
https://blog.csdn.net/kilotwo/article/details/79829669
https://blog.csdn.net/kilotwo/article/details/79952530
15、Introduction to PID
16、PID控制原理与增量式PID算法
17、PID超详细教程——PID原理+串级PID+C代码+在线仿真调参
18、Going Straight with PID
19、Build a PID Controller with Python 2019
20、PID算法原理 一图看懂PID的三个参数
21、一文搞懂PID控制算法
22、PID控制(四)(单环与双环PID)
23、PID控制原理,看了开头,你就会看到结尾!
24、PID算法及机械臂应用(附简单Python实现)
25、PID公式通俗理解
26、使用python模拟实现PID控制算法
27、Implementation of PID controller in Python
28、Controlling Physical Systems
29、PID control文章来源地址https://www.toymoban.com/news/detail-717203.html

到了这里,关于PID 算法详细介绍的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • PID循迹机器人及整定

    如何对线路循迹机器人进行编程 (robotresearchlab.com) PID调谐文章:http://robotresearchlab.com/2019/02/16/pid-line-follower-tuning/ 介绍人们选择对 循迹机器人 进行线路编程的两种主要方式,并比较两者。将详细比较“简单循迹”和“PID 循迹”。在低速下,简单的循迹算法是完全可以接受的

    2024年02月15日
    浏览(40)
  • 基于ROS实现的机器人运动PID控制器

    下面是一个基于ROS实现的机器人运动PID控制器的例子: 首先,需要定义机器人的运动控制器节点,例如: 其中, cmd_vel_pub 是一个发布器,用于发布机器人的运动控制指令; odom_sub 是一个订阅器,用于接收机器人的里程计信息。 然后,需要实现一个PID控制器的类,例如: 其

    2024年02月13日
    浏览(54)
  • 面向低成本巡线机器人的PID控制器优化——附源码

    目录 介绍 测试 电子元器件 系统特征 控制器设计 位置误差的计算 比例控制 积分控制 微分控制 改进的PID控制器 测试轨迹 源码链接 本文对经典PID控制器的改进和开环控制机制的发展进行了讨论,以提高差动轮式机器人的稳定性和鲁棒性。为了部署该算法,使用低成本、现成

    2024年04月08日
    浏览(47)
  • 以报时机器人为例详细介绍tracker_store和event_broker

      报时机器人源码参考[1][2],本文重点介绍当 tracker_store 类型为 SQL 时,events 表的表结构以及数据是如何生成的。以及当 event_broker 类型为 SQL 时,events 表的表结构以及数据是如何生成的。   Rasa 对话系统启动方式详见参考文献[3]中执行程序部分,这里不再赘述。如下所

    2024年01月18日
    浏览(56)
  • 基于蚁群算法的机器人路径规划matlab——代码注释超级详细,都能看懂

    本文对基本蚁群算法代码进行了详细的注释,每一步都简单易懂。程序在matlab中可直接运行,适合刚开始学习本算法的同学入门。 蚁群算法是由意大利学者Dorigo提出的一种仿生智能算法,最早运用在旅行商问题上。蚁群算法模仿蚂蚁觅食过程设计出的智能启发式算法,蚂蚁觅

    2024年02月15日
    浏览(53)
  • MATLAB仿真Gough-Stewart并联机器人斯图尔特6自由度并联机器人逆运动学仿真 动力学控制pid控制

    MATLAB仿真Gough-Stewart并联机器人斯图尔特6自由度并联机器人逆运动学仿真 动力学控制pid控制 1.搭建了六自由度Stewart并联机器人simulink simscape仿真模型 2.建立了逆向运动学仿真 输入位置和姿态求解各个杆长 3.运用pid控制器进行动力学跟踪控制 使用MATLAB进行了Gough-Stewart并联机器

    2024年01月16日
    浏览(58)
  • 【对话机器人】开源机器人项目介绍

    目录 1. 闲聊机器人介绍 2. 青云客平台 3. 思知项目 闲聊机器人是一种基于人工智能和自然语言处理技术的智能对话系统,旨在模拟人类的语言交流能力,与用户进行自然、连贯的对话。闲聊机器人能够理解用户的问题或指令,通过分析和处理文本,生成符合语法和语义规则的

    2024年02月11日
    浏览(57)
  • 机器人控制算法——移动机器人横向控制最优控制LQR算法

    1.Introduction LQR (外文名linear quadratic regulator)即线性二次型调节器,LQR可得到状态线性反馈的最优控制规律,易于构成闭环最优控制。LQR最优控制利用廉价成本可以使原系统达到较好的性能指标(事实也可以对不稳定的系统进行整定) ,而且方法简单便于实现 ,同时利用 Matlab 强

    2024年02月04日
    浏览(49)
  • 扫地机器人(二分算法+贪心算法)

    1.  if(robot[i]-len=sweep)这个代码的意思是——如果机器人向左移动len个长度后,比现在sweep的位置(现在已经覆盖的范围)还要靠左,就是覆盖连续不起来,呢么这个len就是有问题的,退出函数,再继续循环。 2.  显然当每个机器人清扫的范围相同时,所用时间最小,所以这时

    2024年01月20日
    浏览(46)
  • 【WeLink群消息机器人webhook介绍】

    WeLink群消息机器人webhook介绍 一、背景:如何理解bot和webhook? 机器人(bot)是一种新型的应用形态,新的协同方式对话即服务,在应用中典型形态即为bot,用户在聊天界面跟一个机器人的虚拟账号,通过对话的方式,实现跟后端系统的交互,如主动发送消息给机器人,机器人

    2024年01月21日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包