解读 126 · mdp.py(五):命令与课程函数
解读对象:
microduck-replica/upstream/microduck_rl/src/mjlab_microduck/tasks/mdp.py,抽读命令类与课程函数(全文件 7188 行,10 个 class 全是命令项)
需要的前置:解读 22(命令槽怎么配)、解读 26(课程函数"改活配置"原则的速览)
命令(command)是策略的遥控器输入;课程(curriculum)是随训练进度自动拧旋钮的机制。mdp.py 里两者占尽风头:10 个 class 全是命令项,课程函数则散布在 3295-5540 行之间。
命令类:遥控器怎么造
VelocityCommandCommandOnly(4505 行起)继承 mjlab 的速度命令,_resample_command(4508-4533 行)加了一个"原地转"抽签:按 rel_turn_in_place_envs(Cfg 默认 0.0,4570 行)抽中的环境线速度清零、偏航强制到 [0.4·max, max] 且随机左右——注释算过账,均匀采样几乎抽不出"线速≈0 且角速大"的组合(约 2%),不补签原地转就永远练不到。
RelativeHeadingVelocityCommand(4576 行起)改了 cmd[2] 的语义:从偏航速率改成航向误差(体框架下的角度差)。_update_command(4613-4623 行)刻意不调父类——父类的偏航 P 控制器会用角速度覆盖这个槽——而是每步从四元数现算 yaw、wrap 到 ±π、clamp 到 _heading_max。部署时人直接喂这个槽,恒定误差 ≈ 恒定转弯速率。
GroundPickPhaseCommand(4966 行起)把命令槽当乐谱:命令 = [cos 2πφ, sin 2πφ, 0],相位每步推进 dt/period(默认 4 s,sitstand 用 8 s,Cfg 5023-5026 行);reset 时按 randomize_phase 决定随机相位还是从 0(站立)起——False 对齐部署上"按键从头开始"的行为。
SitStandCommand(6234 行起)最讲究:命令是坐/站旗标,内部维护一个斜坡混合 alpha 以 ramp_s=2.0 秒匀速滑向旗标(sit_z=0.060、stand_z=0.115,6263-6266 行)。docstring 讲了为什么必须有斜坡:二值目标下"瞬移坐下"每省一步都拿满分、速度上限惩罚只是线性成本,瞬移赢;换成滑动目标后,跑到斜坡前面只拿零分,跟着斜坡走才是最优(6244-6253 行)。还有个细节:alpha 初始化读真实躯干高度放在 compute() 里而不是 reset() 里(6297-6306 行)——命令管理器重置先于传送机器人的事件执行,在 reset 里读高度读到的是传送前的旧值。
UniformPoseCommand(5061 行起)是通用 N 维均匀采样器,亮点是 zero_command_prob(5098-5100 行):显式抽一个全零命令桶,否则均匀采样几乎永远抽不出"待机"——部署时的静止工况会在训练里缺席。
课程函数:改"活着的"配置
原则(26 篇速览过):各 Manager 初始化时对配置做了 deepcopy,改 env.cfg.xxx 是无效操作,必须经 get_term_cfg 拿经理持有的活配置。本篇看四个变体:
velocity_command_ranges_curriculum(3540-3598 行):按{step, lin_vel_range, ang_vel_range}分档放宽命令范围,forward_only=True时 x 下界锁 0。face_down_prob_curriculum(4477-4502 行):调 Reset 事件的face_down_prob——初期多趴着(任务简单),渐近 0.5。termination_param_curriculum(5370-5402 行):改终止条件的参数,典型用法是把bad_orientation的 limit_angle 后期设成 π,"允许摔倒才能学会自己起来";直接访问tm._term_names/_term_cfgs并对 play 模式做了保护。terrain_levels_slope(3521-3537 行)+slope_move_masks(3504-3518 行):坡地任务的升降级——走了 40% 块长升坡,不足 20% 降坡;注释强调升级阈值必须与terrain_edge_reached终止(块长的 95%)对齐,否则成功的穿越者永远升不了级。
你带走的收获
- 命令分布就是课程的一部分:均匀采样抽不到的工况(原地转、全零待机)要显式留桶。
- 改语义要绕开父类:航向槽从速率改误差后,父类每步更新必须整段跳过。
- 目标斜坡化(slew)能把"瞬移抢奖"变成"跟随斜坡",是反 time-optimal 作弊的通用手段。
- 课程函数四步一套:分档 dict → common_step_counter 比较 →
get_term_cfg改活配置 → 返回标量给 wandb。