第三章、Isaac sim Python脚本(2):Core API概述及教程(Hello World)

第三章、Isaac sim Python脚本(2):Core API概述及教程(Hello World)

0 前言

Debugging With Visual Studio Code官方文档:https://docs.isaacsim.omniverse.nvidia.com/latest/utilities/debugging/tutorial_advanced_python_debugging.html
API官方文档:https://docs.isaacsim.omniverse.nvidia.com/latest/reference_python_api.html
NVIDIA Isaac Sim 中的 Python 脚本可以通过两种方式完成:独立(standalone)和交互式(interactive)。独立 Python 脚本从命令行执行,用于自动执行任务或进行模拟。交互式 Python 脚本在 Python 控制台中执行,用于探索 NVIDIA Isaac Sim API 和调试代码片段。这两种类型的脚本都可用于创建自定义扩展,例如新的机器人控制器或传感器,以及与 Omniverse 应用程序交互。

该章内容主要由以下几个方面展开:

  • 配置vscode
  • Core API 概述
  • Core API 教程

注:后续部分接之前的内容继续

1 Core API 概述

Isaac Sim Core API 是原始USD和物理引擎API包,该包为适应机器人应用而量身定制。官网给出了一部分代码案例(是基于原始API的了解即可)。该部分不做过多叙述,你可以在你的路径中创建一个test.py文件并将该部分内容复制粘贴进去,利用上一章中的交互方式,逐段运行,并在isaacsim窗口中实时的看变化。

2 Core API 教程

本教程,首先,介绍Core API的概念及使用方法。我们首先在场景中添加一个立方体,并在此基础上创建一个多机器人同时执行多个任务的场景,如下图所示
在这里插入图片描述本教程的学习目标:

  • BaseSample、World、Scene类。
  • 通过 Python 向场景添加物体。
  • 添加回调函数。
  • 访问对象的动态属性。
  • 独立程序和应用扩展程序的主要区别。

3 Hello World

1 打开isaac sim
进入Isaac sim 文件夹中,打开终端,输入如下命令启动Isaac sim

./isaac-sim.sh

默认界面如下所示:
在这里插入图片描述
2 打开机器人示例中的源码
按照下图红色框位置依次点击,就可以在vscode中打开该示例的源代码,可以在此基础上进行编辑。
在这里插入图片描述同样的点击8右侧的文件夹图标就可以打开源码所在的文件夹。该文件夹中包含下图文件:
在这里插入图片描述
脚本hello_world.py是应用程序逻辑添加的地方,hello_world_extension.py脚本用来添加应用程序的UI元素中并从而与脚本hello_world.py相链接。

3 如何在以有场景的情况下加载空场景
按照下图红色框位置依次点击,并在弹出的弹框中选择Don't Save
在这里插入图片描述在这里插入图片描述

4 代码概述

1 BaseSample
打开isaacsim/examples/interactive/hello_world/hello_world.py该代码继承自 BaseSample 类,这是一个基础模板类,所有具体的机器人扩展应用都可以继承它,避免重复写底层代码,它提供了一些所有机器人应用都需要的通用功能包括:

  • 加载世界和资产:通过一个按钮初始化模拟环境(例如机器人、场景、物体等)。
  • 清除世界:当创建新场景(stage)时,清理旧场景的资产。
  • 重置对象状态:将模拟环境中的物体恢复到初始位置或状态。
  • 热重载(hot reloading):允许修改代码后实时更新模拟环境,无需重启程序(类似游戏开发中的热更新)。

2 World
作用:该类使用户可以通过简单且模块化的方式实现与机器人模拟器(simulator)的交互,负责管理时间、添加回调、物理模拟、场景重置和添加任务等操作。

3 Scene
一个世界包含一个场景实例。Scene 类管理 USD 场景(Stage)中感兴趣的模拟资产。它提供了一个简单的 API 来添加、操作、检查和重置场景中的不同 USD 资产。

