Source code for embodichain_tasks.classic_control.humanoid.mdp

# ----------------------------------------------------------------------------
# Copyright (c) 2021-2026 DexForce Technology Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ----------------------------------------------------------------------------

"""Backend-independent Humanoid observation and reward functions."""

from __future__ import annotations

import torch

__all__ = ["humanoid_observation", "humanoid_reward"]


[docs] def humanoid_observation( torso_height: torch.Tensor, linear_velocity_local: torch.Tensor, angular_velocity_local: torch.Tensor, yaw: torch.Tensor, roll: torch.Tensor, angle_to_target: torch.Tensor, up_projection: torch.Tensor, heading_projection: torch.Tensor, scaled_joint_position: torch.Tensor, joint_velocity: torch.Tensor, action: torch.Tensor, *, angular_velocity_scale: float, joint_velocity_scale: float, ) -> torch.Tensor: """Build the 63-element observation for the 17-DoF Humanoid asset. Args: torso_height: Root height for each environment. linear_velocity_local: Root linear velocity in the torso frame. angular_velocity_local: Root angular velocity in the torso frame. yaw: Root yaw angles in radians. roll: Root roll angles in radians. angle_to_target: Heading error to the target, in radians. up_projection: Torso up-axis projection on world up. heading_projection: Heading-axis projection toward the target. scaled_joint_position: Joint positions normalized by their limits. joint_velocity: Joint velocities in policy joint order. action: Current clipped effort actions in policy joint order. angular_velocity_scale: Multiplier for angular velocity observations. joint_velocity_scale: Multiplier for joint velocity observations. Returns: A tensor of shape ``(num_envs, 63)`` in the policy observation order. """ normalize = lambda value: torch.atan2(torch.sin(value), torch.cos(value)) return torch.cat( ( torso_height.unsqueeze(-1), linear_velocity_local, angular_velocity_local * angular_velocity_scale, normalize(yaw).unsqueeze(-1), normalize(roll).unsqueeze(-1), normalize(angle_to_target).unsqueeze(-1), up_projection.unsqueeze(-1), heading_projection.unsqueeze(-1), scaled_joint_position, joint_velocity * joint_velocity_scale, action, ), dim=-1, )
[docs] def humanoid_reward( *, action: torch.Tensor, terminated: torch.Tensor, heading_projection: torch.Tensor, up_projection: torch.Tensor, joint_velocity: torch.Tensor, scaled_joint_position: torch.Tensor, progress: torch.Tensor, motor_effort_ratio: torch.Tensor, heading_weight: float, up_weight: float, actions_cost_scale: float, energy_cost_scale: float, joint_velocity_scale: float, death_cost: float, alive_reward_scale: float, ) -> torch.Tensor: """Compute the 17-DoF Humanoid reward with a penalty near either joint limit. Args: action: Current clipped effort actions. terminated: Per-environment failure mask. heading_projection: Heading-axis projection toward the target. up_projection: Torso up-axis projection on world up. joint_velocity: Measured joint velocities. scaled_joint_position: Joint positions normalized by their limits. progress: Change in the task's progress potential. motor_effort_ratio: Per-joint relative motor effort weights. heading_weight: Maximum heading reward. up_weight: Reward for the upright threshold. actions_cost_scale: Weight of squared action cost. energy_cost_scale: Weight of action-velocity effort cost. joint_velocity_scale: Joint velocity multiplier in effort cost. death_cost: Reward assigned to terminated environments. alive_reward_scale: Additive survival reward. Returns: One reward per environment, with death cost replacing failed-row totals. """ heading_reward = torch.where( heading_projection > 0.8, torch.full_like(heading_projection, heading_weight), heading_weight * heading_projection / 0.8, ) up_reward = torch.where( up_projection > 0.93, torch.full_like(up_projection, up_weight), torch.zeros_like(up_projection), ) action_cost = action.square().sum(dim=-1) electricity_cost = ( (action * joint_velocity * joint_velocity_scale).abs() * motor_effort_ratio.unsqueeze(0) ).sum(dim=-1) joint_limit_cost = (scaled_joint_position.abs() > 0.98).sum(dim=-1) reward = ( progress + alive_reward_scale + up_reward + heading_reward - actions_cost_scale * action_cost - energy_cost_scale * electricity_cost - joint_limit_cost ) return torch.where(terminated, torch.full_like(reward, death_cost), reward)