无人机中的PID控制代码略解

2024-03-13 06:50

本文主要是介绍无人机中的PID控制代码略解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

无人机中的PID控制代码略解

  • PID的控制规律:

参考:Amov实验室-PX4中级课程-PID基础

频域函数:
u ( s ) e r r ( s ) = k p + k i s + k d s \frac{u(s)}{err(s)}=k_p+\frac{k_i}{s}+k_ds err(s)u(s)=kp+ski+kds
写成时域的函数:
u ( t ) = k p ( e r r ( t ) + 1 T i ∫ e r r ( t ) d t + T d d e r r ( t ) d t ) (1) u(t)=k_p(err(t)+\frac{1}{T_i} \int err(t)dt+T_d\frac {derr(t)}{dt}) \tag 1 u(t)=kp(err(t)+Ti1err(t)dt+Tddtderr(t))(1)

假设采样间隔为T,则在第K个T时刻,有:
e r r ( K ) = R i n ( K ) − C o u t ( K ) err(K) = R_{in}(K)-C_{out}(K) err(K)=Rin(K)Cout(K)

对于积分环节,按照定义则有:
I ( K ) = T ∗ ( e r r ( 0 ) + e r r ( 1 ) + ⋯ + e r r ( K ) ) = T ∑ i = 0 K e r r ( i ) (2) I(K)=T*(err(0)+err(1)+\cdots + err(K))=T\sum_{i=0}^{K}err(i) \tag 2 I(K)=T(err(0)+err(1)++err(K))=Ti=0Kerr(i)(2)
对于微分环节,按照定义则有:
D ( K ) = e r r ( K ) − e r r ( K − 1 ) T (3) D(K) = \frac{err(K)-err(K-1)}{T} \tag3 D(K)=Terr(K)err(K1)(3)
( 2 ) , ( 3 ) (2),(3) (2),(3)代入回 ( 1 ) (1) (1)则有:
u ( K ) = k p [ e r r ( K ) + T T i ∑ i = 0 K e r r ( i ) + T d e r r ( K ) − e r r ( K − 1 ) T ] u(K)=k_p[err(K)+\frac{T}{T_i}\sum_{i=0}^{K}err(i)+T_d\frac{err(K)-err(K-1)}{T}] u(K)=kp[err(K)+TiTi=0Kerr(i)+TdTerr(K)err(K1)]
化简一下则有:
u ( K ) = k p e r r ( K ) + k i ∑ i = 0 K e r r ( i ) + k d [ e r r ( K ) − e r r ( K − 1 ) ] (4) u(K)=k_perr(K)+k_i\sum_{i=0}^{K}err(i)+k_d[err(K)-err(K-1)] \tag4 u(K)=kperr(K)+kii=0Kerr(i)+kd[err(K)err(K1)](4)
为了减小存储空间,还有增量式PID,可写为:
Δ u ( K ) = k p [ e r r ( K ) − e r r ( K − 1 ) ] + k i ⋅ e r r ( K ) + k d [ e r r ( K ) − 2 e r r ( K − 1 ) + e r r ( K − 2 ) ] \Delta u(K)=k_p[err(K)-err(K-1)]+k_i \cdot err(K)+k_d[err(K)-2err(K-1)+err(K-2)] Δu(K)=kp[err(K)err(K1)]+kierr(K)+kd[err(K)2err(K1)+err(K2)]
u ( K ) u(K) u(K)还可以写为:
u ( K ) = u ( K − 1 ) + Δ u ( K ) u(K)=u(K-1)+\Delta u(K) u(K)=u(K1)+Δu(K)

  • PID的C语言代码初步实现:
