Nvidia Isaac Lab 7 - 在 Isaac Lab 中,训练第一个机器人 - 8. 分析代码

本节将分析代码,将 MDP 框架的思想与 Isaac Lab 的 Manager-based 工作流联系起来,同时讲述一些对训练过程有用的数学内容。这些概念与“Manager”都通过 Python @configclass 定义。

打开以下 Python 文件,仔细查看如何在代码中定义 MDP 元素:source/Cartpole/Cartpole/tasks/manager_based/cartpole/cartpole_env_cfg.py


1. 终止

训练回合何时结束?当小车距离其起始位置过远或超时时,将终止当前训练回合。在某个时刻,如果本回合结果偏离得太远,最好进入下一个回合。

@configclass
class TerminationsCfg:
   """Termination terms for the MDP."""

   # (1) Time out
   time_out = DoneTerm(func=mdp.time_out, time_out=True)
   # (2) Cart out of bounds
   cart_out_of_bounds = DoneTerm(
       func=mdp.joint_pos_out_of_manual_limit,
       params={"asset_cfg": SceneEntityCfg("robot", joint_names=["slider_to_cart"]), "bounds": (-3.0, 3.0)},
   )

2. 动作

小车可以施加力,使小车向左或向右移动。

@configclass
class ActionsCfg:
   """Action specifications for the MDP."""

   joint_effort = mdp.JointEffortActionCfg(asset_name="robot", joint_names=["slider_to_cart"], scale=100.0)

3. 观测

同时观测小车的位置和速度。

@configclass
class ObservationsCfg:
   """Observation specifications for the MDP."""

   @configclass
   class PolicyCfg(ObsGroup):
       """Observations for policy group."""

       # observation terms (order preserved)
       joint_pos_rel = ObsTerm(func=mdp.joint_pos_rel)
       joint_vel_rel = ObsTerm(func=mdp.joint_vel_rel)

4. 奖励

我们对多个方面给予奖励,并且为它们设置不同的权重。在继续阅读前,可以花一点时间思考:如何用物理术语描述平衡?如果不确定也没关系,下面将对此进行解释。

以下是对该任务有效的奖励项:

@configclass
class RewardsCfg:
   """Reward terms for the MDP."""


   # (1) Constant running reward
   alive = RewTerm(func=mdp.is_alive, weight=1.0)
   # (2) Failure penalty
   terminating = RewTerm(func=mdp.is_terminated, weight=-2.0)
   # (3) Primary task: keep pole upright
   pole_pos = RewTerm(
       func=mdp.joint_pos_target_l2,
       weight=-1.0,
       params={"asset_cfg": SceneEntityCfg("robot", joint_names=["cart_to_pole"]), "target": 0.0},
   )
   # (4) Shaping tasks: lower cart velocity
   cart_vel = RewTerm(
       func=mdp.joint_vel_l1,
       weight=-0.01,
       params={"asset_cfg": SceneEntityCfg("robot", joint_names=["slider_to_cart"])},
   )
   # (5) Shaping tasks: lower pole angular velocity
   pole_vel = RewTerm(
       func=mdp.joint_vel_l1,
       weight=-0.005,
       params={"asset_cfg": SceneEntityCfg("robot", joint_names=["cart_to_pole"])},
   )

在“Manager 工作流” 中,通过 func 参数传入实际计算奖励的函数。可以查看 mdp/rewards.py,或继续阅读,了解该函数的更多信息。

下面查看用于 joint_position 的奖励函数。关键在于,该函数不是只为一个环境计算奖励,而是为所有环境计算奖励!实际上,Isaac Lab 利用 PyTorch 张量,同时训练多个 Cartpole。

该函数内部的步骤如下:

注意

仔细观察,可以注意到有多个奖励函数,但只有一个在 rewards.py 中显式定义。为什么?

这是因为 Isaac Lab 提供若干通用奖励函数,因此无需在不同项目中重复定义。这些函数来自 mdp 包。点此查看可用函数的完整列表。

def joint_pos_target_l2(env: ManagerBasedRLEnv, target: float, asset_cfg: SceneEntityCfg) -> torch.Tensor:
   """Penalize joint position deviation from a target value."""
   # extract the used quantities (to enable type-hinting)
   asset: Articulation = env.scene[asset_cfg.name]
   # wrap the joint positions to (-pi, pi)
   joint_pos = wrap_to_pi(asset.data.joint_pos[:, asset_cfg.joint_ids])
   # compute the reward
   return torch.sum(torch.square(joint_pos - target), dim=1)

5. 场景和环境配置

前面已经分别介绍主要组件:Manager 以及奖励函数背后的数学原理。下面看这些内容如何组合成训练场景。

首先是场景配置。

在此处,可以看到如何设置训练环境,从地平面,到机器人,再到穹顶灯。Isaac Lab 支持自定义训练环境本身,因此无需将灯光或其他仅在本次训练中需要的元素直接放到机器人的 USD 文件中。如果训练需要其他道具,比如要抓取的物体,也可以用类似的方式在这里添加。

@configclass
class CartpoleSceneCfg(InteractiveSceneCfg):
    """Configuration for a cart-pole scene."""

    # ground plane
    ground = AssetBaseCfg(
        prim_path="/World/ground",
        spawn=sim_utils.GroundPlaneCfg(size=(100.0, 100.0)),
    )

    # robot
    robot: ArticulationCfg = CARTPOLE_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")

    # lights
    dome_light = AssetBaseCfg(
        prim_path="/World/DomeLight",
        spawn=sim_utils.DomeLightCfg(color=(0.9, 0.9, 0.9), intensity=500.0),
    )

最后,在环境配置中汇集所有内容。

上面定义的所有 Manager 都将在此处被实例化。此外,此处还配置仿真器、抽取设置、时间设置以及回合长度。重点留意,Isaac Lab 如何控制 Isaac Sim 的部分功能,执行训练。

##
# Environment configuration
##

@configclass
class CartpoleEnvCfg(ManagerBasedRLEnvCfg):
    # Scene settings
    scene: CartpoleSceneCfg = CartpoleSceneCfg(num_envs=4096, env_spacing=4.0)
    # Basic settings
    observations: ObservationsCfg = ObservationsCfg()
    actions: ActionsCfg = ActionsCfg()
    events: EventCfg = EventCfg()
    # MDP settings
    rewards: RewardsCfg = RewardsCfg()
    terminations: TerminationsCfg = TerminationsCfg()

    # Post initialization
    def __post_init__(self) -> None:
        """Post initialization."""
        # general settings
        self.decimation = 2
        self.episode_length_s = 5
        # viewer settings
        self.viewer.eye = (8.0, 0.0, 5.0)
        # simulation settings
        self.sim.dt = 1 / 120
        self.sim.render_interval = self.decimation

由于 Isaac Lab 控制仿真器,因此我们拥有按时间“步进”仿真的特殊能力。仿真不是自由运行,而是可以暂停,执行一些工作,然后再步进一定时间,重复这一过程。