解读 125 · mdp.py(四):事件与随机化函数
解读对象:
microduck-replica/upstream/microduck_rl/src/mjlab_microduck/tasks/mdp.py,抽读事件/reset 与域随机化函数(全文件 7188 行)
需要的前置:解读 26(事件 term 时机与"BAM 三兄弟"速览)、解读 54(执行器模型背景)
event term 是在特定时机(重置时、每隔几秒、每步)对仿真动手的函数。域随机化(DR, domain randomization)是其中一大类:故意把物理参数抖开,逼策略学会鲁棒。本篇按"动手对象"分三组。
动手在初速度:重置热启动
reset_with_forward_velocity(158-226 行)让一部分环境"出生即在走":按 fraction_stages(默认 [{"step":0,"fraction":0.8}],可随训练降到 0)抽签,给抽中的环境沿机体朝向写入 0.3–0.8 m/s 前向速度。两个细节值钱:一是四元数必须读 qpos 而非 root_link_quat_w(199-202 行注释)——后者依赖 sim.forward() 刷新,刚写完的朝向还没生效;二是顺手把四个被动轮转速设为 v/r(轮半径 0.0175 m,218-226 行),否则第一轮接触就是"底座在动、轮子不动"的打滑。roller 任务的同款是 reset_rolling_entry(1055-1090 行)。
动手在执行器:增益、延迟与 BAM 摩擦
这组函数不碰 MuJoCo 模型,而是调执行器自己的接口。randomize_delayed_actuator_gains(3146-3194 行)对 BamActuator 逐关节采样 kp/kd 缩放,再按环境平均成单标量写入——执行器只接受全局缩放;先 reset_gains 恢复标称再 set_gains,防止逐回合累积。延迟(动作滞后几拍)本身在执行器配置里(delay_min_lag/delay_max_lag,见解读 127),与增益同属"伺服不完美"随机化。摩擦更绕:BAM 自己算摩擦,MuJoCo 的 dof_frictionloss 被清零(3220-3223 行注释),所以 randomize_bam_friction(3212-3240 行)随机的是执行器的 friction_scale(库仑+Stribeck+负载摩擦的乘数);而 expand_bam_friction_fields(3197-3209 行)是带装饰器的空函数——@requires_model_fields("dof_frictionloss", "dof_damping") 的唯一作用是让 mjlab 把这两个模型字段按环境展开,BAM 每步要写它们,不注册这个事件就会崩。
动手在模型与初始状态:质量、CoM、IMU 与姿势
randomize_mass_and_inertia(3243-3292 行):质量和惯量用同一个缩放因子——各自独立随机会造出物理上不成立的惯量张量,仿真直接不稳;标称值缓存在 env 上,先恢复再缩放。randomize_com(5602-5647 行)随机body_ipos(质心位置),缓存键按(字段名, 体索引)拼接——trunk 和 head 两个事件共用一个字段也不会互相覆盖。randomize_imu_orientation(3706-3771 行)给 IMU site(固定 0 号)转一个 ±max_angle_deg(默认 2°)的小角度,用小角近似四元数[1, θx/2, θy/2, θz/2]手写乘法。- 初始姿势随机化家族:
randomize_base_orientation(4019-4079 行,±10° 俯仰 ±5° 横滚)、set_random_prone_orientation(4122-4154 行,面朝下/上 ±90° 俯仰 + 随机偏航)、set_random_ground_state(4157 行起,趴/仰/坐/站四桶抽签,供 standup)。 - 推搡(push)本体不在本文件:mjlab 自带的
push_by_setting_velocity(mjlab/envs/mdp/events.py:321)每 3–6 秒给 ±0.3 m/s 速度跳变(velocity_env_cfg.py:79-80;从 ±0.5 收紧的注释写着"会训出神经质的救步步态")。
还有一个不像随机化的 Reset 事件:apply_mouth_payload_force(3102-3138 行)把 sample_mouth_payload(3085-3099 行,每次重置抽 0.01–0.04 kg)存好的"嘴里物体"重量,在叼起相位后作为外力施加到嘴尖 site——挂在奖励表里当权重为 0 的钩子,返回永远是 0。
你带走的收获
- DR 函数的统一卫生习惯:先恢复标称、再采新值,累积污染是最常见暗坑。
- 随机化什么要看执行器边界:BAM 自己管摩擦和增益,DR 就得写进执行器的接口,而不是模型字段。
- 质量与惯量必须同因子缩放;IMU/编码器这类"传感器错装"用每环境恒定偏置,而非每步噪声。
- 带装饰器的空函数可以是合法设计:装饰器本身就是注册副作用。