[IsaacLab] 03. Task 설계 구조의 이해 part2
IsaacLab
RL
Task Design
IsaacLab 학습 프레임워크 구조 이해
Introduction
본 문서에서는 direct 방식의 cartpole 환경과, manager 방식의 cartpole 환경을 비교해보고자 합니다.
각 코드는 아래에서 확인이 가능합니다.
/workspace/isaaclab/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/cartpole_env.py
/workspace/isaaclab/source/isaaclab_tasks/isaaclab_tasks/manager_based/classic/cartpole/cartpole_env_cfg.py
코드 설명
Direct 환경
Direct 환경은 전통적인 환경 구현 방식과 유사하며, 하나의 클래스가 모든 구성 요소를 직접 구현합니다. 이는 구현의 투명성을 제공하며, 복잡한 로직 구현에 유리합니다. 또한, PyTorch JIT 또는 Warp와 같은 최적화 프레임워크를 활용해 성능상의 이점을 제공합니다.
코드 보기-cartpole_env.py
# Copyright (c) 2022-2025, The Isaac Lab Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import math
import torch
from collections.abc import Sequence
from isaaclab_assets.robots.cartpole import CARTPOLE_CFG
import isaaclab.sim as sim_utils
from isaaclab.assets import Articulation, ArticulationCfg
from isaaclab.envs import DirectRLEnv, DirectRLEnvCfg
from isaaclab.scene import InteractiveSceneCfg
from isaaclab.sim import SimulationCfg
from isaaclab.sim.spawners.from_files import GroundPlaneCfg, spawn_ground_plane
from isaaclab.utils import configclass
from isaaclab.utils.math import sample_uniform
@configclass
class CartpoleEnvCfg(DirectRLEnvCfg):
# 환경 설정
= 2
decimation = 5.0
episode_length_s = 100.0 # [N]
action_scale = 1
action_space = 4
observation_space = 0
state_space
# 시뮬레이션 설정
= SimulationCfg(dt=1 / 120, render_interval=decimation)
sim: SimulationCfg
# 로봇 설정
= CARTPOLE_CFG.replace(prim_path="/World/envs/env_.*/Robot")
robot_cfg: ArticulationCfg = "slider_to_cart"
cart_dof_name = "cart_to_pole"
pole_dof_name
# 장면 설정
= InteractiveSceneCfg(num_envs=4096, env_spacing=4.0, replicate_physics=True)
scene: InteractiveSceneCfg
# 리셋 설정
= 3.0 # 카트가 이 위치를 초과하면 리셋됩니다 [m]
max_cart_pos = [-0.25, 0.25] # 리셋 시 폴 각도가 샘플링되는 범위 [rad]
initial_pole_angle_range
# 보상 스케일
= 1.0
rew_scale_alive = -2.0
rew_scale_terminated = -1.0
rew_scale_pole_pos = -0.01
rew_scale_cart_vel = -0.005
rew_scale_pole_vel
class CartpoleEnv(DirectRLEnv):
cfg: CartpoleEnvCfg
def __init__(self, cfg: CartpoleEnvCfg, render_mode: str | None = None, **kwargs):
super().__init__(cfg, render_mode, **kwargs)
self._cart_dof_idx, _ = self.cartpole.find_joints(self.cfg.cart_dof_name)
self._pole_dof_idx, _ = self.cartpole.find_joints(self.cfg.pole_dof_name)
self.action_scale = self.cfg.action_scale
self.joint_pos = self.cartpole.data.joint_pos
self.joint_vel = self.cartpole.data.joint_vel
def _setup_scene(self):
self.cartpole = Articulation(self.cfg.robot_cfg)
# 지면 추가
="/World/ground", cfg=GroundPlaneCfg())
spawn_ground_plane(prim_path# 복제 및 복제
self.scene.clone_environments(copy_from_source=False)
# 장면에 관절 추가
self.scene.articulations["cartpole"] = self.cartpole
# 조명 추가
= sim_utils.DomeLightCfg(intensity=2000.0, color=(0.75, 0.75, 0.75))
light_cfg "/World/Light", light_cfg)
light_cfg.func(
def _get_observations(self) -> dict:
= torch.cat(
obs
(self.joint_pos[:, self._pole_dof_idx[0]].unsqueeze(dim=1),
self.joint_vel[:, self._pole_dof_idx[0]].unsqueeze(dim=1),
self.joint_pos[:, self._cart_dof_idx[0]].unsqueeze(dim=1),
self.joint_vel[:, self._cart_dof_idx[0]].unsqueeze(dim=1),
),=-1,
dim
)= {"policy": obs}
observations return observations
def _get_rewards(self) -> torch.Tensor:
= compute_rewards(
total_reward self.cfg.rew_scale_alive,
self.cfg.rew_scale_terminated,
self.cfg.rew_scale_pole_pos,
self.cfg.rew_scale_cart_vel,
self.cfg.rew_scale_pole_vel,
self.joint_pos[:, self._pole_dof_idx[0]],
self.joint_vel[:, self._pole_dof_idx[0]],
self.joint_pos[:, self._cart_dof_idx[0]],
self.joint_vel[:, self._cart_dof_idx[0]],
self.reset_terminated,
)return total_reward
구성 요소 | 설명 |
---|---|
CartpoleEnvCfg |
Direct 환경의 설정을 정의하는 클래스입니다. 시뮬레이션의 decimation, episode 길이, 행동 스케일 등을 설정합니다. |
CartpoleEnv |
Direct 환경을 구현하는 클래스입니다. DirectRLEnv를 상속받아 환경의 초기화, 관찰, 보상 계산 등을 수행합니다. |
_setup_scene |
시뮬레이션 장면을 설정하는 함수입니다. 로봇과 환경을 초기화합니다. |
_get_observations |
에이전트의 관찰 데이터를 수집하여 반환하는 함수입니다. 관절 위치와 속도를 포함합니다. |
_get_rewards |
에이전트의 보상을 계산하는 함수입니다. 보상 계산 로직은 생략되어 있습니다. |
Manager-based 환경
Manager-based 환경은 작업을 개별적으로 관리되는 구성 요소들로 분해하여 모듈화된 구현을 촉진합니다. 이는 협업에 효과적이며, 다양한 구성 요소를 손쉽게 교체할 수 있어 프로토타이핑과 실험에 유리합니다.
코드 보기-cartpole_env_cfg.py
import math
import isaaclab.sim as sim_utils
from isaaclab.assets import ArticulationCfg, AssetBaseCfg
from isaaclab.envs import ManagerBasedRLEnvCfg
from isaaclab.managers import EventTermCfg as EventTerm
from isaaclab.managers import ObservationGroupCfg as ObsGroup
from isaaclab.managers import ObservationTermCfg as ObsTerm
from isaaclab.managers import RewardTermCfg as RewTerm
from isaaclab.managers import SceneEntityCfg
from isaaclab.managers import TerminationTermCfg as DoneTerm
from isaaclab.scene import InteractiveSceneCfg
from isaaclab.utils import configclass
import isaaclab_tasks.manager_based.classic.cartpole.mdp as mdp
##
# Pre-defined configs
##
from isaaclab_assets.robots.cartpole import CARTPOLE_CFG # isort:skip
##
# Scene definition
##
@configclass
class CartpoleSceneCfg(InteractiveSceneCfg):
"""Configuration for a cart-pole scene."""
# ground plane
= AssetBaseCfg(
ground ="/World/ground",
prim_path=sim_utils.GroundPlaneCfg(size=(100.0, 100.0)),
spawn
)
# cartpole
= CARTPOLE_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
robot: ArticulationCfg
# lights
= AssetBaseCfg(
dome_light ="/World/DomeLight",
prim_path=sim_utils.DomeLightCfg(color=(0.9, 0.9, 0.9), intensity=500.0),
spawn
)
##
# MDP settings
##
@configclass
class ActionsCfg:
"""Action specifications for the MDP."""
= mdp.JointEffortActionCfg(asset_name="robot", joint_names=["slider_to_cart"], scale=100.0)
joint_effort
@configclass
class ObservationsCfg:
"""Observation specifications for the MDP."""
@configclass
class PolicyCfg(ObsGroup):
"""Observations for policy group."""
# observation terms (order preserved)
= ObsTerm(func=mdp.joint_pos_rel)
joint_pos_rel = ObsTerm(func=mdp.joint_vel_rel)
joint_vel_rel
def __post_init__(self) -> None:
self.enable_corruption = False
self.concatenate_terms = True
# observation groups
= PolicyCfg()
policy: PolicyCfg
@configclass
class EventCfg:
"""Configuration for events."""
# reset
= EventTerm(
reset_cart_position =mdp.reset_joints_by_offset,
func="reset",
mode={
params"asset_cfg": SceneEntityCfg("robot", joint_names=["slider_to_cart"]),
"position_range": (-1.0, 1.0),
"velocity_range": (-0.5, 0.5),
},
)
= EventTerm(
reset_pole_position =mdp.reset_joints_by_offset,
func="reset",
mode={
params"asset_cfg": SceneEntityCfg("robot", joint_names=["cart_to_pole"]),
"position_range": (-0.25 * math.pi, 0.25 * math.pi),
"velocity_range": (-0.25 * math.pi, 0.25 * math.pi),
},
)
@configclass
class RewardsCfg:
"""Reward terms for the MDP."""
# (1) Constant running reward
= RewTerm(func=mdp.is_alive, weight=1.0)
alive # (2) Failure penalty
= RewTerm(func=mdp.is_terminated, weight=-2.0)
terminating # (3) Primary task: keep pole upright
= RewTerm(
pole_pos =mdp.joint_pos_target_l2,
func=-1.0,
weight={"asset_cfg": SceneEntityCfg("robot", joint_names=["cart_to_pole"]), "target": 0.0},
params
)# (4) Shaping tasks: lower cart velocity
= RewTerm(
cart_vel =mdp.joint_vel_l1,
func=-0.01,
weight={"asset_cfg": SceneEntityCfg("robot", joint_names=["slider_to_cart"])},
params
)# (5) Shaping tasks: lower pole angular velocity
= RewTerm(
pole_vel =mdp.joint_vel_l1,
func=-0.005,
weight={"asset_cfg": SceneEntityCfg("robot", joint_names=["cart_to_pole"])},
params
)
@configclass
class TerminationsCfg:
"""Termination terms for the MDP."""
# (1) Time out
= DoneTerm(func=mdp.time_out, time_out=True)
time_out # (2) Cart out of bounds
= DoneTerm(
cart_out_of_bounds =mdp.joint_pos_out_of_manual_limit,
func={"asset_cfg": SceneEntityCfg("robot", joint_names=["slider_to_cart"]), "bounds": (-3.0, 3.0)},
params
)
##
# Environment configuration
##
@configclass
class CartpoleEnvCfg(ManagerBasedRLEnvCfg):
"""Configuration for the cartpole environment."""
# Scene settings
= CartpoleSceneCfg(num_envs=4096, env_spacing=4.0)
scene: CartpoleSceneCfg # Basic settings
= ObservationsCfg()
observations: ObservationsCfg = ActionsCfg()
actions: ActionsCfg = EventCfg()
events: EventCfg # MDP settings
= RewardsCfg()
rewards: RewardsCfg = TerminationsCfg()
terminations: 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
구성 요소 | 설명 |
---|---|
CartpoleSceneCfg |
카트폴 장면을 설정하는 클래스입니다. 지면, 로봇, 조명 등의 설정을 포함합니다. |
ActionsCfg |
MDP의 행동 사양을 정의하는 클래스입니다. 로봇의 조인트에 대한 힘을 설정합니다. |
ObservationsCfg |
MDP의 관찰 사양을 정의하는 클래스입니다. 정책 그룹에 대한 관찰을 설정합니다. |
EventCfg |
이벤트 구성을 정의하는 클래스입니다. 카트와 폴의 위치를 초기화하는 이벤트를 설정합니다. |
RewardsCfg |
MDP의 보상 항목을 정의하는 클래스입니다. 다양한 보상 조건을 설정합니다. |
TerminationsCfg |
MDP의 종료 조건을 정의하는 클래스입니다. 시간 초과 및 카트의 경계 초과 조건을 설정합니다. |
CartpoleEnvCfg |
카트폴 환경의 구성을 정의하는 클래스입니다. 장면, 관찰, 행동, 이벤트, 보상, 종료 조건을 포함합니다. |
최종 정리
Direct vs Manager-based 비교
특징 | Direct-based | Manager-based |
---|---|---|
모듈화 | 하나의 클래스가 모든 구성 요소를 직접 구현합니다. | 환경을 개별 구성 요소로 분해하여 모듈화된 구현을 촉진합니다. |
구성 요소 교체 용이성 | 구성 요소가 하나의 클래스에 통합되어 있어 교체가 어렵습니다. | 다양한 구성 요소를 손쉽게 교체할 수 있어 프로토타이핑과 실험에 유리합니다. |
세밀한 제어 | 환경의 로직에 대해 보다 세밀한 제어가 가능합니다. | 매니저를 통해 간접적으로 제어하므로 세밀한 제어가 제한적일 수 있습니다. |
협업 | 협업 시 모든 구성 요소가 하나의 클래스에 포함되어 있어 분업이 어려울 수 있습니다. | 모듈화된 구조로 인해 협업에 효과적이며, 개별 개발자가 특정 측면에 집중할 수 있습니다. |
성능 최적화 | PyTorch JIT 또는 Warp와 같은 최적화 프레임워크를 활용해 성능상의 이점을 제공합니다. | 모듈화로 인해 성능 최적화가 제한적일 수 있습니다. |
투명성 | 구현의 투명성을 제공합니다. | 매니저에 의해 로직이 추상화되어 있어 구현의 투명성이 낮을 수 있습니다. |
복잡한 로직 구현 | 복잡한 로직 구현에 유리합니다. | 복잡한 로직을 구현하기에는 적합하지 않을 수 있습니다. |