是什么:PID 的控制量完全由「设定值 − 输出值」这个误差驱动:u = Kp·e + Ki·∫e + Kd·de/dt。它不看对象内部发生了什么,只看「结果差多少」再事后补救。这套范式统治工业八十年,靠的是两条:不依赖模型、结构简单。但放在人形机器人关节上,它的三个短板被放大:
为什么:问题的根源是「扰动不可见」。韩京清(中科院系统科学研究所,ADRC 创始人)的切入点是:与其给每种扰动单独建模,不如把所有「模型对不上 + 外部作用」统一打包成一个量,在线估计它,然后从控制量里减掉。这个打包后的量就叫总扰动:
怎么做:把对象强制写成上式 —— 唯一要求知道的模型信息只有两个:阶次 n(关节位置/速度环通常是二阶)和输入增益 b₀ 的估计值。剩下所有复杂东西都塞进 f。这就是 ADRC「不依赖精确模型」的准确含义:不是不用模型,而是只用的部分少而粗(阶次 + b₀,误差 3 倍以内都能工作)。
面试怎么问:「ADRC 为什么说是不基于模型的?它到底需要知道什么?」——标准答案:需要对象的相对阶次和输入增益估计 b₀,其余(参数摄动、非线性、外扰)全部归入总扰动由 ESO 在线估计;这是它与自抗扰之前所有「先建模再设计」方法的本质区别。
是什么:ADRC(Active Disturbance Rejection Control)= TD + ESO + 状态误差反馈 + 扰动补偿四件套。逻辑链只有三步:
面试怎么问:「画出 ADRC 的结构框图,并指出总扰动从哪进、从哪出。」—— 总扰动「进」在对象方程的加速度端(与 b₀u 同一通道),「出」在 ESO 的扩张状态 z₃,最终以 −z₃/b₀ 的形式汇入控制量。画不出 ESO 双输入(u、y)是常见扣分点。
是什么:TD(Tracking Differentiator,跟踪微分器)是一个二阶动态环节,输入原始指令 v(k),输出两个信号:v₁ —— 平滑跟踪 v 的「过渡过程」,v₂ —— v₁ 的微分。为什么需要它:阶跃指令直接进闭环,误差瞬间达到最大值,积分项迅速饱和 → 超调;而想给 PID 加微分项,直接对测量差分,信噪比崩塌。TD 用「最速跟踪 + 微分在环内产生」同时解决这两个老问题 —— 这是韩京清对 PID「微分噪声放大」死结的正面回答。
怎么做(fhan 最速离散跟踪微分器):
直观理解:fhan 是「最速控制综合函数」—— 它回答「以加速度上限 r,最快多少步能把 x₁ 拉到 0」。把它接进上面两行迭代,得到的 v₁ 就是「在加速度受限下最快又最平滑地跟上 v 的轨迹」,v₂ 就是这条轨迹的速度,天然可用作前馈。
| 参数 | 物理意义 | 调大 | 调小 | 工程经验 |
|---|---|---|---|---|
| r 速度因子 | 「虚拟加速度上限」,决定过渡过程快慢 | 跟踪快,但 r→∞ 时 v₁ 退化为阶跃,失去安排过渡过程的意义 | 过渡平缓、无超调,但响应滞后 | 按「希望几个周期到达」反推;常从阶跃响应时间 T 估 r ≈ 10·v₀/T 量级起试 |
| h₀ 滤波因子 | 等效滤波时间常数,抑制输入噪声 | v₁/v₂ 更平滑,但相位滞后增大,v₂ 滞后于真实微分 | 跟随快,噪声残留多 | h₀ ≥ 采样周期 h,典型 (3~10)·h;输入噪声大时加大 |
工程简化(重要):人形机器人整机控制器通常以 1kHz 下发「位置 + 速度 + 力矩前馈」三元组(q_des, dq_des, τ_ff),指令本身就是平滑轨迹、速度前馈现成 —— 此时关节侧 TD 可省略,直接令 v₁=q_des、v₂=dq_des(00-01 页同样结论)。TD 真正的用武之地是:指令来自阶跃型上位机、或需要从「又脏又跳」的指令里提取干净微分信号的场合。
面试怎么问:「TD 解决什么问题?r 和 h₀ 分别管什么?」——答「安排过渡过程消超调 + 无噪声放大的微分提取」;r 管快慢(等效加速度限幅),h₀ 管滤波(等效噪声采样窗),二者独立可调是 TD 优于「一阶惯性 + 差分」的地方。
是什么:ESO(Extended State Observer,扩张状态观测器)是 ADRC 的心脏。普通状态观测器(见 04-17 状态观测器全解)只估计模型里已有的状态;ESO 的绝招是把「模型之外的一切」—— 总扰动 f —— 也当作一个状态 x₃ = f 扩张进来,让观测器把它连同 x₁ x₂ 一起估出来。对二阶对象(以关节位置环为例,x₁=y、x₂=ẏ、x₃=f):
为什么能收敛:第三行的 ḟ≈0 不是说扰动真的不变,而是「在观测器带宽对应的时标内近似不变」。对扩张系统构造观测器,用输出误差 e = z₁ − y 驱动三个状态的校正,就得到非线性三阶 ESO:
fal 函数与收敛性直觉:当 0 < α < 1 时,|e| 很小则 |e|^α 反而比 |e| 大(例如 e=0.01、α=0.5 时 |e|^α=0.1)——「小误差大增益、大误差小增益」:误差小时强拉快收敛,误差大时增益自动回落防超调,δ 线性段保证过零处增益有限不抖振。这套「幂次增益」与滑模观测器的 sigmoid 边界层、电机控制里的变结构思想一脉相承。收敛性的严格证明较难(韩京清用有限时间稳定性与时间尺度概念给直觉论证),但线性化后看:β 配置使特征多项式全负实部 + 扰动变化率有界 ⇒ 估计误差最终有界收敛;工程上更重要的是下一节的带宽法 —— 它把「β 怎么选」变成一个频率参数。
怎么做(读 ESO 的三个输出):z₁ = 位置估计(可直接替代测量做反馈,滤了噪声)、z₂ = 速度估计(比编码器差分干净,可省掉独立测速滤波)、z₃ = 总扰动估计(重力 + 摩擦 + 负载冲击的「合力」,既送去补偿,也可顺手做碰撞检测:|z₃| 突增即触碰)。观察 z₃ 波形是调 ESO 的第一手诊断量 —— 它应当平滑地跟随重力/摩擦的慢变化。
面试怎么问:「ESO 为什么能估计不知道的扰动?它对扰动做了什么假设?」——标准答案三层:①扩张状态——把 f 当第 n+1 个状态纳入观测器;②唯一假设是扰动「缓变」(ḟ≈0 或变化率有界),观测器带宽决定能跟踪多快的扰动;③收敛靠 β 增益配置使误差动态稳定, fal 的「小误差大增益」进一步加快小误差段收敛。
是什么:非线性 ADRC 的 fal、fhan 里有一堆参数(α₁ α₂ α₃ δ β₁ β₂ β₃…),整定困难、理论分析也难。高志强(克利夫兰州立大学)在 ACC 2003 论文(资源卡 R2)里给出尺度变换 + 带宽参数化:把 ESO 全部增益用单一参数 —— 观测器带宽 ωₒ 表示,办法是把观测器特征多项式的所有极点统一配置在 −ωₒ:
为什么这么配:观测器误差动态的特征多项式就是 s³+β₁s²+β₂s+β₃(对三阶 ESO),把它对比 (s+ωₒ)³ 的展开,β 就全定了 —— 三重极点统一在 −ωₒ,单调无超调的收敛形态,物理意义就是「误差以 ωₒ 为时间尺度的指数速度被拉回」。同理控制器侧把 PD 的两个极点统一配在 −ω_c:k_p=ω_c²、k_d=2ω_c。于是整个二阶 LADRC 只剩三个待定参数:ωₒ、ω_c、b₀,且前两个都是频率量纲、可以直接对着「闭环带宽需求」和「采样率上限」拍板。
为什么工程都用 LADRC:
面试怎么问:「LADRC 的带宽参数化是怎么把多参数问题变成单参数的?」——答:把 ESO(和 PD)特征多项式按 (s+ωₒ)ⁿ/(s+ω_c)ⁿ 展开对比系数,β₁=3ωₒ、β₂=3ωₒ²、β₃=ωₒ³、k_p=ω_c²、k_d=2ω_c;ωₒ 定「估计多快」,ω_c 定「闭环多快」,经验 ωₒ≈(3~5)ω_c。
对象:某关节电机二阶模型 J·θ̈ = u − d(含负载/摩擦总扰动 d),折算到电机端的惯量 J = 0.002 kg·m²,则 b₀ = 1/J = 500(单位 1/(kg·m²),配转矩指令 u 时恰是 rad/s²/N·m 的换算)。取观测器带宽 ωₒ = 150 rad/s、控制器带宽 ωc = 100 rad/s(经验 ωₒ ≈ (3~5)ωc 的中段)。
三阶 ESO 增益(带宽法一步算完):
控制器 PD 增益:kp = ωc² = 100² = 10000,kd = 2ωc = 200。代一组数感受量纲:设位置误差 v₁−z₁ = 0.05 rad、估计速度 z₂ = 2 rad/s、负载扰动 d = 3 N·m(z₃ ≈ −d/J = −1500 rad/s²),则 u₀ = 10000×0.05 − 200×2 = 500 − 400 = 100 rad/s²(加速度指令),控制量 u = (u₀ − z₃)/b₀ = (100 − (−1500))/500 = 1600/500 = 3.2 N·m。拆开看:0.2 N·m 用于加速(u₀/b₀ = 100×0.002),3.0 N·m 用于顶住负载——扰动补偿项占了 94%,这就是 z₃/b₀ 在干活。
采样率校核:由 ωₒ ≤ fs/10 得 fs ≥ 10×150 = 1.5 kHz。对照 §12 分层表:速度/位置环通常跑 1~2 kHz——取 2 kHz 时高于最低要求 1.5 kHz,但余量仅 33%(fs/ωₒ ≈ 13.3 倍,刚过 10 倍准则),环频一旦掉到 1.5 kHz 以下就得降 ωₒ;电流环 20 kHz 相比之下宽裕一个数量级,进一步说明 ESO 放在位置/速度层、电流层仍交给 PI 的分层是自洽的。若现场只剩 1 kHz,反解 ωₒ ≤ 628 rad/s,需把 ωₒ 降到 ~120 rad/s 并同步下调 ωc。
是什么:LADRC 的控制律分两步 —— 先用估计状态做线性 PD(称作 LSEF,Linear State Error Feedback),再做扰动补偿:
怎么理解补偿这一步:对象真实满足 ÿ = f + b·u(真实增益 b)。代入 u=(u₀−z₃)/b₀ 得 ÿ = u₀ + (b/b₀)(f−z₃)·b₀/b₀… 把量纲捋直:ÿ = (b/b₀)·u₀ + [f − (b/b₀)·z₃]。当 b₀≈b 且 z₃≈f 时,ÿ≈u₀ —— 控制器面对的等效对象变成了干净的双积分器,PD 控制双积分器是教科书问题,这就是「ADRC 把复杂对象改造为积分器串联型」的含义。注意两点:①即使 b₀≠b,z₃ 也会把 (b/b₀−1)·u₀ 的部分一起「吸收」掉,这正是 ADRC 对 b₀ 失配鲁棒的来源;②u 的量纲跟随 b₀ 的定义(电压、电流指令或力矩),写代码前先统一。
面试怎么问:「z₃/b₀ 里的 b₀ 是干嘛的?去掉行不行?」——不行:z₃ 是加速度量纲的总扰动,要换算成「控制量」量纲才能在输入端对消,除以 b₀ 就是这个换算;b₀ 是 b 的估计,失配只会降低对消质量,不会破坏结构。
是什么:NLSEF(非线性状态误差反馈)把线性 PD 换成 fal 组合:
与线性 PD 的差别:线性 PD 的增益恒定 —— 误差大时出力「不够狠」,误差小时又「推不动残差」;NLSEF 用幂次函数做变增益:小误差段(α<1)增益趋于无穷大级地放大,消除稳态残差又快又干净;大误差段增益相对收敛,防止猛出力导致超调。再加上「大误差段 α>1 加速合围」的组合策略,理论上比线性更接近时间最优。
| 对比项 | 线性 LSEF(PD) | 非线性 NLSEF |
|---|---|---|
| 增益特性 | 恒定,频域工具齐全 | 随误差幅值变化,「小误差大增益」 |
| 稳态残差 | 依赖 ω_c 与扰动补偿质量 | 幂次增益对小残差「穷追不舍」,更干净 |
| 整定与分析 | ω_c 单参数,可自动化 | 多参数(α、δ、β),无成熟频域方法 |
| 适用场合 | 绝大多数伺服/关节场景(工程默认) | 大范围高精度快速定位、强非线性对象、对极限性能有要求的研究课题 |
怎么做(决策建议):先用线性版把系统跑通、拿到基线性能;只有当「小误差段爬行」「大误差段超调」两类问题同时出现、且线性版调不动时,才考虑把 LSEF 换成 NLSEF —— 并接受整定时间翻倍的代价。韩京清原著(资源卡 R1)对非线性机理讲得最透,可作为进阶阅读。
面试怎么问:「LADRC 已经线性了,韩京清的原始 ADRC 为什么坚持非线性?你选哪个?」——答出取舍即可:非线性版理论性能上限更高(最速性),线性版工程可控性更好;选型看「性能缺口是否存在 + 整定资源是否充裕」,工业界默认线性。
是什么:b₀ 是对象方程 ÿ = f + b·u 中真实输入增益 b 的估计值 —— 「1 单位控制量能产生多少加速度」。位置/速度环里 b ≈ 1/J(J 为折算到该环输出端的转动惯量);电流环一阶模型里 b ≈ 1/L。它出现在两处:ESO 用它把「u 产生的那部分」从总变化里剥离(模型项),控制律用它把 z₃ 换算回控制量量纲(补偿项)。
为什么它决定性能:b₀ 不准时,ESO 与补偿同时「错」,但错的方式部分抵消 —— 所以 ADRC 对 b₀ 误差有 3~5 倍的容忍度(远好于增益调度),但超出后症状对称地出现:
| b₀ 取值 | 补偿效果 | 等效对象 | 典型症状 | 处理方向 |
|---|---|---|---|---|
| b₀ 过小(b₀ < 真实 b) | 过度补偿:同样的 z₃ 被换算出更大的控制量 | 等效增益虚高 | 响应变快但超调、振荡、啸叫,严重时发散 | 增大 b₀ |
| b₀ 过大(b₀ > 真实 b) | 补偿不足:对消不干净 | 等效增益偏低 + 残留扰动 | 响应迟钝、爬行,抗扰恢复慢,像「欠阻尼的软系统」 | 减小 b₀ |
| b₀ 准确(±3 倍内均可工作) | 对消干净 | ≈ 双积分器 | 阶跃快而稳,z₃ 平滑贴合负载变化 | 固化参数 |
面试怎么问:「b₀ 失配会失稳吗?怎么判断往哪个方向调?」——答:多数情况不直接失稳(z₃ 会吸收一部分失配),但性能退化;「振荡 → b₀ 偏小,迟钝 → b₀ 偏大」这组对称口诀必须答出来。判断技巧:比较 |u₀| 与 |z₃/b₀| 的量级 —— 若补偿项远大于反馈项,说明 b₀ 或扰动通道有问题。
怎么做(三条路,由易到难):
面试怎么问:「现场没有惯量数据,如何 10 分钟拿到可用的 b₀?」——答空载小信号阶跃 + 差分求加速度 + 线性回归,并补一句「量测端先做低通再差分,否则噪声把 ä 淹没」。
怎么做:多环系统(电流→速度→位置)遵循「先内环后外环」—— 内环整定完成后,对外环近似为理想力矩源,外环才好整。单环之内按下面流程走:
| 参数 | 起点 | 扫描方向 | 停止判据 |
|---|---|---|---|
| b₀ | 阶跃拟合值 / 1/J | 按症状微调(振荡↑b₀、迟钝↓b₀) | 阶跃无超调、无爬行 |
| ω_c | 需求带宽的一半 | 从小到大 | 轻微振荡后回退 30% |
| ωₒ | (3~5)·ω_c | 从低到高,典型扫到 fs/5~fs/10 为止 | z₃ 平滑、阶跃恢复达标、无啸叫 |
| 限幅 u_max | 执行器能力(电流/力矩) | — | 涵盖补偿项与反馈项之和 |
ωₒ 上限为什么是「典型 1/5~1/10 采样率」:ωₒ 越高,ESO 对突扰动的跟踪越快,但显式欧拉离散的稳定域有限(第 6 节推导),且 β₂=3ωₒ²、β₃=ωₒ³ 会把编码器量化噪声放大进 z₂ z₃。工程折中:先扫到 z₃ 开始「起毛」,再退一档 —— 这比任何公式都可靠。
面试怎么问:「给你一个新关节,LADRC 三参数你怎么下手?顺序能乱吗?」——答 b₀ 先行(没它补偿方向都不知道)、ω_c 按需求、ωₒ 最后且必须 ≥3ω_c;顺序乱调会互相掩盖症状。
为什么用电流环举例:电流环对象是一阶(R-L 电路),对应一阶 LADRC(二阶 ESO),代码最短、收益直观(反电动势 Ke·ω 就是现成的「总扰动」—— ESO 会把它估出来并补偿,等效于免费的自适应反电动势前馈)。对象方程:
一阶 LADRC 完整方程(二阶 ESO,β₁=2ωₒ、β₂=ωₒ²):
面试怎么问:「把 PI 环换成 LADRC,最小改动是什么?哪些必须保持不变?」——答:只替换「误差→控制量」的映射函数,执行周期、输出限幅、保护逻辑、通信接口全部保持;必须保留原方案基线与回滚开关。
是什么:MCU 上跑的是差分方程。对连续 ESO 用前向欧拉(显式)离散最简单 —— 每周期把导数乘以 Ts 直接累加:
为什么 ωₒ 有上限:显式欧拉把连续极点 −ωₒ 映射到 z 平面的 1−ωₒTs,落在单位圆内才稳定,粗略要求 ωₒ·Ts ≲ 1;再考虑三重极点的稳定裕度收紧 5~10 倍,就得到工程经验式:
怎么做(想突破上限怎么办):①改离散方法 —— 后向欧拉/Tustin(双线性)把稳定域扩大,Tustin 下 ωₒ 上限可放宽到 fs/3 左右,代价是每周期多做几次乘加;②精确离散 —— 观测器矩阵是 3×3,可用查表或上电时算一次矩阵指数;③降采样需求 —— 高速环(20kHz)本来就给了 ωₒ 巨大空间,「ωₒ 不够用」通常只发生在拿 1kHz 位置环硬扛大冲击的场合,此时应把 ADRC 下沉到速度环(2kHz+)。
| 控制环 | 典型 fs | ωₒ 上限(fs/10) | 对应 ω_c(取 ωₒ/4) | ESO 阶次建议 |
|---|---|---|---|---|
| 电流环 | 10~20 kHz | 6280~12570 rad/s | ≈2000~3000 rad/s(充裕) | 一阶 LADRC(2 阶 ESO) |
| 速度环 | 1~5 kHz | 628~3140 rad/s | 150~800 rad/s | 二阶 LADRC(3 阶 ESO) |
| 位置环 | 0.5~2 kHz | 314~1257 rad/s | 80~300 rad/s | 二阶 LADRC / PD+前馈 |
面试怎么问:「ωₒ 能配到任意高吗?上限由什么决定?」——三层:①采样与离散(ωₒ≤fs/10,显式欧拉);②噪声(β₃=ωₒ³ 放大编码器量化噪声);③执行器(把噪声顶到电流里成啸叫)。答出任意两层即合格。
是什么:一次 LADRC 计算的代价 ≈ ESO 的乘加次数 + 补偿除法。二阶 LADRC(三阶 ESO)约 30~40 次 FMA + 1 次除法;一阶约一半。
ladrc2_calc() 实测量级 1~2 μs @170MHz、一阶 0.5~1 μs —— 在 20kHz 电流环(50μs 周期)里占比 <4%,1kHz 位置环更是零头。20 个关节全上二阶 LADRC 也吃不满 1kHz 任务的预算;面试怎么问:「STM32G431 跑 20kHz 电流环,能不能塞进一阶 LADRC?算一笔账。」——答:G431 带 FPU,一阶 LADRC 约 0.5~1μs,加 FOC 本体约 10~15μs,20kHz 周期 50μs,占比 <30%,可以;若换 M0 就要定点化或降环频。
inv_b0 = 1/b0,运行期只做乘法(除法在 M4 上 ~14 周期,且定点化后根本没法除);②中断优先级里让 ESO 被高优先级任务打断 —— ESO 状态跨周期不一致等于隐式变步长;③调试时 printf 浮点拖垮实时性 —— 高频环里用 DMA 上传,别在环内做格式化输出。是什么:下面这份代码包含一阶(LADRC1)与二阶(LADRC2)两套结构体和计算函数,前向欧拉离散、参数运行时可改。与 00-01 3D 解剖页的 ADRC_Init/ADRC_Calc 单文件宏定义版相比:那边是「二阶专用、宏参数、零依赖」,适合直接抄进工程演示;本版是「一阶+二阶通用、结构体参数、含输出限幅与上一拍 u 缓存」,适合做在线整定上位机或多关节复用 —— 两版算法内核完全一致,可互移植。
/* ===================================================================
* ladrc.c —— 一阶/二阶 LADRC 教学精简版(前向欧拉离散, float)
* 依赖: 无(纯 float 运算) | 移植: 复制即用, 无动态内存
* 带宽约束: w_o <= fs/10; 经验: w_o ≈ (3~5)*w_c
* ================================================================ */
typedef struct { /* ---- 一阶: 对象 dy = f + b0*u ---- */
float Ts, w_o, w_c, b0; /* 周期 / 观测器带宽 / 控制带宽 / 增益 */
float kp, inv_b0; /* kp = w_c; 预先取倒数避免运行期除法 */
float z1, z2; /* z1: 输出估计 z2: 总扰动估计 */
float u; /* 上一拍输出(ESO 更新要用) */
float u_max; /* 输出限幅 */
} ladrc1_t;
typedef struct { /* ---- 二阶: 对象 ddy = f + b0*u ---- */
float Ts, w_o, w_c, b0;
float kp, kd, inv_b0; /* kp = w_c^2; kd = 2*w_c */
float z1, z2, z3; /* z1: 位置 z2: 速度 z3: 总扰动估计 */
float u;
float u_max;
} ladrc2_t;
void ladrc1_init(ladrc1_t *a, float Ts, float w_o, float w_c,
float b0, float u_max)
{
a->Ts = Ts; a->w_o = w_o; a->w_c = w_c; a->b0 = b0;
a->u_max = u_max;
a->kp = w_c; /* 一阶: 极点统一配在 -w_c */
a->inv_b0 = 1.0f / b0;
a->z1 = 0.0f; a->z2 = 0.0f; a->u = 0.0f;
}
void ladrc2_init(ladrc2_t *a, float Ts, float w_o, float w_c,
float b0, float u_max)
{
a->Ts = Ts; a->w_o = w_o; a->w_c = w_c; a->b0 = b0;
a->u_max = u_max;
a->kp = w_c * w_c; /* 二阶: (s+w_c)^2 = s^2 + 2w_c s + w_c^2 */
a->kd = 2.0f * w_c;
a->inv_b0 = 1.0f / b0;
a->z1 = 0.0f; a->z2 = 0.0f; a->z3 = 0.0f; a->u = 0.0f;
}
/* -------- 一阶 LADRC: 每周期调用一次, v=目标, y=测量(已滤波) -------- */
float ladrc1_calc(ladrc1_t *a, float v, float y)
{
float b1 = 2.0f * a->w_o; /* 极点统一在 -w_o: */
float b2 = a->w_o * a->w_o; /* (s+w_o)^2 = s^2+2w_o s+w_o^2 */
float e, u0;
e = a->z1 - y; /* 输出误差 */
a->z1 += a->Ts * (a->z2 - b1 * e + a->b0 * a->u); /* ESO 欧拉更新 */
a->z2 += a->Ts * (-b2 * e);
u0 = a->kp * (v - a->z1); /* 状态误差反馈(kp=w_c) */
a->u = (u0 - a->z2) * a->inv_b0; /* 扰动补偿 u=(u0-z2)/b0 */
if (a->u > a->u_max) a->u = a->u_max; /* 限幅防饱和 */
if (a->u < -a->u_max) a->u = -a->u_max;
return a->u;
}
/* -------- 二阶 LADRC: v1=目标, v2=目标微分(前馈, 可为0) ------------ */
float ladrc2_calc(ladrc2_t *a, float v1, float v2, float y)
{
float c1 = 3.0f * a->w_o; /* 极点统一在 -w_o: */
float c2 = 3.0f * a->w_o * a->w_o; /* (s+w_o)^3 展开系数 */
float c3 = a->w_o * a->w_o * a->w_o;
float e, u0;
e = a->z1 - y;
a->z1 += a->Ts * (a->z2 - c1 * e);
a->z2 += a->Ts * (a->z3 - c2 * e + a->b0 * a->u);
a->z3 += a->Ts * (-c3 * e);
u0 = a->kp * (v1 - a->z1) + a->kd * (v2 - a->z2);
a->u = (u0 - a->z3) * a->inv_b0;
if (a->u > a->u_max) a->u = a->u_max;
if (a->u < -a->u_max) a->u = -a->u_max;
return a->u;
}
/* -------- 用法示例: 1kHz 位置环(整机下发 q_des/dq_des/tau_ff) ------ */
/* static ladrc2_t g_pos; */
/* void pos_init(void){ ladrc2_init(&g_pos, 0.001f, 240.0f, */
/* 60.0f, 8.0f, 20.0f); } */
/* void pos_1kHz(float q_des,float dq_des,float q) */
/* { float iq = ladrc2_calc(&g_pos, q_des, dq_des, q); */
/* motor_set_iq(iq); 输出送电流环力矩指令 } */
代码四个细节,面试常被追问:
面试怎么问:「你的 LADRC 代码怎么处理输出饱和?」——答限幅三件套:控制量限幅、限幅后的 u 回写进 ESO(而不是裸 u₀−z₃)、必要时对 z₃ 补偿项也做权重衰减;只答「clamp 输出」是不完整的。
| 场景 | 建议 | 理由 |
|---|---|---|
| STM32F4/G4/H7 等带 FPU 内核 | float 直用 | 硬件浮点 1 周期乘加,1~2μs 算完,LADRC 不是算力瓶颈;可读性、可移植性最好 |
| M0/M3 无 FPU、环频 ≤1kHz | float 可接受 | 软件浮点单次几十~百周期,1kHz 周期 1000μs 仍放得下,先跑通再优化 |
| M0/M3、环频 ≥10kHz(电流环 ADRC) | Q15/Q31 定点 | 软浮点撑不住高频;定点乘加用 DSP 扩展指令单周期;但要做归一化与饱和检查(第 6.2 节) |
| 调试/上位机侧 | 永远 float | 整定、仿真、日志全用 float,只在下位机最后一公里定点化 |
开源实现可对照阅读:GitHub 上的 JcZou/ADRC_Lib(float 版 C 库)与 simorxb/ADRC-Pendulum-C(二阶 ADRC 摆杆示例,含 Python 绘图),见资源卡 R11/R12。
怎么做:抗扰实验的标准做法:系统稳定跟踪某一中等幅值指令(速度环或位置环),在 t₀ 时刻突加/突卸负载(对关节即撞块、挂重物、或电流环里注入反向阶跃),记录输出响应。读曲线四步:
面试怎么问:「ADRC 抗扰好,好在这条曲线的哪一段?为什么?」——答:好在扰动后的跌落与恢复段。PI 要等误差积分起来才反击,ADRC 的 ESO 从 u、y 的不一致里「抢先」估出扰动并前馈对消,所以跌落浅、恢复快;阶跃跟踪段两者可以调到接近。
| 对比项 | 三环 PID | LADRC | 结论 |
|---|---|---|---|
| 阶跃响应 | 调好后同样快 | 调好后同样快 | 打平 |
| 超调(有 TD/过渡过程时) | PID 本体难消大误差超调 | TD 安排过渡,天然小超调 | ADRC 优 |
| 抗突发扰动 | 误差驱动,滞后反击 | 扰动前馈对消,跌落浅恢复快 | ADRC 明显优 |
| 参数鲁棒(负载/温度漂移) | 工况变了要重调 | 总扰动兜底,一组参数管宽工况 | ADRC 优 |
| 调试成本(首次) | 3 参数,人人会调 | 3 参数(ωₒ/ω_c/b₀),需理解机理 | PI 略优 |
| 计算量 | ~5 次乘加 | 一阶 ~15、二阶 ~35 次乘加 | PI 优(差距已不重要) |
| 对测量噪声的敏感 | 不用 D 则不敏感 | z₂/z₃ 微分本质,噪声大会起毛 | PI 略优 |
什么时候 ADRC 不值得(诚实清单):
面试怎么问:「ADRC 是不是全面优于 PID?什么时候你会拒绝用 ADRC?」——这是压力题,考察对适用边界的诚实:答出噪声、大时滞、算力三条拒绝理由,比背十条优点加分得多。
怎么做:ADRC 调试 90% 的问题落在「ωₒ、b₀、噪声」三处。把症状 → 原因 → 处理做成查表,现场照单抓药:
| 症状 | 机理 | 确认方法 | 处理 |
|---|---|---|---|
| 观测器振荡/发散 | ωₒ 过高 × 显式欧拉:1−ωₒTs 跑出稳定域;或 Δωₒ 步进太猛 | z₁ z₂ 锯齿状自激,与输入无关;降 ωₒ 立刻消失 | 降 ωₒ 至 ≤fs/10;或改 Tustin/后向欧拉;步进按 1.5× 逐档扫 |
| z₃ 微分噪声(毛刺) | β₃=ωₒ³ 放大编码器量化/采样噪声,以微分形式灌入 z₃ | 静止时 z₃ 不为零且高频抖;z₃ 频谱集中在编码器量化频率 | 提高编码器有效分辨率;y 先过 α-β/二阶低通;降 ωₒ;加大 fal 的 δ(非线性版) |
| b₀ 偏小:振荡/啸叫 | 补偿过度,等效增益虚高(第 4.1 节) | 阶跃超调大、恢复来回摆;增大 b₀ 症状减轻 | 增大 b₀(每次 ×1.5);确认未在饱和区辨识 |
| b₀ 偏大:迟钝/残差 | 补偿不足,扰动残留 | 响应变「软」;稳态有固定残差;减小 b₀ 症状减轻 | 减小 b₀;重做空载阶跃辨识;检查单位折算(rad/count、减速比) |
| 上电瞬间抽动 | z₁ 初始化为 0,y 非 0,首拍误差巨大冲出假 z₃ | 只在使能瞬间出现一次 | 使能首拍同步 z₁=y、z₂=0、z₃=0;或使能前先「预跑」ESO 若干拍不输出 |
| 低速爬行/死区感 | 静摩擦进入总扰动但变化太快,z₃ 跟不上;或输出限幅过紧 | 换向瞬间速度凹陷;|u| 常贴 u_max | 提 ωₒ(留噪声裕量);放宽 u_max;速度环加摩擦前馈双管齐下 |
测量噪声预处理三原则(上 ADRC 之前先做):①源头 —— 编码器线数/细分、采样同步(在 PWM 中央对齐点采电流),比任何滤波都值钱;②前置滤波 —— 给 y 过一个截止频率 ≈ 5ωₒ 的低通,滤波器本身相位滞后要计入预算;③留诊断口 —— z₁ z₂ z₃ 与 u 全部走 DMA 上位机画曲线,盲调 LADRC 等于蒙眼开环。
面试怎么问:「现场 LADRC 电机啸叫,你按什么顺序查?」——标准顺序:①确认啸叫频率(开关频率=电气问题;几十~几百 Hz=控制环)②降 ωₒ 观察(消失→观测器噪声/稳定域问题)③看 z₃ 毛刺(毛刺大→编码器/滤波问题)④查 b₀ 方向(振荡→偏小)⑤都无效→回滚 PI 基线,逐项排除。
是什么:主流整机厂目前普遍采用「三环 PID 底座 + 选择性 ADRC 增强 + 上层 MPC/WBC」的混合架构(即 04-09 页定义的变体 C),而非「全环 ADRC」:
完整的「三环 PID → 三环 ADRC」工程变体表与五阶段升级路线,直接见 04-23 通信与控制算法升级路线页(不在此重复);未来 3~5 年的判断是「底层 ADRC 化 + 上层 MPC/RL 化」的混合架构,关节 MCU 只需做好「接指令 + 本地 ADRC 执行」。
面试怎么问:「宇树的关节用的是 ADRC 吗?为什么大厂不全部上 ADRC?」——答混合架构现状 + 三条工程理由:①PID 三环已满足大部分指标,只补短板性价比高;②全 ADRC 调试与维护成本高,量产要为「产线工人能调」负责;③上层 MPC/RL 前馈已消化大部分可建模扰动,底层只需处理残余。
更多真题与逐题解析见 06-11 保研复试面试题库的 adrc 学科 8 题(含「b₀ 偏小会怎样」等变形题)。
以下资源均经联网核实可达(2026-09)。⭐ 标注为强烈推荐:R1 是理论原著,R2 是带宽法原始论文,R9 是高志强本人 12 集入门讲座。
/help/control/ug/ 路径已迁移至 /help/slcontrol/ug/(本书页采用新地址)。站内配套:00-01 页(ESO 推导 + STM32 代码 + PI/ADRC 交互仿真)、04-09 页(三环 PID → ADRC 变体表)、06-11 页(ADRC 面试 8 题)。