从「电机煎蛋」到稳健落地:强化学习 Sim2Real 中的动作平滑与散热治理
搞具身智能和强化学习控制的人,大概率都经历过这种高光时刻的反面:
你在 Isaac Gym 或者 Genesis 里训出了一个步态极其犀利、抗扰动能力逆天的四足或双足机器人。仿真回放里,它跑得像只羚羊,各种侧推不倒。
然后你满怀信心地把 Policy 烧录进真机,拔掉安全绳开机—— 伴随着高频刺耳的蜂鸣声,机器人的关节开始剧烈抖动(Chattering),像得了帕金森。还没等你反应过来,两分钟后驱动板报过热故障,停机保护,走近一闻,甚至能隐约闻到定子漆包线受热散发的焦糊味。
欢迎来到真实的物理世界。
在 Sim2Real 领域,「高频抖动」和「电机发热」本质上是同一枚硬币的两面。仿真器默认刚体没有形变、力矩响应瞬态完成、关节没有间隙、线圈不会热累积。强化学习策略极其聪明,它很快就会发现:利用高频的 Bang-Bang 控制(极速正反转切换)可以在理想环境里榨取出极高的敏捷度。但放到实物上,这种动作会变成无谓的内阻损耗、剧烈的机械冲击以及灾难性的欧姆热。
每一次电机过热停机甚至烧毁,都是真机在用物理定律教我们做人。今天就来复盘一下,我们是如何在算法层和架构层把这些「抖动」和「热量」一步步驯服的。
一、 奖励函数重构:别让策略把电机当拨片开关
很多人的第一反应是在奖励函数里加个惩罚: $$r_{\text{penalty}} = - | \tau |^2$$
有用,但远远不够。稳态力矩大并不一定会让电机过热到报警,真正把电机送进重症监护室的,是高频交变的力矩变化率(Torque Rate)以及角加速度(Jerk)。电机在频繁换向时,反电动势(Back-EMF)剧烈波动,控制器不断处在峰值电流输出状态,发热功率 $P = I^2 R$ 直接拉满。
我们在实操中必须部署阶梯式的动作平滑惩罚:
- 一阶差分(Action Rate / 动作速率): 约束相邻步输出变化。
- 二阶差分(Action Acceleration / 动作加速度): 消除加速度突变,抑制 Jerk。
- 机械功率惩罚(Mechanical Power): 惩罚力矩与关节速度同向的无用功。
在 PyTorch 的并行环境奖励计算中,通常这样写:
import torch
def compute_smoothness_penalties(
actions: torch.Tensor, # 当前动作 a_t: [num_envs, num_dofs]
last_actions: torch.Tensor, # 上一帧动作 a_{t-1}
last_last_actions: torch.Tensor, # 上上帧动作 a_{t-2}
torques: torch.Tensor, # 关节输出力矩 tau: [num_envs, num_dofs]
dof_vel: torch.Tensor # 关节角速度 q_dot: [num_envs, num_dofs]
) -> dict:
# 1. 一阶动作速率惩罚:约束连续动作阶跃
action_rate = actions - last_actions
penalty_action_rate = torch.sum(torch.square(action_rate), dim=-1)
# 2. 二阶动作加速度惩罚 (Jerk 抑制):消除高频震颤的关键
action_acc = actions - 2.0 * last_actions + last_last_actions
penalty_action_acc = torch.sum(torch.square(action_acc), dim=-1)
# 3. 关节机械功率消耗惩罚:P = tau * v,避免电机做无意义的“高频对冲”
# 只惩罚做正功的部分,或者直接惩罚能量耗散
mechanical_power = torch.clamp(torques * dof_vel, min=0.0)
penalty_power = torch.sum(mechanical_power, dim=-1)
# 4. 力矩变化率惩罚 (Torque Rate)
# 若控制器支持力矩回传,尽量加上这一项
penalty_torque = torch.sum(torch.square(torques), dim=-1)
return {
"action_rate": penalty_action_rate,
"action_acc": penalty_action_acc,
"power": penalty_power,
"torque": penalty_torque,
}
踩坑提醒: 动作平滑权重不能从一开始就给得太大,否则在训练早期 Exploration(探索)阶段,策略很容易被“冻住”,导致机器人连站立都学不会。建议采用 Curriculum Learning(课程学习),在策略学会基本平衡(例如存活超 200 步)后,再逐步线性拉高 Smoothness 惩罚权重。
二、 动作空间重构与滤波:物理世界的低通缰绳
强化学习的策略推理频率通常在 50Hz 到 100Hz,而底层的电机驱动板电流环/速度环在 1kHz 到 20kHz。如果在 50Hz 的控制周期里,Policy 输出一个阶跃,底层 PD 就会瞬间产生一个极大的脉冲电流。
在网络输出和电机指令之间,必须加物理缰绳。
1. 放弃纯绝对位置/力矩输出,改用位置增量或残差控制
直接输出目标关节位置容易产生跳跃,输出相对于默认姿态(Nominal Pose)的 Offset,并在时间步上做插值(Interpolation)或者限幅(Rate Limiter):
$$q_{\text{target}}(t) = q_{\text{target}}(t-1) + \text{clip}(\Delta q, -\delta_{\max}, \delta_{\max})$$
2. 将低通滤波器(LPF)显式纳入环境循环
不要指望真机外部的滤波板能帮你搞定一切。如果你在实物上开了滤波,仿真里就必须一模一样地包含这个滤波器! 否则滤波引入的相位滞后(Phase Lag)会直接摧毁策略在真机上的稳定性。
class ActionFilterEMA:
""" 一阶指数滑动平均 (EMA) 滤波器,等效离散一阶低通滤波 """
def __init__(self, alpha: float, num_envs: int, num_dofs: int, device: str = "cuda"):
# alpha 越小滤波越强,延迟越大;推荐 0.3 ~ 0.7 之间
self.alpha = alpha
self.filtered_action = torch.zeros((num_envs, num_dofs), device=device)
def filter(self, new_action: torch.Tensor) -> torch.Tensor:
self.filtered_action = self.alpha * new_action + (1.0 - self.alpha) * self.filtered_action
return self.filtered_action
def reset(self, env_ids: torch.Tensor):
self.filtered_action[env_ids] = 0.0
在训练环境的 step() 里直接应用经过滤波后的 Action 给物理引擎。这样 Policy 就能在反向传播中“感知”到滤波器的时延,并学会主动向前预测,消除震荡。
三、 执行器动力学建模与延迟注入(Actuator Dynamics)
如果你的仿真执行器是理想的 PD 控制器($F = K_p (q_d - q) - K_d \dot{q}$),那么 Sim2Real 大概率会翻车。
真实的减速电机(无论是一体化关节、准直驱 QDD 还是普通行星减速器)具有:
- 电感/电容引起的力矩爬升时间(带宽限制)。
- 静摩擦与库伦摩擦(Stiction & Coulomb Friction)。
- 不可忽视的通信与计算延迟(Latency):从传感器读取、网络推理到 CAN 总线发送,通常有 10ms ~ 40ms 的随机延迟。
治理方案:
- 时延随机化(Latency Randomization): 在仿真中开辟一个 Ring Buffer,把动作随机延迟 1~3 个 Step 再送入物理求解器。没有时延随机化的 Policy,一到真机上遇到微小的延迟就会发生高频共振,进而快速发热。
- 执行器网络(Actuator Net): 如果做极致控制,用实机测得的“指令目标位置/速度 - 实际力矩”数据训练一个小型的 MLP 替代理想 PD 计算,将电机的动态响应和饱和特性全量拟合进仿真。
四、 真机下地与遥测复盘(Post-Mortem)
改完算法,实测依然是唯一的试金石。
在部署到真机时,我们会在机器人板载上位机(如 Jetson Orin)上开一个低优先级的日志线程,以 100Hz 记录三个关键物理量:
- 电流均方根(RMS Current): 直接对应电机发热。
- 动作功率谱密度(Action PSD): 监控高频频段(10Hz 以上)是否有共振峰。
- 电机外壳与驱动板热电偶温度曲线。
![数据曲线示意] 上图是典型的迭代复盘对比:红线是未经动作平滑的基准策略,高频震颤导致 RMS 电流高达 18A,电机在第 90 秒突破 85°C 触发保护;绿线是引入二阶平滑惩罚 + EMA 动作滤波后的策略,动作圆润,RMS 电流稳定在 6.5A 左右,温升在 20 分钟连续行走后稳定在 48°C。
摔倒与过热,都是极佳的数据。 如果真机下地时发现某个特定的关节(比如髋滚转关节 Hip Roll)温度上升奇快,别急着怪硬件。把真机 Log 的关节轨迹导出来,和仿真里比对一下——十有八九是仿真中该维度的接触刚度设得过高,或者地面摩擦系数(Friction)随机化范围脱离了真实地面,导致左右脚在支撑相交替时出现力矩争抢(Fight)。
结语
在强化学习的游乐场里,数学指标常常会误导我们:Reward 曲线冲得越高,动作可能越歇斯底里。
但工程的魅力恰恰在于这些物理约束。动作平滑性不是牺牲敏捷度换来的妥协,而是为了让控制策略在真实的能量转换定律下保持优雅。
给你的策略套上平滑奖励,把低通滤波写进计算图,留出足够的延迟余量。下一次机器人在实地站起来的时候,你听到的将不再是刺耳的啸叫,而是减速箱运转时平稳低沉的哼鸣。
回到工作台,继续修 Bug,继续跌倒,然后迭代出更稳健的下一次。
许可协议:CC BY-NC 4.0
更新于 12 小时前
觉得文章有帮助?点个赞吧!
0 条评论


