Isaac Lab Tutorial - Interacting with a rigid object

권호떡의 데싸정복·2024년 10월 7일

강체와 상호작용을 해보자

$ python source/standalone/tutorials/01_assets/run_rigid_object.py
# 필수 라이브러리 불ㄹ러오기
import argparse
from omni.isaac.lab.app import AppLauncher

# 명령인자 추가 및 script에 대한 짧은 설명
parser = argparse.ArgumentParser(description="Tutorial on spawning and interacting with a rigid object.")

# 실행 어플리케이션에 명령줄 인자를 추가
AppLauncher.add_app_launcher_args(parser)

# 명령줄 인자를 처리하여 args_cli라는 변수에 저장
args_cli = parser.parse_args()

# 전달된 인자를 바탕으로 어플리케이션 객체 생성
app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app

# torch는 대규모 데이터를 병렬 처리하여 빠르게 연산을 수행할 수 있는 텐서 연산이 가능함. 여기에서는 객체의 위치, 랜덤한 원뿔 위치를 샘플링하는데 사용됨
import torch

# prim을 생성하기 위한 유틸리티 함수
import omni.isaac.core.utils.prims as prim_utils

# 물리 시뮬레이션을 지원하는 유틸리티 함수
import omni.isaac.lab.sim as sim_utils

# 수학적 계산을 위한 유틸리티 함수. 벡터 연산, 랜덤 위치 생성, 물리적 속성 계산등에 사용됨.
import omni.isaac.lab.utils.math as math_utils

# 강체와 강체의 속성을 정의하는 클래스
from omni.isaac.lab.assets import RigidObject, RigidObjectCfg

# 시뮬레이션 환경을 관리하는 클래스. 해당 클래스는 전체적인 컨텍스트를 관리하며, 물리 계산, 객체 업데이트, 시간 관리 등을 수행함.
from omni.isaac.lab.sim import SimulationContext

def design_scene():
    
   	# 지면 생성
    cfg = sim_utils.GroundPlaneCfg()
    cfg.func("/World/defaultGroundPlane", cfg)

    # 광원 생성
    cfg = sim_utils.DomeLightCfg(intensity=2000.0, color=(0.8, 0.8, 0.8))
    cfg.func("/World/Light", cfg)
	
    '''
    origins는 4개 원뿔 각각의 위치를 정의하는 x,y,z 좌표
    create_prim() : 새로운 prim을 만듦.
    f"/World/Origin{i}" : prim이 생성될 경로. /World 루트 아래에 Origin0. Origin1.....등이 생성됨.
    Xform이란? Xform 자체는 물리적 존재나 시각적 외관이 없다. 빈 컨테이너 또는 상위 노드라고 생각하면 된다. 나중에 위치, 방향 등을 구성하고 적용하는 방법일 뿐이다.
    이 코드는 Xform을 origins 좌표에 원뿔을 구성하고 배치하는데 사용한다.
    Xform을 통해 모든 원뿔을 집합적으로 변환을 더 쉽게 할 수 있다.
    '''
    origins = [[0.25, 0.25, 0.0], [-0.25, 0.25, 0.0], [0.25, -0.25, 0.0], [-0.25, -0.25, 0.0]]
    for i, origin in enumerate(origins):
        prim_utils.create_prim(f"/World/Origin{i}", "Xform", translation=origin)

    '''
    RigidObjectCfg() : 강체(여기서는 원뿔)를 생성하는 객체이다.
    prim_path="/World/Origin.*/Cone" : 각 con을 Origin0,1,2,3에 배치한다는 의미
    sim_utils.ConeCfg() : 원뿔의 물리적 속성을 설정하는 객체이다.
    radius는 반지름, height는 원뿔의 높이, rigid_props는 강체의 물리적 속성, mass_props는 원뿔의 질량을 1.0으로 설정, collision_props는 충돌 처리를 위한 속성
    visual_material() : 원뿔의 시각적 속성을 설정함. 여기서는 녹색 원뿔이 생성되고 약간의 금속성 효과가 적용됨.
    '''
    cone_cfg = RigidObjectCfg(
        prim_path="/World/Origin.*/Cone",
        spawn=sim_utils.ConeCfg(
            radius=0.1,
            height=0.2,
            rigid_props=sim_utils.RigidBodyPropertiesCfg(),
            mass_props=sim_utils.MassPropertiesCfg(mass=1.0),
            collision_props=sim_utils.CollisionPropertiesCfg(),
            visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 1.0, 0.0), metallic=0.2),
        ),
        # 강체 객체의 초기 상태를 정의. 특정 값이 제공되지 않으면 초기 속도, 회전없이 기본 위치에 생성
        init_state=RigidObjectCfg.InitialStateCfg(),
    )
    # 위에서 설정한 cone_cfg를 바탕으로원뿔 강체를 생성
    cone_object = RigidObject(cfg=cone_cfg)

    # 모든 원뿔 객체를 포함하는 딕셔너리
    scene_entities = {"cone": cone_object}
    
    # 원뿔 딕셔너리와 원점 리스트를 반환
    return scene_entities, origins