# 从 Isaac Sim 的代码库中导入名为 BaseSample 的基类
from isaacsim.examples.interactive.base_sample import BaseSample #boiler plate of a robotics extension application

# 定义一个名为 HelloWorld 的类,继承自 BaseSample
class HelloWorld(BaseSample):
# 构造函数:初始化 HelloWorld 类实例。
   # super().__init__():调用父类 BaseSample 的构造函数,确保基类的初始化逻辑(如资源加载、模拟器连接)正确执行。
   # return:显式声明返回 None(Python 中可省略)
    def __init__(self) -> None:
        super().__init__()
        return

    # This function is called to setup the assets in the scene for the first time
    # Class variables should not be assigned here, since this function is not called
    # after a hot-reload, its only called to load the world starting from an EMPTY stage
    # 重写父类 BaseSample 的 setup_scene 方法,用于自定义场景的初始化内容。
    # 触发时机:当场景需要加载时(如点击“LOAD”按钮),Isaac Sim 会自动调用此方法。
    # 在热重载时不会加载这个方法
    def setup_scene(self):
        # A world is defined in the BaseSample, can be accessed everywhere EXCEPT __init__
        world = self.get_world()
        # 获取 World 实例:通过 self.get_world() 方法从父类 BaseSample 中获取 World 类的实例。
        # World 是控制模拟器的核心工具,后续通过 world 对象操作场景(如添加物体、控制物理模拟)。
        world.scene.add_default_ground_plane() # adds a default ground plane to the scene
        # 添加默认地面:调用 World 场景的 add_default_ground_plane() 方法,在模拟器中生成一个默认的地面平面。
        return

4 Singleton World(只有一个世界)

在运行 NVIDIA Isaac Sim 时只能存在一个 World,并提供一个全局访问点获取该实例。若存在多个 World 实例,可能导致物理模拟混乱或资源冲突。

from isaacsim.examples.interactive.base_sample import BaseSample
from isaacsim.core.api import World

class HelloWorld(BaseSample):
    def __init__(self) -> None:
        super().__init__()
        return

    def setup_scene(self):
        world = World.instance()
        # 通过单例的全局访问方法 instance() 获取 World 的唯一实例。
        # 与 self.get_world() 的区别:
        # 1 self.get_world() 是 BaseSample 提供的方法,内部可能调用 World.instance()。
        # 2 直接使用 World.instance() 更底层,适用于不依赖 BaseSample 的场景。
        world.scene.add_default_ground_plane()
        return

5 Adding to the Scene(将刚体加入场景)

使用 Python API 将立方体作为刚体添加到场景中。这里只按照官网给出一段代码,最后会给出一个完整的代码。

from isaacsim.examples.interactive.base_sample import BaseSample
import numpy as np
# Can be used to create a new cube or to point to an already existing cube in stage.
from isaacsim.core.api.objects import DynamicCuboid

class HelloWorld(BaseSample):
    def __init__(self) -> None:
        super().__init__()
        return

    def setup_scene(self):
        world = self.get_world()
        world.scene.add_default_ground_plane()
        fancy_cube = world.scene.add(
        # world.scene.add():将物体添加到场景中,并返回该物体的引用(此处为 fancy_cube)
            DynamicCuboid(
                prim_path="/World/random_cube", # The prim path of the cube in the USD stage
                name="fancy_cube", # The unique name used to retrieve the object from the scene later on
                position=np.array([0, 0, 1.0]), # Using the current stage units which is in meters by default.
                scale=np.array([0.5015, 0.5015, 0.5015]), # most arguments accept mainly numpy arrays.
                color=np.array([0, 0, 1.0]), # RGB channels, going from 0-1
            ))
            # DynamicCuboid 参数详解:
            # 1 prim_path:立方体在 USD(Universal Scene Description)场景中的唯一路径。
            # 2 name:立方体的逻辑名称,用于后续从场景中检索对象(如 world.scene.get_object("fancy_cube"))。
            # 3 position:立方体的初始位置(三维坐标)。默认米为单位。
            # 4 scale:立方体的尺寸缩放(长、宽、高)。
            # 5 color:立方体的 RGB 颜色,取值范围 [0.0, 1.0]。
        return
  • 按Ctrl+S保存代码并热重新加载 NVIDIA Isaac Sim。
  • 再次打开菜单。
  • 点击File > New From Stage Template >Empty,然后点击LOAD按钮。如果你在setup_scene中更改了任何内容,则需要执行此操作。否则,你只需按LOAD按钮即可。
  • 按下PLAY按钮开始模拟动态立方体并观察它掉落。(注:如果感兴趣可以调整isaacsim中的physicsScene下的Gravity Direction即重力方向,再点击PLAY按钮会发现方块向你设定的方向自由落体。be like 盗梦空间~)
    在这里插入图片描述

