与关节交互#

本教程展示了如何与模拟中的关节机器人进行交互。这是 与刚性物体交互 教程的延续,其中我们学习了如何与刚体对象交互。除了设置根状态外,我们还将看到如何设置关节状态并向关节机器人应用命令。

代码#

该教程对应于 source/standalone/tutorials/01_assets 目录中的 run_articulation.py 脚本。

代码 run_articulation.py 的内容
  1# Copyright (c) 2022-2024, The Isaac Lab Project Developers.
  2# All rights reserved.
  3#
  4# SPDX-License-Identifier: BSD-3-Clause
  5
  6"""This script demonstrates how to spawn a cart-pole and interact with it.
  7
  8.. code-block:: bash
  9
 10    # Usage
 11    ./isaaclab.sh -p source/standalone/tutorials/01_assets/run_articulation.py
 12
 13"""
 14
 15"""Launch Isaac Sim Simulator first."""
 16
 17
 18import argparse
 19
 20from omni.isaac.lab.app import AppLauncher
 21
 22# add argparse arguments
 23parser = argparse.ArgumentParser(description="Tutorial on spawning and interacting with an articulation.")
 24# append AppLauncher cli args
 25AppLauncher.add_app_launcher_args(parser)
 26# parse the arguments
 27args_cli = parser.parse_args()
 28
 29# launch omniverse app
 30app_launcher = AppLauncher(args_cli)
 31simulation_app = app_launcher.app
 32
 33"""Rest everything follows."""
 34
 35import torch
 36
 37import omni.isaac.core.utils.prims as prim_utils
 38
 39import omni.isaac.lab.sim as sim_utils
 40from omni.isaac.lab.assets import Articulation
 41from omni.isaac.lab.sim import SimulationContext
 42
 43##
 44# Pre-defined configs
 45##
 46from omni.isaac.lab_assets import CARTPOLE_CFG  # isort:skip
 47
 48
 49def design_scene() -> tuple[dict, list[list[float]]]:
 50    """Designs the scene."""
 51    # Ground-plane
 52    cfg = sim_utils.GroundPlaneCfg()
 53    cfg.func("/World/defaultGroundPlane", cfg)
 54    # Lights
 55    cfg = sim_utils.DomeLightCfg(intensity=3000.0, color=(0.75, 0.75, 0.75))
 56    cfg.func("/World/Light", cfg)
 57
 58    # Create separate groups called "Origin1", "Origin2"
 59    # Each group will have a robot in it
 60    origins = [[0.0, 0.0, 0.0], [-1.0, 0.0, 0.0]]
 61    # Origin 1
 62    prim_utils.create_prim("/World/Origin1", "Xform", translation=origins[0])
 63    # Origin 2
 64    prim_utils.create_prim("/World/Origin2", "Xform", translation=origins[1])
 65
 66    # Articulation
 67    cartpole_cfg = CARTPOLE_CFG.copy()
 68    cartpole_cfg.prim_path = "/World/Origin.*/Robot"
 69    cartpole = Articulation(cfg=cartpole_cfg)
 70
 71    # return the scene information
 72    scene_entities = {"cartpole": cartpole}
 73    return scene_entities, origins
 74
 75
 76def run_simulator(sim: sim_utils.SimulationContext, entities: dict[str, Articulation], origins: torch.Tensor):
 77    """Runs the simulation loop."""
 78    # Extract scene entities
 79    # note: we only do this here for readability. In general, it is better to access the entities directly from
 80    #   the dictionary. This dictionary is replaced by the InteractiveScene class in the next tutorial.
 81    robot = entities["cartpole"]
 82    # Define simulation stepping
 83    sim_dt = sim.get_physics_dt()
 84    count = 0
 85    # Simulation loop
 86    while simulation_app.is_running():
 87        # Reset
 88        if count % 500 == 0:
 89            # reset counter
 90            count = 0
 91            # reset the scene entities
 92            # root state
 93            # we offset the root state by the origin since the states are written in simulation world frame
 94            # if this is not done, then the robots will be spawned at the (0, 0, 0) of the simulation world
 95            root_state = robot.data.default_root_state.clone()
 96            root_state[:, :3] += origins
 97            robot.write_root_state_to_sim(root_state)
 98            # set joint positions with some noise
 99            joint_pos, joint_vel = robot.data.default_joint_pos.clone(), robot.data.default_joint_vel.clone()
100            joint_pos += torch.rand_like(joint_pos) * 0.1
101            robot.write_joint_state_to_sim(joint_pos, joint_vel)
102            # clear internal buffers
103            robot.reset()
104            print("[INFO]: Resetting robot state...")
105        # Apply random action
106        # -- generate random joint efforts
107        efforts = torch.randn_like(robot.data.joint_pos) * 5.0
108        # -- apply action to the robot
109        robot.set_joint_effort_target(efforts)
110        # -- write data to sim
111        robot.write_data_to_sim()
112        # Perform step
113        sim.step()
114        # Increment counter
115        count += 1
116        # Update buffers
117        robot.update(sim_dt)
118
119
120def main():
121    """Main function."""
122    # Load kit helper
123    sim_cfg = sim_utils.SimulationCfg(device=args_cli.device)
124    sim = SimulationContext(sim_cfg)
125    # Set main camera
126    sim.set_camera_view([2.5, 0.0, 4.0], [0.0, 0.0, 2.0])
127    # Design scene
128    scene_entities, scene_origins = design_scene()
129    scene_origins = torch.tensor(scene_origins, device=sim.device)
130    # Play the simulator
131    sim.reset()
132    # Now we are ready!
133    print("[INFO]: Setup complete...")
134    # Run the simulator
135    run_simulator(sim, scene_entities, scene_origins)
136
137
138if __name__ == "__main__":
139    # run the main function
140    main()
141    # close sim app
142    simulation_app.close()

