单级和串级pid原理分析以及pid应用与小车的技巧

本文通过实例深入浅出地介绍了PID控制器的工作原理及应用,探讨了比例、积分与微分控制的作用,并对比了串级PID与并联PID的区别。此外,还讨论了PID在循迹小车上的应用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这篇文章主要是帮助理解和使用pid,不会讲复杂的代码公式。

重点在最后,一定要看到最后

   pid可以看作是一种控制器,用来控制某个变量达到你想要的地步。

单级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米。
但是,单单的比例控制存在着一些不足,其中一点就是 –稳态误差!
像上述的例子,根据kp取值不同,系统最后都会达到1米,不会有稳态误差。但是,考虑另外一种情况,假设这个水缸在加水的过程中,存在漏水的情况(可以看作是一些其他外界因素的影响),假设每次加水的过程,都会漏掉0.1米高度的水。仍然假设kp取0.5,那么会存在着某种情况,假设经过几次加水,水缸中的水位到0.8时,水位将不会再变换!!!因为,水位为0.8,则误差error=0.2. 所以每次往水缸中加水的量为u=0.5*0.2=0.1.同时,每次加水缸里又会流出去0.1米的水!!!加入的水和流出的水相抵消,水位将不再变化!!
也就是说,我的目标是1米,但是最后系统达到0.8米的水位就不在变化了,且系统已经达到稳定。由此产生的误差就是稳态误差了。

如果仅仅用比例,可以发现存在暂态误差,最后的水位就卡在0.8了。于是,在控制中,我们再引入一个分量,该分量和误差的积分是正比关系。所以,比例+积分控制算法为:
u=kp*error+ kierror
还是用上面的例子来说明,第一次的误差error是0.8,第二次的误差是0.4,至此,误差的积分(离散情况下积分其实就是做累加),error=0.8+0.4=1.2. 这个时候的控制量,除了比例的那一部分,还有一部分就是一个系数ki乘以这个积分项。由于这个积分项会将前面若干次的误差进行累计,所以可以很好的消除稳态误差(假设在仅有比例项的情况下,系统卡在稳态误差了,即上例中的0.8,由于加入了积分项的存在,会让输入增大,从而使得水缸的水位可以大于0.8,渐渐到达目标的1.0.)这就是积分项的作用。

当水位接近10m时,error会很小,但是由于Kp很大,就会使水位超过10m,系统出现超调。此时就需要引入微分控制(Kd)

u=kd*(error(t)-error(t-1))

在离散情况下,就是error的差值,就是t时刻和t-1时刻error的差。在水位上升过程中,因为error是越来越小的,所以这个微分控制项一定是负数,在控制中加入一个负数项,他存在的作用就是为了防止注入的水太多而导致超过设定水位。

串级pid和并联pid

刚开始我一直以为串级pid就是把两个不相干的控制量串联起来,一起控制某个东西。这里拿小车举例,就是把前进环pid和转向环pid串联起来。后来学习后我才发现这种想法是完全错误的,你如果想让小车同时拥有前进环和转向环(用的是差速转向),让这两个环共同控制小车,这里其实要用到并联pid,就是把两个pid的输出量叠加起来的值赋给电机。

这里我附上了代码展示

82b6c34cc45a4932ad82615e4eb91488.png

 继续说咋们的串级pid,串级pid的目的是更精细化的控制你想要控制的那个量。因此它的外环和内环是有物理联系的,这也是你写串级pid的依据或者说是原理。

假设我们需要解决这样一个问题:

控制小车从当走到红色标签位置,设小车实时位置为x0(t)eb0808dbb2fc45c497e6d02eea50205f.png

 如果我们使用单级PID,运动框图应该如下图所示:

8ea78afaf08143c484cc75d7291ef2d2.png

如果你按照图中的思路设计控制器,那就说明你只对位置有期望,这意味着你对加速度没有期望,也就意味着加速度是什么都无所谓。 

所以实际效果变成什么呢?你会以一个你无所谓的加速度到达你的期望位置。

这时候奇怪的事情发生了,到达你的期望位置时有加速度和速度,那这个就不是到达期望位置了,这叫经过期望位置。你会发现小车在期望位置附近“反复横跳”,超过后,又退回去,退过了,又超过去。

我们想要的期望的是停在期望位置上。什么叫停在期望位置上?就是到达期望位置的同时加速度与速度都为0。

现在我们想控制位置,类似于控制车,你只能踩油门加速,或者刹车进行减速,你只能通过速度控制间接控制位置。

开车的时候是怎么控制位置的呢?你想停在指定位置的时候,你先以一定的速度前往指定位置,快到的时候,通过刹车不断减速,直到速度为0,停到期望的位置。

这时我们发现,我们可以通过控制加速度来控制速度,从而控制我们的位置。所以串级pid就诞生了。

我们重新设计一下控制器,也就是再加一个环控制我们的加速度。

3c88213598c540e59e83a23ad8172608.png

现在我们来重新复盘一下我们的控制器,当小车距离期望位置很远时,位置环输出就很大,因此速度环的期望值就很大,所以速度环输出(加速度)就很大,可以使小车很快到达期望位置。当小车靠近期望位置时,位置环输出很小,因此速度环的期望值就小,速度环输出就很小(加速度接近于0),因此小车在期望位置速度和加速度都为0,小车精准停在期望位置。

  pid在循迹小车上应用

 刚接触pid我一直纠结为什么输入和输出的完全使两种变量可以达到控制的效果,这其中涉及到数学和物理知识的推到。

