DEEP 122 · 第十一辑 · 服务与训练工具逐函数 · LEARN NOTES

收进学习手册 · 2026-09-11 · duck.whatled.com

解读 122 · mdp.py(一):文件结构与公共设施

解读对象:microduck-replica/upstream/microduck_rl/src/mjlab_microduck/tasks/mdp.py(7188 行,220 个顶层 def + 10 个 class;含嵌套共 255 个 def)
需要的前置:解读 21(这个文件被谁加载)、解读 25(兄弟篇:观测函数导览)

mdp.py 是全仓库最大的单文件。所有任务配置文件里写的 func=microduck_mdp.xxx,最终都指向这里。本篇不读具体函数,读它的"骨架":函数怎么组织、文件头四个补丁干了什么、公共工具怎么服务全文件。

函数地图:先 grep 再读

grep -n "^def " 一条命令就能拿到全文件 220 个顶层函数和行号。粗看即见组织规律:按任务家族分段,段与段之间用横线注释分隔——507 行起的 standup/velstand 家族(_fallen_mask、upright_progress、recovery_success)、3141 行的 "Domain Randomization Events"、5692 行的 BallKick、5856 行的 SPIN、6145 行的 backlash 观测、6682 行起的 roulade。同族函数共享前缀(spin_*、roulade_*、posture_*、multistage_*),派生变体带后缀(*_phased、*_from_values,后者是"算好中间量再打分"的可测纯函数版)。10 个 class 全部是命令项(4505-6332),下篇细读。还有一个彩蛋:roller 任务段(1035-1293,如 descent_speed_reward、wheel_glide_reward)的 docstring 是法语,另一条任务线的痕迹。

文件头的四个补丁

23-113 行是四个"猴子补丁"(monkeypatch = 运行时替换库函数,import 即对全项目生效):

每个补丁装上时都 print 一行(66、113 行),启动日志里能确认补丁生效——被替换的是"库的行为",看不见的替换最危险。

公共设施:14 舵机的正典索引

_DEFAULT_ASSET_CFG = SceneEntityCfg("robot")(119 行)是几乎所有函数的默认参数;_NECK_JOINT_PATTERNS(123 行)用四个正则圈定颈/头关节。关键件是 _servo_joint_ids(126-143 行):对带齿隙/轮子/下颌的模型,实体关节表比 14 个舵机宽、且交错插入 passive_*,裸索引会抓错关节;它用 find_joints(r"^(?!passive_).*") 取"非被动"关节并缓存到 env.__dict__(每个 env 的属性字典,当缓存柜用),在普通模型上就是恒等映射。_servo_joint_pos/_servo_joint_vel/_servo_default_joint_pos(146-155 行)三个一行函数全部经它索引——一套奖励代码因此同时服务 5 种模型变体。

函数的统一长相与"挂"在 env 上的状态

绝大多数函数签名是 (env, ..., asset_cfg=_DEFAULT_ASSET_CFG) -> torch.Tensor,返回 (num_envs,)(奖励/惩罚)或 (num_envs, dim)(观测)。跨步记忆不建类,而是挂在 env 的属性上:_prev_leg_actions(动作差分惩罚)、_swing_accum(步态对称累计)、_fallen_tax_armed(滞回闸门)……命名一律下划线开头表示"内部"。有挂就有清:reset_action_history(229-313 行)在回合重置时把这些缓存全部对齐到当前值,否则回合开头会凭空冒出 action_rate 惩罚尖峰。

你带走的收获

延伸

什么鸭 WHATDUCK · 复刻学习笔记 ← 全部手册 · 首页