Isaac Sim 4.5 API参考文档(一)(时效性2025.5)

1,264 阅读42分钟

Isaac Sim API 文档索引

官方手册: docs.isaacsim.omniverse.nvidia.com/4.5.0/refer…

📚 本文档集合概述

本文档集合按功能分类整理了Isaac Sim的主要API,适合学习和快速查阅。涵盖了从基础核心API到高级功能的完整参考。


📑 文档目录

斜体的文档内容位于Isaac Sim 4.5 API参考文档(二)

🏗️ 基础组件

文档描述主要功能
核心API核心API接口World、PhysicsContext、SimulationContext等基础类
场景与任务场景管理和预定义任务Scene管理、Task框架、场景注册等
材质与物理材质系统和物理属性视觉材质、物理材质、粒子材质等

🤖 机器人相关

文档描述主要功能
机器人机器人相关API机械臂、轮式机器人、抓取器等
控制器各种控制器实现关节控制、抓取控制、运动控制等
机器人示例机器人示例代码Franka、UR10等常用机器人示例
运动规划运动规划和行为控制路径规划、行为树等

📡 传感与环境

文档描述主要功能
传感器传感器相关API相机、激光雷达、接触传感器等
对象与几何3D对象和几何体基本形状、关节对象等

🔧 工具与集成

文档描述主要功能
导入工具资产导入工具URDF、MJCF等格式导入
仿真工具仿真相关工具数据生成、UI组件等
ROS2集成ROS2相关集成和桥接ROS2消息、服务、话题等

🚀 快速开始示例

from isaacsim.core.api import World
from omni.isaac.franka import Franka
from isaacsim.core.api.objects import DynamicCuboid
import numpy as np

# 1. 创建仿真世界
world = World()
world.scene.add_default_ground_plane()

# 2. 添加机器人
robot = world.scene.add(Franka(prim_path="/World/Franka", name="my_franka"))

# 3. 添加物体
cube = world.scene.add(
    DynamicCuboid(
        prim_path="/World/Cube",
        name="target_cube",
        position=np.array([0.3, 0.0, 0.05]),
        size=0.04,
        color=np.array([1.0, 0.0, 0.0])
    )
)

# 4. 初始化并运行仿真
world.reset()

for i in range(1000):
    world.step(render=True)
    
    # 在这里添加你的控制逻辑
    if i % 100 == 0:
        print(f"Step {i}: Robot position = {robot.get_world_pose()[0]}")

📖 学习资源

官方资源

社区资源


ℹ️ 使用说明

  1. 查找API: 通过上方的表格快速定位所需功能模块
  2. 示例学习: 查看机器人示例文档获取实际应用代码
  3. 深入了解: 查看具体文档了解详细API参考
  4. 问题解决: 参考官方论坛或GitHub仓库解决实际问题

🤝 贡献指南

如您想为本文档做出贡献:

  1. 提交问题或建议到相关GitHub仓库
  2. 为新功能编写示例代码
  3. 改进现有的文档说明
  4. 分享使用经验和最佳实践

最后更新: 2025-05-10
版本: Isaac Sim 4.5.0
维护者: scilwb

Isaac Sim API - 核心API

📋 概述

核心API接口,包括World、PhysicsContext、SimulationContext等基础类。这些类构成了Isaac Sim仿真的基础架构。


🌟 主要类

🌍 World类

位置: isaacsim.core.api.World

功能说明: 主要仿真世界类,继承自SimulationContext,提供完整的仿真环境管理功能。

代码示例:

from isaacsim.core.api import World

# 创建世界
world = World(
    physics_dt=1.0/60.0,         # 物理时间步长
    rendering_dt=1.0/60.0,       # 渲染时间步长
    stage_units_in_meters=1.0,   # 场景单位
    backend="numpy"              # 后端选择
)

# 添加默认地面
world.scene.add_default_ground_plane()

# 重置世界
world.reset()

# 运行仿真
for i in range(1000):
    world.step(render=True)

关键方法:

  • _init_stage (self, physics_dt=None, rendering_dt=None, ...) → Usd.Stage

    • 初始化舞台
    • 设置物理和渲染参数
  • _initialize_stage_async (self, physics_dt=None, rendering_dt=None, ...) → Usd.Stage

    • 异步初始化舞台
    • 支持异步操作
  • add_physics_callback (self, callback_name: str, callback_fn: Callable[[float], None]) → None

    • 添加物理步骤回调函数
    • 在每次物理步骤前调用
  • add_render_callback (self, callback_name: str, callback_fn: Callable) → None

    • 添加渲染回调函数
    • 在每次渲染后调用
  • add_stage_callback (self, callback_name: str, callback_fn: Callable) → None

    • 添加舞台事件回调
    • 处理打开/关闭等事件

⚡ PhysicsContext类

位置: isaacsim.core.api.PhysicsContext

功能说明: 提供物理场景及其设置的高级管理功能。处理物理场景的创建、配置和管理。

代码示例:

from isaacsim.core.api import PhysicsContext

# 创建物理上下文
physics_context = PhysicsContext(
    physics_dt=1.0/60.0,                    # 物理时间步长
    prim_path="/physicsScene",              # 物理场景路径
    set_defaults=True                       # 设置默认值
)

# 启用功能
physics_context.enable_ccd(True)            # 启用连续碰撞检测
physics_context.enable_gpu_dynamics(True)   # 启用GPU动力学
physics_context.enable_stablization(True)   # 启用稳定化

关键方法:

  • enable_ccd (self, flag: bool) → None

    • 启用连续碰撞检测
    • 防止高速物体穿透
  • enable_gpu_dynamics (self, flag: bool) → None

    • 启用GPU动力学管道
    • 用于可变形体等
  • enable_stablization (self, flag: bool) → None

    • 启用求解器稳定化
    • 提高物理稳定性
  • get_broadphase_type (self) → str

    • 获取广相碰撞检测算法类型
  • get_current_physics_scene_prim (self) → Optional[Usd.Prim]

    • 返回当前物理场景Prim

🔄 SimulationContext类

位置: isaacsim.core.api.SimulationContext

功能说明: 处理时间相关事件,管理物理和渲染步骤,包含PhysicsContext实例。

代码示例:

from isaacsim.core.api import SimulationContext

# 创建仿真上下文
sim_context = SimulationContext(
    physics_dt=1.0/60.0,        # 物理时间步
    rendering_dt=1.0/60.0,      # 渲染时间步
    backend="numpy",            # 后端
    device="cuda"               # 设备
)

# 添加回调函数
def my_physics_callback(dt):
    print(f"Physics step: dt={dt}")

sim_context.add_physics_callback("my_callback", my_physics_callback)

关键方法:

  • add_physics_callback (self, callback_name: str, callback_fn: Callable[[float], None]) → None

    • 添加物理步骤回调函数
  • add_render_callback (self, callback_name: str, callback_fn: Callable) → None

    • 添加渲染回调函数
  • add_stage_callback (self, callback_name: str, callback_fn: Callable) → None

    • 添加舞台事件回调
  • _physics_timer_callback_fn (self, step_size: int)

    • 物理计时器回调函数
  • _timeline_timer_callback_fn (self, event)

    • 时间轴计时器回调函数

💡 实际应用示例

创建完整的仿真环境

from isaacsim.core.api import World, PhysicsContext
import numpy as np

class MySimulation:
    def __init__(self):
        # 创建世界
        self.world = World(physics_dt=1.0/120.0)  # 高精度物理
        
        # 配置物理
        physics_context = self.world.get_physics_context()
        physics_context.enable_ccd(True)
        physics_context.enable_gpu_dynamics(True)
        
        # 添加回调
        self.setup_callbacks()
        
    def setup_callbacks(self):
        # 物理回调
        self.world.add_physics_callback("physics_update", self.physics_update)
        
        # 渲染回调
        self.world.add_render_callback("render_update", self.render_update)
        
    def physics_update(self, dt):
        # 在每个物理步骤执行
        print(f"Physics step: {dt}")
        
    def render_update(self):
        # 在每个渲染步骤执行
        pass
        
    def run(self):
        # 重置世界
        self.world.reset()
        
        # 运行仿真
        for i in range(1000):
            self.world.step(render=True)
            
            # 每100步打印信息
            if i % 100 == 0:
                print(f"Simulation step: {i}")

# 使用示例
sim = MySimulation()
sim.run()

异步仿真初始化

import asyncio
from isaacsim.core.api import World

async def async_simulation_setup():
    # 创建世界
    world = World()
    
    # 异步初始化舞台
    await world._initialize_stage_async(
        physics_dt=1.0/60.0,
        rendering_dt=1.0/30.0,
        set_defaults=True
    )
    
    # 添加地面
    world.scene.add_default_ground_plane()
    
    # 重置世界
    world.reset()
    
    return world

# 运行异步初始化
async def main():
    world = await async_simulation_setup()
    
    # 运行仿真
    for i in range(100):
        world.step(render=True)
        await asyncio.sleep(0.01)  # 模拟异步操作

# 执行
asyncio.run(main())

🔧 常见问题解决

1. 物理不稳定问题

# 增加物理精度,启用额外功能
physics_context = world.get_physics_context()
physics_context.set_physics_dt(1.0/180.0)  # 更高频率
physics_context.enable_stablization(True)   # 稳定化
physics_context.enable_ccd(True)           # 连续碰撞检测

2. 性能优化

# 使用GPU加速
world = World(
    physics_dt=1.0/60.0,
    backend="torch",     # 使用PyTorch后端
    device="cuda"        # 使用GPU
)

# 启用GPU动力学
physics_context = world.get_physics_context()
physics_context.enable_gpu_dynamics(True)

3. 回调函数管理

class CallbackManager:
    def __init__(self, world):
        self.world = world
        self.callbacks = {}
        
    def add_callback(self, name, callback_type, function):
        if callback_type == "physics":
            self.world.add_physics_callback(name, function)
        elif callback_type == "render":
            self.world.add_render_callback(name, function)
        
        self.callbacks[name] = (callback_type, function)
        
    def remove_callback(self, name):
        if name in self.callbacks:
            callback_type, _ = self.callbacks[name]
            if callback_type == "physics":
                self.world.remove_physics_callback(name)
            elif callback_type == "render":
                self.world.remove_render_callback(name)
            del self.callbacks[name]

📚 API继承关系

BaseClass
    ↓
SimulationContext
    ↓
World
  • World 继承 SimulationContext
  • SimulationContext 包含 PhysicsContext
  • 每个类都有特定的职责和功能

最后更新: 2025-05-10
版本: Isaac Sim 4.5.0

Isaac Sim API - 场景与任务

📋 概述

场景管理和预定义任务,提供完整的场景构建和任务规划框架。支持灵活的场景对象管理和模块化任务设计。


🎬 场景管理

🌍 Scene类

位置: isaacsim.core.api.scenes.Scene

功能说明: 管理场景中的所有对象,处理对象注册、状态重置等。

代码示例:

from isaacsim.core.api.scenes import Scene
from isaacsim.core.api.objects import DynamicCuboid, GroundPlane
from isaacsim.robot.manipulators import SingleManipulator
import numpy as np

# 创建场景实例
scene = Scene()

# 添加地面平面
ground_plane = scene.add_default_ground_plane(
    z_position=0,
    name="default_ground",
    static_friction=0.5,
    dynamic_friction=0.5,
    restitution=0.8
)

# 添加物体
cube = scene.add(DynamicCuboid(
    prim_path="/World/Cube",
    name="target_cube",
    position=np.array([0.3, 0.0, 0.05]),
    size=0.04,
    color=np.array([1.0, 0.0, 0.0])
))

# 添加机器人
robot = scene.add(SingleManipulator(
    prim_path="/World/Robot",
    name="my_robot",
    end_effector_prim_name="end_effector"
))

# 获取场景对象
retrieved_cube = scene.get_object("target_cube")
retrieved_robot = scene.get_object("my_robot")

# 检查对象是否存在
if scene.object_exists("target_cube"):
    print("Cube found in scene")

# 计算对象边界框
min_bounds, max_bounds = scene.compute_object_AABB("target_cube")
print(f"Cube bounds: min={min_bounds}, max={max_bounds}")

# 启用边界框计算
scene.enable_bounding_boxes_computations()

# 清空场景(可选仅清空注册表)
scene.clear(registry_only=False)  # 清空整个场景
scene.clear(registry_only=True)   # 仅清空注册表