代码解析#

场景设计#

与上一个教程相似,我们在场景中添加了地面平面和远程光线。现在,我们不再产生刚性物体,而是从其 USD 文件中生成一个车杆关节。车杆是一个简单的机器人,由一个小车和一个连接到它的杆组成。小车可以沿 x 轴自由移动,而杆可以围绕小车自由旋转。车杆的 USD 文件包含了机器人的几何形状、关节和其他物理性质。

对于车杆,我们使用其预定义的配置对象,这是 assets.ArticulationCfg 类的一个实例。这个类包含关于关节产生策略、默认初始状态、不同关节的执行器模型和其他元信息的信息。如何创建这个配置对象的更深入介绍在 编写资产配置 教程中提供。

正如在上一个教程中看到的,我们可以通过创建 assets.Articulation 类的实例并将配置对象传递给它的构造函数的方式类似地将关节放入场景中。

    # Create separate groups called "Origin1", "Origin2"
    # Each group will have a robot in it
    origins = [[0.0, 0.0, 0.0], [-1.0, 0.0, 0.0]]
    # Origin 1
    prim_utils.create_prim("/World/Origin1", "Xform", translation=origins[0])
    # Origin 2
    prim_utils.create_prim("/World/Origin2", "Xform", translation=origins[1])

    # Articulation
    cartpole_cfg = CARTPOLE_CFG.copy()
    cartpole_cfg.prim_path = "/World/Origin.*/Robot"
    cartpole = Articulation(cfg=cartpole_cfg)

运行模拟循环#

从上一个教程中继续,我们定期重置模拟,对关节机器人设置命令,推进模拟,并更新关节机器人的内部缓冲区。

重置模拟#

与刚体物体类似,关节机器人也有一个根状态。这个状态对应于关节机器人树中的根体。在根状态之上,关节机器人还有关节状态。这些状态对应于关节的位置和速度。

为了重置关节机器人,我们首先通过调用 Articulation.write_root_state_to_sim() 方法设置根状态。类似地,我们通过调用 Articulation.write_joint_state_to_sim() 方法设置关节状态。最后,我们调用 Articulation.reset() 方法重置任何内部缓冲区和缓存。

            # reset the scene entities
            # root state
            # we offset the root state by the origin since the states are written in simulation world frame
            # if this is not done, then the robots will be spawned at the (0, 0, 0) of the simulation world
            root_state = robot.data.default_root_state.clone()
            root_state[:, :3] += origins
            robot.write_root_state_to_sim(root_state)
            # set joint positions with some noise
            joint_pos, joint_vel = robot.data.default_joint_pos.clone(), robot.data.default_joint_vel.clone()
            joint_pos += torch.rand_like(joint_pos) * 0.1
            robot.write_joint_state_to_sim(joint_pos, joint_vel)
            # clear internal buffers
            robot.reset()

推进模拟#

向关节机器人应用命令涉及两个步骤:

  1. 设置关节目标: 这为关节机器人设置期望的关节位置、速度或努力目标。

  2. 将数据写入模拟: 根据关节机器人的配置,这一步处理任何 动作转换 并将转换后的值写入 PhysX 缓冲区。

在本教程中,我们使用关节努力命令来控制关节机器人。为此工作,我们需要将关节机器人的刚度和阻尼参数设置为零。这是在车杆的预定义配置对象内部预先完成的。

在每一步中,我们随机采样关节努力并通过调用 Articulation.set_joint_effort_target() 方法将它们设置给关节机器人。在设置好目标后,我们通过调用 Articulation.write_data_to_sim() 方法将数据写入 PhysX 缓冲区。最后,我们推进模拟。

        # Apply random action
        # -- generate random joint efforts
        efforts = torch.randn_like(robot.data.joint_pos) * 5.0
        # -- apply action to the robot
        robot.set_joint_effort_target(efforts)
        # -- write data to sim
        robot.write_data_to_sim()

更新状态#

每个关节机器人类包含一个 assets.ArticulationData 对象。这个对象保存了关节机器人的状态。为了更新缓冲区内的状态,我们调用 assets.Articulation.update() 方法。

        # Update buffers
        robot.update(sim_dt)

代码执行#

要运行代码并查看结果,让我们从终端运行脚本:

./isaaclab.sh -p source/standalone/tutorials/01_assets/run_articulation.py

这个命令应该会打开一个包含地面平面、灯光和两个随机移动的cart-poles的场景。要停止模拟,您可以关闭窗口,或在终端中按 Ctrl+C

run_articulation.py 的结果

在本教程中,我们学会了如何创建和交互一个简单的关节机器人。我们看到了如何设置关节机器人的状态(其根和关节状态),以及如何对其应用命令。我们还看到了如何更新其缓冲区,以从模拟中读取最新状态。

除了这个教程之外,我们还提供了一些生成不同机器人的其他脚本。这些包括在 source/standalone/demos 目录中。您可以运行这些脚本,比如:

# Spawn many different single-arm manipulators
./isaaclab.sh -p source/standalone/demos/arms.py

# Spawn many different quadrupeds
./isaaclab.sh -p source/standalone/demos/quadrupeds.py