我们其实只需要会用这个pid控制器就可以了,你只需要知道你输出什么量他就会控制什么量就欧克了。输入位置(循迹模块)他就会控制位置,输入速度(编码器值)就会控制速度。

对于循迹小车来说,一般只使用pd控制器。

一般来说pid的输入必须使线性的,但一般小车上都是用的数字灰度传感器,为了能够使用pid控制器就需要给每一路灰度赋予不同的权值,就比如5路灰度循迹(传感器越多肯定控制的越丝滑,如果要使用pid的话,最少应该有5路,不然pid毫无意义),左边第一个赋予权重是10,左边第二个权重是5,相对应的右边传感器的权值就应该为负,权重越大,输出的pwm值就越大,所以当小车偏移角度比较大时,也能摆回来。

使用数字量循迹对参数的配置要求比较高,但是更适合于那种复杂赛道,比如直角,岔路,十字路口等。模拟量灰度(一般三路就ok了,但是需要对adc采集到的数据进行处理才可以使用pid)更适合与那种简单赛道基本都是直线的那种。

模拟量灰度数据融合的两种方法:

第一种:将三个灰度的adc值整合成一条线性的直线代入pid计算,这种方法处理过程较为复杂,当你想把三个灰度扩展到5个的时候非常有难度。

这篇文章详细讲解了处理方法:http://t.csdn.cn/gFUBq

第二种:adc读取5个灰度的值,找到adc数值最小和第二小的传感器,那么黑线此时肯定在这两个传感器中间,通过比例求出两点之间的具体位置,然后根据传感器的距离算出距离黑线的位置,代入pid控制。这种方法处理过程简单,并且线性度也高。

无论是那种循迹模块在测试时都会出现小车频繁左右摇摆的情况(即使加入了积分控制也不行),此时就需要用到pid死区

 当小车偏差非常小的适合不做处理,会有效解决掉小车摇摆的情况。

### PID控制在路径跟踪中的应用 #### 什么是PID控制? PID控制系统由两个或多个闭环回路组成,其中一个控制器的输出作为另一个控制器的目标输入。这种结构通常分为外环内环两部分。在外环中,目标变量(如位置或速度)被设定为目标值;而在内环中,则通过快速响应来调节实际执行器的动作[^3]。 #### 如何实现PID控制用于路径跟踪? 1. **外环设计** 外环的主要功能是计算期望的速度或加速度信号,以便使系统的整体行为接近预设路径。这一步骤可以通过高控制策略(如模型预测控制MPC)完成,或者直接利用简单的比例控制逻辑。假设当前的实际位置为 \(x_{\text{actual}}\),预期位置为 \(x_{\text{desired}}\),那么外环的误差定义如下: \[ e_x = x_{\text{desired}} - x_{\text{actual}} \] 使用这个误差,外环生成一个中间参考量(通常是速度),供内环使用[^1]。 2. **内环设计** 内环的任务是对低别的物理动作进行精确控制,比如电机转速或舵面偏角。它接收来自外环的速度指令,并将其转化为具体的驱动命令。如果以无人机为例,内环可能负责调整螺旋桨的旋转速率以改变升力大小。具体而言,内环会进一步分解成三个组成部分——比例项、积分项以及微分项: ```python def pid_controller(error, kp, ki, kd, dt): proportional_term = kp * error integral_term += ki * error * dt derivative_term = kd * (error - previous_error) / dt output = proportional_term + integral_term + derivative_term previous_error = error return output ``` 上述代码展示了如何基于误差动态更新控制信号的过程。 3. **协调内外环工作** 在某些情况下,仅依靠单一层次的PID难以满足复杂环境下的需求。因此引入了多层架构的理念,其中每层专注于特定方面的问题解决。例如,在自动驾驶汽车场景下,外部的大脑模块决定总体方向变化趋势,而内部的小型伺服机制则确保轮胎角度精准匹配所需转弯半径[^2]。 4. **参数调优技巧** 对于任何类型的PID系统来说,合理设置Kp(比例系数),Ki(积分时间常数), Kd(微分校正因子)至关重要。这些数值直接影响到整个体系能否平稳运作而不发生震荡现象。一种常用的方法是从零开始逐步增加各参数直到达到满意效果为止; 另一方面也可以借助现代工具包自动寻找最佳组合方案[^4]。 ```matlab % MATLAB伪代码示例 function control_signal = cascaded_pid(x_desired, x_actual, v_previous) % Outer loop calculation position_error = x_desired - x_actual; velocity_reference = outer_loop_pid(position_error); % Inner loop calculation velocity_error = velocity_reference - v_previous; control_signal = inner_loop_pid(velocity_error); end function signal = outer_loop_pid(e_outer) global OUTER_KP OUTER_KI OUTER_KD DT static intg_out = 0; propo_out = OUTER_KP*e_outer; intg_out = intg_out + OUTER_KI*e_outer*DT; diff_out = OUTER_KD*(e_outer-last_e_outer)/DT; last_e_outer = e_outer; signal = propo_out + intg_out + diff_out; end function signal = inner_loop_pid(e_inner) global INNER_KP INNER_KI INNER_KD DT static intg_inn = 0; propo_inn = INNER_KP*e_inner; intg_inn = intg_inn + INNER_KI*e_inner*DT; diff_inn = INNER_KD*(e_inner-last_e_inner)/DT; last_e_inner = e_inner; signal = propo_inn + intg_inn + diff_inn; end ``` 上述MATLAB脚本提供了一个基本框架用来搭建双层联式的PID调控网络。 ---
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值