ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

从PID到ADRC:嵌入式自抗扰控制C代码落地实战

从PID到ADRC:嵌入式自抗扰控制C代码落地实战 简介本资源为面向嵌入式控制工程师与自动化专业学习者的自抗扰控制ADRC算法C语言工程化实现聚焦电机调速、伺服系统等实时控制场景解决传统PID在模型不确定、外部扰动强时鲁棒性不足的问题。压缩包共36个文件约32KB包含10个可直接运行的示例工程sample、4个主控逻辑模板master、2个核心头文件ADRC.h等、1个参数配置说明文本以及.git版本控制相关元数据文件其中ADRC.c与ADRC.h封装了改进型跟踪微分器TD、三阶扩张状态观测器ESO、非线性反馈组合及扰动补偿模块支持r、h、N、beta系列参数在线调节。已有128人下载学习提供开箱即用的轻量级C代码无需依赖第三方库便于移植至STM32、GD32等MCU平台配合注释清晰的参数接口与典型调参说明显著降低ADRC算法落地门槛。 三年前调试一台高速贴片机X/Y轴我遇到一件特别拧巴的事位置环用PID把给定跟随调快了阶跃超调把超调压下去追踪S曲线时又甩出明显滞后更头疼的是更换负载后整个增益都要重来一遍。当时翻到自抗扰控制ADRC的资料第一反应是公式太多、能直接落地的工程资料太少。直到自己把C代码跑起来才明白它解决的就是这类“跟随和抗扰两头不讨好”的根子问题——把内部动态、外部扰动、未建模特性统统归成一个总扰动再用扩张状态观测器观测出来最后一步补偿掉。这篇文章把我整理的ADRC的C代码实现过程完整写出来从数学直觉、最小线性版本到非线性fal版本再到嵌入式里真正能跑的工程细节包括参数整定顺序和一系列容易翻车的坑。适合已经会PID、想在单片机或控制卡上把ADRC落地的人参考。我不会只给代码会给每个设计选择背后的理由这样你才能真正在项目里改得动、调得通。1. 我为什么在嵌入式控制里换掉PID1.1 PID调不动的那台电机先还原一下当时的场景。X/Y轴是典型的二阶运动对象位置环输出速度指令速度环再带电流环。原来位置环就是PD加个前馈。为了抑制胶头在高速停止时的位置过冲我把比例增益压得很低结果追踪高速轨迹时动态误差大得肉眼可见。把增益提上去阶跃又有明显的超调甚至在某几个速度段出现机械共振的呻吟声。这就是单环PID的结构性矛盾给定跟随带宽和抗扰动带宽被锁在同一个误差信号里。输出误差大时比例项同时承担“追参考”和“顶扰动”的功能但追参考需要高增益顶扰动在高频段反而被积分项拖后腿。你调出来的每一个参数都是在给一个耦合问题打补丁。后来我尝试在PID基础上加各种前馈、摩擦补偿、陷波器能跑通但每换一台设备、换一套机械负载整套参数就要重调一遍。这种“每个项目都从零开始”的滋味做过运动控制的工程师都懂。1.2 主动抗扰到底在“抗”什么ADRC的全称是Active Disturbance Rejection Control核心思想就是“别去分辨扰动是摩擦、重力还是负载突变把它们的总和当成一个状态量直接观测然后抵消”。这句话听上去简单做起来有一套完整闭环先把被控对象写成积分串联型把系统内部动态和外部扰动合并成一个总扰动项然后用扩张状态观测器ESO把总扰动估出来最后用估计值做前向补偿。补偿完之后原本复杂的对象在你的控制器眼里就变成了一个“积分串联型”的标称系统再给它配一个简单的PD控制器就可以同时兼顾跟随带宽和抗扰能力。相比PIDADRC不需要高精度的模型也不需要精确的扰动特性只需要知道一个大概的控制增益b0。这个特性在嵌入式环境里非常实用因为单片机里根本跑不了复杂系统辨识算法。1.3 哪些场景最适合先上ADRC我实践下来这几类场景ADRC收益最大伺服/步进位置环、转速环尤其是有明显负载突变或摩擦非线性的工况机器人关节力矩和位置控制无人机姿态角控制以及所有“模型不精确但有可用的控制输入和输出测量”的系统。如果你只是做一个实验平台、控制对象是理想的一阶水箱或者没有测量反馈的纯开环系统那ADRC优势不大。ADRC需要实时测量输出yESO才有意义。特别提醒一句ADRC的C代码实现本身并不复杂真正的功夫在采样周期、参数收敛和抗测量噪声这些工程细节上后文会逐个展开。2. ADRC三件套的数学直觉先别急着写代码2.1 把任意被控对象写成积分串联型所有ADRC推导都从这种形式出发y f(y, y, w, t) b0 * u其中u是控制输入y是输出f代表所有“不知道的东西”未建模动态、摩擦、重力、负载突变统统打包。b0是控制输入的增益估计代表“我给一份控制量对象大概能产生多少加速度”。之所以写成y而不是更高阶是因为绝大多数机械系统本质上是二阶的位置到速度、速度到加速度。这个公式的工程含义是不管对象多复杂只要我把扰动f估计出来并在控制量里减掉剩下的就是一个“单位增益的积分器串联模型”y ≈ u0这就是ADRC整个思想的落脚点。PID是在“不知道扰动是多少”的时候被动纠正误差而ADRC是主动把扰动抠出来补偿掉。2.2 跟踪微分器TD给信号装一个不超调的引路人阶跃信号直接送给控制器本质上是一种很暴力的请求。老司机起步不会一脚油门踩到底而会先缓后急地给油门。TDTracking Differentiator就是干这个的对参考信号安排一个过渡过程同时输出参考信号的一阶导数和二阶导数。数学上TD是一个快速最优控制系统。它有两个状态v1跟踪参考信号v2是v1的导数。通过一个非线性函数fst让v1以尽量快的速度到达参考值同时不产生超调。这样位置环面对的不再是生硬的阶跃而是一条平滑的目标轨线过冲从源头就被消灭了。实践中有人会问参考资料本身已经是S曲线为什么还要TD我的经验是TD更多用来解决“测量信号不光滑”的问题比如旋变或者光栅尺读数毛刺多时TD输出的微分比直接差分稳定得多。即使参考信号已经平滑TD的微分信号也可以直接拿来做前馈。2.3 扩张状态观测器ESO把总扰动“看”出来ESO是ADRC的地基。它的输入是输出测量y和控制量u输出是三个估计值z1估计yz2估计yz3估计总扰动f。关键就在这个第三阶状态上——它把原来模型中“没有建模”的f扩张成了新的状态所以叫扩张状态观测器。以线性ESO为例形式是z1 z2 - β1(z1 - y) z2 z3 - β2(z1 - y) b0*u z3 -β3(z1 - y)其中β1、β2、β3是观测器增益。z1追yz2追yz3就把跟踪过程中的残差一路累积成对总扰动的估计。可以理解为一个有经验的仪表工不用打开机器只看输出仪表读数与控制量就能判断设备当前的负载状态z3就是那个“状态估计”。2.4 控制律补偿之后用最朴素的PD接管有了z3控制量设计就变成了u (u0 - z3) / b0如果z3≈f代回原方程y≈u0扰动被抵消。剩下的u0就采用最经典的形式u0 kp*(v1 - z1) kd*(v2 - z2)把控制器极点配置到目标带宽上。因为对象已经被改造成“单位增益积分串联型”所以同样的kp、kd规则可以跨平台复用这就是ADRC参数通用性的由来。3. 最小可行LADRC三个参数就能跑起来的C代码3.1 数据结构与初始化先不碰非线性起步用线性ADRCLADRC参数少、行为可预测能跑通再升级。我的C实现用一个结构体把所有状态和参数装起来typedef struct { float dt; // 采样周期, 单位s float r; // TD速度因子, 决定过渡过程快慢 float b0; // 控制增益估计 float w0; // 观测器带宽 rad/s float wc; // 控制器带宽 rad/s float umax; // 控制量限幅 // TD状态 float v1, v2; // ESO状态 float z1, z2, z3; // 由带宽算出的增益 float beta1, beta2, beta3; float kp, kd; } ADRC;初始化函数void adrc_init(ADRC *p, float dt, float r, float b0, float w0, float wc, float umax) { p-dt dt; p-r r; p-b0 b0; p-w0 w0; p-wc wc; p-umax umax; p-v1 p-v2 0.0f; p-z1 p-z2 p-z3 0.0f; // 线性ESO采用带宽法配置极点 p-beta1 3.0f * w0; p-beta2 3.0f * w0 * w0; p-beta3 w0 * w0 * w0; // 控制器极点配置在wc, 临界阻尼 p-kp wc * wc; p-kd 2.0f * wc; }带宽法把观测器和控制器的极点分别放在w0和wc上。这样我只需要关心两个物理意义明确的值而不是beta1、kp等六个没有直觉的数字。3.2 跟踪微分器的fst函数实现TD用的fst函数是韩京清先生给出的离散最速控制综合函数。我直接用标准形式static inline float sgn(float x) { return (x 0.0f) - (x 0.0f); } // 最速跟踪微分器的离散综合函数 // 输入x1,x2为TD状态, v为参考, r为速度因子, h为采样周期 static void fst(float x1, float x2, float v, float r, float h, float *fh) { float d r * h; float d0 h * d; float y x1 - v h * x2; float a0 sqrtf(d * d 8.0f * r * fabsf(y)); float a (fabsf(y) d0) ? (x2 y / h) : (x2 0.5f * (a0 - d) * sgn(y)); *fh (fabsf(a) d) ? (-r * a / d) : (-r * sgn(a)); }看到没有整个非线性体现在这个a的折线处理上。|y|小时进入线性区相当于阻尼|y|大时使用最大加速度饱和相当于限幅。这个函数的输出就是TD给状态v2的加速度指令。3.3 线性扩张状态观测器与控制律最重要的单步计算函数我放在这里static inline float clipf(float x, float lo, float hi) { return (x lo) ? lo : (x hi) ? hi : x; } float adrc_step(ADRC *p, float ref, float y) { float fh; float e, u0, u_cmd, u_real; // 1. 跟踪微分器安排过渡过程 fst(p-v1, p-v2, ref, p-r, p-dt, fh); p-v1 p-dt * p-v2; p-v2 p-dt * fh; // 2. 控制律: 加总扰动补偿 e p-z1 - y; u0 p-kp * (p-v1 - p-z1) p-kd * (p-v2 - p-z2); u_cmd (u0 - p-z3) / p-b0; u_real clipf(u_cmd, -p-umax, p-umax); // 3. 扩张状态观测器更新, 注意一定要用限幅后的u_real p-z1 p-dt * (p-z2 - p-beta1 * e); p-z2 p-dt * (p-z3 - p-beta2 * e p-b0 * u_real); p-z3 p-dt * (-p-beta3 * e); return u_real; }这个函数每周期调用一次即可。你只需要保证调用周期和p-dt一致这是最关键的约束后面会专门说。3.4 一个完整的位置环调用示例以位置环为例被控对象是电机负载void control_loop_1kHz(void) { static ADRC pos_adrc; float ref_pos, actual_pos, torque; // 每1ms调用一次 adrc_init(pos_adrc, 0.001f, 50.0f, 800.0f, 80.0f, 20.0f, 10.0f); while (1) { ref_pos get_target_position(); // 来自上位机 actual_pos get_encoder_position(); torque adrc_step(pos_adrc, ref_pos, actual_pos); set_motor_torque(torque); delay_until_next_1ms(); } }在这个例子里r50代表过渡速度b0800是估计的“单位力矩产生的加速度”w080是观测器带宽wc20是控制带宽umax10是限幅。这些不是拍脑袋整定方法放到第五章。这个最小框架在STM32、TMS320、甚至很多国产MCU上都能跑只要支持浮点运算。4. 非线性ADRC完整实现fal函数与离散化取舍4.1 fal函数死区、增益和抖振的权衡非线性ADRC和线性版本最主要的区别是把观测器误差e的处理从“固定增益”变成“小误差大增益、大误差小增益”的fal函数让观测器在误差小的时候更敏感、误差大的时候更从容static inline float fal(float e, float a, float delta) { if (fabsf(e) delta) { return e / powf(delta, 1.0f - a); // 原点附近线性段 } return powf(fabsf(e), a) * sgn(e); // 非线性段 }delta是线性段宽度通常取0.01到0.1太大会把fal退化成线性太小会在零点附近产生抖振。a取0.5附近指数越低小误差下的增益越高但数字化实现时的浮点舍入问题也更明显。4.2 非线性ESO与非线性反馈律的C实现把线性ESO里的e替换成fal(e, 0.5)和fal(e, 0.25)再给反馈律也用fal就成了完整的非线性ADRCfloat adrc_step_nl(ADRC *p, float ref, float y) { float fh, e, fe, fe1; float ev, ed, u0, u_cmd, u_real; fst(p-v1, p-v2, ref, p-r, p-dt, fh); p-v1 p-dt * p-v2; p-v2 p-dt * fh; e p-z1 - y; fe fal(e, 0.5f, 0.01f); fe1 fal(e, 0.25f, 0.01f); ev p-v1 - p-z1; ed p-v2 - p-z2; u0 p-kp * fal(ev, 0.5f, 0.01f) p a hrefhttps://download.csdn.net/download/2401_84572204/91681498 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p
返回列表