Nvidia Isaac Lab 8 - 在 Isaac Lab 中,训练第二个机器人 - 6. 自定义奖励函数

本节将添加用于决定策略奖励的底层数学函数。第一种方法将结合两种形式的奖励,用于衡量位置误差(即机器人距离目标位置有多远)。


1. 定义自定义奖励函数

之前的奖励管理器配置文件引用若干尚不存在的 MDP 函数。下面定义这些函数。如前所述,为清晰起见,将这些函数放在 mdp 文件夹中。

  1. 打开如下 Python 文件:source/Reach/Reach/tasks/manager_based/reach/mdp/rewards.py
  1. 清空文件内容,将其替换为以下导入语句。
    # Copyright (c) 2022-2025, The Isaac Lab Project Developers.
    # All rights reserved.
    #
    # SPDX-License-Identifier: BSD-3-Clause
    
    from __future__ import annotations
    
    import torch
    from typing import TYPE_CHECKING
    
    from isaaclab.managers import SceneEntityCfg
    from isaaclab.utils.math import combine_frame_transforms
    
    from isaaclab.assets import RigidObject
    from isaaclab.managers import SceneEntityCfg
    from isaaclab.utils.math import combine_frame_transforms, quat_error_magnitude, quat_mul
    
    
    if TYPE_CHECKING:
        from isaaclab.envs import ManagerBasedRLEnv

掌握 PyTorch、线性代数和三角学对于强化学习学习之旅至关重要。


2. 位置命令误差

该函数计算期望位置(来自命令)与资产本体当前位置(在世界坐标系下)之间的位置误差。通过期望位置与当前位置之差的 L2 范数计算位置误差。

什么是 L2 范数?

L2 范数,也称为欧几里得范数,是衡量空间中向量长度或大小的一种方式。

该函数如何与管理器及场景交互?

环境对象被传入 - 其中包含 Stage 上的所有机器人,因此涉及 PyTorch 的张量运算。这正是大规模并行训练特性的体现!

在前面的代码中,奖励管理器的某个奖励项引用该函数。简而言之,这里定义如何计算该奖励项,最终各项奖励被累加成最终的奖励值。

请将此代码添加到 Reach/tasks/manager_based/reach/mdp/rewards.py 文件中。

def position_command_error(env: ManagerBasedRLEnv, command_name: str, asset_cfg: SceneEntityCfg) -> torch.Tensor:
    """Penalize tracking of the position error using L2-norm.

    The function computes the position error between the desired position (from the command) and the
    current position of the asset's body (in world frame). The position error is computed as the L2-norm
    of the difference between the desired and current positions.
    """
    # extract the asset (to enable type hinting)
    asset: RigidObject = env.scene[asset_cfg.name]
    command = env.command_manager.get_command(command_name)
    # obtain the desired and current positions
    des_pos_b = command[:, :3]
    des_pos_w, _ = combine_frame_transforms(asset.data.root_state_w[:, :3], asset.data.root_state_w[:, 3:7], des_pos_b)
    curr_pos_w = asset.data.body_state_w[:, asset_cfg.body_ids[0], :3]  # type: ignore
    return torch.norm(curr_pos_w - des_pos_w, dim=1)

3. 位置命令误差 Tanh

该函数计算期望位置(来自命令)与资产本体当前位置(在世界坐标系下)之间的位置误差,并且将其通过 tanh 核函数进行映射。

为什么需要第二个位置命令奖励项?

当位置误差趋近于零时,与线性误差项相比,tanh 函数产生更大的梯度。这将放大对微小错误的权重更新,从而加速向目标收敛。同时,也将输出值限制在 −1 到 1 之间。

请将此代码添加到 Reach/tasks/manager_based/reach/mdp/rewards.py 文件中。

def position_command_error_tanh(
    env: ManagerBasedRLEnv, std: float, command_name: str, asset_cfg: SceneEntityCfg
) -> torch.Tensor:
    """Reward tracking of the position using the tanh kernel.

    The function computes the position error between the desired position (from the command) and the
    current position of the asset's body (in world frame) and maps it with a tanh kernel.
    """
    # extract the asset (to enable type hinting)
    asset: RigidObject = env.scene[asset_cfg.name]
    command = env.command_manager.get_command(command_name)
    # obtain the desired and current positions
    des_pos_b = command[:, :3]
    des_pos_w, _ = combine_frame_transforms(asset.data.root_state_w[:, :3], asset.data.root_state_w[:, 3:7], des_pos_b)
    curr_pos_w = asset.data.body_state_w[:, asset_cfg.body_ids[0], :3]  # type: ignore
    distance = torch.norm(curr_pos_w - des_pos_w, dim=1)
    return 1 - torch.tanh(distance / std)

4. 完整的 Reward 文件

# Copyright (c) 2022-2025, The Isaac Lab Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

from __future__ import annotations

import torch
from typing import TYPE_CHECKING

from isaaclab.managers import SceneEntityCfg
from isaaclab.utils.math import combine_frame_transforms

