Constrained Hand Motion Tracking with Adaptive Trade-off Control
任务是让机器人手(xArm7 + XHand,单手或双手)在仿真里复现一段人手操作物体的演示。参考给出逐帧的关节轨迹(人手重定向得到)、物体位姿和手–物接触标注。策略输出关节残差,关节目标 = 参考关节 + 残差。奖励分三路:任务 \(r_g\)(物体位姿),风格 \(r_s\)(臂与手指关节、接触),惩罚 \(r_p\)(速度与加速度)。每个片段单独训练一个策略。论文
| 方法 | 进度 ↑ | 物体位置 (m) ↓ | 物体旋转 (rad) ↓ | 手指误差 (rad) ↓ | 接触 F1 ↑ | 接触点 (m) ↓ |
|---|---|---|---|---|---|---|
| ConTrack | 0.899 ± 0.195 | 0.026 ± 0.006 | 0.272 ± 0.105 | 0.163 ± 0.014 | 0.784 ± 0.072 | 0.018 ± 0.005 |
| ManipTrans | 0.743 ± 0.292 | 0.012 ± 0.009 | 0.207 ± 0.078 | 0.277 ± 0.089 | 0.620 ± 0.068 | 0.030 ± 0.010 |
| DexMachina | 0.246 ± 0.052 | 0.038 ± 0.018 | 0.348 ± 0.121 | 0.147 ± 0.016 | 0.708 ± 0.041 | 0.024 ± 0.003 |
| SPIDER | 0.444 ± 0.341 | 0.201 ± 0.113 | 1.104 ± 0.599 | 0.157 ± 0.019 | 0.191 ± 0.225 | 0.036 ± 0.011 |
论文表 2。13 个片段(GRAB 5、ARCTIC 4、DexterHand 4)的均值 ± 标准差,每片段 5000 次 PPO 更新。评估一律从第一帧开始,物体平移误差超过 0.10 m 或旋转误差超过 1.00 rad 即终止;进度 = 终止帧 / (T − 1)。蓝色为各列最好。ManipTrans 为作者重新实现,DexMachina 只移植了其虚拟物体控制器。论文
四件事:参考跟踪是怎样的 MDP,PPO 的核心,约束强化学习与对偶变量,以及"每个回合从哪里开始"的几种做法。公式编号用 (B·)。
一段参考片段长 T 个控制步。仿真的物理状态 \(x_t\) 包括机器人关节角和角速度、物体位姿和速度。参考在每一帧给出关节目标 \(q^{\text{ref}}_t\in\mathbb R^D\)(D 是驱动关节数)、每个物体的位置 \(p^{\text{ref}}_{t,o}\in\mathbb R^3\) 和单位四元数 \(\bar q^{\text{ref}}_{t,o}\),以及每个手部连杆 ℓ 与物体 o 的接触标注 \(c^{\text{ref}}_{t,o,\ell}\in\{0,1\}\)。ConTrack 把帧号并进状态:论文 3.1
帧号必须属于状态:同一个物理状态,在第 10 帧和第 200 帧该做的动作不同。这也是"从中途开始"成立的前提:把仿真设成某个状态、把帧号设成 k,就得到一个合法的起点。
动作是参考关节上的残差 \(a_t\):
残差参数化让刚初始化的策略也大致贴着参考运动,探索只发生在参考附近。目标是折扣回报,γ ∈ (0, 1] 是折扣因子:
回合在两种情况下结束:物体偏离参考超过阈值(ConTrack 评估用 0.10 m 和 1.00 rad),或到达最后一帧。前一种终止让"能跟多远"成了天然的难度信号:回合在哪里断,哪一段就难。
PPO 是在线策略梯度方法。每次迭代先用当前策略在 N 个并行环境里各跑 H 步(ConTrack 的 H = 16),再用这批数据估计优势,做若干轮小批量梯度更新,然后丢掉数据。优势 \(\hat A_t\) 回答"这一步的动作比这个状态下的平均水平好多少"。用 critic \(V\) 估计状态价值,先算一步的 TD 残差(\(d_{t+1}=1\) 表示第 t 步之后回合结束):
再把后续各步的残差按 \((\gamma\lambda_{\text{GAE}})^l\) 衰减相加,得到广义优势估计(GAE)。为了不和后面的对偶变量 λ 混淆,GAE 的参数写成 \(\lambda_{\text{GAE}}\):
策略更新用裁剪目标。\(\rho_t=\pi_\theta(a_t\mid s_t)/\pi_{\text{old}}(a_t\mid s_t)\) 是新旧策略的概率比,ε 是裁剪范围:
裁剪让每次更新后的策略不离开采样时的策略太远,于是同一批数据可以反复用几轮。ConTrack 的设置:γ = 0.99,\(\lambda_{\text{GAE}}\) = 0.95,ε = 0.2,每次更新 10 轮、每轮 16 个小批量,按 KL 自适应调学习率(目标 KL 0.01)。代码 xhand/agents/rsl_rl_ppo_cfg.py:39-58
(B4)(B5) 对奖励和价值都是线性的。若奖励是两路之和 \(r=r^{(1)}+r^{(2)}\),critic 也输出两个值且 \(V=V^{(1)}+V^{(2)}\),那么两路分别算出的优势相加,就等于总奖励的优势:
所以可以先分别估计各路优势,再用随时变化的权重组合,效果等同于"按这个权重重新加权奖励",不必重算 GAE。ConTrack 就是这样在线改权重的。有一个前提:若每一路在组合前先各自标准化(减均值、除标准差),(B7) 不再成立,权重作用在标准化之后的量上。ConTrack 的代码属于这种情况,见全程第 6 步。
约束 MDP(CMDP)在一个回报上加约束,优化另一个回报。c 是约束的下限:
拉格朗日松弛把约束搬进目标,乘子 \(\mu\ge 0\):
求解是一个鞍点问题:策略对 \(\mathcal L\) 做上升,乘子对 \(\mathcal L\) 做下降。\(\mathcal L\) 对 μ 的导数是 \(J_g-c\),所以乘子沿 \(c-J_g\) 方向走,η 是步长,并截断在非负区间:
读法:约束没满足(\(J_g\lt c\))时 μ 增大,任务回报在目标里的分量变重;约束满足且有余量时 μ 减小,把优化压力还给风格。μ 相当于约束的价格。RCPO(Tessler 等 2018)等方法用的就是这种原始–对偶更新,论文引用了它们。论文 2、3.2
ConTrack 在这套框架上改了两处:
这一段是本文的推导,论文没有这样写。推断 利用 \(\sigma(\lambda)/(1-\sigma(\lambda))=e^\lambda\):
正的因子 \(1-\sigma(\lambda)\) 不改变最大值点(对策略梯度只是缩放步长),常数项 \(-\mu c\) 与策略无关,所以按 \(w=\sigma(\lambda)\) 混合,与乘子取 \(\mu=e^\lambda\) 的 (B9) 有相同的最优策略。两个推论:
数值例子。η = 0.05、α = 0.9 时,若比值一直停在 0.8,λ 每次更新增加 0.005,1000 次后 λ = 5,\(w=\sigma(5)\approx 0.993\),几乎只优化任务。若比值停在 1.0,λ 每次减少 0.005。
片段长、失败早时,从第一帧开始的回合大多在前几十帧就终止,后面的接触阶段几乎采不到样本,学习信号也要跨很长的时间才能传回前面。重置策略决定训练样本在片段上的分布。常见做法:
| 做法 | 起点状态 | 起点帧怎样选 | 代表 | 问题 |
|---|---|---|---|---|
| 总从第一帧 | 参考第 0 帧 | 只有 0 | 与评估协议相同 | 后段样本少,早期失败主导数据 |
| 均匀中途重置 | 参考第 k 帧 | k 均匀 | DeepMimic 的参考状态初始化 | 已学会的段落占同样多的样本;手物交互中参考状态可能不可实现 |
| 按难度重置 | 参考第 k 帧 | 按各段失败率加权 | BeyondMimic、SONIC 的自适应采样 | 参考状态的问题仍在;要防止全部集中到最难的段 |
| 课程式后移 | 演示中的状态 | 先靠近末尾,逐渐前移 | Backplay | 需要规定前移的节奏 |
| 从到达过的状态重置 | 策略自己跑到过的仿真状态 | 按难度加权 | Go-Explore 的存档思路;ConTrack | 只能从跑到过的地方开始;库的内容随策略变化 |
人形跟踪里,参考帧可以直接写进仿真:关节角、根部位姿、速度写进去,机器人站在地上,物理上基本一致。手物交互的参考帧不行,原因有三:
论文的表述是:这类重置可能在物理上不一致,因为接触构型在仿真动力学下不一定可实现,会产生无法挽回的起点。论文 2、3.3
两种应对:在参考状态上加临时辅助(例如开头给物体一个托住它的外力,再在短时间内撤掉),或者只从策略自己跑到过的状态开始(ConTrack 的做法,见全程第 3 步)。后者的状态一定是仿真可实现的;代价是库的内容取决于当前策略,而且第 0 帧和尚未到达的帧仍只能用参考状态。代码
训练时的起点分布只为让样本更有用。评估回答"从头跑能跟多远",所以 ConTrack 评估一律从第一帧开始。设 τ 为终止帧,进度定义为:论文 4.2
重置库越把训练集中到中后段,越需要保证"从第 0 帧的参考状态出发"这一种起点也被练到。全程第 4 步会算出它在代码里得到的份额。
按开源代码(提交 f5efe18)把一次训练从准备到评估走一遍,以 XHand 版为主。路径前缀 source/ConTrack/ConTrack/tasks/manager_based/mimic_xarm_xhand/ 简写为 xhand/,PPO 在 rsl_rl_contrack/。每一步给出整体流程、关键公式(编号 C·)和从代码提取的伪代码。论文和代码说法不同的地方集中在第 9 节。
ManagerBasedRLEnv.step:物理、终止、奖励、reset 事件、interval 事件、观测;ConTrack 把写库放在 reset 事件、把推进帧号放在 interval 事件里。代码 xhand/xarm_xhand_env_cfg.py:503-524DELTA = 100,EMA_ALPHA = 0.05,HARD_RESET_TOPK = 64,EPSILON_GREEDY = 0.5,TAU = 1.0 xhand/mdp/state.py:33-37xhand/agents/rsl_rl_ppo_cfg.py:52-57xhand/xarm_xhand_env_cfg.py:46-47,rsl_rl_ppo_cfg.py:26xhand/mdp/state.py:40-129(读取),:132-176(缓存),:179-373(准备)
:96-119:153-159:220-245:247-317# xhand/mdp/state.py: prepare_reference_state(提取) ref = load_reference(h5) # 40-129:15 段 → 10 连杆,NaN → 0 ref.quat = make_sign_continuous(ref.quat) # 153-159 T = floor((T_raw - 1) * f_act / f_raw) + 1 # 220-223,(C1) q_ref, p_ref = lerp(ref, T); quat_ref = nlerp(ref.quat, T) contact_ref = nearest(ref.contact, T) # 237-239 hand_vel, obj_vel, obj_angvel = central_diff(...) # 247-288,(C2) B[0:T] = concat(q_ref, hand_vel, p_ref, quat_ref, obj_vel, obj_angvel) # 290-295,(C3) ell_bar[0:T] = 0; ell_max[0:T] = 0 # 296-299 eps_pos, eps_rot = 0.10, 1.0 # 359-370:终止阈值的初值
这一步决定了库的一个事实:每一帧在被访问之前都是参考状态,第 0 帧永远是参考状态(第 3 步解释为什么)。论文没有提到库的初值。代码
xhand/mdp/actions.py:266-291,xhand/mdp/terminations.py:6-51,xhand/mdp/rewards.py,xhand/mdp/state.py:469-494
训练时阈值不是固定的。每批结束的回合里到达末帧的比例记为 SR,做滑动平均后线性插值出阈值:代码 xhand/mdp/state.py:469-494,xarm_xhand_env_cfg.py:84-90, 605-614
ACTION_SCALE,xarm_xhand_env_cfg.py:50);⊙:逐元素乘。# 一个控制步(顺序由 IsaacLab ManagerBasedRLEnv.step 决定) q_tar = q_ref[f] + scale * clip(a, -1, 1) # actions.py:280-287,(C4) for _ in range(2): physics_step(dt=1/120) time_out = f >= T - 1 # terminations.py:38-51 failed = any(pos_err > eps_pos or rot_err > eps_rot) # terminations.py:6-35,(C5) r_g, r_s, r_p = rewards_against(ref[f]) # 第 7 步 reset_event(envs where time_out or failed) # state.py:394,第 3、4 步 interval_event(all other envs) # state.py:658,第 2 步 obs = observe(f) # 第 7 步
xhand/mdp/state.py:658-731(advance_reference_frame)
没有结束的环境,在这一步的物理推进之后,把当前仿真状态写进它自己的回合缓冲区,位置是"当前帧号 − 起点帧号",并标记这一格已写;然后记下关节和物体的速度(下一步的加速度惩罚要用),帧号加一,最多到 T − 1。
# xhand/mdp/state.py: advance_reference_frame(提取)
for e in envs_not_reset: # 674
x = concat(joint_pos, joint_vel, obj_pos - origin, obj_quat, obj_linvel, obj_angvel) # 677-702
E[e][f[e] - start[e]] = x; filled[e][f[e] - start[e]] = True # 703-705
prev_vel[e] = current_vel[e] # 707-726
f[e] = min(f[e] + 1, T - 1) # 728-731
库里第 k 帧存的是什么时刻的状态。由这个顺序可知,第 k 帧对应的是"跟踪第 k 帧这一步结束后"的仿真状态。环境被重置到 \(B[k]\) 时帧号设为 k,下一步再次跟踪第 k 帧。这和从参考第 0 帧出发的约定一致:初始状态就是参考第 0 帧,第一步跟踪的也是第 0 帧。代码
xhand/mdp/state.py:436-548(reset_reference_episode 的前半)
每当有环境结束(reset 事件),对这一批结束的环境:
:436-468:469-497:498-513:514-521:522:523-548# xhand/mdp/state.py: reset_reference_episode,写入部分(提取)
for e in ended_envs with a valid episode: # 436
E[e][end[e] - start[e]] = current_state(e) # 464-468:终止状态
update_threshold_curriculum(success = end == T - 1) # 469-494,(C6)
pairs = [(k, e, end[e] - k + 1) for e in ended # 498-513,(C8)
for k in range(start[e], end[e] + 1) if filled[e][k - start[e]]]
for k in frames_in(pairs): # 514-521,(C9)
ell_bar[k] = 0.95 * ell_bar[k] + 0.05 * mean(l for (k', _, l) in pairs if k' == k)
ell_max *= 0.99999 # 522
better = [(k, e, l) for (k, e, l) in pairs if k != 0 and l > ell_max[k]] # 523-530
for k, e, l in longest_per_frame(better): # 531-546
B[k] = E[e][k - start[e]]; ell_max[k] = l # 547-548,(C10)
frames != 0,:523),始终是参考状态。评估正是从这一帧开始。xhand/mdp/state.py:550-597(reset_reference_episode 的后半)
:550-554:555-560:561-567:569-597# xhand/mdp/state.py: reset_reference_episode,采样部分(提取) u = ell_bar[0:T-1] / (T - arange(T-1)) # 550-554,(C11) g = zeros_like(u); g[:-1] = u[1:] - u[:-1] # 555-556 K = topk(g, 64).indices # 557-558 if 0 not in K: K[-1] = 0 # 559-560 k = multinomial(softmax(-u / 1.0), n) # 561,(C12) hard = rand(n) < 0.5 # 562 k[hard] = clamp(K[randint(64)] - 100, min=0) # 563-567,(C13) write_to_sim(B[k]); f = k # 570-591 E[:, 0] = B[k]; filled[:, 0] = True; start = k # 593-597
torch.topk 的实现决定,图中未画。软分支几乎是平的,最大与最小权重之比约 2.5。xarm_xhand_env_cfg.py:54-56论文 4.6 节与图 5;日志 scripts/rsl_rl/train.py:556-650
reset_library/reset_index(train.py:610-650),论文没有展示这张图。推算train.py:687-695)。rsl_rl_contrack/algorithms/ppo.py,rsl_rl_contrack/env/cons_mimic_reward_wrapper.py:129-158,rsl_rl_contrack/storage/rollout_storage.py:134-157
约束 MDP、拉格朗日乘子和 σ(λ) 的含义见基础第 3 节。
xarm_xhand_env_cfg.py:615-633,wrapper:130-134ppo.py:194,modules/actor_critic.py:69,rollout_storage.py:134-157ppo.py:183-190ppo.py:231-242ppo.py:338-356ppo.py:449-455# rsl_rl_contrack/algorithms/ppo.py(提取)
process_env_step: # 175-212
ep_rg += r_g; for done e: vg_buffer.append(ep_rg[e]); ep_rg[e] = 0 # 183-190
store reward = (r_g + r_p, r_s + r_p) # 194
compute_returns: GAE per channel, then normalize per channel # storage 134-157
update:
n_updates += 1
if n_updates <= warmup: lam = 20.0; w = 1.0 # 231-233,默认 warmup = 0
elif n_updates == warmup + 1: lam = lam_init; w = sigmoid(lam) # 234-236
else: w = sigmoid(lam) # 237-238
vg_hat = mean(vg_buffer); vg_hat_buf.append(vg_hat); vg_star = max(vg_hat_buf) # 240-242
for minibatch: A = w * A[...,0] + (1 - w) * A[...,1]; PPO clipped loss # 340-356
if n_updates > warmup: lam += 0.05 * (0.9 - vg_hat / (vg_star + 1e-8)) # 449-455,(C16)
lambda_raw.fill_(20.0) 在什么条件下触发self.num_updates <= self.cmdp_warmup_iters。num_updates 在每次 update() 开头加一,从 1 开始。cmdp_warmup_iters 在构造函数(ppo.py:46)和配置(rsl_rl_ppo_cfg.py:18, 54)里都是 0,而 num_updates 至少为 1,条件不成立。XHand 和 Sharpa 的配置相同;README 的训练命令没有改它(train.py 通过 Hydra 接受配置覆盖,train.py:88, 130, 281,所以用户可以手动打开)。:449 条件不成立),但 \(\hat J_g\)、\(J_g^\star\) 照常统计。第 N + 1 次更新把 λ 重置为 cmdp_lambda_init(默认 0),之后正常更新。runners/on_policy_runner.py:401-402)。| 变体(论文表 4) | 进度 ↑ | 物体位置 (m) ↓ | 物体旋转 (rad) ↓ | 手指误差 (rad) ↓ | 接触 F1 ↑ | 接触点 (m) ↓ |
|---|---|---|---|---|---|---|
| 自适应(ConTrack) | 0.899 ± 0.195 | 0.026 ± 0.006 | 0.272 ± 0.105 | 0.163 ± 0.014 | 0.784 ± 0.072 | 0.018 ± 0.005 |
| 只用任务 | 0.764 ± 0.172 | 0.026 ± 0.004 | 0.250 ± 0.031 | 0.157 ± 0.021 | 0.679 ± 0.131 | 0.022 ± 0.004 |
| 固定 1:1 | 0.868 ± 0.107 | 0.029 ± 0.008 | 0.297 ± 0.029 | 0.165 ± 0.028 | 0.701 ± 0.106 | 0.023 ± 0.002 |
xhand/mdp/rewards.py,xhand/mdp/observations.py,权重 xarm_xhand_env_cfg.py:62-81,论文附录 B 表 8
记 \(\operatorname{mse}(z)=\|z\|_2^2/m\)(m 为 z 的维数)。\(e^p_t\) 是所有物体的位置误差拼成的向量,\(\bar\theta_t\) 是各物体旋转误差的平均,\(e^a_t,e^f_t\) 是臂、手指的关节误差:
rewards.py:299-309,observations.py:214-236rewards.py:308xarm_xhand_env_cfg.py:57-59, 457-500。论文附录 C 说执行器只看带延迟和噪声的位姿与速度,未来参考、接触和相位只给 critic。
| 变体(论文表 6) | 进度 ↑ | 物体位置 (m) ↓ | 物体旋转 (rad) ↓ | 手指误差 (rad) ↓ | 接触 F1 ↑ | 接触点 (m) ↓ |
|---|---|---|---|---|---|---|
| 完整(ConTrack) | 0.899 ± 0.195 | 0.026 ± 0.006 | 0.272 ± 0.105 | 0.163 ± 0.014 | 0.784 ± 0.072 | 0.018 ± 0.005 |
| 去掉接触事件奖励 | 0.861 ± 0.173 | 0.032 ± 0.010 | 0.320 ± 0.044 | 0.168 ± 0.019 | 0.699 ± 0.092 | 0.020 ± 0.005 |
| 去掉接触距离奖励 | 0.868 ± 0.057 | 0.032 ± 0.011 | 0.288 ± 0.071 | 0.149 ± 0.016 | 0.753 ± 0.089 | 0.023 ± 0.005 |
xhand/__init__.py:22-30,xarm_xhand_env_cfg.py:527-533, 669-673,xhand/mdp/state.py:600-655
Isaac-Xarm-Xhand-Mimic-Manager-Play-v0 用 reset_reference_episode_first_frame,写入 \(B[0]\),即参考第 0 帧的状态与差分速度。它不更新阈值课程,阈值保持初值 0.10 m、1.0 rad,与论文一致。代码scripts/rsl_rl/play.py 只跑策略、录视频;仓库里没有计算进度、F1、接触点误差的代码。max_iterations = 100_000(rsl_rl_ppo_cfg.py:27),README 命令没有传 --max_iterations,照抄会训练 100,000 次。附录 G 的 Ring 长训用的正是 100,000 次。"论文"包括正文、算法框和附录;"代码"指提交 f5efe18。影响一栏凡属推断均已标注。
| # | 项目 | 论文 | 代码 | 影响 |
|---|---|---|---|---|
| 1 | 库的初值 | 没有说明;正文强调不复制参考状态 | 每一帧先填参考状态与差分速度,未访问的帧和第 0 帧一直是参考状态(state.py:247-295) | 早期与未到达帧的重置仍是参考状态 推断 |
| 2 | 最佳续航 | 算法 2:不衰减的运行最大值 | 每次调用乘 0.99999;第 0 帧永不覆盖(state.py:522-523) | 8 万步后衰减到约 0.45,旧纪录可被较短的续航覆盖 推算 |
| 3 | 平均续航的更新 | 算法 2:每个结束的回合各做一次滑动平均 | 同一批中经过同一帧的回合先平均,再做一次滑动平均(state.py:514-521) | 有效平滑窗口随并行环境数变化 推断 |
| 4 | 起点采样 | 正文与算法 2 只有 p(k) ∝ exp(−uk/τ);附录 D 补充 50% 的边界分支 | 边界 = 向后差分最大的 64 处(只取正向跳升),并强制包含第 0 帧(state.py:555-567) | 起点的集中主要来自边界分支 推导 |
| 5 | 任务回报估计 | 算法 1 第 3 行:折扣回报 | 不打折扣的回合累计,且已乘 dt(ppo.py:183-190) | 回合长度随起点变化,\(\hat J_g\) 受起点分布影响 推断 |
| 6 | \(J_g^\star\) | 算法 1:全程最大值;附录 D:最近 20 次更新的最大值 | 最近 20 次更新的最大值(ppo.py:135, 241-242) | 论文内部不一致,代码随附录 |
| 7 | 优势混合 | 式 (5):三路优势,惩罚权重为 1 | 两路(惩罚并入两路),各自标准化后再混合(ppo.py:194, 340;rollout_storage.py:154-157) | 标准化后 w 不再严格等于奖励权重 推断 |
| 8 | 执行器观测 | 附录 C:只有带延迟、带噪声的位姿与速度 | 与 critic 相同,含未来 5 帧参考、接触标志、相位;延迟和噪声默认为 0(env_cfg:57-59, 461-482) | 开源策略不是论文描述的非对称结构 |
| 9 | 训练时的终止阈值 | 只给出评估阈值 0.10 m、1.00 rad | 按成功率收紧到 0.05 m、0.5 rad(state.py:469-494;env_cfg:84-90) | 训练终止比评估严格 |
| 10 | 动作 | \(q^{\text{tar}}=q^{\text{ref}}+a\) | a 截到 [−1, 1],乘以 0.01 rad(臂)、0.25 rad(手指)(actions.py:280-287) | 臂的修正幅度很小 |
| 11 | 训练时长 | 每片段 5000 次更新 | 默认 100,000 次,README 命令未覆盖(rsl_rl_ppo_cfg.py:27) | 照 README 复现会多训 20 倍 |
| 12 | λ 预热 | 没有提到 | 可选预热:前 N 次 λ = 20、w = 1;默认 N = 0(ppo.py:231-236) | 默认不生效 |
| 13 | 旋转误差 | \(2\arccos(\bar q^\top\bar q^{\text{ref}})\) | \(2\arccos|\bar q^\top\bar q^{\text{ref}}|\)(terminations.py:25-30) | 代码对四元数符号不敏感,属正确写法 |
| 14 | 图 4 与表 4 | 图 4 中 α = 0.9 为 (0.945, 0.850),固定 100%、50% 为 0.925、0.882 | — | 与表 2、表 4 的 0.899/0.784、0.764、0.868 不同,论文内部不一致 |
此外,环境配置里域随机化(物体 xy 扰动、PD 增益)默认关闭(env_cfg:54-56),论文附录没有列出训练时的随机化范围。
对比 mimic_rby1a_sharpa/mdp/state.py 与 mimic_xarm_xhand/mdp/state.py。代码
sharpa state.py:37-41);把资产名和维度统一替换后,写入与采样的代码逐行一致。sharpa state.py:365)。rby1a_sharpa 里。单手片段时,另一侧的关节在每次重置(包括评估重置)时写回默认姿态、速度为 0(sharpa state.py:413-427, 674-681, 746-753),并在启动时关闭那一侧的碰撞(rby1a_sharpa_env_cfg.py:110, 523-524)。XHand 版两侧是两个独立关节体,片段里没有的一侧不加载。sharpa state.py:43-108)。