关键方法:

  • add (self, obj: SingleXFormPrim) → SingleXFormPrim

    • 添加对象到场景注册表
  • add_default_ground_plane (self, z_position=0, name='default_ground_plane', ...) → GroundPlane

    • 创建并添加默认地面平面
  • add_ground_plane (self, size=None, z_position=0, name='ground_plane', ...) → GroundPlane

    • 创建并添加自定义地面平面
  • get_object (self, name: str) → SingleXFormPrim

    • 根据名称获取注册的对象
  • object_exists (self, name: str) → bool

    • 检查对象是否存在于场景中
  • compute_object_AABB (self, name: str) → Tuple[numpy.ndarray, numpy.ndarray]

    • 计算对象的轴对齐边界框
  • enable_bounding_boxes_computations (self) → None

    • 启用边界框计算
  • disable_bounding_boxes_computations (self) → None

    • 禁用边界框计算
  • clear (self, registry_only: bool = False) → None

    • 清空场景或仅清空注册表

📝 SceneRegistry类

位置: isaacsim.core.api.scenes.SceneRegistry

功能说明: 追踪和管理场景中不同类型的对象。

代码示例:

from isaacsim.core.api.scenes import SceneRegistry

# 创建场景注册表
registry = SceneRegistry()

# 注册不同类型的对象
registry.add_articulated_system("robot1", robot)
registry.add_rigid_object("cube1", cube)
registry.add_sensor("camera1", camera)
registry.add_task("pick_place", pick_place_task)
registry.add_material("plastic", plastic_material)
registry.add_deformable("cloth1", cloth_object)

# 按类型获取对象
robots = registry.get_articulated_systems()
cubes = registry.get_rigid_objects()
cameras = registry.get_sensors()

# 获取特定对象
robot = registry.get_articulated_system("robot1")
cube = registry.get_rigid_object("cube1")

# 获取所有对象名称
all_names = registry.get_all_object_names()

对象类型方法:

关节系统:

  • add_articulated_system(name, system)
  • get_articulated_system(name)
  • get_articulated_systems()

关节视图:

  • add_articulated_view(name, view)
  • get_articulated_view(name)
  • get_articulated_views()

刚体对象:

  • add_rigid_object(name, object)
  • get_rigid_object(name)
  • get_rigid_objects()

几何对象:

  • add_geometry_object(name, object)
  • get_geometry_object(name)
  • get_geometry_objects()

可变形体:

  • add_deformable(name, deformable)
  • get_deformable(name)
  • get_deformables()

布料:

  • add_cloth(name, cloth)
  • get_cloth(name)
  • get_cloths()

材质:

  • add_material(name, material)
  • get_material(name)
  • get_materials()

传感器:

  • add_sensor(name, sensor)
  • get_sensor(name)
  • get_sensors()

任务:

  • add_task(name, task)
  • get_task(name)
  • get_tasks()

回调管理:

  • add_callbacks(callbacks)
  • get_callbacks_on_physics_step()
  • get_callbacks_on_render()

📋 任务框架

📚 BaseTask类

位置: isaacsim.core.api.tasks.BaseTask

功能说明: 任务的基础类,提供模块化的任务设计框架。

代码示例:

from isaacsim.core.api.tasks import BaseTask
import numpy as np

class CustomTask(BaseTask):
    def __init__(self, name="my_task", offset=None):
        super().__init__(name=name, offset=offset)
        
        # 定义任务所需的观测值
        self.observation_space = {
            "robot_joint_positions": 7,  # 机器人关节位置
            "object_position": 3,        # 物体位置
            "object_orientation": 4      # 物体方向
        }
        
        # 初始化任务状态
        self.reset()
        
    def set_up_scene(self, scene: Scene) → None:
        """设置场景"""
        super().set_up_scene(scene)
        
        # 添加场景对象
        self.robot = scene.add(SingleManipulator(
            prim_path="/World/Robot",
            name="task_robot"
        ))
        
        self.target_object = scene.add(DynamicCuboid(
            prim_path="/World/Target",
            name="target_object",
            position=np.array([0.5, 0.0, 0.05])
        ))
        
        # 设置为任务对象
        self._task_objects = {
            "robot": self.robot,
            "target": self.target_object
        }
        
    def get_observations(self) → dict:
        """获取观测值"""
        observations = super().get_observations()
        
        # 添加任务特定的观测
        observations.update({
            "robot_joint_positions": self.robot.get_joint_positions(),
            "object_position": self.target_object.get_world_pose()[0],
            "object_orientation": self.target_object.get_world_pose()[1]
        })
        
        return observations
        
    def calculate_metrics(self) → dict:
        """计算任务指标"""
        # 计算成功率、距离等指标
        robot_ee_pos, _ = self.robot.get_end_effector_pose()
        object_pos, _ = self.target_object.get_world_pose()
        
        distance = np.linalg.norm(robot_ee_pos - object_pos)
        
        return {
            "distance_to_object": distance,
            "success": distance < 0.05,
        }
        
    def is_done(self) → bool:
        """检查任务是否完成"""
        metrics = self.calculate_metrics()
        return metrics.get("success", False)
        
    def get_description(self) → str:
        """获取任务描述"""
        return "Move robot end-effector to target object"
        
    def get_params(self) → dict:
        """获取任务参数"""
        return {
            "task_type": "reach",
            "target_object": "cube",
            "robot_type": "manipulator"
        }
        
    def post_reset(self) → None:
        """重置后调用"""
        super().post_reset()
        
        # 重置物体位置
        random_pos = np.array([
            np.random.uniform(0.3, 0.7),
            np.random.uniform(-0.3, 0.3),
            0.05
        ])
        self.target_object.set_world_pose(position=random_pos)
        
    def pre_step(self, time_step_index: int, simulation_time: float) → None:
        """仿真步前调用"""
        super().pre_step(time_step_index, simulation_time)
        
        # 执行任务逻辑
        if time_step_index % 10 == 0:
            self.check_progress()
            
    def cleanup(self) → None:
        """清理临时对象"""
        # 清理任务创建的临时对象
        pass

# 使用自定义任务
task = CustomTask(name="reach_task")
world.add_task(task)

关键方法:

  • set_up_scene (self, scene: Scene) → None

    • 设置任务场景
  • get_observations (self) → dict

    • 获取当前观测值
  • calculate_metrics (self) → dict

    • 计算任务相关指标
  • is_done (self) → bool

    • 检查任务是否完成
  • get_description (self) → str

    • 获取任务描述
  • get_params (self) → dict

    • 获取任务参数
  • get_task_objects (self) → dict

    • 获取任务相关对象
  • post_reset (self) → None

    • 重置后调用
  • pre_step (self, time_step_index: int, simulation_time: float) → None

    • 仿真步前调用
  • cleanup (self) → None

    • 清理临时对象

🎯 预定义任务

📦 拾放任务 - PickPlace

位置: isaacsim.core.api.tasks.PickPlace

功能说明: 模拟机器人拾放操作的任务。

代码示例:

from isaacsim.core.api.tasks import PickPlace
import numpy as np

# 创建拾放任务
pick_place_task = PickPlace(
    name="pick_place_demo",
    cube_initial_position=np.array([0.3, 0.0, 0.05]),
    cube_initial_orientation=np.array([0, 0, 0, 1]),
    target_position=np.array([0.5, 0.0, 0.05]),
    cube_size=np.array([0.04, 0.04, 0.04]),
    offset=np.array([0, 0, 0])
)

# 设置场景
pick_place_task.set_up_scene(scene)

# 执行任务循环
for i in range(1000):
    # 获取观测
    observations = pick_place_task.get_observations()
    print(f"Observations: {observations}")
    
    # 计算指标
    metrics = pick_place_task.calculate_metrics()
    print(f"Metrics: {metrics}")
    
    # 检查是否完成
    if pick_place_task.is_done():
        print("Task completed!")
        break
        
    # 执行仿真步
    world.step(render=True)
    
# 清理任务
pick_place_task.cleanup()

关键属性:

  • cube_initial_position: 立方体初始位置
  • cube_initial_orientation: 立方体初始方向
  • target_position: 目标放置位置
  • cube_size: 立方体尺寸

🎯 跟随目标任务 - FollowTarget

位置: isaacsim.core.api.tasks.FollowTarget

功能说明: 让机器人跟随移动目标的任务。

代码示例:

from isaacsim.core.api.tasks import FollowTarget

# 创建跟随目标任务
follow_task = FollowTarget(
    name="follow_demo",
    target_prim_path=None,           # 自动创建目标
    target_name="moving_target",
    target_position=np.array([1.0, 0.0, 0.5]),
    target_orientation=np.array([0, 0, 0, 1]),
    offset=np.array([0, 0, 0])
)

# 设置场景
follow_task.set_up_scene(scene)

# 添加障碍物
obstacle_pos = np.array([0.5, 0.5, 0.1])
follow_task.add_obstacle(position=obstacle_pos)

# 执行任务
for i in range(1000):
    # 更新目标位置(模拟运动轨迹)
    time = i * 0.01
    target_pos = np.array([
        0.5 + 0.5 * np.cos(time),
        0.5 * np.sin(time),
        0.5
    ])
    follow_task.set_target_position(target_pos)
    
    # 获取观测
    observations = follow_task.get_observations()
    
    # 计算指标
    metrics = follow_task.calculate_metrics()
    
    # 检查是否完成
    if follow_task.is_done():
        print("Target reached!")
        
    # 执行仿真步
    world.step(render=True)
    
    # 动态管理障碍物
    if i == 500:
        follow_task.add_obstacle(position=np.array([0.8, 0.2, 0.1]))
    if i == 700:
        follow_task.remove_obstacle()

关键方法:

  • add_obstacle (self, position=None)

    • 添加障碍物
  • get_obstacle_to_delete (self) → None

    • 获取要删除的障碍物

📚 堆叠任务 - Stacking

位置: isaacsim.core.api.tasks.Stacking

功能说明: 多物体堆叠任务。

代码示例:

from isaacsim.core.api.tasks import Stacking

# 创建堆叠任务
stacking_task = Stacking(
    name="stacking_demo",
    cube_initial_positions=np.array([
        [0.2, -0.2, 0.025],
        [0.3, 0.0, 0.025],
        [0.4, 0.2, 0.025]
    ]),
    cube_initial_orientations=None,  # 使用默认方向
    stack_target_position=np.array([0.6, 0.0, 0.025]),
    cube_size=np.array([0.03, 0.03, 0.05]),
    offset=np.array([0, 0, 0])
)

# 设置场景
stacking_task.set_up_scene(scene)

# 获取立方体名称
cube_names = stacking_task.get_cube_names()
print(f"Cubes to stack: {cube_names}")

# 执行堆叠任务
for i in range(2000):
    # 预步处理
    stacking_task.pre_step(i, world.current_time)
    
    # 获取观测
    observations = stacking_task.get_observations()
    
    # 计算指标
    metrics = stacking_task.calculate_metrics()
    print(f"Stacking metrics: {metrics}")
    
    # 检查是否完成
    if stacking_task.is_done():
        print("Stacking completed!")
        break
        
    # 执行仿真步
    world.step(render=True)
    
# 重置任务
stacking_task.post_reset()

关键方法:

  • get_cube_names (self) → List[str]

    • 获取立方体名称列表
  • pre_step (self, time_step_index: int, simulation_time: float) → None

    • 每步前处理

💡 实际应用示例

多任务管理器

