fix: dt in state.reward, feet_air_time first_contact timing
This commit is contained in:
@@ -547,21 +547,53 @@ class DreamWaQTask(Go1WalkTask):
|
|||||||
# stand_still 在上游被注释掉
|
# stand_still 在上游被注释掉
|
||||||
}
|
}
|
||||||
|
|
||||||
# _reward_feet_air_time 使用基类实现(walk_np.py),
|
def update_feet_air_time(self, info: dict):
|
||||||
# 之前 override 读了不存在的 key 导致 reward 永远为 0
|
"""覆盖基类 — 在清零前保存 first_contact 供奖励函数使用。"""
|
||||||
|
feet_air_time = info["feet_air_time"]
|
||||||
|
contacts = info["contacts"]
|
||||||
|
# 保存着地瞬间的状态(脚刚触地,且之前腾空时间 > 0)
|
||||||
|
info["first_contact"] = (feet_air_time > 0.0) & contacts
|
||||||
|
info["air_time_at_contact"] = feet_air_time.copy()
|
||||||
|
# 基类逻辑:累加 dt,着地清零
|
||||||
|
feet_air_time = feet_air_time + self.cfg.ctrl_dt
|
||||||
|
feet_air_time = feet_air_time * (~contacts)
|
||||||
|
info["feet_air_time"] = feet_air_time
|
||||||
|
return feet_air_time
|
||||||
|
|
||||||
|
def _reward_feet_air_time(self, commands, info):
|
||||||
|
"""足部腾空时间奖励——与上游 legged_robot.py 完全对齐。
|
||||||
|
|
||||||
|
使用 update_feet_air_time 保存的 first_contact / air_time_at_contact。
|
||||||
|
"""
|
||||||
|
first_contact = info.get("first_contact")
|
||||||
|
air_time = info.get("air_time_at_contact")
|
||||||
|
if first_contact is None or air_time is None:
|
||||||
|
return np.zeros(self._num_envs, dtype=np.float32)
|
||||||
|
rew = np.sum((air_time - 0.5) * first_contact, axis=1)
|
||||||
|
rew *= np.linalg.norm(commands[:, :2], axis=1) > 0.1
|
||||||
|
return rew
|
||||||
|
|
||||||
def update_reward(self, state):
|
def update_reward(self, state):
|
||||||
"""存储各项奖励到 TensorBoard + 累计 episode 总和。"""
|
"""存储各项奖励到 TensorBoard + 更新 state.reward。
|
||||||
|
|
||||||
|
与上游 _prepare_reward_function 对齐:所有 scales × dt。
|
||||||
|
"""
|
||||||
reward_dict = self._get_reward(state.data, state.info)
|
reward_dict = self._get_reward(state.data, state.info)
|
||||||
# 乘系数 + dt(与上游 _prepare_reward_function 对齐)
|
|
||||||
scales = self._cfg.reward_config.scales
|
scales = self._cfg.reward_config.scales
|
||||||
dt = self._cfg.ctrl_dt
|
dt = self._cfg.ctrl_dt
|
||||||
scaled_terms = {
|
scaled_terms = {
|
||||||
k: v * scales.get(k, 0.0) * dt
|
k: v * scales.get(k, 0.0) * dt
|
||||||
for k, v in reward_dict.items()
|
for k, v in reward_dict.items()
|
||||||
}
|
}
|
||||||
|
# state.reward 直接用带 dt 的值(不调 super,super 不带 dt)
|
||||||
|
state = state.replace(reward=np.zeros(self._num_envs, dtype=np.float32))
|
||||||
|
for v in scaled_terms.values():
|
||||||
|
state.reward += v
|
||||||
|
if self._cfg.reward_config.only_positive_rewards:
|
||||||
|
state.reward = np.maximum(state.reward, 0.0)
|
||||||
|
|
||||||
|
# TensorBoard 日志
|
||||||
state.info["reward_terms"] = {k: float(np.mean(v)) for k, v in scaled_terms.items()}
|
state.info["reward_terms"] = {k: float(np.mean(v)) for k, v in scaled_terms.items()}
|
||||||
# 累计 episode 总和
|
|
||||||
for k, v in scaled_terms.items():
|
for k, v in scaled_terms.items():
|
||||||
ek = f"ep_{k}"
|
ek = f"ep_{k}"
|
||||||
state.info[ek] = state.info.get(ek, np.zeros(self._num_envs, dtype=np.float32)) + v
|
state.info[ek] = state.info.get(ek, np.zeros(self._num_envs, dtype=np.float32)) + v
|
||||||
@@ -579,9 +611,6 @@ class DreamWaQTask(Go1WalkTask):
|
|||||||
ep_report["terrain_level"] = float(np.mean(tl))
|
ep_report["terrain_level"] = float(np.mean(tl))
|
||||||
state.info["ep_report"] = ep_report
|
state.info["ep_report"] = ep_report
|
||||||
|
|
||||||
state = super().update_reward(state)
|
|
||||||
if self._cfg.reward_config.only_positive_rewards:
|
|
||||||
state = state.replace(reward=np.maximum(state.reward, 0.0))
|
|
||||||
return state
|
return state
|
||||||
|
|
||||||
# ── 额外奖励函数 ──
|
# ── 额外奖励函数 ──
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ class rslrl:
|
|||||||
class Go1DreamWaQWalkRslrlPpo(RslrlCfg):
|
class Go1DreamWaQWalkRslrlPpo(RslrlCfg):
|
||||||
"""Go1 DreamWaQ walk — CENet VAE + 不对称特权观测。"""
|
"""Go1 DreamWaQ walk — CENet VAE + 不对称特权观测。"""
|
||||||
|
|
||||||
num_envs: int = 1024 # 上游 4096,CPU/GPU 安全默认
|
num_envs: int = 2048
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
runner = self.runner
|
runner = self.runner
|
||||||
@@ -126,6 +126,7 @@ class rslrl:
|
|||||||
runner.algorithm.entropy_coef = 0.01 # 上游 Go1RoughCfgPPO
|
runner.algorithm.entropy_coef = 0.01 # 上游 Go1RoughCfgPPO
|
||||||
runner.algorithm.desired_kl = 0.01 # 上游 0.01 (默认 0.008)
|
runner.algorithm.desired_kl = 0.01 # 上游 0.01 (默认 0.008)
|
||||||
runner.algorithm.clip_param = 0.2
|
runner.algorithm.clip_param = 0.2
|
||||||
|
runner.algorithm.schedule = "fixed" # 固定 schedule,防止 noise_std 发散
|
||||||
runner.algorithm.gamma = 0.99
|
runner.algorithm.gamma = 0.99
|
||||||
runner.algorithm.lam = 0.95
|
runner.algorithm.lam = 0.95
|
||||||
runner.algorithm.max_grad_norm = 1.0
|
runner.algorithm.max_grad_norm = 1.0
|
||||||
@@ -135,7 +136,7 @@ class rslrl:
|
|||||||
runner.actor.class_name = (
|
runner.actor.class_name = (
|
||||||
"motrix_rl.rslrl.torch.models.cenet_actor:CENetActorModel")
|
"motrix_rl.rslrl.torch.models.cenet_actor:CENetActorModel")
|
||||||
runner.actor.hidden_dims = [512, 256, 128]
|
runner.actor.hidden_dims = [512, 256, 128]
|
||||||
runner.actor.init_noise_std = 1.0 # 上游原值
|
runner.actor.init_noise_std = 0.5 # 降低探索噪声,1024 envs 不需要太高
|
||||||
|
|
||||||
# Critic:标准 MLPModel,输入 privileged_obs
|
# Critic:标准 MLPModel,输入 privileged_obs
|
||||||
runner.critic.class_name = "MLPModel"
|
runner.critic.class_name = "MLPModel"
|
||||||
|
|||||||
Reference in New Issue
Block a user