def run_simulator(sim: sim_utils.SimulationContext, entities: dict[str, RigidObject], origins: torch.Tensor):
    # 딕셔너리를 이용해 원뿔 객체를 cone_object에 저장
    cone_object = entities["cone"]

    # sim.get_physics_dt() 함수는 물리 시뮬레이션에서 사용되는 dt를 반환함
    sim_dt = sim.get_physics_dt()  # Get the simulation time step
    sim_time = 0.0 # 시뮬레이션에서 경과한 시간을 저장하는 변수
    count = 0 # 시뮬레이션 스템 수를 세는 카운터

    # 앱이 계속 실행 중일때 무한 반복
    while simulation_app.is_running():
        # 250 스텝마다 상태를 초기화함
        # 초기화 이유는 원뿔 객체의 위치와 상태를 다시 설정해주어 랜덤한 위치에서 시작하기 위함이다.
        if count % 250 == 0:
            sim_time = 0.0
            count = 0

            # 원뿔 객체의 기본 상태를 복사하여 시뮬레이션에 다시 사용할 수 있게함.
            root_state = cone_object.data.default_root_state.clone()

            '''
            root_state : 슬라이싱을 사용하여 root_state 텐서의 특정 부분을 선택
            원뿔의 위치, 회전 및 기타 물리적 속성이 포함됨
            각 행은 위치(x,y,z), 회전(쿼터니언) 같은 속성을 저장함
            [:, :3] : root_state 텐서에서 특정 요소를 선택함. 첫번째 : 는 모든 원뿔 즉 4개의 원뿔을 모두 선택함. 두번째 :3 은 각 행의 처음 3개 요소(열)을 선택함을 의미. 해당 경우는 x,y,z 즉 위치를 참조함
            root_state[:, :3] += origins는 위 origins 좌표를 더해 모든 원뿔 위치를 업데이트함.
            root_state[:, :3] += math_utils.sample_cylinder() : 임의의 오프셋을 추가하여 원점 주변의 원통형 영역 내의 임의 위치에 각 원뿔을 배치한다.
            반경 0.1과 h_range(0.25, 0.5)는 원뿔이 배치될 수직 높이를 정의함 0.25~0.5 사이의 랜덤한 값으로 원뿔 높이가 정의됨.
            size=cone_object.num_instances : 원뿔 개체 수만큼 임의의 위치를 생성하도록함 즉 무작위 위치 4개가 설정됨                     
            '''
            root_state[:, :3] += origins
            root_state[:, :3] += math_utils.sample_cylinder(
                radius=0.1, h_range=(0.25, 0.5), size=cone_object.num_instances, device=cone_object.device
            )

            # 새로운 위치와 상태를 시뮬레이션에 적용
            cone_object.write_root_state_to_sim(root_state)

            # 원뿔 객체의 버퍼를 초기화하여 새롭게 시작할 수 있도록함
            cone_object.reset()
            print("----------------------------------------")
            print("[INFO]: Resetting object state...")

        # 원뿔의 현재 상태(위치, 속도 등)를 시뮬레이션으로 전송해 물리 엔진이 잘 작동하도록 함
        cone_object.write_data_to_sim()

        # perform step
        sim.step()

        # 스텝 수 추적
        sim_time += sim_dt
        count += 1

        # 원뿔의 객체 상태를 물리적으로 업데이트함. 이를 통해 원뿔이 중력, 충돌 등의 물리 효과를 반영하여 시뮬레이션이 진행됨
        cone_object.update(sim_dt)

        # 50 스텝마다. 
        if count % 50 == 0:
            print(f"Root position (in world): {cone_object.data.root_state_w[:, :3]}")

def main():
    
    sim_cfg = sim_utils.SimulationCfg(device=args_cli.device)
    sim = SimulationContext(sim_cfg)

    # Set main camera
    sim.set_camera_view(eye=[1.5, 0.0, 1.0], target=[0.0, 0.0, 0.0])

    # Design scene
    scene_entities, scene_origins = design_scene()
    
    # 원뿔의 원래 위치를 PyTorch 텐서로 변환.
    # 텐서로 변환해야 빠른 계산이 가능하며 GPU를 사용할 수 있기 때문
    scene_origins = torch.tensor(scene_origins, device=sim.device)

    # Play the simulator
    sim.reset()

    # Now we are ready!
    print("[INFO]: Setup complete...")

    # Run the simulator
    run_simulator(sim, scene_entities, scene_origins)
    
if __name__ == "__main__":
    # run the main function
    main()
    # close sim app
    simulation_app.close()
profile
데이터사이언스정복

0개의 댓글