class TaskManager:
    def __init__(self, scene):
        self.scene = scene
        self.tasks = {}
        self.current_task = None
        self.task_history = []
        
    def add_task(self, task_name, task):
        """添加任务"""
        self.tasks[task_name] = task
        task.set_up_scene(self.scene)
        
    def start_task(self, task_name):
        """开始执行任务"""
        if task_name not in self.tasks:
            raise ValueError(f"Task {task_name} not found")
            
        # 结束当前任务
        if self.current_task:
            self.current_task.cleanup()
            
        # 开始新任务
        self.current_task = self.tasks[task_name]
        self.current_task.post_reset()
        self.task_history.append(task_name)
        
        print(f"Started task: {task_name}")
        
    def update_current_task(self):
        """更新当前任务"""
        if not self.current_task:
            return None
            
        # 获取观测
        observations = self.current_task.get_observations()
        
        # 计算指标
        metrics = self.current_task.calculate_metrics()
        
        # 检查是否完成
        is_done = self.current_task.is_done()
        
        return {
            "observations": observations,
            "metrics": metrics,
            "is_done": is_done
        }
        
    def get_task_sequence(self):
        """获取任务序列"""
        return self.task_history
        
    def execute_task_sequence(self, task_sequence, max_steps_per_task=1000):
        """执行任务序列"""
        results = []
        
        for task_name in task_sequence:
            print(f"Executing task: {task_name}")
            self.start_task(task_name)
            
            # 执行任务直到完成或超时
            for step in range(max_steps_per_task):
                # 预步处理
                self.current_task.pre_step(step, step * 0.01)
                
                # 更新任务
                task_result = self.update_current_task()
                
                # 执行仿真步
                world.step(render=True)
                
                # 检查是否完成
                if task_result["is_done"]:
                    results.append({
                        "task": task_name,
                        "status": "completed",
                        "steps": step + 1,
                        "metrics": task_result["metrics"]
                    })
                    break
            else:
                # 超时
                results.append({
                    "task": task_name,
                    "status": "timeout",
                    "steps": max_steps_per_task,
                    "metrics": task_result["metrics"]
                })
        
        return results

# 使用示例
task_manager = TaskManager(scene)

# 添加多个任务
task_manager.add_task("pick_place_1", PickPlace(
    name="pick_1",
    cube_initial_position=np.array([0.3, 0.0, 0.05]),
    target_position=np.array([0.5, 0.0, 0.05])
))

task_manager.add_task("pick_place_2", PickPlace(
    name="pick_2",
    cube_initial_position=np.array([0.4, 0.2, 0.05]),
    target_position=np.array([0.6, 0.2, 0.05])
))

task_manager.add_task("stacking", Stacking(
    name="stack_3_cubes",
    cube_initial_positions=np.array([
        [0.3, -0.1, 0.025],
        [0.3, 0.0, 0.025],
        [0.3, 0.1, 0.025]
    ]),
    stack_target_position=np.array([0.7, 0.0, 0.025])
))

# 执行任务序列
task_sequence = ["pick_place_1", "pick_place_2", "stacking"]
results = task_manager.execute_task_sequence(task_sequence)

# 打印结果
for result in results:
    print(f"Task: {result['task']}")
    print(f"Status: {result['status']}")
    print(f"Steps: {result['steps']}")
    print(f"Metrics: {result['metrics']}")
    print("---")

场景配置管理器

class SceneConfigurationManager:
    def __init__(self):
        self.configurations = {}
        
    def save_configuration(self, name, scene):
        """保存场景配置"""
        config = {
            "objects": {},
            "materials": {},
            "lighting": {},
            "physics": {}
        }
        
        # 保存所有注册对象
        registry = scene.scene_registry
        for obj_name in registry.get_all_object_names():
            obj = registry.get_object(obj_name)
            config["objects"][obj_name] = {
                "type": type(obj).__name__,
                "prim_path": obj.prim_path,
                "position": obj.get_world_pose()[0].tolist() if hasattr(obj, 'get_world_pose') else None,
                "orientation": obj.get_world_pose()[1].tolist() if hasattr(obj, 'get_world_pose') else None
            }
        
        self.configurations[name] = config
        print(f"Saved configuration: {name}")
        
    def load_configuration(self, name, scene):
        """加载场景配置"""
        if name not in self.configurations:
            raise ValueError(f"Configuration {name} not found")
            
        config = self.configurations[name]
        
        # 清空当前场景
        scene.clear(registry_only=False)
        
        # 重建场景
        for obj_name, obj_config in config["objects"].items():
            # 这里需要根据对象类型创建相应的对象
            # 简化示例
            if obj_config["type"] == "DynamicCuboid":
                obj = DynamicCuboid(
                    prim_path=obj_config["prim_path"],
                    name=obj_name,
                    position=np.array(obj_config["position"]) if obj_config["position"] else None,
                    orientation=np.array(obj_config["orientation"]) if obj_config["orientation"] else None
                )
                scene.add(obj)
                
        print(f"Loaded configuration: {name}")
        
    def list_configurations(self):
        """列出所有配置"""
        return list(self.configurations.keys())
        
    def create_configuration_from_template(self, name, template_type):
        """根据模板创建配置"""
        templates = {
            "pick_place": {
                "objects": {
                    "robot": {"type": "Franka", "position": [0, 0, 0]},
                    "cube": {"type": "DynamicCuboid", "position": [0.3, 0.0, 0.05]},
                    "table": {"type": "FixedCuboid", "position": [0.5, 0, -0.5]}
                }
            },
            "assembly": {
                "objects": {
                    "robot": {"type": "UR10", "position": [0, -0.5, 0]},
                    "part1": {"type": "DynamicCuboid", "position": [0.2, 0.2, 0.05]},
                    "part2": {"type": "DynamicCuboid", "position": [0.3, 0.2, 0.05]},
                    "assembly_area": {"type": "FixedCuboid", "position": [0.5, 0, 0]}
                }
            }
        }
        
        if template_type in templates:
            self.configurations[name] = templates[template_type]
        else:
            raise ValueError(f"Template {template_type} not found")

# 使用示例
config_manager = SceneConfigurationManager()

# 保存当前场景配置
config_manager.save_configuration("pick_place_scenario", scene)

# 创建模板配置
config_manager.create_configuration_from_template("assembly_task", "assembly")

# 加载配置
config_manager.load_configuration("assembly_task", scene)

# 列出所有配置
configs = config_manager.list_configurations()
print(f"Available configurations: {configs}")

任务性能分析器

class TaskPerformanceAnalyzer:
    def __init__(self):
        self.metrics_history = {}
        self.task_timelines = {}
        
    def start_analysis(self, task_name):
        """开始分析任务"""
        self.metrics_history[task_name] = []
        self.task_timelines[task_name] = {
            "start_time": time.time(),
            "events": []
        }
        
    def record_metrics(self, task_name, step, metrics):
        """记录指标"""
        if task_name not in self.metrics_history:
            self.start_analysis(task_name)
            
        timestamp = time.time()
        record = {
            "step": step,
            "timestamp": timestamp,
            "metrics": metrics.copy()
        }
        
        self.metrics_history[task_name].append(record)
        
    def record_event(self, task_name, event_type, description):
        """记录事件"""
        if task_name not in self.task_timelines:
            self.start_analysis(task_name)
            
        event = {
            "timestamp": time.time(),
            "type": event_type,
            "description": description
        }
        
        self.task_timelines[task_name]["events"].append(event)
        
    def analyze_task_performance(self, task_name):
        """分析任务性能"""
        if task_name not in self.metrics_history:
            return None
            
        metrics_history = self.metrics_history[task_name]
        timeline = self.task_timelines[task_name]
        
        # 计算统计信息
        completion_time = (metrics_history[-1]["timestamp"] - 
                          timeline["start_time"])
        total_steps = metrics_history[-1]["step"]
        
        # 分析成功/失败事件
        success_events = [e for e in timeline["events"] if e["type"] == "success"]
        failure_events = [e for e in timeline["events"] if e["type"] == "failure"]
        
        # 计算平均指标
        avg_metrics = {}
        for key in metrics_history[0]["metrics"].keys():
            values = [record["metrics"][key] for record in metrics_history 
                     if key in record["metrics"]]
            if values:
                avg_metrics[key] = np.mean(values)
        
        analysis = {
            "task_name": task_name,
            "completion_time": completion_time,
            "total_steps": total_steps,
            "average_metrics": avg_metrics,
            "success_count": len(success_events),
            "failure_count": len(failure_events),
            "timeline": timeline["events"]
        }
        
        return analysis
        
    def generate_report(self, task_names=None):
        """生成性能报告"""
        if task_names is None:
            task_names = list(self.metrics_history.keys())
            
        report = {
            "generation_time": time.time(),
            "tasks": {}
        }
        
        for task_name in task_names:
            analysis = self.analyze_task_performance(task_name)
            if analysis:
                report["tasks"][task_name] = analysis
        
        # 计算总体统计
        if task_names:
            report["summary"] = {
                "total_tasks": len(task_names),
                "average_completion_time": np.mean([
                    report["tasks"][t]["completion_time"] 
                    for t in task_names
                ]),
                "total_success_rate": (
                    sum(report["tasks"][t]["success_count"] for t in task_names) /
                    len(task_names)
                )
            }
        
        return report

# 使用示例
analyzer = TaskPerformanceAnalyzer()

# 分析任务执行
task_name = "pick_place_task"
analyzer.start_analysis(task_name)

for step in range(1000):
    # 记录指标
    metrics = task.calculate_metrics()
    analyzer.record_metrics(task_name, step, metrics)
    
    # 记录重要事件
    if metrics.get("success", False):
        analyzer.record_event(task_name, "success", "Task completed successfully")
        break
    elif step % 100 == 0:
        analyzer.record_event(task_name, "checkpoint", f"Step {step} reached")
    
    world.step(render=True)

# 生成报告
report = analyzer.generate_report()
print(json.dumps(report, indent=2))

🔧 常见问题解决

1. 场景对象管理

def debug_scene_objects(scene):
    """调试场景对象"""
    # 获取所有对象
    registry = scene.scene_registry
    all_objects = registry.get_all_object_names()
    
    print(f"Total objects: {len(all_objects)}")
    
    # 按类型分类
    object_types = {}
    for obj_name in all_objects:
        obj = registry.get_object(obj_name)
        obj_type = type(obj).__name__
        
        if obj_type not in object_types:
            object_types[obj_type] = []
        object_types[obj_type].append(obj_name)
    
    # 打印分类信息
    for obj_type, names in object_types.items():
        print(f"{obj_type}: {len(names)} objects")
        for name in names:
            print(f"  - {name}")

2. 任务状态管理

class TaskStateManager:
    def __init__(self):
        self.task_states = {}
        self.state_history = {}
        
    def save_state(self, task_name, state_data):
        """保存任务状态"""
        self.task_states[task_name] = state_data.copy()
        
        if task_name not in self.state_history:
            self.state_history[task_name] = []
        
        self.state_history[task_name].append({
            "timestamp": time.time(),
            "state": state_data.copy()
        })
        
    def restore_state(self, task_name):
        """恢复任务状态"""
        if task_name not in self.task_states:
            return None
        
        return self.task_states[task_name].copy()
        
    def get_state_history(self, task_name):
        """获取状态历史"""
        return self.state_history.get(task_name, [])

# 使用示例
state_manager = TaskStateManager()

# 保存当前状态
current_state = {
    "robot_position": robot.get_joint_positions(),
    "object_positions": {
        "cube1": cube1.get_world_pose()[0],
        "cube2": cube2.get_world_pose()[0]
    },
    "task_progress": 0.7
}

state_manager.save_state("stacking_task", current_state)

# 恢复状态
restored_state = state_manager.restore_state("stacking_task")
if restored_state:
    robot.set_joint_positions(restored_state["robot_position"])

3. 性能优化

class ScenePerformanceOptimizer:
    @staticmethod
    def optimize_physics_settings(world):
        """优化物理设置"""
        physics_context = world.get_physics_context()
        
        # 使用GPU物理
        physics_context.enable_gpu_dynamics(True)
        
        # 调整求解器参数
        physics_context.set_solver_iterations(4)
        physics_context.set_solver_type("PGS")
        
        # 启用CCD
        physics_context.enable_ccd(True)
        
    @staticmethod
    def optimize_rendering_settings(world):
        """优化渲染设置"""
        # 调整渲染频率
        world.set_rendering_dt(1/30.0)  # 30 FPS
        
        # 减少阴影质量
        # 设置LOD等级
        pass
        
    @staticmethod
    def batch_operations(scene, operations):
        """批量操作优化"""
        # 关闭实时更新
        scene.disable_bounding_boxes_computations()
        
        # 执行批量操作
        for operation in operations:
            operation()
        
        # 重新启用更新
        scene.enable_bounding_boxes_computations()

📊 任务类型对比

任务类型主要功能适用场景关键指标
PickPlace拾放物体基础操作训练成功率、时间
FollowTarget跟随移动目标跟踪控制跟踪误差、响应速度
Stacking物体堆叠精细操作堆叠高度、稳定性
CustomTask自定义任务特殊需求任务特定指标

最后更新: 2025-05-10
版本: Isaac Sim 4.5.0

Isaac Sim API - 材质与物理

📋 概述

材质系统和物理属性,包括视觉材质、物理材质等。涵盖从基础材质到高级物理特性的完整管理。