6 Inspecting Object Properties(查看对象性质)

打印立方体的世界姿势和速度。

from isaacsim.examples.interactive.base_sample import BaseSample
import numpy as np
from isaacsim.core.api.objects import DynamicCuboid

class HelloWorld(BaseSample):
    def __init__(self) -> None:
        super().__init__()
        return

    def setup_scene(self):
        world = self.get_world()
        world.scene.add_default_ground_plane()
        fancy_cube = world.scene.add(
            DynamicCuboid(
                prim_path="/World/random_cube",
                name="fancy_cube",
                position=np.array([0, 0, 1.0]),
                scale=np.array([0.5015, 0.5015, 0.5015]),
                color=np.array([0, 0, 1.0]),
            ))
        return

    # Here we assign the class's variables
    # this function is called after load button is pressed
    # regardless starting from an empty stage or not
    # this is called after setup_scene and after
    # one physics time step to propagate appropriate
    # physics handles which are needed to retrieve
    # many physical properties of the different objects
    async def setup_post_load(self):
        self._world = self.get_world()
        # self.get_world():从父类 BaseSample 继承的方法,返回全局唯一的 World 单例实例。
        self._cube = self._world.scene.get_object("fancy_cube")
        # self._world.scene.get_object():通过名称(name) "fancy_cube" 从场景中获取之前添加的立方体对象。
        position, orientation = self._cube.get_world_pose()
        # get_world_pose() 方法:返回立方体的全局坐标系下的位置和方向。
        linear_velocity = self._cube.get_linear_velocity()
        # get_linear_velocity() 方法:返回立方体在全局坐标系下的线速度(三维向量)。
        # will be shown on terminal
        print("Cube position is : " + str(position))
        print("Cube's orientation is : " + str(orientation))
        print("Cube's linear velocity is : " + str(linear_velocity))
        return

7 Continuously Inspecting the Object Properties during Simulation(在仿真模拟过程中持续检查对象属性)

这段代码实现了 在 Isaac Sim 的物理模拟过程中,实时监控并打印立方体的位置、方向和速度信息。通过注册物理回调函数(physics callback),在每次物理步进(physics step)前执行自定义逻辑(打印物体状态)。

from isaacsim.examples.interactive.base_sample import BaseSample
import numpy as np
from isaacsim.core.api.objects import DynamicCuboid

