这篇文章要解决的,不是“whole-body control 这个词是什么意思”,而是你在真正搭一台人形机器人时,什么时候必须上全身控制、控制器应该先管住什么、怎么验证它不是只会在仿真里站一会儿。适合已经在做双足、双臂或上半身协同平台的人。最关键的工程判断只有一句话:全身控制不是拿来“让动作更炫”的,它首先是用来在多任务、多接触、有限执行器能力之间做可验证的让步与取舍。
这篇适合谁
- 已经有 URDF / 电机驱动 / 基本状态估计,准备把“能动”升级到“能协同”的团队。
- 在做双足、双臂、躯干协同,或者腿臂一体操作的平台。
- 已经发现单关节 PID、末端 IK、步态规划各跑各的,系统一上真机就互相打架的人。
如果你现在只有一条机械臂,或者还没把编码器、IMU、接触检测跑稳,先别急着堆 whole-body control。WBC 不是第一块积木,它是你把前面几块积木接起来之后,为了不互相拆台才引入的协调层。
先纠正几个很常见的误区
- 误区 1,WBC = 更高级的逆运动学。
逆运动学只回答“姿态和位置怎么解”,WBC 还要同时处理动力学、接触力、关节限制、摩擦锥、力矩上限和任务优先级。 - 误区 2,只要优化器能解出来,控制器就算搭好了。
真机翻车往往不在求解器,而在模型参数、状态估计延迟、接触误判、驱动器饱和、热降额和模式切换。 - 误区 3,先把所有任务都塞进一个 QP 再慢慢调权重。
如果你一开始没有明确“哪些是硬约束,哪些是软目标”,最后通常只会得到一个靠魔法系数维持的演示控制器。
关键实现判断
真正可落地的 WBC,通常都先做三件事,而不是先追求复杂动作:
- 先定义不允许被破坏的硬边界。 例如支撑脚不滑、关节不过限、力矩不过限、躯干姿态不失控。
- 再定义当前阶段最值得保的少数任务。 例如 COM 稳定、摆腿轨迹、手端位姿,别一开始把头、腰、手指、视线全丢进去。
- 最后才处理从控制输出到驱动器的真实落地链路。 你输出的是关节加速度、期望力矩,还是位置-速度-力矩混合命令,这会直接决定控制效果上限。
从工程角度看,WBC 最重要的价值不是“让机器人什么都能同时做”,而是让系统在资源不够的时候,仍然知道应该先保命、再保接触、最后才保动作质量。
分步实践指南
第 1 步,先把控制边界和循环频率定死
在写第一行任务优先级代码前,先把这几个问题写清楚:
- 高层步态 / 操作规划频率是多少,WBC 主循环频率是多少,电机内环频率是多少。
- WBC 输出什么,关节期望加速度、力矩,还是送给驱动器前再过一层低级控制。
- 哪些量是估计值,哪些量来自直接测量,延迟各是多少。
很多团队一开始把 WBC 写成“一个大控制节点”,最后发现规划、状态估计、执行器反馈都在不同频率和不同时间戳上,控制器本身再漂亮也救不回来。这里可以借鉴 ros2_control 的思路,把硬件接口、状态读取、命令下发和控制器生命周期边界先切清楚,避免任务层直接和电机总线纠缠在一起。
第 2 步,先把模型和坐标系做对,再谈任务
WBC 的地基不是优化器,而是模型。至少要先确认:
- URDF / 惯量 / 质心位置不是拍脑袋填的。
- 基座、足底、手端、IMU、力传感器坐标系定义一致。
- 关节方向、减速比、零位、软限位和实际硬件一致。
Pinocchio 之类的动力学库之所以常被拿来做 WBC 底层,不是因为“学术味重”,而是因为你需要稳定地拿到 Jacobian、逆动力学、质量矩阵和约束相关量。模型差 5%,在静态站立时可能看不出来,但到了换脚、蹲起、抬臂搬物时,误差会直接放大成接触力分配错误和力矩饱和。
第 3 步,把任务栈收窄到最小可用集合
一个对新人更稳的最小任务栈,通常是:
- 浮动基座姿态或躯干姿态稳定。
- 质心高度与横摆控制。
- 支撑脚约束保持。
- 摆腿轨迹或单个手端位姿任务。
- 关节姿态正则项,用来防止冗余自由度乱飞。
这里最容易犯的错,是一上来就把双手、头部、腰部、视觉朝向和步态相位全做成“重要任务”。更稳妥的做法,是先按硬约束、主任务、次任务三级收敛。TSID 这类任务空间逆动力学库给出的最大启发,不是“直接拿来即用”,而是它把任务、约束和优先级拆得足够清楚,你可以照这个思路把自己的任务栈整理干净。
第 4 步,先把接触判断做稳,再谈优雅行走
人形机器人一旦涉及脚底、手掌、支撑面切换,WBC 最怕的不是“不会走”,而是接触状态判断比真实世界慢半拍。常见做法包括:
- 用足底力、关节残差、IMU 和速度阈值联合判断接触,而不是只看单一阈值。
- 接触建立和接触释放用不同门槛,避免抖动。
- 把接触切换设计成显式状态机,不要让求解器自己“猜”。
如果接触一会儿算支撑、一会儿算摆动,你后面的摩擦约束、力矩分配、重心控制全会跟着抽风。OpenLoong-Dyn-Control 这类开源项目值得参考的地方,不是某个参数抄过来能直接用,而是它把 MPC 和 WBC 分层,并给了 walking、jumping、blind stepping 这类不同场景下的控制组织方式,便于你理解“规划层给什么,WBC 保什么”。
第 5 步,把执行器现实约束放进设计里,不要最后才补
控制器里如果没有以下现实约束,真机几乎必翻:
- 连续力矩和峰值力矩的区别。
- 母线电压波动下可用力矩下降。
- 减速器间隙、摩擦和回差。
- 热降额后同一动作第二次做不出来。
所以 WBC 绝不只是数学层。你要明确:哪些关节允许力矩控制,哪些只能近似成位置/速度接口;当驱动器不接受直接力矩时,中间映射层怎么做;饱和时优先砍哪类任务。很多演示控制器之所以只能录视频,是因为它从来没认真面对执行器约束。
第 6 步,留出降级与接管通道
只要你的平台会在真实地面上工作,就不要假设 WBC 永远能解出“漂亮解”。你至少应该准备:
- 求解失败时的保底姿态或切换到更保守的平衡模式。
- 接触状态异常时冻结摆腿、降低速度、收窄动作范围。
- 遥操作 / 人工接管入口,别让整机在错误任务栈里硬撑。
真正成熟的控制栈,往往不是解得最漂亮的那个,而是最知道什么时候该放弃复杂动作、退回保守模式的那个。
第 7 步,按阶梯验证,不要一步上全身动态动作
推荐的验证顺序通常是:
- 空载悬挂,验证关节方向、限位、零位、模型一致性。
- 双脚固定站立,验证姿态任务、关节力矩趋势和估计延迟。
- 静态重心转移,验证接触力分配和饱和行为。
- 单脚减载但不完全离地,验证接触切换逻辑。
- 低速摆腿、原地踏步,再到小步行走。
- 最后才是带手臂动作、搬运、转体等耦合任务。
如果你跳过前面几层,直接追求整机行走视频,最后调出来的通常不是系统能力,而是一次性参数运气。
最容易翻车的地方
- 状态估计延迟被低估。 看起来是控制抖,其实是 IMU、编码器、接触判定时间没对齐。
- 任务权重全靠手感。 这会让不同场景之间完全不可迁移。
- 把摩擦锥和接触约束当成“以后再补”。 这样真机一旦地面变化,系统立刻露底。
- 模型和硬件版本漂移。 换了脚掌垫片、换了减速器、换了电池,结果还在用旧参数。
- 只看是否站住,不看力矩、电流、温升和求解残差。 这会把很多将来的翻车点藏起来。
怎么验证你真的搭对了
- 同一组站立与重心转移动作,连续做 30 到 50 次,姿态误差、足底接触判定和关节温升是否稳定。
- 故意注入轻微模型误差、地面高度误差和延迟,观察控制器是平稳降级还是突然发散。
- 记录每轮任务残差、约束违反次数、力矩饱和比例,而不只是录视频。
- 让手臂任务和步态任务同时存在,确认系统会不会因为上肢动作把平衡预算吃光。
- 做一次“失去接触置信度”测试,确认控制器会降级,而不是继续输出危险动作。
你真正想看到的,不是某次演示特别顺,而是系统在小误差、小扰动和重复运行下仍然能解释得通。
下一步怎么做
如果你已经把最小 WBC 跑稳,下一步优先级通常不是马上加花哨技能,而是:
- 把接触切换、上肢协同和步态规划之间的接口冻结下来。
- 把模型参数标定、日志回放、温升监控和版本管理补齐。
- 再逐步引入更复杂的双臂协作、动态步态和操作任务。
先把“站得住、切得稳、退得回去”这三件事做扎实,WBC 才会从 demo 技术变成你整机系统里真正能依赖的控制骨架。
延伸阅读 / Sources
- Pinocchio 官方文档,适合理解刚体动力学、Jacobian、逆动力学与约束求解基础:
https://stack-of-tasks.github.io/pinocchio/ - TSID(Task Space Inverse Dynamics)开源项目,可参考任务、约束、优先级的组织方式:
https://github.com/stack-of-tasks/tsid - OpenLoong-Dyn-Control,适合参考 MPC + WBC 分层、MuJoCo 验证与人形控制框架落地:
https://github.com/loongOpen/OpenLoong-Dyn-Control - ros2_control 官方文档,适合理解硬件接口、控制器生命周期与多自由度硬件边界:
https://control.ros.org/humble/doc/getting_started/getting_started.html