类和配置

目录

类和配置#

要开始,请导航到任务: source/isaac_lab_tutorial/isaac_lab_tutorial/tasks/direct/isaac_lab_tutorial ,查看 isaac_lab_tutorial_env_cfg.py 的内容。您应该看到以下内容

from isaaclab_assets.robots.cartpole import CARTPOLE_CFG

from isaaclab.assets import ArticulationCfg
from isaaclab.envs import DirectRLEnvCfg
from isaaclab.scene import InteractiveSceneCfg
from isaaclab.sim import SimulationCfg
from isaaclab.utils import configclass


@configclass
class IsaacLabTutorialEnvCfg(DirectRLEnvCfg):

    # Some useful fields
    .
    .
    .

    # simulation
    sim: SimulationCfg = SimulationCfg(dt=1 / 120, render_interval=2)

    # robot(s)
    robot_cfg: ArticulationCfg = CARTPOLE_CFG.replace(prim_path="/World/envs/env_.*/Robot")

    # scene
    scene: InteractiveSceneCfg = InteractiveSceneCfg(num_envs=4096, env_spacing=4.0, replicate_physics=True)

    # Some more useful fields
    .
    .
    .

这是一个简单的倒立摆环境的默认配置,与模板一起提供,并定义了对应环境中任何操作的 self 作用域。

首先要注意的是 @configclass 装饰器的存在。这将一个类定义为配置类,在 Isaac Lab 中具有特殊功能。根据您的目标,Isaac Lab 提供不同的基本配置类,而在这种情况下,我们使用 DirectRLEnvCfg 类,因为我们对在直接工作流中执行强化学习感兴趣。

其次要注意的是配置类的内容。作为作者,您可以指定任何您希望定义的字段,但通常来说,您总是会在此处定义三件事: simscenerobot 。请注意,这些字段也是配置类!这种配置类的组合方式是解决克隆任意复杂环境的方案之一。

simSimulationCfg 的一个实例,这是控制我们正在构建的模拟现实性质的配置。这个字段是基类 DirecRLEnvCfg 的成员,但具有默认的模拟配置,因此 从技术上讲 它是可选的。 SimulationCfg 决定了时间步长(dt)的精度,重力的方向,甚至是如何模拟物理。在这种情况下,我们仅指定时间步长和渲染间隔,前者指示每个时间步长模拟 \(1/120\) 秒,后者是我们在渲染一帧之前应该采取的步骤数量(值为2表示每隔一帧渲染一次)。

sceneInteractiveSceneCfg 的一个实例。场景描述了舞台上发生的事情,并管理要在各个环境中复制的模拟实体。场景也是基类 DirectRLEnvCfg 的成员,但与 sim 不同,它没有默认值,必须在每一个 DirectRLEnvCfg 中定义。 InteractiveSceneCfg 描述了我们想要为训练创建多少个场景的副本,以及它们在舞台上应该被分隔多远。

最后,我们有 robot 的定义,它是 ArticulationCfg 的一个实例。一个环境可能有多个关节,因此不严格要求存在 ArticulationCfg 来定义 DirectRLEnv 。相反,通常的工作流程是为机器人定义一个正则表达式路径,并在基本配置中替换 prim_path 属性。在这种情况下, CARTPOLE_CFG 是在 isaaclab_assets.robots.cartpole 中定义的配置,通过用 /World/envs/env_.*/Robot 替换 prim 路径,我们在暗示舞台上的每个场景都有一个名为 Robot 的机器人。

环境#

接下来,让我们看看我们任务目录中的另一个 python 文件的内容: isaac_lab_tutorial_env_cfg.py

#imports
.
.
.
from .isaac_lab_tutorial_env_cfg import IsaacLabTutorialEnvCfg

class IsaacLabTutorialEnv(DirectRLEnv):
    cfg: IsaacLabTutorialEnvCfg

    def __init__(self, cfg: IsaacLabTutorialEnvCfg, render_mode: str | None = None, **kwargs):
        super().__init__(cfg, render_mode, **kwargs)
        . . .

    def _setup_scene(self):
        self.robot = Articulation(self.cfg.robot_cfg)
        # add ground plane
        spawn_ground_plane(prim_path="/World/ground", cfg=GroundPlaneCfg())
        # add articulation to scene
        self.scene.articulations["robot"] = self.robot
        # clone and replicate
        self.scene.clone_environments(copy_from_source=False)
        # add lights
        light_cfg = sim_utils.DomeLightCfg(intensity=2000.0, color=(0.75, 0.75, 0.75))
        light_cfg.func("/World/Light", light_cfg)

    def _pre_physics_step(self, actions: torch.Tensor) -> None:
        . . .

    def _apply_action(self) -> None:
        . . .

    def _get_observations(self) -> dict:
        . . .

    def _get_rewards(self) -> torch.Tensor:
        total_reward = compute_rewards(...)
        return total_reward

    def _get_dones(self) -> tuple[torch.Tensor, torch.Tensor]:
        . . .

    def _reset_idx(self, env_ids: Sequence[int] | None):
        . . .

@torch.jit.script
def compute_rewards(...):
    . . .
    return total_reward

为了便于讨论,某些代码已被省略。这是直接工作流的实际 “核心” 存在之处,我们会在此处进行大部分修改以调整模板以满足我们的需求。当前, IsaacLabTutorialEnv 的所有成员函数都直接从 DirectRLEnv 继承。这个已知接口是 Isaac Lab 及其支持的 RL 框架与环境交互的方式。

当环境初始化时,它接收到自己的配置作为参数,然后立即传递给 super,以初始化 DirectRLEnv 。这个 super 调用还调用 _setup_scene ,它实际上构建了场景并适当地克隆了它。值得注意的是如何在 _setup_scene 中创建机器人并将其注册到场景中。首先,通过使用我们在 IsaacLabTutorialEnvCfg 中定义的 robot_config 创建机器人关节: 在此之前,它是不存在的!当关节创建时,机器人存在于舞台上的 /World/envs/env_0/Robot 处。然后调用 scene.clone_environments 适当地复制了 env_0 。此时,机器人作为多个副本存在于舞台上,所以唯一剩下的就是通知 scene 对象这个关节的存在以进行跟踪。场景的关节被保存为一个字典,因此 scene.articulations["robot"] = self.robot 创建了 articulations 字典的一个新的 robot 元素,并将值设置为 self.robot

还请注意,其余函数除了 _reset_idx 不接受附加参数之外。这是因为环境只管理将动作应用于正在模拟的智能体,并更新模拟。这就是 _pre_physics_step_apply_action 步骤的作用: 我们设置机器人的驱动命令,这样当模拟向前走时,动作被应用并关节被驱动到新的目标。这样分步处理的过程旨在确保对环境的执行有系统性控制,并且在管理工作流中特别重要。类似的关系也存在于 _get_dones 函数和 _reset_idx 之间。前者, _get_dones 确定每个环境是否处于终端状态,并生成表示哪些环境因进入终端状态而中止,而哪些因超时而中止的布尔值张量。后者, _reset_idx 会取一个环境索引值(整数)的列表,然后实际重置这些环境。重要的是,像更新驱动目标或重置环境这样的操作不应该发生在物理或渲染步骤 期间 ,因此通过这种方式分割接口有助于防止这种情况发生。