from isaaclab.assets import RigidObject
from isaaclab.managers import SceneEntityCfg
from isaaclab.utils.math import combine_frame_transforms, quat_error_magnitude, quat_mul

if TYPE_CHECKING:
    from isaaclab.envs import ManagerBasedRLEnv

def position_command_error(env: ManagerBasedRLEnv, command_name: str, asset_cfg: SceneEntityCfg) -> torch.Tensor:
    """Penalize tracking of the position error using L2-norm.

    The function computes the position error between the desired position (from the command) and the
    current position of the asset's body (in world frame). The position error is computed as the L2-norm
    of the difference between the desired and current positions.
    """
    # extract the asset (to enable type hinting)
    asset: RigidObject = env.scene[asset_cfg.name]
    command = env.command_manager.get_command(command_name)
    # obtain the desired and current positions
    des_pos_b = command[:, :3]
    des_pos_w, _ = combine_frame_transforms(asset.data.root_state_w[:, :3], asset.data.root_state_w[:, 3:7], des_pos_b)
    curr_pos_w = asset.data.body_state_w[:, asset_cfg.body_ids[0], :3]  # type: ignore
    return torch.norm(curr_pos_w - des_pos_w, dim=1)

def position_command_error_tanh(
    env: ManagerBasedRLEnv, std: float, command_name: str, asset_cfg: SceneEntityCfg
) -> torch.Tensor:
    """Reward tracking of the position using the tanh kernel.

    The function computes the position error between the desired position (from the command) and the
    current position of the asset's body (in world frame) and maps it with a tanh kernel.
    """
    # extract the asset (to enable type hinting)
    asset: RigidObject = env.scene[asset_cfg.name]
    command = env.command_manager.get_command(command_name)
    # obtain the desired and current positions
    des_pos_b = command[:, :3]
    des_pos_w, _ = combine_frame_transforms(asset.data.root_state_w[:, :3], asset.data.root_state_w[:, 3:7], des_pos_b)
    curr_pos_w = asset.data.body_state_w[:, asset_cfg.body_ids[0], :3]  # type: ignore
    distance = torch.norm(curr_pos_w - des_pos_w, dim=1)
    return 1 - torch.tanh(distance / std)

5. 配置超参数

用于 PPO 的设置和超参数

最后,替换 source/Reach/Reach/tasks/manager_based/reach/agents/skrl_ppo_cfg.yaml 中的代码。

该配置文件用于定义使用 SKRL 库中的近端策略优化(PPO)算法训练强化学习智能体时的设置和超参数。

该文件对于定制 PPO 在 Isaac Lab 中的运行方式至关重要。虽然本节不详细讨论这些配置,但下面的文件中提供相关链接,可供进一步学习。

了解 PPO 背后的直观原理

seed: 42


# Models are instantiated using skrl's model instantiator utility
# https://skrl.readthedocs.io/en/latest/api/utils/model_instantiators.html
models:
  separate: False
  policy:  # see gaussian_model parameters
    class: GaussianMixin
    clip_actions: False
    clip_log_std: True
    min_log_std: -20.0
    max_log_std: 2.0
    initial_log_std: 0.0
    network:
      - name: net
        input: STATES
        layers: [64, 64]
        activations: elu
    output: ACTIONS
  value:  # see deterministic_model parameters
    class: DeterministicMixin
    clip_actions: False
    network:
      - name: net
        input: STATES
        layers: [64, 64]
        activations: elu
    output: ONE


# Rollout memory
# https://skrl.readthedocs.io/en/latest/api/memories/random.html
memory:
  class: RandomMemory
  memory_size: -1  # automatically determined (same as agent:rollouts)


# PPO agent configuration (field names are from PPO_DEFAULT_CONFIG)
# https://skrl.readthedocs.io/en/latest/api/agents/ppo.html
agent:
  class: PPO
  rollouts: 24
  learning_epochs: 5
  mini_batches: 4
  discount_factor: 0.99
  lambda: 0.95
  learning_rate: 1.0e-03
  learning_rate_scheduler: KLAdaptiveLR
  learning_rate_scheduler_kwargs:
    kl_threshold: 0.01
  state_preprocessor: RunningStandardScaler
  state_preprocessor_kwargs: null
  value_preprocessor: RunningStandardScaler
  value_preprocessor_kwargs: null
  random_timesteps: 0
  learning_starts: 0
  grad_norm_clip: 1.0
  ratio_clip: 0.2
  value_clip: 0.2
  clip_predicted_values: True
  entropy_loss_scale: 0.01
  value_loss_scale: 1.0
  kl_threshold: 0.0
  rewards_shaper_scale: 1.0
  time_limit_bootstrap: False
  # logging and checkpoint
  experiment:
    directory: "reach_ur10"
    experiment_name: ""
    write_interval: auto
    checkpoint_interval: auto


# Sequential trainer
# https://skrl.readthedocs.io/en/latest/api/trainers/sequential.html
trainer:
  class: SequentialTrainer
  timesteps: 24000
  environment_info: log