Post

NVIDIA Isaac Sim - Robot Running

Introduction

이전 포스팅에서는 내가 가진 WeCAR2.0과 비슷한 QCar를 NVIDIA Isaac Sim에서 import하는지에 대해서 다루었다. 이번 포스팅에서는 불러온 로봇을 코드로 불러오고 불러온 로봇을 어떻게 구동할 수 있을지 작성해보도록 하겠다. 아직 본인의 로봇을 Import하지 않은 경우, 이전 포스팅으로 돌아가서 로봇을 Import하는 방법에 대해서 확인하고 오길 바란다.

Sensor Setting

내가 가지고 있는 WeCAR2.0 모델에는 아래와 같은 센서 구성을 가지고 있다.

  1. ZED Camera (Streo Camera)
  2. YDLidar
  3. NVIDIA Jetson Orin

1, 2번은 나중에 센서를 이용한 recognition과 perception을 수행할 예정이니 센서 설정을 맞춰주면 좋다. 3번의 경우, 굳이 실제 로봇을 돌리지 않을 거라면 맞춰주지 않아도 된다. 시뮬레이션에서도 Orin을 통해서 사용할 것은 아니니….

Code

일단 처음으로 우리는 로봇의 USD를 만들었으니 로봇의 USD를 불러와서 simulation을 실행할 줄 알아야한다. 기본적으로 Isaac-Sim의 코드 예제들은 아래의 위치에서 확인할 수 있다. 기본적으로 isaac-sim을 설치할 떄 경로를 나는 사용하고 있기 떄문에 아래의 코드를 terminal에서 사용하면 예제 python 코드들이 모여있는 곳으로 이동할 수 있다.

1
$ /home/{user name}/.local/share/ov/pkg/{isaac-sim-version}/standalone_example

기본적인 예제로 현재로 진행을 하겠다. 내가 직접 짠 코드가 있지만 복잡하기 떄문에 기본기부터 차근차근해보자.

1
2
3
from omni.isaac.kit import SimulationApp

app = SimulationApp({"headless": False})

기본적으로 이 코드를 사용하지 않으면 시뮬레이터가 실행되지 않는다. 다음으로 isaac sim api들을 불러와보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from omni.isaac.core import World
omni.isaac.wheeled_robots.controllers.differential_controller import DifferentialController
from omni.isaac.wheeled_robots.robots import WheeledRobot

world = World()
robot = world.scene.add(
    WheeledRobot(
        prim_path="/World/Wecar",
        name="wecar",
        wheel_dof_names = ["base_hubfl_joint", "base_hubfr_joint", "base_wheelrl_joint". "base_wheelrr_joint"],
        create_robot = False,
        usd_path = wecar_path,
        position = np.array([0.0, 0.0, 0.0])
    )
)
world.scene.add_default_ground_plane()
controller = DifferentialCotnroller(name="simple_control", wheel_radius=0.03, wheel_base=0.1125)
world.reset()

기본적인 구성은 위처럼 같다. 여기서 조심해야할 점은 simulation을 불러오기 전에 from omni.isaac.core import World와 같이 api를 미리 불러오게 되면 에러가 걸리면서 실행이 안된다. 시뮬레이션을 불러오고 나서 실행해야하는 것을 잊지 말자.

isaac에서는 world를 불러오는 방법은 2가지가 있다.

  • SimulationContext: 상위적인 개념이라 만약 이걸 이용해서 뭔가를 configuration하고 싶다면 사용하면 된다.
  • World: World 클래스는 SimulationContext 클래스를 상속 받아서 사용하기 때문에 단순하게 나는 world만 받아와서 사용하고 싶다면 사용하면 된다.

world를 불러올떄 아래와 같은 변수들을 사용할 수 있지만, 그것은 나중에 다른 예제를 사용할 떄 기회가 있으면 사용하도록 하겠다.

1
2
3
4
5
6
7
world = World(physics_dt=None,
              rendering_dt=None,
              stage_units_in_meters=None,
              physics_prim_path="/physicsScene",
              set_defaults=True,
              backend="numpy",
              device=None)

