๐ฉโ๐ปOrbit Existing Scripts
Orbit
์ IsaacLab
์ผ๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค.
Orbit ์๋ฆฌ์ฆ์ ๋๋ฒ์งธ ํฌ์คํ ์ผ๋ก ์ด๋ฒ์๋ Orbit์์ ์ ๊ณตํ๋ scripts๋ฅผ ์ดํด๋ณด๋ฉฐ Orbit์ผ๋ก ์ด๋ค ํ๋ก๊ทธ๋๋ฐ์ ํ ์ ์์์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค. ๊ณต์ Documents์์ Running existing scripts๋ฅผ ๋ฐ๋ผ๊ฐ๋ณด๋ฉฐ ์งํ๋ ์์ ์ ๋๋ค.
1 API Demos
Orbit์ ๋ฉ์ธ ๊ธฐ๋ฅ๋ค์ ์ ๊ณตํ๋ ๋ชจ๋์ omni.isaac.orbit
์
๋๋ค. ํด๋น ๋ชจ๋์์๋ ๋ก๋ด๋ค์ actuator๋ object, sensor ๋ฑ์ ํธํ๊ฒ ์ฌ์ฉํ ์ ์๋ interface๋ฅผ ์ ๊ณตํ๊ณ ์์ต๋๋ค. ์์ ์๋ฆฌ์ฆ ํฌ์คํ
์์ ๊ฐ๋จํ๊ฒ 4์กฑ ๋ณดํ๋ก๋ด๋ค์ ๋์๋ณด๋ script๋ฅผ ์คํ ์์ผ๋ณด์์๋๋ฐ ์ด์ ๊ฐ์ standlone/demo
์์ ์ ๊ณตํ๋ ๋ช๊ฐ์ง ์์ ๋ค์ ์คํํด๋ณด๊ฒ ์ต๋๋ค.
Orbit ์๋ฆฌ์ฆ ํฌ์คํ
์ ๊ธฐ๋ฐ์ผ๋ก ์ด์ ํฌ์คํ
์ ์ด์ด์ ์งํ๋๋ ํฌ์คํ
์ด๋ฏ๋ก Orbit
ํ์ผ์ Github์์ ๋ค์ด๋ฐ๊ณ orbit ์ค์น๋ฅผ ์ ์ ๋ก ์งํ๋ฉ๋๋ค. ์ด์ ์ Orbit repository๋ฅผ ๋ค์ด ๋ฐ์ ์์น์์ ์งํํด์ฃผ์ธ์. orbit ์คํ ๋ช
๋ น์ด๋ orbit
์ผ๋ก ๋์ผํฉ๋๋ค. -p
์ต์
์ Isaac Sim์ python.sh๋ฅผ ์ฌ์ฉํ์ฌ python ํ์ผ์ ์คํ์ํค๋๋ก ํ๋ ์ต์
์
๋๋ค.
4์กฑ ๋ณดํ ๋ก๋ด๋ค์ ๋๊ณ ๋ฐ(feet) marker๋ฅผ ์๊ฐํํ๊ณ stadning pose๋ฅผ ์ ์งํ๋๋ก position command๋ฅผ ์ ์ฉ์ํจ ์์
orbit -p source/standalone/demo/play_quadrupeds.py
2๋์ Franka ๋งค๋ํฐ๋ ์ดํฐ๋ฅผ ๋๊ณ ๋๋คํ position command๋ฅผ ์ ์ฉ์์ผ์ ์์ง์ด๊ฒ ํ๋ ์์
orbit -p source/standalone/demo/play_arms.py --robot franka_panda
128๋์ Franka ๋งค๋ํฐ๋ ์ดํฐ๋ฅผ ๋๊ณ inverse kinematics controller๋ฅผ ์ด์ฉํ์ฌ ์ ์ดํ๋ ์์
orbit -p source/standalone/demo/play_ik_control.py --robot franka_panda --num_envs 128
์นด๋ฉ๋ผ๋ฅผ ์ค์ ํ๊ณ pointcloud๋ฅผ ์ป๋ ์์ (cpu์ gpu ์ ํ๊ฐ๋ฅ)
# CPU orbit -p source/standalone/demo/play_camera.py # GPU orbit -p source/standalone/demo/play_camera.py --gpu
2 Code ์ดํด๋ณด๊ธฐ
์์ ์์ ์ฝ๋๋ค ์ค source/standalone/demo/play_quadrupeds.py
๋ฅผ ํ๋์ฉ ์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉฐ orbit์์ ์ด๋ค ๋ชจ๋๋ค์ ์ ๊ณตํ๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค. ํด๋น ์์ ์์๋ 3์ข
๋ฅ์ 4์กฑ ๋ณดํ๋ก๋ด์ ๋ถ๋ฌ์ ์งํํ๋๋ฐ ๊ฐ ๋ก๋ด์ ํ๋ซํผ์ ๋ํด ๊ถ๊ธํ์ ๋ถ๋ค์ ์๋ ๋งํฌ๋ฅผ ๋๋ฌ์ ํ์ธํด๋ณด์๋ฉด ๋ฉ๋๋ค.
2.1 Modules
Orbit์ด ๊ธฐ๋ฐํ๊ณ ์๋ Isaac Sim Simulator์ ๋จผ์ ํค๊ธฐ ์ํด SimulationApp
class๋ฅผ ์ด์ฉํ์ฌ ์๋ฎฌ๋ ์ดํฐ ์ฑ์ ์ค์ ํด์ค๋๋ค. ์ด๋ headless
๋ ์๋ฎฌ๋ ์ดํฐ์ GUI๋ฅผ ๋์ฐ์ง ์๊ณ ์คํํ๋ ์ต์
์ ๊ฐ๋ฆฌํต๋๋ค.
"""Launch Isaac Sim Simulator first."""
from omni.isaac.kit import SimulationApp
import argparse
# add argparse arguments
parser = argparse.ArgumentParser("Welcome to Orbit: Omniverse Robotics Environments!")
parser.add_argument("--headless", action="store_true", default=False, help="Force display off at all times.")
args_cli = parser.parse_args()
# launch omniverse app
config = {"headless": args_cli.headless}
simulation_app = SimulationApp(config)
๋ค์์ผ๋ก importํ๋ orbit์ core
๋ชจ๋์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
prim_utils
: ํ์ฌ USD stage์ prim์ ์์ฑํ๊ธฐ ์ํ ๋ชจ๋. (์์ธํ prim์ ๋ํ ๋ด์ฉ์ ๋ค์ ํฌ์คํ ์์ ๋ค๋ฃจ๋๋ก ํ๊ฒ ์ต๋๋ค. ์ฐ์ ๊ฐ๋จํ๊ฒ ์๋ฎฌ๋ ์ดํฐ์ ์ค๋ธ์ ํธ๋ค์prim
์ผ๋ก ๋ณธ๋ค๊ณ ์๊ฐํ๊ณ ์งํํ๊ฒ ์ต๋๋ค.)SimulationContext
: ํ์๋ผ์ธ ๊ด๋ จ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๊ณ (simulator ์ผ์ ์ค์ง, ์ฌ์, ๋จ๊ณ์ ์คํ ๋๋ ์ค์ง ๋ฑ), stage๋ฅผ ๊ตฌ์ฑํ๋ฉฐ(stage ๋จ์๋ ์/ํ ๋ฐฉํฅ๊ณผ ๊ฐ์ ์ค์ ),physicsScene
prim์ ์์ฑํฉ๋๋ค(์ค๋ ฅ ๋ฐฉํฅ ๋ฐ ํฌ๊ธฐ, ์๋ฎฌ๋ ์ด์ ์๊ฐ ๊ฐ๊ฒฉ ํฌ๊ธฐ, ๊ณ ๊ธ ์๋ฒ ์๊ณ ๋ฆฌ์ฆ ์ค์ ๊ณผ ๊ฐ์ ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์ ๋งค๊ฐ ๋ณ์๋ฅผ ์ ๊ณต). ์ฌ๊ธฐ์physicsScene
prim์ ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์ ์ ์ํ ์ด๊ธฐํ ๋ฐ ์ค์ ์ ๋ด๋นํ๋ ๊ฐ์ฒด๋ฅผ ๋งํ๋ฉฐ,SimulationContext
๋ ์ด๋ฌํphysicsScene
prim์ ์์ฑํ๊ณ ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์ ์ค์ ์ ๊ด๋ฆฌํ๋ฉฐ, ํ์๋ผ์ธ ๊ด๋ จ ์ด๋ฒคํธ ์ฒ๋ฆฌ์ ์คํ ์ด์ง ์ค์ ์ ๋ด๋นํฉ๋๋ค.set_camera_view
: stage์์ ์นด๋ฉ๋ผ prim์ ์์น์ ๋์์ ์ค์ ํ๊ณ , ํด๋น prim์ ๊ฒฝ๋ก๋ฅผ ์ง์ ํฉ๋๋ค. ์ฌ๊ธฐ์ ์นด๋ฉ๋ผ prim์ stage ์นด๋ฉ๋ผ๋ก ์ฌ์ฉ๋ ๊ฐ์ฒด๋ฅผ ์๋ฏธํ๋ฉฐ, ์์น(location)์ ๋์(target)์ ๊ฐ๊ฐ ์นด๋ฉ๋ผ์ ์์น์ ์นด๋ฉ๋ผ๊ฐ ๋ฐ๋ผ๋ณด๋ ๋์์ ์์น๋ฅผ ์ง์ ํ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ๊ฒฝ๋ก(path)๋ ์คํ ์ด์ง์์ ํด๋น ์นด๋ฉ๋ผ prim์ ๊ฐ๋ฆฌํค๋ ์ด๋ฆ์ด๋ ๊ฒฝ๋ก๋ฅผ ์๋ฏธํฉ๋๋ค.
์ด์ธ์ ๋ชจ๋์ค์์ kit_utils
๋ ์๋ฎฌ๋ ์ดํฐ์์ ์ ๊ณตํ๋ ground๋ฅผ ๋ถ๋ฌ์ค๊ธฐ ์ํ(create_ground_plane
) ๋ชจ๋์ด๋ฉฐ ๋ก๋ด์ ๋ฐ ์์น ๋ง์ปค๋ฅผ ํ์ํ๊ธฐ ์ํด markers
๋ชจ๋์์ PointMarker
, StaticMarker
๋ฅผ ๋ถ๋ฌ์ต๋๋ค.
๋ค์์ผ๋ก robot
๋ชจ๋์์ 4์กฑ๋ณดํ๋ก๋ด๋ค์ ์ํ configuration๋ค์ ๋ถ๋ฌ์ฌ ์ ์์ต๋๋ค.
# from core
import omni.isaac.core.utils.prims as prim_utils
from omni.isaac.core.simulation_context import SimulationContext
from omni.isaac.core.utils.viewports import set_camera_view
import omni.isaac.orbit.utils.kit as kit_utils
from omni.isaac.orbit.markers import PointMarker, StaticMarker
from omni.isaac.orbit.robots.config.anymal import ANYMAL_B_CFG, ANYMAL_C_CFG
from omni.isaac.orbit.robots.config.unitree import UNITREE_A1_CFG
from omni.isaac.orbit.robots.legged_robot import LeggedRobot
2.2 Helpers
Main ์ฝ๋์์ ์๋ฎฌ๋ ์ดํฐ์ Scene์ ๊ตฌ์ฑํ๊ธฐ ์ํด์ Ground-plane
, Lights
๋ค์ ํธํ๊ฒ ๊ตฌ์ฑํ๊ธฐ ์ํด์ helper ํจ์ design_scene()
๋ฅผ ๋ง๋ค์ด์ค๋๋ค. ์์ importํ๋ kit_utils
๋ฅผ ์ด์ฉํด์ ground๋ฅผ ๋ถ๋ฌ์ค๊ณ prim_utils
๋ฅผ ์ด์ฉํ์ฌ ๋น ์ค์ ์ ํด์ค๋๋ค.
def design_scene():
"""Add prims to the scene."""
# Ground-plane
kit_utils.create_ground_plane(
"/World/defaultGroundPlane",
static_friction=0.5,
dynamic_friction=0.5,
restitution=0.8,
improve_patch_friction=True,
)
# Lights-1
prim_utils.create_prim(
"/World/Light/GreySphere",
"SphereLight",
translation=(4.5, 3.5, 10.0),
attributes={"radius": 2.5, "intensity": 600.0, "color": (0.75, 0.75, 0.75)},
)
# Lights-2
prim_utils.create_prim(
"/World/Light/WhiteSphere",
"SphereLight",
translation=(-4.5, 3.5, 10.0),
attributes={"radius": 2.5, "intensity": 600.0, "color": (1.0, 1.0, 1.0)},
)
2.3 Main
๋ฉ์ธ ์ฝ๋์์๋ ๋จผ์ SimulationContext
๋ฅผ ์ด์ฉํ์ฌ ์๋ฎฌ๋ ์ดํฐ์ ์๊ฐ๊ด๋ จ ์ค์ ๋ฑ์ ์งํํฉ๋๋ค. dt๊ฐ 0.005๋ผ๋ ๊ฒ์ ์๊ฐ ๋จ์๊ฐ second๋ก ์๊ฐ๊ฐ๊ฒฉ์ด 0.005์ด๋ก ์ค์ ํ๋ ๊ฒ์ ๋งํฉ๋๋ค. ๋ํ backend๋ ์ดํ ํฌ์คํ
์์๋ ์ค๋ช
ํ๊ฒ ์ง๋ง ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ดํฐ์์ ๋ฐํ๋๋ tensor๋ค์ ์ด๋ค backend๋ก ์บ์คํ
ํ ๊ฒ์ธ์ง ์ค์ ํ๋ ๋ถ๋ถ์
๋๋ค. ํ์ฌ orbit์์๋ torch
๋ง ์ง์ํ๊ณ ์์ต๋๋ค.
์๋ฎฌ๋ ์ดํฐ์ ์์ ์ด ๋๋ ์นด๋ฉ๋ผ๋ฅผ ์ค์ ํ๊ณ ๊ฐ ๋ก๋ด์ ์ด๋์ ๋์์ง ์ ํ๋ translation
ํ๋ผ๋ฏธํฐ์ ํจ๊ป spawningํ๊ณ ๋ง์ง๋ง์ผ๋ก helper ํจ์๋ก ๋ง๋ค์ด์ฃผ์๋ design_scene()
์ ์ด์ฉํ์ฌ ground์ light๋ฅผ ์ค์ ํฉ๋๋ค.
"""Imports all legged robots supported in Orbit and applies zero actions."""
# Load kit helper
sim = SimulationContext(stage_units_in_meters=1.0, physics_dt=0.005, rendering_dt=0.005, backend="torch")
# Set main camera
set_camera_view(eye=[3.5, 3.5, 3.5], target=[0.0, 0.0, 0.0])
# Spawn things into stage
# -- anymal-b
robot_b = LeggedRobot(cfg=ANYMAL_B_CFG)
robot_b.spawn("/World/Anymal_b/Robot_1", translation=(0.0, -1.5, 0.65))
robot_b.spawn("/World/Anymal_b/Robot_2", translation=(0.0, -0.5, 0.65))
# -- anymal-c
robot_c = LeggedRobot(cfg=ANYMAL_C_CFG)
robot_c.spawn("/World/Anymal_c/Robot_1", translation=(1.5, -1.5, 0.65))
robot_c.spawn("/World/Anymal_c/Robot_2", translation=(1.5, -0.5, 0.65))
# -- unitree a1
robot_a = LeggedRobot(cfg=UNITREE_A1_CFG)
robot_a.spawn("/World/Unitree_A1/Robot_1", translation=(1.5, 0.5, 0.42))
robot_a.spawn("/World/Unitree_A1/Robot_2", translation=(1.5, 1.5, 0.42))
# design props
design_scene()
์๋ฎฌ๋ ์ดํฐ๋ฅผ ์ด๊ธฐํํ๋ reset์ ๋จผ์ ์งํํด์ค๋๋ค. ๊ฐ ๋ก๋ด์ handle ๋ํ ์ด๊ธฐํ๋ฅผ ์์ผ์ค๋๋ค. ๋ก๋ด์ ๊ฐ ์ ๋ณด๋ฅผ ๋ด๊ธฐ ์ํ buffer๋ reset์ ํด์ ๋ณธ๊ฒฉ์ ์ธ ์คํ์ ์ค๋นํฉ๋๋ค.
# Play the simulator
sim.reset()
# Acquire handles
# Initialize handles
robot_b.initialize("/World/Anymal_b/Robot.*")
robot_c.initialize("/World/Anymal_c/Robot.*")
robot_a.initialize("/World/Unitree_A1/Robot.*")
# Reset states
robot_b.reset_buffers()
robot_c.reset_buffers()
robot_a.reset_buffers()
4์กฑ ๋ณดํ ๋ก๋ด์ ์ ์ด๋ฅผ ํ ๋ ๋ฐ์ ์์ง์์ด ๋งค์ฐ ์ค์ํฉ๋๋ค. ๋ฐ์ ์์น์ ๋ง์ปค๋ฅผ ์์น์์ผ์ ๋ฐ์ ๋ํ ์ ๋ณด๋ฅผ ์ป๊ธฐ ์ํด marker๋ฅผ ์ค์ ํด์ค๋๋ค. ๋ฐ์ x, y, z ์ถ์ ์๊ฐํํ๊ธฐ ์ํด์ StaticMarker
๋ฅผ ์ด์ฉํ์ฌ ์ค์ ํ๊ณ ๋ฐ์ด contact ํฌ์ธํธ๋ฅผ ๋ณด๊ธฐ ์ํด PointMarker
๋ฅผ ์ค์ ํฉ๋๋ค.
# Debug visualization markers.
# -- feet markers
feet_markers: List[StaticMarker] = list()
feet_contact_markers: List[PointMarker] = list()
# iterate over robots
for robot_name in ["Anymal_b", "Anymal_c", "Unitree_A1"]:
# foot
marker = StaticMarker(f"/World/Visuals/{robot_name}/feet", 4 * robot_c.count, scale=(0.1, 0.1, 0.1))
feet_markers.append(marker)
# contact
marker = PointMarker(f"/World/Visuals/{robot_name}/feet_contact", 4 * robot_c.count, radius=0.035)
feet_contact_markers.append(marker)
๊ฐ ๋ก๋ด์ action์ ํ๊ฒ๋๊ณ ์ด๋ฅผ ๋ก๋ด์ ์ ์ดํ๋ค๊ณ ๋ณผ ์ ์์ต๋๋ค. get_default_dof_state()
์ ๋ก๋ด์ ๊ฐ ๊ฐ์ฒด์ ์๋ method๋ก ๊ฐ ๋ก๋ด์ standing ์์ธ์ ๋ํ joint position(dof) ์ ๋ณด๊ฐ ๋ค์ด์์ต๋๋ค.
# dummy action
actions = torch.zeros(robot_a.count, robot_a.num_actions, device=robot_a.device)
# Define simulation stepping
sim_dt = sim.get_physics_dt()
sim_time = 0.0
count = 0
# Simulate physics
while simulation_app.is_running():
# If simulation is stopped, then exit.
if sim.is_stopped():
break
# If simulation is paused, then skip.
if not sim.is_playing():
sim.step(render=not args_cli.headless)
continue
# reset
if count % 1000 == 0:
# reset counters
sim_time = 0.0
count = 0
# reset dof state
for robot in [robot_a, robot_b, robot_c]:
dof_pos, dof_vel = robot.get_default_dof_state()
robot.set_dof_state(dof_pos, dof_vel)
robot.reset_buffers()
# reset command
actions = torch.zeros(robot_a.count, robot_a.num_actions, device=robot_a.device)
print(">>>>>>>> Reset!")
# apply actions
robot_b.apply_action(actions)
robot_c.apply_action(actions)
robot_a.apply_action(actions)
# perform step
sim.step()
# update sim-time
sim_time += sim_dt
count += 1
์๋ฎฌ๋ ์ดํฐ ์ด๊ธฐํํ ๋ resetํ๋ buffer์ ๊ฐ ๋ก๋ด์ ์ ๋ณด๋ฅผ ๋ด์ต๋๋ค. marker๋ก ์ค์ ํด๋์๋ foot_marker
์ contact_marker
๋ ๊ฐ ๋ก๋ด์์ ๋ถ๋ฌ์์ state update๋ฅผ ์งํํฉ๋๋ค.
# note: to deal with timeline events such as stopping, we need to check if the simulation is playing
if sim.is_playing():
# update buffers
robot_b.update_buffers(sim_dt)
robot_c.update_buffers(sim_dt)
robot_a.update_buffers(sim_dt)
# update marker positions
for foot_marker, contact_marker, robot in zip(
feet_markers, feet_contact_markers, [robot_b, robot_c, robot_a]
):
# feet
foot_marker.set_world_poses(
robot.data.feet_state_w[..., 0:3].view(-1, 3), robot.data.feet_state_w[..., 3:7].view(-1, 4)
)
# contact sensors
contact_marker.set_world_poses(
robot.data.feet_state_w[..., 0:3].view(-1, 3), robot.data.feet_state_w[..., 3:7].view(-1, 4)
)
contact_marker.set_status(torch.where(robot.data.feet_air_time.view(-1) > 0.0, 1, 2))
3 Closing
์ด๋ฒ ํฌ์คํ
์์๋ standalone example๋ก ๋์์๋ play_quadrupeds.py
์ฝ๋์ ์ ์ฒด์ ์ธ ๊ตฌ์ฑ๊ณผ ์ฝ๋์ ๋ํด ์์๋ณด์์ต๋๋ค. ์์ง orbit์ ๋ง์ ๋ชจ๋๋ค์ ์ต์ํ์ง ์์ roughํ๊ฒ ์ฝ๋์ ํ๋ฆ์ ์ดํด๋ณด์์ง๋ง ๋ค์ ํฌ์คํ
์์๋ ๊ฐ์ฅ ๊ฐ๋จํ empty scene์์ ์์ํ๋ฉด์ ์ข ๋ ์์ธํ ์ดํด๋ณผ ์์ ์ด๋ ๋ค์ ํฌ์คํ
์์ ์ข ๋ orbit๊ณผ ์นํด์ ธ๋ด
์๋ค.