🎨 视觉材质

🌈 OmniPBR材质

位置: isaacsim.core.api.materials.OmniPBR

功能说明: 基于物理的渲染材质,支持完整的PBR工作流。

代码示例:

from isaacsim.core.api.materials import OmniPBR
import numpy as np

# 创建PBR材质
pbr_material = OmniPBR(
    prim_path="/World/Looks/MyPBRMaterial",
    name="my_pbr_material",
    color=np.array([0.8, 0.1, 0.1]),  # 基础颜色
    texture_path="/path/to/texture.png",
    texture_scale=np.array([2.0, 2.0])  # 纹理缩放
)

# 设置材质属性
pbr_material.set_color(np.array([0.9, 0.2, 0.2]))
pbr_material.set_metallic_constant(0.5)        # 金属度
pbr_material.set_reflection_roughness(0.3)     # 粗糙度
pbr_material.set_project_uvw(True)             # 启用UV投影

# 获取材质属性
color = pbr_material.get_color()
metallic = pbr_material.get_metallic_constant()
roughness = pbr_material.get_reflection_roughness()

# 应用到对象
object.apply_visual_material(pbr_material)

关键方法:

  • set_color (self, color: numpy.ndarray) → None

    • 设置基础颜色 (RGB)
  • get_color (self) → numpy.ndarray

    • 获取基础颜色
  • set_metallic_constant (self, amount: float) → None

    • 设置金属度 (0.0-1.0)
  • get_metallic_constant (self) → float

    • 获取金属度
  • set_reflection_roughness (self, amount: float) → None

    • 设置表面粗糙度
  • get_reflection_roughness (self) → float

    • 获取粗糙度
  • set_texture (self, texture_path: str) → None

    • 设置纹理贴图
  • get_texture (self) → str

    • 获取纹理路径
  • set_texture_scale (self, scale: numpy.ndarray) → None

    • 设置纹理缩放
  • get_texture_scale (self) → numpy.ndarray

    • 获取纹理缩放
  • set_texture_translate (self, translate: numpy.ndarray) → None

    • 设置纹理偏移
  • get_texture_translate (self) → numpy.ndarray

    • 获取纹理偏移
  • set_project_uvw (self, flag: bool) → None

    • 设置UV投影模式
  • get_project_uvw (self) → bool

    • 获取UV投影状态

🔍 OmniGlass材质

位置: isaacsim.core.api.materials.OmniGlass

功能说明: 高质量玻璃材质,支持折射和透射。

代码示例:

from isaacsim.core.api.materials import OmniGlass

# 创建玻璃材质
glass_material = OmniGlass(
    prim_path="/World/Looks/GlassMaterial",
    name="glass_material",
    color=np.array([0.8, 0.9, 1.0]),  # 玻璃颜色
    ior=1.5,                          # 折射率
    depth=0.02,                       # 厚度
    thin_walled=False                 # 是否薄壁
)

# 设置玻璃属性
glass_material.set_ior(1.3)          # 设置折射率
glass_material.set_depth(0.05)       # 设置厚度
glass_material.set_thin_walled(True) # 设置薄壁模式

# 获取属性
color = glass_material.get_color()
ior = glass_material.get_ior()
depth = glass_material.get_depth()
thin_walled = glass_material.get_thin_walled()

# 应用到对象
glass_object.apply_visual_material(glass_material)

关键方法:

  • set_color (self, color: numpy.ndarray) → None

    • 设置玻璃颜色
  • get_color (self) → Optional[numpy.ndarray]

    • 获取玻璃颜色
  • set_ior (self, ior: float) → None

    • 设置折射率 (Index of Refraction)
  • get_ior (self) → Optional[float]

    • 获取折射率
  • set_depth (self, depth: float) → None

    • 设置玻璃厚度
  • get_depth (self) → Optional[float]

    • 获取玻璃厚度
  • set_thin_walled (self, thin_walled: bool) → None

    • 设置薄壁模式
  • get_thin_walled (self) → Optional[bool]

    • 获取薄壁模式状态

📺 PreviewSurface材质

位置: isaacsim.core.api.materials.PreviewSurface

功能说明: 轻量级预览材质,适合快速原型。

代码示例:

from isaacsim.core.api.materials import PreviewSurface

# 创建预览材质
preview_material = PreviewSurface(
    prim_path="/World/Looks/PreviewMaterial",
    name="preview_material",
    color=np.array([0.5, 0.5, 0.5]),
    roughness=0.7,
    metallic=0.0
)

# 设置材质属性
preview_material.set_color(np.array([0.8, 0.4, 0.2]))
preview_material.set_roughness(0.5)
preview_material.set_metallic(0.1)

# 应用材质
object.apply_visual_material(preview_material)

关键方法:

  • set_color (self, color: numpy.ndarray) → None

    • 设置材质颜色
  • get_color (self) → numpy.ndarray

    • 获取材质颜色
  • set_roughness (self, roughness: float) → None

    • 设置粗糙度
  • get_roughness (self) → float

    • 获取粗糙度
  • set_metallic (self, metallic: float) → None

    • 设置金属度
  • get_metallic (self) → float

    • 获取金属度

⚙️ 物理材质

🧱 PhysicsMaterial材质

位置: isaacsim.core.api.materials.PhysicsMaterial

功能说明: 刚体物理材质,控制摩擦和弹性。

代码示例:

from isaacsim.core.api.materials import PhysicsMaterial

# 创建物理材质
physics_material = PhysicsMaterial(
    prim_path="/World/Physics/Material",
    name="physics_material",
    static_friction=0.7,    # 静摩擦系数
    dynamic_friction=0.5,   # 动摩擦系数
    restitution=0.3        # 弹性系数
)

# 设置物理属性
physics_material.set_static_friction(0.8)
physics_material.set_dynamic_friction(0.6)
physics_material.set_restitution(0.4)

# 获取属性
static_friction = physics_material.get_static_friction()
dynamic_friction = physics_material.get_dynamic_friction()
restitution = physics_material.get_restitution()

# 应用到刚体
rigid_body.apply_physics_material(physics_material)

关键方法:

  • set_static_friction (self, friction: float) → None

    • 设置静摩擦系数
  • get_static_friction (self) → float

    • 获取静摩擦系数
  • set_dynamic_friction (self, friction: float) → None

    • 设置动摩擦系数
  • get_dynamic_friction (self) → float

    • 获取动摩擦系数
  • set_restitution (self, restitution: float) → None

    • 设置弹性系数 (0.0-1.0)
  • get_restitution (self) → float

    • 获取弹性系数

🌊 DeformableMaterial材质

位置: isaacsim.core.api.materials.DeformableMaterial

功能说明: 可变形体材质,用于模拟软体。

代码示例:

from isaacsim.core.api.materials import DeformableMaterial

# 创建可变形材质
deformable_material = DeformableMaterial(
    prim_path="/World/Physics/DeformableMaterial",
    name="soft_material"
)

# 设置材质属性
deformable_material.set_youngs_modulus(1e6)      # 杨氏模量
deformable_material.set_poissons_ratio(0.3)      # 泊松比
deformable_material.set_damping_scale(0.1)       # 阻尼系数
deformable_material.set_elasticity_damping(0.1)  # 弹性阻尼
deformable_material.set_dynamic_friction(0.5)    # 摩擦系数

# 获取属性
youngs = deformable_material.get_youngs_modulus()
poisson = deformable_material.get_poissons_ratio()
damping = deformable_material.get_damping_scale()

# 应用到软体
soft_body.apply_deformable_material(deformable_material)

关键方法:

  • set_youngs_modulus (self, value: float) → None

    • 设置杨氏模量(刚度)
  • get_youngs_modulus (self) → float

    • 获取杨氏模量
  • set_poissons_ratio (self, value: float) → None

    • 设置泊松比
  • get_poissons_ratio (self) → float

    • 获取泊松比
  • set_damping_scale (self, value: float) → None

    • 设置整体阻尼系数
  • get_damping_scale (self) → float

    • 获取阻尼系数
  • set_elasticity_damping (self, value: float) → None

    • 设置弹性阻尼
  • get_elasticity_damping (self) → float

    • 获取弹性阻尼
  • set_dynamic_friction (self, value: float) → None

    • 设置动摩擦系数
  • get_dynamic_friction (self) → float

    • 获取动摩擦系数

💧 ParticleMaterial材质

位置: isaacsim.core.api.materials.ParticleMaterial

功能说明: 粒子材质,用于流体、布料等模拟。

代码示例:

from isaacsim.core.api.materials import ParticleMaterial

# 创建粒子材质
particle_material = ParticleMaterial(
    prim_path="/World/Physics/ParticleMaterial",
    name="fluid_material"
)

# 设置粒子属性
particle_material.set_friction(0.5)              # 摩擦力
particle_material.set_drag(0.1)                  # 阻力
particle_material.set_cohesion(0.01)             # 内聚力
particle_material.set_adhesion(0.0)              # 粘附力
particle_material.set_damping(0.0)               # 阻尼
particle_material.set_gravity_scale(1.0)         # 重力缩放
particle_material.set_particle_friction_scale(1.0) # 粒子摩擦缩放
particle_material.set_particle_adhesion_scale(1.0) # 粒子粘附缩放

# 获取属性
friction = particle_material.get_friction()
drag = particle_material.get_drag()
cohesion = particle_material.get_cohesion()

# 应用到粒子系统
particle_system.apply_particle_material(particle_material)

关键方法:

  • set_friction (self, value: float) → None

    • 设置粒子摩擦系数
  • get_friction (self) → float

    • 获取摩擦系数
  • set_drag (self, value: float) → None

    • 设置阻力系数
  • get_drag (self) → float

    • 获取阻力系数
  • set_cohesion (self, value: float) → None

    • 设置内聚力
  • get_cohesion (self) → float

    • 获取内聚力
  • set_adhesion (self, value: float) → None

    • 设置粘附力
  • get_adhesion (self) → float

    • 获取粘附力
  • set_damping (self, value: float) → None

    • 设置阻尼
  • get_damping (self) → float

    • 获取阻尼
  • set_gravity_scale (self, value: float) → None

    • 设置重力缩放
  • get_gravity_scale (self) → float

    • 获取重力缩放
  • set_particle_friction_scale (self, value: float) → None

    • 设置粒子间摩擦缩放
  • get_particle_friction_scale (self) → float

    • 获取粒子间摩擦缩放
  • set_particle_adhesion_scale (self, value: float) → None

    • 设置粒子间粘附缩放
  • get_particle_adhesion_scale (self) → float

    • 获取粒子间粘附缩放

📊 材质视图类

🔍 DeformableMaterialView类

位置: isaacsim.core.api.materials.DeformableMaterialView

功能说明: 批量处理可变形材质的视图类。

代码示例:

from isaacsim.core.api.materials import DeformableMaterialView
import numpy as np

# 创建可变形材质视图
material_view = DeformableMaterialView(
    prim_paths_expr="/World/Physics/SoftBodies/*/Material",
    name="deformable_materials"
)

# 初始化
material_view.initialize()

# 批量设置属性
youngs_moduli = np.array([1e6, 5e5, 2e6])  # 多个材质的杨氏模量
material_view.set_youngs_moduli(youngs_moduli)

# 批量获取属性
dampings = material_view.get_damping_scales()  # 返回所有材质的阻尼值
frictions = material_view.get_dynamic_frictions()  # 返回所有材质的摩擦系数

# 按索引设置特定材质
material_view.set_youngs_moduli(
    values=np.array([2e6]), 
    indices=[0]  # 只设置第一个材质
)

💧 ParticleMaterialView类

位置: isaacsim.core.api.materials.ParticleMaterialView

功能说明: 批量处理粒子材质的视图类。

代码示例:

from isaacsim.core.api.materials import ParticleMaterialView

# 创建粒子材质视图
particle_view = ParticleMaterialView(
    prim_paths_expr="/World/Particles/*/Material",
    name="particle_materials"
)

# 批量设置属性
frictions = np.array([0.5, 0.3, 0.7])
particle_view.set_frictions(frictions)

# 批量获取属性
drags = particle_view.get_drags()
cohesions = particle_view.get_cohesions()

💡 实际应用示例

复合材质系统