//定义pid结构体,定义主要参数
struct _pid{float SetSpeed;float ActualSpeed;float err;float err_last;	//err(K-1)float Kp,Ki,Kd;float voltage;//Object Signalfloat integral;float err_llast;//err(K-2)
}pid;//初始化pid模块
void PID_init(){pid.SetSpeed = 0;pid.ActualSpeed=0.0;pid.err = 0;pid.err_last = 0;pid.voltage = 0;pid.integral = 0;//Set Each PID Gainpid.Kp = 0.4;pid.Ki = 0.3;pid.Kd = 0.2;pid.err_llast = 0;
}//pid实现,包括增量形式的pid,输入为目标速度,输出为当前的速度
float PID_realize(float speed){pid.SetSpeed = speed;pid.err = pid.SetSpeed - pid.ActualSpeed;//PID Calculatepid.voltage = pid.Kp*pid.err + \pid.Ki*pid.integral + \pid.Kd*(pid.err-pid.err_last);//Increment Type
/*  float incrementVoltage;incrementVoltage = pid.Kp*(pid.err-pid.err_last)+\pid.Ki*pid.err+\pid.Kd*(pid.err-2*pid.err_last+pid.err_llast);pid.voltage += incrementVoltage;pid.err_llast = pid.err_last;
*/    //Update Parameterspid.err_last = pid.err;pid.ActualSpeed = pid.voltage*1.0;return pid.ActualSpeed;
}
  • PX4中姿态控制介绍:

PX4中的控制主要分为***姿态控制*** 和***位置控制***,这两者都采用***串级 P I D PID PID*** 控制,这样的好处是可以增加系统的稳定性,抗干扰,因为参数更多了,直观上自然能够适应的情况就相对来说多一点。位置控制中外环是位置,内环是速度,由内环得到的速度积分就是位置的改变量。而姿态控制中,外环是角度差,内环是角速度差,这是因为角度的变化同时也是由角速度过渡来的。参考:Pixhawk-串级pid介绍

因为时间关系,我下面介绍一下内环角速度PID控制的实现:

  1. 首先是角速度PID环控制器的类,成员函数主要由:设置初始PID增益,设置积分器的最大绝对值,设置前馈增益,饱和状态(和Mixer有关),重设积分项,获取状态信息,积分项特别调控以及PID最终的计算结果实现。不要看其这么复杂,其实主要的函数就是最后两个,而这两个函数也只是在我之前介绍的简易PID实现的基础上加了一点点工业上的限制。
class RateControl
{
public:RateControl() = default;~RateControl() = default;/*** Set the rate control gains* @param P 3D vector of proportional gains for body x,y,z axis* @param I 3D vector of integral gains* @param D 3D vector of derivative gains*/void setGains(const matrix::Vector3f &P, const matrix::Vector3f &I, const matrix::Vector3f &D);/*** Set the mximum absolute value of the integrator for all axes* @param integrator_limit limit value for all axes x, y, z*/void setIntegratorLimit(const matrix::Vector3f &integrator_limit) { _lim_int = integrator_limit; };/*** Set direct rate to torque feed forward gain* @see _gain_ff* @param FF 3D vector of feed forward gains for body x,y,z axis*/void setFeedForwardGain(const matrix::Vector3f &FF) { _gain_ff = FF; };/*** Set saturation status* @param status message from mixer reporting about saturation*/void setSaturationStatus(const MultirotorMixer::saturation_status &status);/*** Run one control loop cycle calculation* @param rate estimation of the current vehicle angular rate* @param rate_sp desired vehicle angular rate setpoint* @param dt desired vehicle angular rate setpoint* @return [-1,1] normalized torque vector to apply to the vehicle*/matrix::Vector3f update(const matrix::Vector3f &rate, const matrix::Vector3f &rate_sp,const matrix::Vector3f &angular_accel, const float dt, const bool landed);/*** Set the integral term to 0 to prevent windup* @see _rate_int*/void resetIntegral() { _rate_int.zero(); }/*** Get status message of controller for logging/debugging* @param rate_ctrl_status status message to fill with internal states*/void getRateControlStatus(rate_ctrl_status_s &rate_ctrl_status);private:void updateIntegral(matrix::Vector3f &rate_error, const float dt);// Gainsmatrix::Vector3f _gain_p; ///< rate control proportional gain for all axes x, y, zmatrix::Vector3f _gain_i; ///< rate control integral gainmatrix::Vector3f _gain_d; ///< rate control derivative gainmatrix::Vector3f _lim_int; ///< integrator term maximum absolute valuematrix::Vector3f _gain_ff; ///< direct rate to torque feed forward gain only useful for helicopters// Statesmatrix::Vector3f _rate_int; ///< integral term of the rate controllerbool _mixer_saturation_positive[3] {};bool _mixer_saturation_negative[3] {};
};
  1. 说一下积分项特别调控和PID的计算输出两个模块:

积分项特别调控:

void RateControl::updateIntegral(Vector3f &rate_error, const float dt)
{for (int i = 0; i < 3; i++) {// prevent further positive control saturationif (_mixer_saturation_positive[i]) {rate_error(i) = math::min(rate_error(i), 0.f);}// prevent further negative control saturationif (_mixer_saturation_negative[i]) {rate_error(i) = math::max(rate_error(i), 0.f);}// I term factor: reduce the I gain with increasing rate error.// This counteracts a non-linear effect where the integral builds up quickly upon a large setpoint// change (noticeable in a bounce-back effect after a flip).// The formula leads to a gradual decrease w/o steps, while only affecting the cases where it should:// with the parameter set to 400 degrees, up to 100 deg rate error, i_factor is almost 1 (having no effect),// and up to 200 deg error leads to <25% reduction of I.float i_factor = rate_error(i) / math::radians(400.f);i_factor = math::max(0.0f, 1.f - i_factor * i_factor);// Perform the integration using a first order methodfloat rate_i = _rate_int(i) + i_factor * _gain_i(i) * rate_error(i) * dt;// do not propagate the result if out of range or invalidif (PX4_ISFINITE(rate_i)) {_rate_int(i) = math::constrain(rate_i, -_lim_int(i), _lim_int(i));}}
}

首先是积分饱和的限制:

		// prevent further positive control saturation	if (_mixer_saturation_positive[i]) {rate_error(i) = math::min(rate_error(i), 0.f);}// prevent further negative control saturationif (_mixer_saturation_negative[i]) {rate_error(i) = math::max(rate_error(i), 0.f);}

在实际过程中,如果系统一直存在一个方向的偏差,PID的输出因为积分项的存在可能会变得非常大,但是执行器的输入是有限的。当执行器的输入达到上限,PID的输出持续增大,此时就进入了饱和区,这主要是由于积分项饱和造成的。一旦系统出现了反向的偏差,此时积分项就要逐渐减小,但是由于进入了饱和区,不可能一下从饱和区中退出来,使得执行机构的输入一直在极限状态,无法立刻减小,进入饱和区时间越长,越难退出来,这就导致了像是失控一样现象。所以为了抑制这种现象,必须让积分项在PID的输出达到执行器饱和的时候停止让PID输出的绝对值继续增加,包括正向和负向,这就有了上面这两句函数。

其次注意这个函数中以下两句函数:

		float i_factor = rate_error(i) / math::radians(400.f);i_factor = math::max(0.0f, 1.f - i_factor * i_factor);float rate_i = _rate_int(i) + i_factor * _gain_i(i) * rate_error(i) * dt;

这个对于积分项的计算可以看成如下的公式:
R a t e I n t e g r a l ( K ) = ∑ i = 0 K − 1 e r r ( i ) + i f a c t o r ∗ k i ∗ e r r ( K ) ∗ d t RateIntegral(K)=\sum_{i=0}^{K-1}err(i)+i_{factor}*k_i*err(K)*dt RateIntegral(K)=i=0K1err(i)+ifactorkierr(K)dt
其中, i f a c t o r i_{factor} ifactor的计算如下:
i f a c t o r = 1 − ( e r r 40 0 ∘ ) 2 i_{factor} = 1-(\frac{err}{400^\circ})^2 ifactor=1(400err)2
整个函数限制了积分增益不能太大,当期望的角速度误差在 20 0 ∘ 200^\circ 200的时候,就可以看到积分增益减少到25%了,而当角速度误差超过 40 0 ∘ 400^\circ 400的时候,此时积分的增益就会完全为0。这样做是为了防止积分项导致PID的输出非常巨大,产生超调,甚至引起积分饱和。

PID最终的计算:

Vector3f RateControl::update(const Vector3f &rate, const Vector3f &rate_sp, const Vector3f &angular_accel,const float dt, const bool landed)
{// angular rates errorVector3f rate_error = rate_sp - rate;// PID control with feed forward// 带有前馈的PID控制// torque=p*rate_error(比例项)+_rate_int(积分项)-d*angular_accel(微分项)+ff*rate_sp(前馈)const Vector3f torque = _gain_p.emult(rate_error) + _rate_int - _gain_d.emult(angular_accel) + _gain_ff.emult(rate_sp);// update integral only if we are not landedif (!landed) {updateIntegral(rate_error, dt);}return torque;
}

这里大家可能会有疑惑,为什么要加一个前馈的控制呢?实际上这和积分项的滞后有关,加入前馈调节可以使得系统的控制速度更快,提高系统的响应速度:参考:多旋翼姿态控制中前馈的作用

加入前馈矫正的串级PID系统框图

可以看到,其中在外环已经产生一个角速度期望控制了,可是由于内环积分器的滞后(分析积分环节的频域响应可知,中高频段的相角滞后严重),前馈的作用是跳过积分器,直接从输入到输出,以提高系统的响应速度

设PID控制环节的传递函数 G c ( s ) = K p + K i s + K d s G_c(s) = K_p+\frac{K_i}{s}+K_ds Gc(s)=Kp+sKi+Kds

则有不加前馈的开环传递函数(从 θ d \theta_d θd θ \theta θ):
G 1 ( s ) = P G c J s 2 + G c s G_1(s)=\frac{PG_c}{Js^2+G_cs} G1(s)=Js2+GcsPGc
加了前馈的开环传递函数为:
G 1 ( s ) = P K + P G c J s 2 + G c s G_1(s)=\frac{PK+PG_c}{Js^2+G_cs} G1(s)=Js2+GcsPK+PGc
假如我们简略一点,把 G c G_c Gc看成常数,也就是说只有比例增益,至少很容易看出此时这个二阶系统的增益变大了,这样的话系统的响应速度变快,稳态误差减小;同时系统的自然频率变大,阻尼比不变,相应的系统的闭环带宽增加,系统能够响应更多的高频分量使得控制系统的快速性提高。 G c G_c Gc为一般的情况下,也有类似的分析,主要就是提高了截止频率,使得带宽增加,相角裕度减小,超调量增加,系统快速性增强。

这篇关于无人机中的PID控制代码略解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/803967

相关文章

内卷时代无人机培训机构如何做大做强

在当今社会,随着科技的飞速发展,“内卷”一词频繁被提及,反映了各行业竞争日益激烈的现象。对于无人机培训行业而言,如何在这样的时代背景下脱颖而出,实现做大做强的目标,成为每个培训机构必须深思的问题。以下是从八个关键方面提出的策略,旨在帮助无人机培训机构在内卷时代中稳步前行。 1. 精准定位市场需求 深入研究市场:通过市场调研,了解无人机行业的最新趋势、政策导向及未来发展方向。 明确目标

Matlab/Simulink和AMEsim联合仿真(以PSO-PID算法为例)

目录 安装软件和配置环境变量 Matlab/Simulink和AMEsim联合仿真详细流程 非常重要的一点 Simulink模型和AMEsim模型用S-Function建立连接 从AMEsim软件打开Matlab Matlab里的设置 Matlab的.m文件修改(对于PSO-PID算法) 运行程序 我印象中好像做过Matlab/Simulink和AMEsim联合仿真的分享似的

无人机执照拿到后怎么就业?方向有哪些?就业率如何?

无人机执照拿到后,就业方向广泛且多样,就业率也呈现出逐年上升的趋势。这主要得益于无人机技术的广泛应用和无人机市场的不断扩大。以下是对无人机执照持有者就业情况的详细分析: 就业方向 1. 无人机飞行操作: 无人机飞手可以从事无人机的起飞、飞行和降落等具体操作,满足不同行业对无人机飞行的需求。 应用领域包括但不限于农业植保、电力巡线、石油管道巡线、航拍、国土资源勘查、应急救援、交通监控

无人机种类详解!!!

一、按飞行平台构型分类 固定翼无人机:这类无人机类似于传统飞机,拥有一对固定的机翼,通过前进的速度和机翼产生的升力实现飞行。 旋翼无人机:包括多旋翼(如四轴、六轴、八轴等)和单旋翼无人机。 无人飞艇:利用氦气等轻气体实现浮力,适用于长时间、低速的巡航任务,常用于气象监测和通信中继。 伞翼无人机:类似于滑翔伞,依靠空气动力实现飞行,具有成本低、操作简便的特点,多用于娱乐和低成本的环境监测。

Windows11上使用WSL2,提示:系统尚未使用systemd作为初始化系统(PID 1)启动

前言 略 报错信息 System has not been booted with systemd as init system (PID 1). Can't operate. Failed to connect to bus: Host is down 解决方法 使用如下命令 # windows终端,执行如下命令wsl --update# 登录ubuntu系统,执行如下命令s

军事目标无人机视角检测数据集 3500张 坦克 带标注voc

数据集概述 该数据集包含3500张无人机拍摄的图像,主要用于坦克目标的检测。数据集已经按照VOC(Visual Object Classes)标准进行了标注,适用于训练深度学习模型,特别是物体检测模型。 数据集特点 目标明确:专注于坦克这一特定军事目标的检测。多样视角:图像采集自无人机的不同飞行高度和角度,涵盖了各种环境下的坦克图像。高质量标注:每个坦克实例都被精确标注,包括位置信息和类别

LiveQing视频点播流媒体RTMP推流服务功能-支持大疆等无人机RTMP推流支持OBS推流一步一步搭建RTMP视频流媒体服务示例

LiveQing支持大疆等无人机RTMP推流支持OBS推流一步一步搭建RTMP视频流媒体服务示例 1、流媒体服务搭建2、推流工具准备3、创建鉴权直播间4、获取推流地址5、配置OBS推流6、推流及播放7、获取播放地址7.1 页面查看视频源地址7.2 接口查询 8、相关问题8.1、大疆无人机推流花屏 9、RTMP推流视频直播和点播流媒体服务 1、流媒体服务搭建 Windows/Lin

带死区的PID控制算法

带死区的PID控制算法 带死区的PID控制算法: 注:本文内容摘自《先进PID控制MATLAB仿真(第4版)》刘金琨 编著,研读此书受益匪浅,感谢作者! 带死区的PID控制算法: 在计算机控制系统中,某些系统为了避免控制作用过于频繁,消除由于频繁动作所引起的震荡,可采用带死区的PID控制算法,控制算式为: e ( k ) = { 0 ∣ e ( k ) ∣ ≤ ∣ e 0

微分先行PID控制算法

微分先行PID控制算法 微分先行PID控制算法: 注:本文内容摘自《先进PID控制MATLAB仿真(第4版)》刘金琨 编著,研读此书受益匪浅,感谢作者! 微分先行PID控制算法: 微分先行PID控制结构,其特点是只对输出量 y ( k ) y(k) y(k)进行微分,而对给定值 y d ( k k ) y_d(kk) yd​(kk)不做微分。这样,在改变给定值时,输出不会改变

不完全微分PID控制算法

不完全微分PID控制算法 注:本文内容摘自《先进PID控制MATLAB仿真(第4版)》刘金琨 编著,研读此书受益匪浅,感谢作者! 在PID控制中,微分信号的引入可改善系统的动态特性,但也容易引起高频干扰,在误差扰动突变时尤其显出微分项的不足。若在控制算法中加入低通滤波器,则可以使系统性能得到改善。 克服上述缺点的方法之一是在PID算法中加入一个一阶惯性环节(低通滤波器) G f