이번 단계 목표: 코드를 더 쓰기 전에, Isaac Lab이 세상을 어떻게 조직하는지 뼈대를 잡습니다. 시즌 1에서 익힌 Genesis 개념에 하나씩 대응시키는 방식으로 가면 러닝커브가 생각보다 완만합니다.
네 개의 패키지
Isaac Lab을 설치하면 실제로는 패키지 여러 개가 들어옵니다. 우리가 만질 것은 넷입니다.
| 패키지 | 역할 | 이 시리즈에서 |
|---|---|---|
isaaclab |
코어 — 시뮬레이션·에셋(Articulation)·센서·매니저 | 00~03편의 직접 조작 |
isaaclab_assets |
로봇 설정 모음 (G1, H1, Anymal, …) | G1_CFG를 여기서 가져옵니다 |
isaaclab_tasks |
완성된 RL 환경들 (Isaac-Velocity-Flat-G1-v0 등) |
04편부터의 주 무대 |
isaaclab_rl |
RSL-RL 등 러너 연동 래퍼 | 05편 학습부터 |
Cfg 문화 — “설정이 곧 코드”
Genesis에서는 씬을 함수 호출로 조립했습니다(scene.add_entity(...)). Isaac Lab의 문법은 다릅니다. 모든 것이 설정 클래스(*Cfg)로 먼저 선언되고, 실체는 그 설정에서 생성됩니다.
# Genesis 방식 — 호출로 조립
robot = scene.add_entity(gs.morphs.URDF(file="g1.urdf", pos=(0, 0, 0.8)))
# Isaac Lab 방식 — 선언 후 생성
robot_cfg = G1_CFG.replace(prim_path="/World/G1") # 설정(불변)을 복제·수정
robot = Articulation(robot_cfg) # 설정 → 실체
처음엔 번거롭습니다. 대신 이 문화 덕분에 “환경 전체”가 하나의 설정 트리로 표현되고, 상속·복제(replace, copy)로 변형됩니다. 04편에서 볼 내장 보행 환경도 결국 ~EnvCfg라는 커다란 설정 클래스 하나예요. 설정 클래스를 읽을 줄 알면 Isaac Lab의 절반을 읽을 줄 아는 겁니다.
용어 대응표 (시즌 1 → 시즌 2)
| Genesis (시즌 1) | Isaac Lab (시즌 2) | 메모 |
|---|---|---|
gs.init() |
AppLauncher |
앱 기동. import 순서 제약이 생김 (00편) |
gs.Scene |
SimulationContext + InteractiveScene |
물리 문맥과 씬 구성이 분리됨 |
scene.add_entity(URDF) |
Articulation(ArticulationCfg) |
로봇 = Articulation |
robot.joints / DOF 인덱스 |
robot.joint_names / 정규식 매칭 |
관절 그룹을 이름 정규식으로 지정하는 문화 (".*_knee_joint") |
robot.control_dofs_position(...) |
robot.set_joint_position_target(...) + write_data_to_sim() |
쓰기가 명시적 2단계 |
| 위치/속도 읽기 | robot.data.* (root_pos_w, joint_pos, …) |
읽기 전 robot.update(dt) 필요 |
| PD 게인 (kp/kd 직접 설정) | ImplicitActuatorCfg(stiffness=, damping=) |
액추에이터가 설정 계층으로 분리 |
scene.build(n_envs=4096) |
InteractiveSceneCfg(num_envs=4096) |
병렬 환경 복제 개념은 동일 |
| 손으로 짠 보상 함수들 | Manager (Reward/Observation/Event/…) | 아래에서 따로 |
Manager — 시즌 1에서 손으로 짰던 것들의 정리함
시즌 1의 train/ 코드는 관측 조립, 보상 항목, 밀치기 이벤트, 종료 판정을 전부 한 클래스에 손으로 짰습니다. Isaac Lab의 manager-based 환경은 그 각각을 표준 슬롯으로 분리합니다.
| Manager | 시즌 1에서의 대응물 |
|---|---|
| ObservationManager | get_observations()에 이어붙이던 텐서들 |
| RewardManager | _reward_* 함수 + 가중치 딕셔너리 |
| EventManager | 4초마다 밀치기, 스폰 랜덤화 (시즌 1 09편) |
| TerminationManager | “넘어지면 리셋” 판정 |
| CommandManager | 속도·회전 명령 샘플링 (시즌 1 08편) |
| CurriculumManager | 지형 난이도 승급 (시즌 1 15·18편에서 손으로 하던 것) |
각 슬롯에 “항목(term) = 함수 + 가중치 + 대상”을 등록하면 환경이 됩니다. 즉 시즌 1에서 우리가 발명하며 배운 구조가, 여기서는 프레임워크의 공식 문법인 거예요. 개념은 이미 다 아는 것이고 이름만 새로 익히면 됩니다.
개념 박스 — manager-based vs direct Isaac Lab에는 환경 작성 방식이 둘 있습니다. manager-based는 위의 슬롯 문법 (선언적, 내장 환경 대부분이 이 방식), direct는 시즌 1처럼 한 클래스에 전부 직접 쓰는 방식(자유도 높음)입니다. 이 시리즈는 내장 환경을 해부해야 하니 manager-based를 주로 쓰고, 03편의 자세 유지 같은 소품만 direct 감각으로 만듭니다.
태스크 레지스트리 — 환경을 이름으로 부른다
완성된 환경은 gym 스타일 ID로 등록되어 있습니다. G1 보행이라면:
Isaac-Velocity-Flat-G1-v0— 평지 보행 (04~05편)Isaac-Velocity-Rough-G1-v0— 거친 지형 + 높이맵 관측 (다음 시즌의 주인공)...-Play-v0— 평가·재생용 (환경 수 적고 랜덤화 꺼짐)
그래서 학습 실행이 한 줄이 됩니다.
python train.py --task Isaac-Velocity-Flat-G1-v0 --num_envs 4096 --headless
시즌 1과의 결정적 차이가 여기 있습니다. Genesis에서는 g1_train.py에 환경이 통째로 들어 있어 전부 우리 것이었습니다. Isaac Lab에서는 환경이 남이 튜닝해 둔 완성품으로 옵니다. 편하지만, 해부하지 않고 쓰면 아무것도 배우지 못해요.
다음 단계
그래서 04편은 학습 버튼을 누르기 전에 이 환경의 관측·보상·종료를 시즌 1의 손코딩과 항목별로 대조하는 데 통째로 씁니다. 그 전에 먼저 로봇부터 무대에 세우죠 → 02. G1 불러오기