class CompositeMaterialSystem:
    def __init__(self):
        self.materials = {}
        
    def create_metal_material(self, name, color, metallic=0.9, roughness=0.3):
        """创建金属材质"""
        material = OmniPBR(
            prim_path=f"/World/Looks/{name}",
            name=name,
            color=color
        )
        material.set_metallic_constant(metallic)
        material.set_reflection_roughness(roughness)
        self.materials[name] = material
        return material
        
    def create_plastic_material(self, name, color, roughness=0.5):
        """创建塑料材质"""
        material = OmniPBR(
            prim_path=f"/World/Looks/{name}",
            name=name,
            color=color
        )
        material.set_metallic_constant(0.0)
        material.set_reflection_roughness(roughness)
        self.materials[name] = material
        return material
        
    def create_glass_material(self, name, color, ior=1.5, thin_walled=False):
        """创建玻璃材质"""
        material = OmniGlass(
            prim_path=f"/World/Looks/{name}",
            name=name,
            color=color,
            ior=ior,
            thin_walled=thin_walled
        )
        self.materials[name] = material
        return material
        
    def create_physical_material(self, name, static_friction=0.7, 
                               dynamic_friction=0.5, restitution=0.0):
        """创建物理材质"""
        material = PhysicsMaterial(
            prim_path=f"/World/Physics/{name}",
            name=name,
            static_friction=static_friction,
            dynamic_friction=dynamic_friction,
            restitution=restitution
        )
        self.materials[name] = material
        return material
        
    def apply_complete_material(self, object, visual_material_name, 
                              physics_material_name):
        """应用完整材质(视觉+物理)"""
        visual_material = self.materials.get(visual_material_name)
        physics_material = self.materials.get(physics_material_name)
        
        if visual_material:
            object.apply_visual_material(visual_material)
        if physics_material:
            object.apply_physics_material(physics_material)

# 使用示例
material_system = CompositeMaterialSystem()

# 创建各种材质
metal_material = material_system.create_metal_material(
    "steel", np.array([0.7, 0.7, 0.8]), metallic=0.9, roughness=0.2
)

plastic_material = material_system.create_plastic_material(
    "red_plastic", np.array([0.8, 0.1, 0.1]), roughness=0.4
)

glass_material = material_system.create_glass_material(
    "clear_glass", np.array([0.9, 0.95, 1.0]), ior=1.5
)

# 创建物理材质
rubber_physics = material_system.create_physical_material(
    "rubber", static_friction=1.2, dynamic_friction=1.0, restitution=0.8
)

# 应用材质到对象
material_system.apply_complete_material(
    my_object, 
    visual_material_name="red_plastic",
    physics_material_name="rubber"
)

动态材质控制器

class DynamicMaterialController:
    def __init__(self):
        self.material_presets = self.create_presets()
        self.current_preset = None
        
    def create_presets(self):
        """创建材质预设"""
        presets = {}
        
        # 金属预设
        presets["steel"] = {
            "visual": {
                "type": "pbr",
                "color": np.array([0.7, 0.7, 0.8]),
                "metallic": 0.9,
                "roughness": 0.2
            },
            "physics": {
                "static_friction": 0.6,
                "dynamic_friction": 0.4,
                "restitution": 0.0
            }
        }
        
        # 橡胶预设
        presets["rubber"] = {
            "visual": {
                "type": "pbr",
                "color": np.array([0.2, 0.2, 0.2]),
                "metallic": 0.0,
                "roughness": 0.9
            },
            "physics": {
                "static_friction": 1.2,
                "dynamic_friction": 1.0,
                "restitution": 0.8
            }
        }
        
        # 冰预设
        presets["ice"] = {
            "visual": {
                "type": "glass",
                "color": np.array([0.9, 0.95, 1.0]),
                "ior": 1.31,
                "thin_walled": False
            },
            "physics": {
                "static_friction": 0.1,
                "dynamic_friction": 0.05,
                "restitution": 0.2
            }
        }
        
        return presets
        
    def apply_preset(self, object, preset_name):
        """应用材质预设"""
        if preset_name not in self.material_presets:
            raise ValueError(f"Preset {preset_name} not found")
            
        preset = self.material_presets[preset_name]
        
        # 创建并应用视觉材质
        visual_config = preset["visual"]
        if visual_config["type"] == "pbr":
            visual_material = OmniPBR(
                prim_path=f"/World/Looks/{preset_name}_visual",
                name=f"{preset_name}_visual",
                color=visual_config["color"]
            )
            visual_material.set_metallic_constant(visual_config["metallic"])
            visual_material.set_reflection_roughness(visual_config["roughness"])
        elif visual_config["type"] == "glass":
            visual_material = OmniGlass(
                prim_path=f"/World/Looks/{preset_name}_visual",
                name=f"{preset_name}_visual",
                color=visual_config["color"],
                ior=visual_config["ior"],
                thin_walled=visual_config["thin_walled"]
            )
            
        # 创建并应用物理材质
        physics_config = preset["physics"]
        physics_material = PhysicsMaterial(
            prim_path=f"/World/Physics/{preset_name}_physics",
            name=f"{preset_name}_physics",
            static_friction=physics_config["static_friction"],
            dynamic_friction=physics_config["dynamic_friction"],
            restitution=physics_config["restitution"]
        )
        
        # 应用材质
        object.apply_visual_material(visual_material)
        object.apply_physics_material(physics_material)
        
        self.current_preset = preset_name
        
    def interpolate_materials(self, object, preset1, preset2, factor):
        """在两个预设间插值"""
        config1 = self.material_presets[preset1]
        config2 = self.material_presets[preset2]
        
        # 插值视觉属性
        color1 = config1["visual"]["color"]
        color2 = config2["visual"]["color"]
        interpolated_color = color1 * (1 - factor) + color2 * factor
        
        # 创建插值材质
        visual_material = OmniPBR(
            prim_path="/World/Looks/interpolated_visual",
            name="interpolated_visual",
            color=interpolated_color
        )
        
        # 插值物理属性
        physics1 = config1["physics"]
        physics2 = config2["physics"]
        
        physics_material = PhysicsMaterial(
            prim_path="/World/Physics/interpolated_physics",
            name="interpolated_physics",
            static_friction=physics1["static_friction"] * (1 - factor) + physics2["static_friction"] * factor,
            dynamic_friction=physics1["dynamic_friction"] * (1 - factor) + physics2["dynamic_friction"] * factor,
            restitution=physics1["restitution"] * (1 - factor) + physics2["restitution"] * factor
        )
        
        # 应用材质
        object.apply_visual_material(visual_material)
        object.apply_physics_material(physics_material)

# 使用示例
material_controller = DynamicMaterialController()

# 应用预设
material_controller.apply_preset(my_object, "steel")

# 材质过渡动画
for t in np.linspace(0, 1, 100):
    material_controller.interpolate_materials(my_object, "steel", "rubber", t)
    world.step(render=True)

软体材质配置器

class SoftBodyMaterialConfigurator:
    def __init__(self):
        self.presets = {
            "jelly": {
                "youngs_modulus": 1e4,
                "poissons_ratio": 0.45,
                "damping_scale": 0.1,
                "elasticity_damping": 0.2,
                "dynamic_friction": 0.3
            },
            "rubber": {
                "youngs_modulus": 1e6,
                "poissons_ratio": 0.4,
                "damping_scale": 0.05,
                "elasticity_damping": 0.05,
                "dynamic_friction": 0.8
            },
            "cloth": {
                "youngs_modulus": 5e4,
                "poissons_ratio": 0.3,
                "damping_scale": 0.2,
                "elasticity_damping": 0.1,
                "dynamic_friction": 0.5
            }
        }
        
    def configure_deformable(self, object, preset_name):
        """配置可变形材质"""
        if preset_name not in self.presets:
            raise ValueError(f"Preset {preset_name} not found")
            
        preset = self.presets[preset_name]
        
        # 创建可变形材质
        material = DeformableMaterial(
            prim_path=f"/World/Physics/Deformable/{preset_name}",
            name=f"deformable_{preset_name}"
        )
        
        # 应用预设属性
        material.set_youngs_modulus(preset["youngs_modulus"])
        material.set_poissons_ratio(preset["poissons_ratio"])
        material.set_damping_scale(preset["damping_scale"])
        material.set_elasticity_damping(preset["elasticity_damping"])
        material.set_dynamic_friction(preset["dynamic_friction"])
        
        # 应用到对象
        object.apply_deformable_material(material)
        
        return material
        
    def create_custom_deformable(self, object, name, **properties):
        """创建自定义可变形材质"""
        material = DeformableMaterial(
            prim_path=f"/World/Physics/Deformable/{name}",
            name=f"deformable_{name}"
        )
        
        # 应用自定义属性
        if "youngs_modulus" in properties:
            material.set_youngs_modulus(properties["youngs_modulus"])
        if "poissons_ratio" in properties:
            material.set_poissons_ratio(properties["poissons_ratio"])
        if "damping_scale" in properties:
            material.set_damping_scale(properties["damping_scale"])
        if "elasticity_damping" in properties:
            material.set_elasticity_damping(properties["elasticity_damping"])
        if "dynamic_friction" in properties:
            material.set_dynamic_friction(properties["dynamic_friction"])
            
        # 应用到对象
        object.apply_deformable_material(material)
        
        return material

# 使用示例
configurator = SoftBodyMaterialConfigurator()

# 应用预设
soft_object = world.scene.add(SoftBody(prim_path="/World/SoftObject"))
configurator.configure_deformable(soft_object, "jelly")

# 创建自定义材质
custom_object = world.scene.add(SoftBody(prim_path="/World/CustomSoft"))
configurator.create_custom_deformable(
    custom_object,
    "custom_soft",
    youngs_modulus=5e5,
    poissons_ratio=0.35,
    damping_scale=0.15,
    elasticity_damping=0.1,
    dynamic_friction=0.6
)

🔧 常见问题解决

1. 材质不生效

def debug_material_application(object):
    """诊断材质应用问题"""
    # 检查对象类型
    print(f"Object type: {type(object)}")
    
    # 检查是否有碰撞形状
    if hasattr(object, 'get_collision_approximation'):
        print(f"Collision approximation: {object.get_collision_approximation()}")
    
    # 尝试直接在USD层面应用材质
    from omni.usd import get_context
    stage = get_context().get_stage()
    prim = stage.GetPrimAtPath(object.prim_path)
    
    # 检查材质绑定
    if prim.HasAPI(UsdShade.MaterialBindingAPI):
        binding_api = UsdShade.MaterialBindingAPI(prim)
        material_binding = binding_api.GetDirectBinding()
        print(f"Current material binding: {material_binding}")

2. 物理材质优化

class PhysicsMaterialOptimizer:
    def __init__(self):
        self.optimal_configurations = {
            "high_friction_contact": {
                "static_friction": 1.5,
                "dynamic_friction": 1.2
            },
            "low_friction_sliding": {
                "static_friction": 0.1,
                "dynamic_friction": 0.05
            },
            "bouncy_surface": {
                "restitution": 0.9,
                "static_friction": 0.5,
                "dynamic_friction": 0.4
            }
        }
        
    def optimize_contact(self, object1, object2, contact_type):
        """优化两个对象间的接触"""
        config = self.optimal_configurations.get(contact_type)
        if not config:
            return
            
        # 创建优化的材质
        material = PhysicsMaterial(
            prim_path=f"/World/Physics/Optimized_{contact_type}",
            name=f"optimized_{contact_type}",
            static_friction=config.get("static_friction", 0.7),
            dynamic_friction=config.get("dynamic_friction", 0.5),
            restitution=config.get("restitution", 0.0)
        )
        
        # 应用到两个对象
        object1.apply_physics_material(material)
        object2.apply_physics_material(material)

3. 材质性能优化

class MaterialPerformanceOptimizer:
    @staticmethod
    def optimize_material_for_realtime(material):
        """优化材质以提高实时性能"""
        if isinstance(material, OmniPBR):
            # 降低纹理分辨率
            material.set_texture_scale(np.array([0.5, 0.5]))
            
            # 简化反射计算
            material.set_reflection_roughness(0.5)  # 适中的粗糙度
            
        elif isinstance(material, OmniGlass):
            # 减少折射复杂度
            material.set_thin_walled(True)
            
    @staticmethod
    def batch_optimize_materials(materials):
        """批量优化多个材质"""
        for material in materials:
            MaterialPerformanceOptimizer.optimize_material_for_realtime(material)

📊 材质属性参考表

物理材质常用数值