위에 나와있는 변수들은 모두 default값이니 변경하고 싶은 값들이 있다고 하면 변경해서 사용하면 된다.

다음으로는, WheeledRobot 클래스에 대해서 살펴보도록하겠다.

  • prim_path: 시뮬레이션에서 어떤 위치에서 불러올 것인지에 대한 변수이다. 예제에서는 /World/Wecar라고 정했지만 원하는 path가 따로 있다면 설정하는 것이 좋다.
  • name: 로봇을 불러올 때 어떤 이름으로 불러올 것인지에 대한 변수이다. wecar로 설정했으니 simulation상에는 wecar라는 이름으로 생성이 되는 것이다.
  • wheeled_dof_names: 로봇을 구동하려면 기본적으로 dof 이름들을 넣어줘야 구동이 가능하다. 우리는 바퀴 4개이니, 4개에 대한 joint를 모두 넣어주면 된다.
  • create_robot: 로봇을 만들것인지 아닌지 설정하는 변수이다. 우리는 로봇을 만들 것이니 True로 설정해주면 된다.
  • usd_path: 앞에서도 말했듯이 우리는 urdf를 매번 설정해서 불러오는 것보다 코드를 이용해서 simulation을 실행시키는 것이 좋다. 그렇기 때문에, urdf를 import할 때 생성되었던 usd의 경로를 입력해주면 된다.
  • position: 로봇이 초기에 생성될 때 어떠한 position에 생성할 것인지에 대한 변수이다. 그냥 list안에 넣어주어도 되고, numpy를 이용해서 정의해주어도 된다.

위의 변수 이외에도 robot_path, wheel_dof_indices, orientation같은 변수들도 설정해 줄 수 있다.

다음으로 world.scene.add_default_ground_plane()는 isaac sim에서 기본적으로 제공하는 격자무늬의 ground가 있다. 만약 본인이 만든 환경을 불러오고 싶은 경우 usd 파일을 불러오면 되고, isaac sim에서 기본적으로 제공하는 환경을 불러오고 싶다면, 내가 작성해놓은 이전 포스팅을 참고해보면 된다.

1
controller = DifferentialCotnroller(name="simple_control", wheel_radius=0.03, wheel_base=0.1125)

여기서는 정의한 DifferentialController는 differential drive를 사용하고 싶은 경우 사용하면 된다. 이것은 로봇의 컨트롤러의 종류에 따라서 설정하면 되는데, DifferentialController, HolonomicController, WheelBasePoseController를 사용할 수 있다.

1
world.reset()

이 부분은 코드상으로 보기만 해도 알 수 있듯이 우리가 처음에 정의한 world를 초기화하는 코드이다. 이 코드를 실행하면 우리가 로봇의 초기상태로 돌아가는 것을 볼 수가 있을 것이다.

다음 코드를 보겠다.

1
2
3
4
5
6
while app.is_running():
    world.step(render=True)
    if world.is_playing():
        print("Simulation is running!!")

app.close()

app.is_running()은 isaac sim 어플리케이션이 실행되는 동안 돌아갈 수 있게 하는 코드이고, world.is_playing()의 경우에는 isaac sim이 실행되면 play 버튼을 누를 수 있을 것이다. play 버튼이 실행이 되어 있는 경우 돌아가는 코드이다.

여기서 world.step(render=True)이 코드는 world에서 한 step이 지나갈 때마다 rendering을 시킬건지에 대한 내용이다.

Caution

갑자기 WheeledRobot에서 articulation을 못찾겠다면서 에러가 나면서 시뮬레이션이 실행되지 않는다.

1
2
3
2024-04-19 10:40:18 [148,533ms] [Error] [omni.isaac.dynamic_control.plugin] DcGetArticulationRootBody: Invalid or expired articulation handle

2024-04-19 10:40:18 [148,534ms] [Error] [omni.physx.tensors.plugin] Pattern '/World/Wecar' did not match any articulations

WheeledRobot클래스의 문제인 것인지 prim_path의 문제인것인지 한번 살펴보자.

This post is licensed under CC BY 4.0 by the author.