OpenDuckMini强化学习框架入门教程-域随机化
纠错,疑问,交流: 请进入讨论区或 请点击进入页面,扫码加入微信群或Q群进行交流
获取最新文章: 扫一扫加入“创客智造”公众号
欢迎加入我们的openduckmini交流群,微信扫描右侧二维码立即进群交流
域随机化
- 理解域随机化,包含核心函数,随机化参数,随机化范围分析,实现细节,域随机化的作用,与训练系统的集成等
概述
域随机化(Domain Randomization) 是强化学习中一种重要的泛化技术,通过在训练过程中随机变化仿真环境的物理参数,使得训练出的策略能够更好地迁移到真实环境(sim-to-real transfer)。Open Duck Playground 的域随机化在 playground/common/randomize.py 中实现。
核心函数
def domain_randomize(model: mjx.Model, rng: jax.Array):
该函数接受 MJX 模型和随机数生成器,返回随机化后的模型和参数变化掩码。每次环境 step 时调用,实现物理参数的在线变化。
随机化参数
1. 地面摩擦系数
随机变化机器人足部与地面的摩擦系数:
# 范围: 0.5 ~ 1.0(均匀分布)
geom_friction[FLOOR_GEOM_ID, 0] = uniform(0.5, 1.0)
这使策略学会在不同摩擦系数的地面上都能保持稳定——无论是光滑地板还是粗糙路面。
2. 关节摩擦
随机缩放执行器关节的静摩擦力:
# 范围: 0.9 ~ 1.1(乘积因子)
dof_frictionloss *= uniform(0.9, 1.1)
3. 关节惯性
随机缩放关节的 armature(旋转惯量):
# 范围: 1.0 ~ 1.05(乘积因子)
dof_armature *= uniform(1.0, 1.05)
4. 质心偏移
随机偏移躯干的质心位置:
# 范围: ±0.05 m
body_ipos[TORSO_BODY_ID] += uniform(-0.05, 0.05)
这模拟了机器人携带不同负载或重心变化的情况。
5. 质量变化
随机缩放所有连杆的质量:
# 范围: 0.9 ~ 1.1(乘积因子)
body_mass *= uniform(0.9, 1.1)
# 额外在躯干上 ±0.1 kg 的变化
body_mass[TORSO_BODY_ID] += uniform(-0.1, 0.1)
6. 关节零位偏移
随机偏移关节的初始零位(qpos0):
# 范围: ±0.03 rad
qpos0[joint_addr] += uniform(-0.03, 0.03)
7. 执行器 KP 增益
随机缩放位置控制器的 KP(比例增益):
# 范围: 0.9 ~ 1.1(乘积因子)
actuator_gainprm *= uniform(0.9, 1.1)
actuator_biasprm *= (-kp * factor) # 同步更新偏置
这模拟了舵机性能差异或随时间老化的影响。
参数变化汇总
| 参数 | 变化方式 | 范围 | 仿真效果 |
|---|---|---|---|
| 地面摩擦 | 直接设置 | [0.5, 1.0] | 不同地面条件 |
| 关节静摩擦 | 乘积缩放 | ×[0.9, 1.1] | 关节灵活性变化 |
| 关节惯量 | 乘积缩放 | ×[1.0, 1.05] | 关节响应速度变化 |
| 质心位置 | 位置偏移 | ±0.05 m | 负载分布变化 |
| 连杆质量 | 乘积缩放 | ×[0.9, 1.1] | 整体重量变化 |
| 躯干附加质量 | 直接偏移 | ±0.1 kg | 额外负载 |
| 关节零位 | 角度偏移 | ±0.03 rad | 装配误差 |
| 执行器 KP | 乘积缩放 | ×[0.9, 1.1] | 舵机性能差异 |
随机化范围分析
从简单到困难
easy ←─────────────────────────→ hard
平坦地形 + 小随机化 粗糙地形 + 大随机化
(起始训练) (高级泛化训练)
在训练策略时可以调整随机化范围:
- 初始阶段:使用较小的随机化范围,让策略先学会基础运动
- 后期阶段:逐步扩大范围,提高策略的鲁棒性
- 最终部署:使用完整随机化范围训练,确保在真实环境的表现
与地形的协同作用
域随机化与地形选择相互配合:
| 地形 | 域随机化作用 |
|---|---|
| 平坦地形 + 随机化 | 策略学会应对不同地面条件 |
| 粗糙地形 + 随机化 | 策略学会在复杂地形上适应变化 |
| 回差模型 + 随机化 | 策略学会在真实机构误差下保持性能 |
实现细节
vmap 向量化
域随机化函数使用 @jax.vmap 实现的函数进行并行计算,支持 JAX 的自动向量化:
@jax.vmap
def rand_dynamics(rng):
# 对每个参数生成随机变化
# ... 7 种参数变化 ...
return (friction, body_ipos, frictionloss, armature, body_mass, qpos0,
actuator_gainprm, actuator_biasprm)
模型更新
使用 tree_replace 高效更新 MJX 模型参数:
model = model.tree_replace({
"geom_friction": friction,
"body_ipos": body_ipos,
"dof_frictionloss": frictionloss,
"dof_armature": armature,
"body_mass": body_mass,
"qpos0": qpos0,
"actuator_gainprm": actuator_gainprm,
"actuator_biasprm": actuator_biasprm,
})
变化掩码
同时返回 in_axes 参数变化掩码,指示哪些参数发生了变化:
in_axes = jax.tree_util.tree_map(lambda x: None, model)
in_axes = in_axes.tree_replace({
"geom_friction": 0, # 第一个维度变化
"body_ipos": 0,
# ...
})
这用于 JAX 的 vmap 映射机制,确保正确广播。
域随机化的作用
域随机化在 sim-to-real 迁移中发挥关键作用:
- 弥合仿真-现实差距:真实机器人存在制造公差、舵机性能差异、地面条件变化等
- 提高鲁棒性:策略学会适应各种物理参数变化,而不是过拟合到特定值
- 避免脆弱行为:防止策略利用仿真中的物理漏洞(如过大的摩擦力)
- 便于部署:策略在多种条件下训练,无需为每个机器人单独微调
与训练系统的集成
在 runner.py 中,域随机化函数作为参数传递给 PPO 训练器:
self.randomizer = randomize.domain_randomize
train_fn = functools.partial(
ppo.train,
randomization_fn=self.randomizer, # 注入域随机化
...
)
PPO 训练器会在每个训练步调用此函数,随机化环境参数,使得策略在每次交互中面对略有不同的物理世界。
纠错,疑问,交流: 请进入讨论区或 请点击进入页面,扫码加入微信群或Q群进行交流
获取最新文章: 扫一扫加入“创客智造”公众号
欢迎加入我们的openduckmini交流群,微信扫描右侧二维码立即进群交流


