材料类型静摩擦系数动摩擦系数弹性系数
钢铁0.5-0.70.4-0.60.0-0.1
橡胶1.0-1.50.8-1.20.6-0.9
塑料0.3-0.50.2-0.40.1-0.3
玻璃0.4-0.60.3-0.50.0-0.2
0.1-0.20.05-0.10.1-0.3
布料0.5-0.80.4-0.70.0-0.1

可变形材质参考

材料类型杨氏模量 (Pa)泊松比阻尼系数
橡胶1e6 - 1e70.4-0.450.05-0.1
海绵1e4 - 1e50.3-0.40.1-0.2
皮革1e7 - 1e80.3-0.350.02-0.05
布料1e6 - 5e60.2-0.30.1-0.2
凝胶1e3 - 1e40.45-0.490.2-0.5

最后更新: 2025-05-10
版本: Isaac Sim 4.5.0

Isaac Sim API - 机器人

📋 概述

机器人相关API,包括机械臂、轮式机器人、抓取器等。提供完整的机器人控制、运动规划和操作功能。


🤖 主要类

🦾 机械臂 - SingleManipulator

位置: isaacsim.robot.manipulators.SingleManipulator

功能说明: 管理单个末端执行器的机械臂,可选配抓取器。

代码示例:

from isaacsim.robot.manipulators import SingleManipulator
from isaacsim.core.api import World

# 创建世界
world = World()

# 创建机械臂
manipulator = SingleManipulator(
    prim_path="/World/Manipulator",
    name="my_arm",
    end_effector_prim_name="end_effector",
    gripper=None  # 可选配抓取器
)

# 设置关节位置
joint_positions = [0.0, -1.0, 0.0, -2.0, 0.0, 1.0, 0.0]
manipulator.set_joint_positions(joint_positions)

# 获取末端执行器位置
ee_position, ee_orientation = manipulator.get_end_effector_pose()
print(f"End effector position: {ee_position}")

关键方法:

  • apply_action (self, control_actions: ArticulationAction) → None

    • 应用关节位置、速度或力矩控制
    • 支持多种控制模式
  • get_applied_action (self) → ArticulationAction

    • 获取最后应用的动作
  • get_applied_joint_efforts (self, joint_indices=None) → numpy.ndarray

    • 获取关节力矩
  • get_articulation_body_count (self) → int

    • 获取机器人连杆数量
  • enable_gravity (self) → None

    • 启用重力影响
  • disable_gravity (self) → None

    • 禁用重力影响
  • apply_visual_material (self, visual_material, weaker_than_descendants=False) → None

    • 应用视觉材质

🚗 轮式机器人控制器

差速控制器 - DifferentialController

位置: isaacsim.robot.wheeled_robots.DifferentialController

功能说明: 使用单轮模型的差速驱动控制器。

代码示例:

from isaacsim.robot.wheeled_robots import DifferentialController
import numpy as np

# 创建差速控制器
controller = DifferentialController(
    name="diff_controller",
    wheel_radius=0.035,    # 轮半径
    wheel_base=0.12       # 轮间距
)

# 发送控制命令 [线速度, 角速度]
command = np.array([0.5, 0.1])  # 0.5 m/s前进,0.1 rad/s转向
action = controller.forward(command)

# 应用到机器人
robot.apply_action(action)

控制公式:

  • ω_R = 1/(2r) × (2V + ω×b)
  • ω_L = 1/(2r) × (2V - ω×b)

其中:

  • ω_R, ω_L: 右轮、左轮角速度
  • V: 期望线速度
  • ω: 期望角速度
  • r: 轮半径
  • b: 轮间距

关键方法:

  • forward (self, command: numpy.ndarray) → ArticulationAction

    • 将 [线速度, 角速度] 转换为 [左轮, 右轮] 目标
  • reset (self) → None

    • 重置控制器状态
阿克曼控制器 - AckermannController

位置: isaacsim.robot.wheeled_robots.AckermannController

功能说明: 使用自行车模型的阿克曼转向控制器。

代码示例:

from isaacsim.robot.wheeled_robots import AckermannController

# 创建阿克曼控制器
controller = AckermannController(
    name="ackermann_controller",
    wheel_base=0.3,          # 前后轴距
    track_width=0.25,        # 左右轮距
    front_wheel_radius=0.05, # 前轮半径
    back_wheel_radius=0.05,  # 后轮半径
    max_wheel_velocity=10.0  # 最大轮速
)

# 发送控制命令 [转向角, 前进速度]
command = np.array([0.2, 1.0])  # 0.2 rad转向,1.0 m/s前进
action = controller.forward(command)

关键方法:

  • forward (self, command: numpy.ndarray) → ArticulationAction

    • 计算左右轮角度和角速度
  • reset (self) → None

    • 重置控制器状态
全向轮控制器 - HolonomicController

位置: isaacsim.robot.wheeled_robots.HolonomicController

功能说明: 计算全向移动所需的关节驱动命令。使用二次规划最小化"净力"。

代码示例:

from isaacsim.robot.wheeled_robots import HolonomicController

# 创建全向控制器(需要预先定义轮子属性)
controller = HolonomicController(
    name="holonomic_controller",
    wheel_dof_names=["wheel_fl", "wheel_fr", "wheel_bl", "wheel_br"]
)

# 设置麦轮属性
controller.setup_mecanum_wheels(
    wheel_positions=[...],  # 轮子位置
    roller_angles=[...]     # 滚轮角度
)

# 发送控制命令 [前进, 侧移, 旋转]
command = np.array([0.5, 0.2, 0.1])
action = controller.forward(command)

关键方法:

  • build_base (self)

    • 构建控制器基础
  • forward (self, command: numpy.ndarray) → ArticulationAction

    • 计算轮速以实现期望速度
  • reset (self) → None

    • 重置控制器

🤲 抓取器

平行抓手 - ParallelGripper

位置: isaacsim.robot.manipulators.grippers.ParallelGripper

功能说明: 管理具有两个手指的平行抓手。

代码示例:

from isaacsim.robot.manipulators.grippers import ParallelGripper
import numpy as np

# 创建平行抓手
gripper = ParallelGripper(
    end_effector_prim_path="/World/Robot/gripper",
    joint_prim_names=["left_finger", "right_finger"],
    joint_opened_positions=np.array([0.02, 0.02]),
    joint_closed_positions=np.array([0.0, 0.0]),
    action_deltas=np.array([0.001, 0.001])  # 增量步长
)

# 使用抓手
gripper.open()   # 打开
gripper.close()  # 关闭

# 应用自定义动作
action = gripper.forward("open")
robot.apply_action(action)

关键方法:

  • open (self) → None

    • 打开抓手
  • close (self) → None

    • 关闭抓手
  • forward (self, action: str) → ArticulationAction

    • 根据动作字符串返回关节动作
  • get_action_deltas (self) → numpy.ndarray

    • 获取动作增量
  • apply_action (self, control_actions: ArticulationAction) → None

    • 应用关节动作
吸盘抓手 - SurfaceGripper

位置: isaacsim.robot.manipulators.grippers.SurfaceGripper

功能说明: 管理表面抓手(如吸盘)。

代码示例:

from isaacsim.robot.manipulators.grippers import SurfaceGripper

# 创建吸盘抓手
surface_gripper = SurfaceGripper(
    end_effector_prim_path="/World/Robot/suction_cup",
    translate=0.0,          # 平移距离
    direction="x",          # 方向
    grip_threshold=0.01,    # 抓取阈值
    force_limit=1.0e6,      # 力限制
    torque_limit=1.0e4      # 扭矩限制
)

# 使用吸盘
surface_gripper.close()  # 启动吸盘
surface_gripper.open()   # 关闭吸盘

关键方法:

  • forward (self, action: str) → ArticulationAction

    • 计算对应的关节动作
  • close (self) → None

    • 激活吸盘
  • open (self) → None

    • 关闭吸盘

🔧 工具函数

轮式机器人工具函数

位置: isaacsim.robot.wheeled_robots

角度标准化
def normalize_angle(angle):
    """将角度标准化到 [-pi, pi]"""
    while angle > np.pi:
        angle -= 2 * np.pi
    while angle < -np.pi:
        angle += 2 * np.pi
    return angle
PID控制
def pid_control(target, current, Kp=0.1):
    """简单的比例控制器"""
    return Kp * (target - current)
Stanley控制器
def stanley_control(state, cx, cy, cyaw, last_target_idx, 
                   p=0.5, i=0.01, d=10, k=0.5):
    """Stanley转向控制算法"""
    # 实现Stanley算法逻辑
    pass
五次多项式规划
def quintic_polynomials_planner(sx, sy, syaw, sv, sa, 
                               gx, gy, gyaw, gv, ga, 
                               max_accel, max_jerk, dt):
    """五次多项式轨迹规划器"""
    # 实现五次多项式规划
    pass
目标索引计算
def calc_target_index(state, cx, cy):
    """计算轨迹列表中的目标索引"""
    # 实现目标点计算逻辑
    pass

💡 实际应用示例

机械臂拾放任务

from isaacsim.core.api import World
from isaacsim.robot.manipulators import SingleManipulator
from isaacsim.robot.manipulators.grippers import ParallelGripper
from isaacsim.robot.manipulators.controllers import PickPlaceController
import numpy as np

class RobotPickPlace:
    def __init__(self):
        # 创建环境
        self.world = World()
        self.world.scene.add_default_ground_plane()
        
        # 创建机器人
        self.robot = self.world.scene.add(SingleManipulator(
            prim_path="/World/Robot",
            name="pick_place_robot"
        ))
        
        # 创建抓手
        self.gripper = ParallelGripper(
            end_effector_prim_path="/World/Robot/gripper"
        )
        
        # 创建拾放控制器
        self.controller = PickPlaceController(
            name="pick_place_controller",
            gripper=self.gripper,
            robot_articulation=self.robot
        )
        
    def pick_and_place(self, pick_pos, place_pos):
        # 重置环境
        self.world.reset()
        
        # 执行拾放动作
        while not self.controller.is_done():
            current_positions = self.robot.get_joint_positions()
            
            action = self.controller.forward(
                picking_position=pick_pos,
                placing_position=place_pos,
                current_joint_positions=current_positions,
                end_effector_offset=np.array([0, 0, 0.1])
            )
            
            self.robot.apply_action(action)
            self.world.step(render=True)
            
        print("Pick and place task completed!")
        
    def run(self):
        # 定义拾放位置
        pick_position = np.array([0.3, 0.0, 0.05])
        place_position = np.array([0.5, 0.0, 0.1])
        
        # 执行任务
        self.pick_and_place(pick_position, place_position)

# 运行示例
demo = RobotPickPlace()
demo.run()

轮式机器人导航

from isaacsim.core.api import World
from isaacsim.robot.wheeled_robots import DifferentialController
import numpy as np

class DifferentialRobotNavigation:
    def __init__(self):
        self.world = World()
        
        # 创建轮式机器人(假设已定义)
        self.robot = self.world.scene.add(DifferentialRobot(
            prim_path="/World/DiffRobot",
            wheel_radius=0.05,
            wheel_base=0.2
        ))
        
        # 创建控制器
        self.controller = DifferentialController(
            name="nav_controller",
            wheel_radius=0.05,
            wheel_base=0.2
        )
        
    def navigate_to_target(self, target_position):
        self.world.reset()
        
        while True:
            # 获取当前状态
            current_pos, current_rot = self.robot.get_world_pose()
            
            # 计算到目标的向量
            to_target = target_position - current_pos[:2]
            distance = np.linalg.norm(to_target)
            
            # 如果到达目标,停止
            if distance < 0.1:
                break
                
            # 计算所需角度
            target_angle = np.arctan2(to_target[1], to_target[0])
            current_angle = self.get_yaw_from_quaternion(current_rot)
            angle_diff = self.normalize_angle(target_angle - current_angle)
            
            # 生成控制命令
            linear_vel = min(distance * 2.0, 1.0)  # 比例控制
            angular_vel = angle_diff * 3.0
            
            command = np.array([linear_vel, angular_vel])
            action = self.controller.forward(command)
            
            # 应用控制
            self.robot.apply_action(action)
            self.world.step(render=True)
            
    def normalize_angle(self, angle):
        while angle > np.pi:
            angle -= 2 * np.pi
        while angle < -np.pi:
            angle += 2 * np.pi
        return angle
    
    def get_yaw_from_quaternion(self, quat):
        # 从四元数计算yaw角
        siny_cosp = 2 * (quat[3] * quat[2] + quat[0] * quat[1])
        cosy_cosp = 1 - 2 * (quat[1] * quat[1] + quat[2] * quat[2])
        return np.arctan2(siny_cosp, cosy_cosp)