class HelloWorld(BaseSample):
    def __init__(self) -> None:
        super().__init__()
        return

    def setup_scene(self):
        world = self.get_world()
        world.scene.add_default_ground_plane()
        fancy_cube = world.scene.add(
            DynamicCuboid(
                prim_path="/World/random_cube",
                name="fancy_cube",
                position=np.array([0, 0, 1.0]),
                scale=np.array([0.5015, 0.5015, 0.5015]),
                color=np.array([0, 0, 1.0]),
            ))
        return

    async def setup_post_load(self):
        self._world = self.get_world()
        self._cube = self._world.scene.get_object("fancy_cube")
        self._world.add_physics_callback("sim_step", callback_fn=self.print_cube_info) #callback names have to be unique
        # add_physics_callback("sim_step", callback_fn=self.print_cube_info):
        # 功能:向 World 实例添加一个物理回调函数
        # 参数:
        # 1 "sim_step":回调函数名称(需唯一,避免与其他回调冲突)。
        # 2 callback_fn=self.print_cube_info:回调函数本身(每次物理步进前调用)。
        # 触发时机:在 Isaac Sim 的物理引擎执行每个物理步进(step_physics)之前调用。
        return

    # here we define the physics callback to be called before each physics step, all physics callbacks must take
    # step_size as an argument
    def print_cube_info(self, step_size):
    	 # 物理回调函数 print_cube_info
    	 # 参数:step_size(物理步长时间,单位为秒)。
    	 # Isaac Sim 要求所有物理回调函数必须接收此参数(即使未使用)。
        position, orientation = self._cube.get_world_pose()
        # 获取立方体状态:位置、方向、线速度。
        linear_velocity = self._cube.get_linear_velocity()
        # will be shown on terminal
        print("Cube position is : " + str(position))
        print("Cube's orientation is : " + str(orientation))
        print("Cube's linear velocity is : " + str(linear_velocity))
        # 打印信息:将状态输出到终端。

8 Converting the Example to a Standalone Application(将示例转换为独立程序)

什么是独立程序呢?
简单来说就是可以直接在命令行输入./python.sh ***.py运行的程序。

#launch Isaac Sim before any other imports
#default first two lines in any standalone application
# 初始化并启动 Isaac Sim 应用程序。
from isaacsim import SimulationApp
simulation_app = SimulationApp({"headless": False}) # we can also run as headless.

from isaacsim.core.api import World
from isaacsim.core.api.objects import DynamicCuboid
import numpy as np

# 创建 World 单例实例(全局唯一)。注意没有.instance()
world = World()
# 在场景中添加无限延伸的默认地面,用于物理碰撞检测。
world.scene.add_default_ground_plane()
# 添加动态立方体
fancy_cube =  world.scene.add(
    DynamicCuboid(
        prim_path="/World/random_cube",
        name="fancy_cube",
        position=np.array([0, 0, 1.0]),
        scale=np.array([0.5015, 0.5015, 0.5015]),
        color=np.array([0, 0, 1.0]),
    ))
# Resetting the world needs to be called before querying anything related to an articulation specifically.
# Its recommended to always do a reset after adding your assets, for physics handles to be propagated properly
# 重置世界:在查询物体属性(如速度、位姿)或启动模拟前,必须调用此方法。
# 1 初始化所有物理句柄(如刚体、关节的物理属性)。
# 2 确保新添加的物体(如立方体)正确注册到物理引擎。
world.reset()
# 推进物理模拟并监控状态
for i in range(500):
# 循环 500 次:执行 500 次物理步进
    position, orientation = fancy_cube.get_world_pose()
    linear_velocity = fancy_cube.get_linear_velocity()
    # # 获取立方体状态
    # will be shown on terminal
    print("Cube position is : " + str(position))
    print("Cube's orientation is : " + str(orientation))
    print("Cube's linear velocity is : " + str(linear_velocity))
    # we have control over stepping physics and rendering in this workflow
    # things run in sync
    world.step(render=True) # execute one physics step and one rendering step
    # 推进模拟
    # 1 物理步进:按默认步长(通常 1/60 秒)更新物理引擎。
    # 2 渲染更新:更新 3D 窗口中的视觉效果(因 render=True)。
simulation_app.close() # close Isaac Sim
# 安全关闭 Isaac Sim 进程,释放资源。

补充:将循环部分代码替换为如下代码,方块会运行到下面归位重置再次继续仿真

for j in range(5):
    world.reset()
    for i in range(50):
        position, orientation = fancy_cube.get_world_pose()
        linear_velocity = fancy_cube.get_linear_velocity()
        # will be shown on terminal
        print("Cube position is : " + str(position))
        print("Cube's orientation is : " + str(orientation))
        print("Cube's linear velocity is : " + str(linear_velocity))
        # we have control over stepping physics and rendering in this workflow
        # things run in sync
        world.step(render=True) # execute one physics step and one rendering step
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值