# 运行示例
nav_robot = DifferentialRobotNavigation()
target = np.array([5.0, 3.0])  # 目标位置
nav_robot.navigate_to_target(target)

全向轮机器人控制

class HolonomicRobotController:
    def __init__(self):
        self.world = World()
        
        # 创建麦轮机器人(假设已定义)
        self.robot = self.world.scene.add(MecanumRobot(
            prim_path="/World/MecanumRobot"
        ))
        
        # 创建全向控制器
        self.controller = HolonomicController(
            name="mecanum_controller",
            wheel_dof_names=[
                "wheel_fl", "wheel_fr", 
                "wheel_bl", "wheel_br"
            ]
        )
        
        # 设置麦轮属性
        self.setup_mecanum_properties()
        
    def setup_mecanum_properties(self):
        # 设置轮子位置和滚轮角度
        wheel_positions = np.array([
            [0.2, 0.2],   # 前左
            [0.2, -0.2],  # 前右
            [-0.2, 0.2],  # 后左
            [-0.2, -0.2]  # 后右
        ])
        
        roller_angles = np.array([
            np.pi/4, -np.pi/4, 
            -np.pi/4, np.pi/4
        ])
        
        # 配置控制器
        self.controller.setup_mecanum_wheels(
            wheel_positions, roller_angles
        )
        
    def move_omnidirectional(self, forward, lateral, rotate):
        # 生成控制命令
        command = np.array([forward, lateral, rotate])
        action = self.controller.forward(command)
        
        # 应用控制
        self.robot.apply_action(action)
        
    def run_demo(self):
        self.world.reset()
        
        # 前进
        for _ in range(100):
            self.move_omnidirectional(1.0, 0.0, 0.0)
            self.world.step(render=True)
            
        # 侧移
        for _ in range(100):
            self.move_omnidirectional(0.0, 1.0, 0.0)
            self.world.step(render=True)
            
        # 旋转
        for _ in range(100):
            self.move_omnidirectional(0.0, 0.0, 1.0)
            self.world.step(render=True)
            
        # 组合运动
        for _ in range(100):
            self.move_omnidirectional(0.5, 0.5, 0.5)
            self.world.step(render=True)

# 运行示例
holonomic_demo = HolonomicRobotController()
holonomic_demo.run_demo()

🔧 常见问题解决

1. 关节控制不响应

# 检查关节配置
def check_articulation(robot):
    print(f"DOF Count: {robot.num_dof}")
    print(f"Joint Names: {robot.dof_names}")
    print(f"Joint Positions: {robot.get_joint_positions()}")
    print(f"Joint Velocities: {robot.get_joint_velocities()}")
    
    # 设置合理的增益
    robot.set_gains(
        kps=np.array([1000] * robot.num_dof),
        kds=np.array([100] * robot.num_dof)
    )

2. 轮式机器人滑动问题

# 设置合适的物理材质
from isaacsim.core.api.materials import PhysicsMaterial

# 创建高摩擦材质
tire_material = PhysicsMaterial(
    prim_path="/World/Materials/TireMaterial",
    static_friction=1.5,
    dynamic_friction=1.0,
    restitution=0.0
)

# 应用到轮子
for wheel in robot.get_wheel_prims():
    wheel.apply_physics_material(tire_material)

3. 抓手精度问题

# 优化抓手控制精度
def fine_tune_gripper(gripper):
    # 减小增量步长
    gripper.set_action_deltas(np.array([0.0001, 0.0001]))
    
    # 增加控制频率
    gripper.set_control_frequency(240)  # Hz
    
    # 使用位置控制模式
    gripper.set_effort_modes("position")

📚 API继承关系

BaseClass
    ↓
SingleXFormPrim
    ↓
SingleArticulation
    ↓
SingleManipulator
    ↓
Robot类 (Franka, UR10 等)

最后更新: 2025-05-10
版本: Isaac Sim 4.5.0

Isaac Sim API - 控制器

📋 概述

各种控制器实现,包括关节控制、抓取控制、运动控制等。提供灵活的控制器架构和预定义控制算法。


🎯 主要类

🔧 关节控制器 - ArticulationController

位置: isaacsim.core.api.controllers.ArticulationController

功能说明: PD控制器,支持位置、速度和力矩控制所有自由度。

代码示例:

from isaacsim.core.api.controllers import ArticulationController
from isaacsim.core.api import World
import numpy as np

# 创建世界和机器人
world = World()
robot = world.scene.add(Robot(prim_path="/World/Robot"))

# 创建关节控制器
controller = ArticulationController(
    name="robot_controller",
    articulation_view=robot.get_articulation_view()
)

# 初始化控制器
controller.initialize()

# 设置PD增益
kps = np.array([100, 100, 100, 50, 50, 50, 10])   # 位置增益
kds = np.array([10, 10, 10, 5, 5, 5, 1])          # 阻尼增益
controller.set_gains(kps=kps, kds=kds)

# 设置关节目标位置
target_positions = np.array([0, -1.57, 0, -2.0, 0, 1.57, 0.7])
action = ArticulationAction(joint_positions=target_positions)
controller.apply_action(action)

# 运行控制循环
for i in range(1000):
    world.step(render=True)
    
    # 可以实时调整目标
    if i % 100 == 0:
        current_pos = robot.get_joint_positions()
        print(f"Current joint positions: {current_pos}")

关键方法:

  • apply_action (self, control_actions: ArticulationAction) → None

    • 应用关节控制动作
    • 支持位置、速度、力矩控制
  • get_applied_action (self) → ArticulationAction

    • 获取最后应用的动作
  • set_gains (self, kps=None, kds=None, save_to_usd=False) → None

    • 设置PD控制器增益
    • kps: 位置增益
    • kds: 阻尼增益
  • set_max_efforts (self, values: numpy.ndarray, joint_indices=None) → None

    • 设置最大力矩
  • set_effort_modes (self, mode: str, joint_indices=None) → None

    • 设置控制模式("force", "acceleration")
  • get_joint_limits (self) → Tuple[numpy.ndarray, numpy.ndarray]

    • 获取关节限位
  • get_effort_modes (self) → List[str]

    • 获取当前控制模式

📦 抓取控制器基类 - BaseGripperController

位置: isaacsim.core.api.controllers.BaseGripperController

功能说明: 抓取器控制的基础接口。

代码示例:

from isaacsim.core.api.controllers import BaseGripperController
from isaacsim.robot.manipulators.grippers import ParallelGripper

class CustomGripperController(BaseGripperController):
    def __init__(self, gripper):
        super().__init__(name="custom_gripper_controller")
        self.gripper = gripper
        
    def forward(self, action: str, current_joint_positions: np.ndarray) → ArticulationAction:
        """实现抓取逻辑"""
        if action == "open":
            return self.open(current_joint_positions)
        elif action == "close":
            return self.close(current_joint_positions)
        else:
            raise ValueError(f"Unknown action: {action}")
            
    def open(self, current_joint_positions: np.ndarray) → ArticulationAction:
        """打开抓手"""
        # 返回打开动作
        return ArticulationAction(
            joint_positions=self.gripper.joint_opened_positions
        )
        
    def close(self, current_joint_positions: np.ndarray) → ArticulationAction:
        """关闭抓手"""
        # 返回关闭动作
        return ArticulationAction(
            joint_positions=self.gripper.joint_closed_positions
        )

# 使用自定义控制器
gripper = ParallelGripper(end_effector_prim_path="/World/Robot/gripper")
controller = CustomGripperController(gripper)

# 控制抓手
action = controller.forward("close", robot.get_joint_positions())
robot.apply_action(action)

关键方法:

  • forward (self, action: str, current_joint_positions: numpy.ndarray) → ArticulationAction

    • 主控制方法
  • open (self, current_joint_positions: numpy.ndarray) → ArticulationAction

    • 打开抓手
  • close (self, current_joint_positions: numpy.ndarray) → ArticulationAction

    • 关闭抓手
  • reset (self) → None

    • 重置控制器状态

📦 拾放控制器 - PickPlaceController

位置: isaacsim.robot.manipulators.controllers.PickPlaceController

功能说明: 执行拾放任务的状态机控制器。

代码示例:

from isaacsim.robot.manipulators.controllers import PickPlaceController
from isaacsim.robot.manipulators.grippers import ParallelGripper

# 创建拾放控制器
pick_place_controller = PickPlaceController(
    name="pick_place",
    gripper=gripper,
    robot_articulation=robot,
    events_dt=[1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],  # 各阶段持续时间
    end_effector_initial_height=0.3,   # 末端执行器初始高度
    end_effector_grasp_height=0.03     # 抓取高度
)

# 执行拾放任务
picking_position = np.array([0.3, 0.0, 0.05])  # 拾取位置
placing_position = np.array([0.5, 0.0, 0.1])   # 放置位置

world.reset()

# 主控制循环
while not pick_place_controller.is_done():
    current_positions = robot.get_joint_positions()
    
    # 生成控制动作
    action = pick_place_controller.forward(
        picking_position=picking_position,
        placing_position=placing_position,
        current_joint_positions=current_positions,
        end_effector_offset=np.array([0, 0, 0.1]),    # 末端偏移
        end_effector_orientation=np.array([0, 1, 0, 0])  # 末端方向
    )
    
    # 应用动作
    robot.apply_action(action)
    
    # 执行仿真步进
    world.step(render=True)
    
    # 获取当前阶段
    current_event = pick_place_controller.get_current_event()
    print(f"Current phase: {current_event}")

print("Pick and place task completed!")

状态机阶段:

  1. Phase 0: 移动到拾取位置上方
  2. Phase 1: 下降到拾取高度
  3. Phase 2: 等待稳定
  4. Phase 3: 关闭抓手
  5. Phase 4: 抬起物体
  6. Phase 5: 移动到放置位置上方
  7. Phase 6: 下降到放置高度
  8. Phase 7: 打开抓手
  9. Phase 8: 抬起末端执行器
  10. Phase 9: 返回初始位置

关键方法:

  • forward (self, picking_position, placing_position, current_joint_positions, ...) → ArticulationAction

    • 执行当前阶段的控制
  • is_done (self) → bool

    • 检查任务是否完成
  • get_current_event (self) → int

    • 获取当前执行阶段
  • pause (self) → None

    • 暂停状态机
  • is_paused (self) → bool

    • 检查是否暂停
  • reset (self) → None

    • 重置状态机

📚 堆叠控制器 - StackingController

位置: isaacsim.robot.manipulators.controllers.StackingController

功能说明: 管理多物体堆叠任务的控制器。

代码示例:

from isaacsim.robot.manipulators.controllers import StackingController

# 创建堆叠控制器
stacking_controller = StackingController(
    name="stacking_controller",
    pick_place_controller=pick_place_controller,
    picking_order_cube_names=["cube1", "cube2", "cube3"],
    robot_observation_name="robot_observations"
)

# 重置控制器
stacking_controller.reset(picking_order_cube_names=["cube1", "cube2", "cube3"])

# 执行堆叠任务
while not stacking_controller.is_done():
    # 获取观测值
    observations = world.scene.get_observations()
    
    # 生成控制动作
    action = stacking_controller.forward(
        observations=observations,
        end_effector_orientation=np.array([0, 1, 0, 0])
    )
    
    # 应用动作
    robot.apply_action(action)
    world.step(render=True)
    
    # 监控进度
    current_cube = stacking_controller.get_current_cube()
    print(f"Currently stacking: {current_cube}")

print("Stacking task completed!")

关键方法:

  • forward (self, observations: dict, end_effector_orientation=None, end_effector_offset=None) → ArticulationAction

    • 执行堆叠逻辑
  • is_done (self) → bool

    • 检查堆叠任务是否完成
  • reset (self, picking_order_cube_names=None) → None

    • 重置堆叠任务

📊 动作数据结构

ArticulationAction 类

位置: isaacsim.core.utils.types.ArticulationAction

功能说明: 表示关节动作的数据结构。

代码示例:

from isaacsim.core.utils.types import ArticulationAction
import numpy as np

# 创建关节动作
action = ArticulationAction(
    joint_positions=np.array([0, 1, 0, -1, 0, 1, 0]),  # 目标位置
    joint_velocities=np.array([0, 0, 0, 0, 0, 0, 0]),  # 目标速度
    joint_efforts=None                                  # 目标力矩
)

# 访问数据
print(f"Joint positions: {action.joint_positions}")
print(f"Joint velocities: {action.joint_velocities}")

# 获取单个关节动作
dof_action = action.get_dof_action(index=2)
print(f"DOF 2 action: {dof_action}")

# 转换为字典
action_dict = action.get_dict()
print(f"Action as dict: {action_dict}")

# 获取动作长度
length = action.get_length()
print(f"Action length: {length}")

关键方法:

  • get_dict (self) → dict

    • 转换为字典格式
  • get_dof_action (self, index: int) → dict

    • 获取特定自由度的动作
  • get_length (self) → Optional[int]

    • 获取动作维度

ArticulationActions 类(批处理)

位置: isaacsim.core.utils.types.ArticulationActions

功能说明: 批量关节动作数据结构。

代码示例:

from isaacsim.core.utils.types import ArticulationActions
import numpy as np

# 创建批量动作
batch_actions = ArticulationActions(
    joint_positions=np.array([
        [0, 1, 0, -1, 0, 1, 0],
        [0.1, 1.1, 0.1, -1.1, 0.1, 1.1, 0.1]
    ]),  # 2个动作
    joint_velocities=None,
    joint_efforts=None,
    joint_indices=np.array([0, 1, 2, 3, 4, 5, 6])  # 指定关节索引
)

# 访问数据
print(f"Batch size: {batch_actions.batch_size}")
print(f"Joint positions shape: {batch_actions.joint_positions.shape}")

💡 实际应用示例

自定义PD控制器

class CustomPDController:
    def __init__(self, robot):
        self.robot = robot
        self.target_positions = None
        self.target_velocities = None
        
        # PD参数
        self.kp = np.array([1000, 1000, 500, 500, 200, 200, 100])
        self.kd = np.array([100, 100, 50, 50, 20, 20, 10])
        
        # 积分项(PID)
        self.ki = np.array([1, 1, 0.5, 0.5, 0.2, 0.2, 0.1])
        self.error_integral = np.zeros(7)
        
        # 最大力矩限制
        self.max_efforts = np.array([100, 100, 50, 50, 20, 20, 10])
        
    def set_target(self, positions, velocities=None):
        """设置目标位置和速度"""
        self.target_positions = positions
        self.target_velocities = velocities if velocities is not None else np.zeros_like(positions)
        
    def compute_torques(self, dt=1/60.0):
        """计算关节力矩"""
        # 获取当前状态
        current_positions = self.robot.get_joint_positions()
        current_velocities = self.robot.get_joint_velocities()
        
        # 计算误差
        position_error = self.target_positions - current_positions
        velocity_error = self.target_velocities - current_velocities
        
        # 更新积分项
        self.error_integral += position_error * dt
        
        # PID控制
        torques = (self.kp * position_error + 
                  self.kd * velocity_error + 
                  self.ki * self.error_integral)
        
        # 应用力矩限制
        torques = np.clip(torques, -self.max_efforts, self.max_efforts)
        
        return torques
        
    def step(self):
        """执行一步控制"""
        if self.target_positions is None:
            return
            
        # 计算力矩
        torques = self.compute_torques()
        
        # 应用控制
        action = ArticulationAction(joint_efforts=torques)
        self.robot.apply_action(action)
        
# 使用示例
controller = CustomPDController(robot)
controller.set_target(target_positions)

for i in range(1000):
    controller.step()
    world.step(render=True)

任务空间控制器

class TaskSpaceController:
    def __init__(self, robot):
        self.robot = robot
        self.end_effector_link = "end_effector"
        
        # 控制增益
        self.position_gain = 1000
        self.orientation_gain = 100
        
        # 雅可比矩阵相关
        self.jacobian = None
        self.joint_damping = 0.01
        
    def compute_jacobian(self):
        """计算雅可比矩阵"""
        # 这里需要根据具体机器人实现
        # 一般通过机器人模型API获取
        pass
        
    def compute_inverse_kinematics(self, target_pose):
        """使用雅可比矩阵求逆运动学"""
        # 获取当前末端位姿
        current_pose = self.robot.get_end_effector_pose()
        
        # 计算位姿误差
        position_error = target_pose[:3] - current_pose[:3]
        orientation_error = self.compute_orientation_error(target_pose[3:], current_pose[3:])
        
        # 组合误差
        task_error = np.concatenate([
            self.position_gain * position_error,
            self.orientation_gain * orientation_error
        ])
        
        # 计算雅可比矩阵
        self.compute_jacobian()
        
        # 伪逆法求解关节速度
        joint_velocities = np.linalg.pinv(
            self.jacobian + self.joint_damping * np.eye(self.jacobian.shape[1])
        ) @ task_error
        
        return joint_velocities
        
    def compute_orientation_error(self, target_quat, current_quat):
        """计算方向误差"""
        # 四元数误差计算
        # 这里简化实现,实际应该用四元数乘法
        return target_quat - current_quat
        
    def control_to_pose(self, target_pose):
        """控制到目标位姿"""
        # 计算关节速度
        joint_velocities = self.compute_inverse_kinematics(target_pose)
        
        # 应用速度控制
        action = ArticulationAction(joint_velocities=joint_velocities)
        self.robot.apply_action(action)
        
# 使用示例
task_controller = TaskSpaceController(robot)

# 设置目标位姿 [x, y, z, qx, qy, qz, qw]
target_pose = np.array([0.5, 0.0, 0.5, 0, 0, 0, 1])

# 执行控制
for i in range(1000):
    task_controller.control_to_pose(target_pose)
    world.step(render=True)

行为树控制器

from enum import Enum

class TaskStatus(Enum):
    RUNNING = 0
    SUCCESS = 1
    FAILURE = 2

class BehaviorTreeNode:
    def __init__(self, name):
        self.name = name
        self.status = TaskStatus.RUNNING
        
    def tick(self, blackboard):
        """执行节点逻辑"""
        raise NotImplementedError
        
class SequenceNode(BehaviorTreeNode):
    def __init__(self, name, children):
        super().__init__(name)
        self.children = children
        self.current_child = 0
        
    def tick(self, blackboard):
        """按顺序执行子节点"""
        if self.current_child >= len(self.children):
            self.status = TaskStatus.SUCCESS
            return self.status
            
        child_status = self.children[self.current_child].tick(blackboard)
        
        if child_status == TaskStatus.SUCCESS:
            self.current_child += 1
            if self.current_child >= len(self.children):
                self.status = TaskStatus.SUCCESS
        elif child_status == TaskStatus.FAILURE:
            self.status = TaskStatus.FAILURE
            self.current_child = 0  # 重置
        else:
            self.status = TaskStatus.RUNNING
            
        return self.status

class MoveToPositionNode(BehaviorTreeNode):
    def __init__(self, name, target_position):
        super().__init__(name)
        self.target_position = target_position
        self.threshold = 0.01
        
    def tick(self, blackboard):
        """移动到目标位置"""
        robot = blackboard["robot"]
        controller = blackboard["controller"]
        
        # 获取当前位置
        current_pos, _ = robot.get_end_effector_pose()
        
        # 计算距离
        distance = np.linalg.norm(current_pos[:3] - self.target_position)
        
        if distance < self.threshold:
            self.status = TaskStatus.SUCCESS
        else:
            # 生成移动命令
            direction = self.target_position - current_pos[:3]
            direction = direction / np.linalg.norm(direction)
            
            # 计算关节目标
            target_pose = np.concatenate([self.target_position, [0, 0, 0, 1]])
            joint_vels = controller.compute_inverse_kinematics(target_pose)
            
            # 应用控制
            action = ArticulationAction(joint_velocities=joint_vels)
            robot.apply_action(action)
            
            self.status = TaskStatus.RUNNING
            
        return self.status

class GripperNode(BehaviorTreeNode):
    def __init__(self, name, action):  # action: "open" or "close"
        super().__init__(name)
        self.action = action
        
    def tick(self, blackboard):
        gripper_controller = blackboard["gripper_controller"]
        robot = blackboard["robot"]
        
        # 执行抓手动作
        current_positions = robot.get_joint_positions()
        action = gripper_controller.forward(self.action, current_positions)
        robot.apply_action(action)
        
        # 等待动作完成
        # 这里简化,实际应检查抓手状态
        self.status = TaskStatus.SUCCESS
        return self.status

# 构建行为树
behavior_tree = SequenceNode("pick_and_place", [
    MoveToPositionNode("move_to_pick", np.array([0.3, 0.0, 0.05])),
    GripperNode("open_gripper", "open"),
    MoveToPositionNode("approach_object", np.array([0.3, 0.0, 0.01])),
    GripperNode("close_gripper", "close"),
    MoveToPositionNode("lift_object", np.array([0.3, 0.0, 0.1])),
    MoveToPositionNode("move_to_place", np.array([0.5, 0.0, 0.1])),
    MoveToPositionNode("lower_object", np.array([0.5, 0.0, 0.01])),
    GripperNode("release_object", "open"),
    MoveToPositionNode("move_away", np.array([0.5, 0.0, 0.2]))
])

# 初始化黑板
blackboard = {
    "robot": robot,
    "controller": task_controller,
    "gripper_controller": gripper_controller
}

# 执行行为树
while behavior_tree.status == TaskStatus.RUNNING:
    behavior_tree.tick(blackboard)
    world.step(render=True)
    
if behavior_tree.status == TaskStatus.SUCCESS:
    print("Task completed successfully!")
else:
    print("Task failed!")

🔧 常见问题解决

1. 控制精度问题

def improve_control_precision():
    # 增加PD增益
    controller.set_gains(
        kps=np.array([2000, 2000, 1500, 1000, 500, 500, 200]),
        kds=np.array([200, 200, 150, 100, 50, 50, 20])
    )
    
    # 增加控制频率
    world = World(physics_dt=1/240.0)  # 从60Hz增加到240Hz
    
    # 使用更精确的积分器
    physics_context = world.get_physics_context()
    physics_context.set_solver_type("PGS")  # 或 "TGS"
    physics_context.set_solver_iterations(4)

2. 控制抖动问题

class SmoothController:
    def __init__(self, controller):
        self.controller = controller
        self.filter_factor = 0.9  # 低通滤波系数
        self.last_action = None
        
    def apply_action(self, action):
        """应用平滑后的动作"""
        if self.last_action is None:
            self.last_action = action
        else:
            # 低通滤波
            if action.joint_positions is not None:
                action.joint_positions = (
                    self.filter_factor * self.last_action.joint_positions +
                    (1 - self.filter_factor) * action.joint_positions
                )
                
        self.last_action = action
        self.controller.apply_action(action)

3. 控制器状态管理

class ControllerManager:
    def __init__(self):
        self.controllers = {}
        self.active_controller = None
        
    def add_controller(self, name, controller):
        """添加控制器"""
        self.controllers[name] = controller
        
    def switch_controller(self, name):
        """切换控制器"""
        if name in self.controllers:
            if self.active_controller:
                self.active_controller.reset()
            self.active_controller = self.controllers[name]
            print(f"Switched to controller: {name}")
        else:
            raise ValueError(f"Controller {name} not found")
            
    def update(self, *args, **kwargs):
        """更新当前控制器"""
        if self.active_controller:
            return self.active_controller.forward(*args, **kwargs)
        return None
        
# 使用示例
manager = ControllerManager()
manager.add_controller("pick_place", pick_place_controller)
manager.add_controller("stacking", stacking_controller)

# 根据任务切换控制器
manager.switch_controller("pick_place")
# ... 执行拾放任务
manager.switch_controller("stacking")
# ... 执行堆叠任务

📚 控制器模式比较

控制模式适用场景优点缺点
位置控制精确定位任务精度高,稳定响应慢,刚性强
速度控制轨迹跟踪响应快,平滑精度稍差
力控制接触任务柔顺性好稳定性要求高
混合控制复杂任务灵活性高实现复杂

🎯 控制器设计准则

  1. 模块化设计: 每个控制器专注于特定任务
  2. 状态管理: 清晰的状态转换逻辑
  3. 参数可调: 提供可调节的控制参数
  4. 错误处理: 优雅处理异常情况
  5. 性能优化: 考虑实时性要求

最后更新: 2025-05-10
版本: Isaac Sim 4.5.0