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

1,161 阅读34分钟

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消息、服务、话题等

Isaac Sim API - 机器人示例

📋 概述

机器人相关示例代码,包括Franka、UR10等常用机器人的具体实现。这些示例展示了如何在Isaac Sim中配置和控制各种机器人。


🤖 主要机器人示例

🦾 Franka机器人

📦 Franka类

位置: isaacsim.robot.manipulators.examples.franka.Franka

功能说明: Franka Panda机械臂的高级封装,集成了标准配置和控制接口。

使用示例:

from isaacsim.robot.manipulators.examples.franka import Franka
import numpy as np

# 创建Franka机器人
franka = Franka(
    prim_path="/World/Franka",
    name="my_franka",
    position=np.array([0.0, 0.0, 0.0]),
    orientation=np.array([1.0, 0.0, 0.0, 0.0])
)

# 初始化
franka.initialize()

# 获取末端执行器位置
ee_pos, ee_rot = franka.end_effector.get_world_pose()

主要方法:

  • apply_action() - 应用关节控制
  • get_applied_action() - 获取已应用的控制动作
  • disable_gravity() - 禁用重力影响
  • enable_gravity() - 启用重力影响
  • get_angular_velocity() - 获取角速度
  • get_articulation_body_count() - 获取关节体数量
🔧 KinematicsSolver类

位置: isaacsim.robot.manipulators.examples.franka.KinematicsSolver

功能说明: Franka机器人的运动学求解器。

代码示例:

from isaacsim.robot.manipulators.examples.franka import KinematicsSolver

# 创建运动学求解器
solver = KinematicsSolver(robot_articulation=franka)

# 正向运动学
ee_pos, ee_rot = solver.compute_end_effector_pose()

# 逆向运动学
target_pos = np.array([0.5, 0.0, 0.5])
target_rot = np.array([0.0, 1.0, 0.0, 0.0])
action, success = solver.compute_inverse_kinematics(
    target_position=target_pos,
    target_orientation=target_rot
)

主要方法:

方法名描述返回值
compute_end_effector_pose()计算末端执行器姿态(位置, 旋转)
compute_inverse_kinematics()逆运动学求解(控制动作, 成功标志)
get_end_effector_frame()获取末端执行器坐标系str
set_end_effector_frame()设置末端执行器坐标系None

🔩 UR10机器人

📦 UR10类

位置: isaacsim.robot.manipulators.examples.universal_robots.UR10

功能说明: Universal Robots UR10机械臂的实现。

创建示例:

from isaacsim.robot.manipulators.examples.universal_robots import UR10

# 创建UR10机器人(带抓手)
ur10 = UR10(
    prim_path="/World/UR10",
    name="ur10_robot",
    attach_gripper=True,
    position=np.array([1.0, 0.0, 0.0])
)

# 初始化
ur10.initialize()

# 控制机器人
joint_positions = np.array([0.0, -1.5, 1.5, -1.5, -1.5, 0.0])
ur10.set_joint_positions(joint_positions)

主要特性:

  • 支持标准配置和抓手配置
  • 内置运动学求解器
  • 完整的关节控制接口
  • 与Isaac Sim的紧密集成
🔧 KinematicsSolver类

位置: isaacsim.robot.manipulators.examples.universal_robots.KinematicsSolver

功能说明: UR10机器人的运动学求解器。

特殊参数:

参数类型描述
robot_articulationSingleArticulationUR10机器人对象
end_effector_frame_nameOptional[str]末端执行器坐标系名称
attach_gripperOptional[bool]是否包含抓手

🎮 交互式示例

🎯 FollowTarget示例

📦 FollowTarget类

位置: isaacsim.examples.interactive.follow_target.FollowTarget

功能说明: 机器人跟随目标点的交互式示例。

主要方法:

方法名描述
_on_follow_target_event_async()异步处理跟随事件
_on_add_obstacle_event()添加障碍物事件
_on_remove_obstacle_event()移除障碍物事件
_world_cleanup()清理世界环境
load_world_async()异步加载世界
🔄 ReplayFollowTarget类

位置: isaacsim.examples.interactive.replay_follow_target.ReplayFollowTarget

功能说明: 回放跟随目标的轨迹数据。

使用场景:

  • 轨迹数据分析
  • 行为复现
  • 性能评估

🧠 FrankaCortex示例

📦 FrankaCortexExtension

位置: isaacsim.examples.interactive.franka_cortex.FrankaCortexExtension

功能说明: Franka机器人的Cortex控制集成示例。

特点:

  • 与NVIDIA Cortex集成
  • 高级AI控制能力
  • 实时响应优化

📊 示例代码模板

基础机器人控制模板

from isaacsim.core.api import World
from isaacsim.robot.manipulators.examples.franka import Franka
import numpy as np

def main():
    # 创建世界
    world = World()
    
    # 添加机器人
    robot = world.scene.add(
        Franka(
            prim_path="/World/Franka",
            name="my_franka"
        )
    )
    
    # 初始化场景
    world.reset()
    
    # 控制循环
    for i in range(1000):
        # 设置目标位置
        target_positions = np.array([0.0, -1.0, 0.0, -2.0, 0.0, 1.5, 0.8])
        
        # 应用控制
        robot.set_joint_positions(target_positions)
        
        # 执行仿真步
        world.step(render=True)
        
        # 打印状态
        if i % 100 == 0:
            current_pos = robot.get_joint_positions()
            print(f"Step {i}: Joint positions = {current_pos}")

if __name__ == "__main__":
    main()

运动学求解示例

def inverse_kinematics_example():
    # 创建机器人和求解器
    robot = Franka(prim_path="/World/Franka", name="franka")
    solver = KinematicsSolver(robot_articulation=robot)
    
    # 设置目标位置
    target_position = np.array([0.5, 0.0, 0.3])
    target_orientation = np.array([0.0, 1.0, 0.0, 0.0])
    
    # 求解逆运动学
    action, success = solver.compute_inverse_kinematics(
        target_position=target_position,
        target_orientation=target_orientation,
        position_tolerance=0.001,
        orientation_tolerance=0.01
    )
    
    if success:
        print("逆运动学求解成功!")
        robot.apply_action(action)
    else:
        print("逆运动学求解失败,目标不可达")

🏭 扩展和定制

创建自定义机器人

from isaacsim.robot.manipulators import SingleManipulator

class CustomRobot(SingleManipulator):
    def __init__(self, prim_path, **kwargs):
        # 调用父类构造函数
        super().__init__(
            prim_path=prim_path,
            name=kwargs.get("name", "custom_robot"),
            usd_path=kwargs.get("usd_path", "path/to/custom_robot.usd"),
            **kwargs
        )
        
    def custom_behavior(self):
        """实现自定义行为"""
        # 你的自定义代码
        pass

Isaac Sim API - 运动规划

📋 概述

运动规划和行为控制API,包括路径规划、行为树等。提供完整的机器人运动规划解决方案。


🗺️ 路径规划

🔀 基础规划算法

from isaacsim.core.api import World
from isaacsim.robot_motion.motion_planning import PathPlanner

# 创建路径规划器
planner = PathPlanner(
    robot_description_path="robot.urdf",
    planning_algorithm="RRT*"
)

# 设置规划参数
planner.set_planning_time(5.0)
planner.set_simplify_solution(True)

# 规划路径
start_pose = np.array([0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0])
goal_pose = np.array([1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0])

path, success = planner.plan_to_pose(start_pose, goal_pose)

🛠️ 规划算法选项

算法特点适用场景
RRT随机快速扩展树高维空间规划
RRT*优化版RRT需要最优路径
PRM概率路线图多查询场景
A*启发式搜索已知环境地图
Dijkstra经典图搜索完备性要求高

🎯 约束规划

# 添加关节限制
planner.add_joint_constraints(
    joint_names=["shoulder_pan_joint", "shoulder_lift_joint"],
    lower_bounds=[-np.pi, -np.pi],
    upper_bounds=[np.pi, np.pi]
)

# 添加末端执行器约束
planner.add_pose_constraint(
    link_name="ee_link",
    position_tolerance=0.01,
    orientation_tolerance=0.05
)

# 添加避障约束
planner.add_collision_objects([
    CollisionObject(
        name="table",
        mesh_path="table.stl",
        pose=[0.5, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0]
    )
])

🌳 行为树

📊 行为节点类型

from isaacsim.robot_motion.behavior_tree import *

# 动作节点
class GripperAction(Action):
    def __init__(self, gripper_cmd):
        super().__init__("GripperAction")
        self.gripper_cmd = gripper_cmd
        
    def execute(self):
        # 执行抓手操作
        self.gripper.apply_action(self.gripper_cmd)
        return self.SUCCESS

# 条件节点
class ObjectDetected(Condition):
    def __init__(self, camera):
        super().__init__("ObjectDetected")
        self.camera = camera
        
    def evaluate(self):
        # 检查是否检测到物体
        objects = self.camera.detect_objects()
        return len(objects) > 0

# 复合节点
pick_and_place_tree = Sequence([
    ObjectDetected(camera),
    NavigateToObject(),
    GripperAction("open"),
    ApproachObject(),
    GripperAction("close"),
    LiftObject(),
    NavigateToDropZone(),
    GripperAction("open")
])

🔄 行为树执行

class BehaviorTreeRunner:
    def __init__(self, root_node):
        self.root = root_node
        self.blackboard = Blackboard()
        
    def tick(self):
        """执行行为树的一个tick"""
        return self.root.tick(self.blackboard)
        
    def run_until_complete(self, max_ticks=1000):
        """运行直到完成或达到最大tick数"""
        for i in range(max_ticks):
            status = self.tick()
            
            if status in [Status.SUCCESS, Status.FAILURE]:
                return status
                
        return Status.FAILURE

# 使用示例
runner = BehaviorTreeRunner(pick_and_place_tree)
status = runner.run_until_complete()

📝 行为树调试

# 行为树可视化
def visualize_tree(node, depth=0):
    indent = "  " * depth
    status_symbol = {
        Status.SUCCESS: "✓",
        Status.FAILURE: "✗",
        Status.RUNNING: "→"
    }
    
    symbol = status_symbol.get(node.status, "?")
    print(f"{indent}{symbol} {node.name}")
    
    for child in node.children:
        visualize_tree(child, depth + 1)

# 状态记录器
class BehaviorLogger:
    def __init__(self):
        self.log = []
        
    def on_node_tick(self, node):
        self.log.append({
            "timestamp": time.time(),
            "node": node.name,
            "status": node.status,
            "data": node.get_debug_info()
        })
        
    def save_log(self, filename):
        with open(filename, 'w') as f:
            json.dump(self.log, f, indent=2)

🎮 轨迹控制

📈 轨迹生成

from isaacsim.robot_motion.trajectory import TrajectoryGenerator

# 多项式轨迹
poly_traj = TrajectoryGenerator.polynomial(
    start_pos=start_joints,
    end_pos=goal_joints,
    duration=2.0,
    order=5
)

# 正弦轨迹
sin_traj = TrajectoryGenerator.sinusoidal(
    amplitude=0.5,
    frequency=1.0,
    offset=joint_offsets,
    duration=3.0
)

# 样条轨迹
waypoints = [
    np.array([0.0, 0.0, 0.0]),
    np.array([0.5, 0.5, 0.5]),
    np.array([1.0, 0.0, 1.0])
]

spline_traj = TrajectoryGenerator.cubic_spline(
    waypoints=waypoints,
    velocities=None,  # 自动计算
    duration=3.0
)

🎯 轨迹插值

class TrajectoryInterpolator:
    """轨迹插值器"""
    
    def __init__(self, trajectory, timestep=0.01):
        self.trajectory = trajectory
        self.timestep = timestep
        self.current_time = 0.0
        
    def get_next_point(self):
        """获取下一个轨迹点"""
        if self.current_time > self.trajectory.duration:
            return None
            
        point = self.trajectory.sample(self.current_time)
        self.current_time += self.timestep
        
        return {
            "position": point.position,
            "velocity": point.velocity,
            "acceleration": point.acceleration
        }
        
    def preview_trajectory(self, num_points=100):
        """预览轨迹"""
        points = []
        time_samples = np.linspace(0, self.trajectory.duration, num_points)
        
        for t in time_samples:
            points.append(self.trajectory.sample(t))
            
        return points

🔀 自适应轨迹修正

class AdaptiveTrajectoryController:
    """自适应轨迹控制器"""
    
    def __init__(self, base_trajectory):
        self.base_trajectory = base_trajectory
        self.current_trajectory = base_trajectory
        self.obstacle_detector = ObstacleDetector()
        
    def update(self, current_state):
        """更新轨迹,处理动态障碍"""
        # 检测障碍
        obstacles = self.obstacle_detector.detect()
        
        if obstacles:
            # 重新规划轨迹段
            modified_segment = self.replan_segment(
                current_state,
                obstacles
            )
            
            # 平滑连接
            self.current_trajectory = self.blend_trajectories(
                self.current_trajectory,
                modified_segment
            )
            
        return self.current_trajectory.sample(time.time())

🤖 复杂任务规划

🏗️ 分层任务网络 (HTN)

from isaacsim.robot_motion.htn import HTNPlanner

# 定义任务层次
htn_domain = {
    "compound_tasks": {
        "pick_and_place": [
            ["navigate_to_object"],
            ["pick_object"],
            ["navigate_to_target"],
            ["place_object"]
        ]
    },
    "primitive_tasks": {
        "navigate_to_object": NavigateAction,
        "pick_object": PickAction,
        "navigate_to_target": NavigateAction,
        "place_object": PlaceAction
    }
}

# 创建规划器
planner = HTNPlanner(domain=htn_domain)

# 规划任务
task_sequence = planner.plan(
    initial_state=current_world_state,
    goal_task="pick_and_place",
    parameters={"object": "cube", "target": "table"}
)

🧩 任务分解示例

def assembly_task_planning():
    """多部件装配任务规划"""
    
    # 定义装配任务
    assembly_task = HTNTask("assemble_device", [
        # 准备阶段
        SubTask("gather_components", [
            "pick_base",
            "pick_cover",
            "pick_screws"
        ]),
        
        # 装配阶段
        SubTask("assemble_main", [
            "align_cover_with_base",
            "insert_screw",
            "tighten_screw",
            "verify_assembly"
        ]),
        
        # 完成阶段
        SubTask("finalize", [
            "quality_check",
            "package_device"
        ])
    ])
    
    return assembly_task.plan()

📊 规划性能监控

📈 指标收集

class PlanningMetrics:
    """规划性能指标"""
    
    def __init__(self):
        self.metrics = {
            "planning_time": [],
            "path_length": [],
            "smoothness": [],
            "collision_checks": [],
            "success_rate": []
        }
        
    def record_plan(self, plan_result):
        """记录单次规划结果"""
        self.metrics["planning_time"].append(plan_result.time)
        self.metrics["path_length"].append(plan_result.path_length)
        self.metrics["smoothness"].append(self.calculate_smoothness(plan_result.path))
        self.metrics["collision_checks"].append(plan_result.collision_checks)
        
    def get_statistics(self):
        """获取统计信息"""
        stats = {}
        for metric, values in self.metrics.items():
            stats[metric] = {
                "mean": np.mean(values),
                "std": np.std(values),
                "min": np.min(values),
                "max": np.max(values)
            }
        return stats

📊 实时监控

class PlanningDashboard:
    """规划过程实时监控"""
    
    def __init__(self):
        self.live_metrics = {}
        self.update_callbacks = []
        
    def start_monitoring(self, planner):
        """开始监控规划器"""
        planner.register_callback("on_iteration", self.on_planning_iteration)
        planner.register_callback("on_solution_found", self.on_solution_found)
        
    def on_planning_iteration(self, iteration_data):
        """处理规划迭代数据"""
        self.live_metrics.update({
            "iterations": iteration_data.count,
            "best_cost": iteration_data.best_cost,
            "tree_size": iteration_data.tree_size
        })
        
        # 触发更新回调
        for callback in self.update_callbacks:
            callback(self.live_metrics)

Isaac Sim API - 传感器

📋 概述

传感器相关API,包括相机、激光雷达、接触传感器等。提供完整的传感器模拟和数据获取功能。


🎥 主要类

📷 相机 - Camera

位置: isaacsim.sensors.camera.Camera

功能说明: 管理相机传感器及其标注器,支持多种数据采集模式。

代码示例:

from isaacsim.sensors.camera import Camera
from isaacsim.core.api import World
import numpy as np

# 创建世界
world = World()

# 创建相机
camera = Camera(
    prim_path="/World/Camera",
    name="my_camera",
    frequency=30,                # 采集频率
    resolution=(512, 512),       # 分辨率
    position=np.array([2, 0, 1]), # 位置
    orientation=np.array([0, 0, 0, 1]) # 方向
)

# 添加标注器
camera.add_rgb_to_frame()                    # RGB图像
camera.add_depth_to_frame()                  # 深度图
camera.add_semantic_segmentation_to_frame()  # 语义分割
camera.add_instance_id_segmentation_to_frame() # 实例分割
camera.add_bounding_box_2d_tight_to_frame()  # 2D边界框
camera.add_bounding_box_3d_to_frame()        # 3D边界框

# 初始化相机
camera.initialize()

# 获取数据
world.reset()
world.step(render=True)  # 执行一步生成数据

# 获取当前帧数据
frame_data = camera.get_current_frame()
rgb = frame_data["rgb"]
depth = frame_data["depth"]
semantic = frame_data["semantic_segmentation"]

关键方法:

  • add_rgb_to_frame (self, init_params=None) → None

    • 添加RGB图像标注器
  • add_depth_to_frame (self, init_params=None) → None

    • 添加深度图标注器
  • add_semantic_segmentation_to_frame (self, init_params=None) → None

    • 添加语义分割标注器
  • add_instance_id_segmentation_to_frame (self, init_params=None) → None

    • 添加实例分割标注器
  • add_bounding_box_2d_tight_to_frame (self, init_params=None) → None

    • 添加紧凑2D边界框标注器
  • add_bounding_box_2d_loose_to_frame (self, init_params=None) → None

    • 添加松散2D边界框标注器
  • add_bounding_box_3d_to_frame (self, init_params=None) → None

    • 添加3D边界框标注器
  • add_distance_to_camera_to_frame (self, init_params=None) → None

    • 添加到相机距离标注器
  • add_distance_to_image_plane_to_frame (self, init_params=None) → None

    • 添加到图像平面距离标注器

📊 相机视图 - CameraView

位置: isaacsim.sensors.camera.CameraView

功能说明: 批量管理多个相机,支持平铺/批处理数据。

代码示例:

from isaacsim.sensors.camera.camera_view import CameraView

# 创建相机视图(管理多个相机)
camera_view = CameraView(
    prim_paths_expr="/World/Camera_*",  # 匹配多个相机
    name="multi_cam_view"
)

# 初始化
camera_view.initialize()

# 批量获取数据
rgb_data = camera_view.get_rgb()     # Shape: (N, H, W, 3)
depth_data = camera_view.get_depth() # Shape: (N, H, W)

关键方法:

  • get_rgb (self, clone=True) → Union[numpy.ndarray, torch.Tensor]

    • 获取所有相机的RGB数据
  • get_depth (self, clone=True) → Union[numpy.ndarray, torch.Tensor]

    • 获取深度数据
  • get_semantic_segmentation (self, clone=True) → Union[numpy.ndarray, torch.Tensor]

    • 获取语义分割数据
  • get_instance_id_segmentation (self, clone=True) → Union[numpy.ndarray, torch.Tensor]

    • 获取实例分割数据
  • get_bounding_box_2d_tight (self, clone=True) → Union[numpy.ndarray, torch.Tensor]

    • 获取2D边界框数据
  • get_bounding_box_3d (self, clone=True) → Union[numpy.ndarray, torch.Tensor]

    • 获取3D边界框数据

📡 基础传感器 - BaseSensor

位置: isaacsim.sensors.camera.BaseSensor

功能说明: 提供传感器的公共属性和方法,继承自SingleXFormPrim

关键方法:

  • initialize (self, physics_sim_view=None) → None

    • 创建物理仿真视图
  • get_world_pose (self) → Tuple[numpy.ndarray, numpy.ndarray]

    • 获取世界坐标系下的位姿
  • set_world_pose (self, position=None, orientation=None) → None

    • 设置世界坐标系下的位姿

🔧 标注器注册表 - AnnotatorRegistry

位置: isaacsim.sensors.rtx.AnnotatorRegistry

功能说明: 管理标注器的注册表,提供数据写入功能。

代码示例:

from isaacsim.sensors.rtx import AnnotatorRegistry

# 获取标注器
annotator = AnnotatorRegistry.get_annotator(
    name="rgb",
    init_params={"camera_prim": "/World/Camera"}
)

# 注册自定义标注器
AnnotatorRegistry.register_annotator_from_node(
    name="custom_annotator",
    input_rendervars=["LdrColor"],
    node_type_id="omni.graph.custom.Node",
    output_data_type=np.uint8,
    output_channels=3
)

关键方法:

  • get_annotator (name: str, init_params=None, render_product_idxs=None, device=None) → Annotator

    • 创建指定名称的标注器实例
  • get_registered_annotators () → List[str]

    • 返回已注册的标注器列表
  • register_annotator_from_node (name, input_rendervars, node_type_id, ...) → None

    • 从omnigraph节点定义注册标注器
  • register_annotator_from_aov (aov, output_data_type=None, ...) → None

    • 从AOV注册标注器
  • detach (annotator, render_products) → None

    • 从渲染产品分离标注器

🌐 RTX传感器

🛰️ IDS传感器 - IsaacSensorCreateRtxIDS

位置: isaacsim.sensors.rtx.IsaacSensorCreateRtxIDS

功能说明: 创建RTX IDS传感器的命令。

📡 雷达传感器 - IsaacSensorCreateRtxRadar

位置: isaacsim.sensors.rtx.IsaacSensorCreateRtxRadar

功能说明: 创建RTX雷达传感器的命令。

📍 激光雷达 - IsaacRtxLidarSensorAPI

位置: isaacsim.sensors.camera.IsaacRtxLidarSensorAPI

功能说明: RTX激光雷达传感器的API模式。


🔧 工具函数

相机相关函数

位置: isaacsim.sensors.camera

定义Prim
def define_prim(prim_path: str, prim_type: str = 'Xform', fabric: bool = False) → Prim:
    """在指定路径创建USD Prim"""
    pass
获取所有相机对象
def get_all_camera_objects(root_prim: str = '/'):
    """检索场景中所有相机的Camera对象"""
    pass
设置/获取分辨率
def set_resolution(render_product_path: str, resolution: Tuple[int]):
    """设置渲染产品的分辨率"""
    pass

def get_resolution(render_product_path: str):
    """获取渲染产品的分辨率"""
    pass
相机路径设置
def set_camera_prim_path(render_product_path: str, camera_prim_path: str):
    """设置渲染产品的相机prim路径"""
    pass
镜头畸变函数
def distort_point_kannala_brandt(camera_matrix, distortion_model, x, y):
    """使用Kannala Brandt鱼眼模型畸变点"""
    pass

def distort_point_rational_polynomial(camera_matrix, distortion_model, x, y):
    """使用有理多项式模型畸变点"""
    pass
角度计算
def point_to_theta(camera_matrix, x, y):
    """计算点的theta角度"""
    pass

RTX传感器工具函数

位置: isaacsim.sensors.rtx

Prim操作
def delete_prim(prim_path: str) → None:
    """从场景中删除USD Prim及其子项"""
    pass

def get_next_free_path(path: str, parent: str = None) → str:
    """返回当前舞台的下一个可用USD路径"""
    pass
变换设置
def reset_and_set_xform_ops(prim: Usd.Prim, translation: Gf.Vec3d, 
                          orientation: Gf.Quatd, scale: Gf.Vec3d = Gf.Vec3d(1.0, 1.0, 1.0)):
    """重置xform操作到Isaac Sim默认值,并设置其值"""
    pass
舞台遍历
def traverse_stage(fabric=False) → Iterable:
    """遍历打开的USD舞台中的所有prim(包括隐藏的)"""
    pass

💡 实际应用示例

多相机数据采集系统

from isaacsim.core.api import World
from isaacsim.sensors.camera import Camera
from isaacsim.sensors.camera.camera_view import CameraView
import numpy as np
import cv2

class MultiCameraSystem:
    def __init__(self):
        self.world = World()
        self.world.scene.add_default_ground_plane()
        
        # 创建多个相机
        self.cameras = []
        for i in range(4):
            angle = i * np.pi / 2
            position = np.array([
                2 * np.cos(angle),
                2 * np.sin(angle),
                1.5
            ])
            
            camera = Camera(
                prim_path=f"/World/Camera_{i}",
                name=f"camera_{i}",
                resolution=(640, 480),
                position=position,
                target=np.array([0, 0, 0])  # 看向原点
            )
            
            # 添加标注器
            camera.add_rgb_to_frame()
            camera.add_depth_to_frame()
            camera.add_semantic_segmentation_to_frame()
            
            self.cameras.append(camera)
            
        # 创建相机视图
        self.camera_view = CameraView(
            prim_paths_expr="/World/Camera_*",
            name="multi_camera_view"
        )
        
    def capture_synchronized_data(self):
        """同步采集所有相机数据"""
        # 确保仿真步进
        self.world.step(render=True)
        
        # 批量获取数据
        rgb_data = self.camera_view.get_rgb()
        depth_data = self.camera_view.get_depth()
        semantic_data = self.camera_view.get_semantic_segmentation()
        
        # 返回字典格式
        data = {
            "timestamp": self.world.current_time,
            "rgb": rgb_data,
            "depth": depth_data,
            "semantic": semantic_data
        }
        
        return data
        
    def save_captures(self, output_dir: str):
        """保存采集的数据"""
        import os
        os.makedirs(output_dir, exist_ok=True)
        
        # 采集数据
        data = self.capture_synchronized_data()
        
        # 保存每个相机的数据
        for i in range(len(self.cameras)):
            # 保存RGB图像
            rgb_img = data["rgb"][i]
            cv2.imwrite(
                os.path.join(output_dir, f"camera_{i}_rgb.png"),
                cv2.cvtColor(rgb_img, cv2.COLOR_RGB2BGR)
            )
            
            # 保存深度图
            depth_img = (data["depth"][i] * 1000).astype(np.uint16)
            cv2.imwrite(
                os.path.join(output_dir, f"camera_{i}_depth.png"),
                depth_img
            )
            
            # 保存语义分割
            semantic_img = data["semantic"][i]
            cv2.imwrite(
                os.path.join(output_dir, f"camera_{i}_semantic.png"),
                semantic_img
            )
            
    def run_capture_sequence(self, num_frames=100):
        """运行采集序列"""
        self.world.reset()
        
        for i in range(num_frames):
            # 采集数据
            data = self.capture_synchronized_data()
            
            # 保存数据
            self.save_captures(f"outputs/frame_{i:04d}")
            
            # 进度提示
            if i % 10 == 0:
                print(f"Captured frame {i}/{num_frames}")
                
        print("Capture sequence completed!")

# 使用示例
camera_system = MultiCameraSystem()
camera_system.run_capture_sequence(100)

动态相机控制系统

class DynamicCameraController:
    def __init__(self):
        self.world = World()
        
        # 创建主相机
        self.camera = Camera(
            prim_path="/World/MainCamera",
            name="main_camera",
            resolution=(1280, 720),
            frequency=60
        )
        
        # 添加所有标注器
        self.add_all_annotators()
        
        # 相机轨迹参数
        self.trajectory_radius = 3.0
        self.trajectory_height = 2.0
        self.target_position = np.array([0, 0, 1])
        
    def add_all_annotators(self):
        """添加所有可用标注器"""
        annotators = [
            "rgb", "depth", "semantic_segmentation",
            "instance_id_segmentation", "bounding_box_2d_tight",
            "bounding_box_3d", "distance_to_camera",
            "distance_to_image_plane"
        ]
        
        for annotator in annotators:
            method_name = f"add_{annotator}_to_frame"
            if hasattr(self.camera, method_name):
                getattr(self.camera, method_name)()
                
    def update_camera_pose(self, time):
        """根据时间更新相机位置"""
        # 计算圆形轨迹位置
        angle = time * 0.5  # 旋转速度
        x = self.trajectory_radius * np.cos(angle)
        y = self.trajectory_radius * np.sin(angle)
        z = self.trajectory_height
        
        position = np.array([x, y, z])
        
        # 计算朝向目标的方向
        direction = self.target_position - position
        direction = direction / np.linalg.norm(direction)
        
        # 计算旋转四元数
        up = np.array([0, 0, 1])
        right = np.cross(direction, up)
        right = right / np.linalg.norm(right)
        up = np.cross(right, direction)
        
        # 构建旋转矩阵
        rotation_matrix = np.array([right, up, -direction]).T
        
        # 转换为四元数
        from scipy.spatial.transform import Rotation
        rotation = Rotation.from_matrix(rotation_matrix)
        quaternion = rotation.as_quat()[[3, 0, 1, 2]]  # [w, x, y, z]
        
        # 更新相机位姿
        self.camera.set_world_pose(position, quaternion)
        
    def run_dynamic_capture(self, duration=10.0, output_dir="dynamic_captures"):
        """运行动态相机采集"""
        import os
        os.makedirs(output_dir, exist_ok=True)
        
        self.world.reset()
        start_time = self.world.current_time
        frame_count = 0
        
        while self.world.current_time - start_time < duration:
            # 更新相机位置
            self.update_camera_pose(self.world.current_time)
            
            # 执行仿真步进
            self.world.step(render=True)
            
            # 采集数据
            frame_data = self.camera.get_current_frame()
            
            # 保存数据
            for data_type, data in frame_data.items():
                if isinstance(data, np.ndarray):
                    filename = os.path.join(
                        output_dir, 
                        f"frame_{frame_count:04d}_{data_type}.npy"
                    )
                    np.save(filename, data)
                    
            frame_count += 1
            
            if frame_count % 60 == 0:
                print(f"Captured {frame_count} frames...")
                
        print(f"Dynamic capture completed! Total frames: {frame_count}")

# 使用示例
controller = DynamicCameraController()
controller.run_dynamic_capture(duration=30.0)

自定义标注器示例

from isaacsim.sensors.rtx import AnnotatorRegistry
import numpy as np

class CustomAnnotatorExample:
    def __init__(self):
        self.world = World()
        
        # 注册自定义标注器
        self.register_custom_annotators()
        
        # 创建相机
        self.camera = Camera(
            prim_path="/World/CustomCamera",
            name="custom_camera"
        )
        
    def register_custom_annotators(self):
        """注册自定义标注器"""
        
        # 1. 注册基于AOV的标注器
        AnnotatorRegistry.register_annotator_from_aov(
            aov="aov:MyCustomOutput",
            output_data_type=np.float32,
            output_channels=4,
            name="custom_aov_annotator",
            documentation="Custom AOV-based annotator"
        )
        
        # 2. 注册基于节点的标注器
        AnnotatorRegistry.register_annotator_from_node(
            name="custom_node_annotator",
            input_rendervars=["LdrColor", "Depth"],
            node_type_id="omni.graph.custom.ProcessingNode",
            init_params={
                "threshold": 0.5,
                "scale": 1.0
            },
            output_rendervars=["ProcessedOutput"],
            output_data_type=np.uint8,
            output_channels=3,
            documentation="Custom node-based annotator"
        )
        
    def use_custom_annotators(self):
        """使用自定义标注器"""
        
        # 获取自定义标注器
        custom_annotator = AnnotatorRegistry.get_annotator(
            name="custom_node_annotator",
            init_params={"threshold": 0.7}
        )
        
        # 附加到相机
        render_product = self.camera.render_product_path
        custom_annotator.attach([render_product])
        
        # 采集数据
        self.world.step(render=True)
        custom_data = custom_annotator.get_data()
        
        return custom_data
        
    def process_annotations(self):
        """处理标注数据"""
        # 获取标准标注
        frame_data = self.camera.get_current_frame()
        
        # 获取自定义标注
        custom_data = self.use_custom_annotators()
        
        # 组合处理
        combined_data = {
            **frame_data,
            "custom": custom_data
        }
        
        return combined_data

# 使用示例
annotator_demo = CustomAnnotatorExample()
result = annotator_demo.process_annotations()

🔧 常见问题解决

1. 相机数据获取失败

def debug_camera_setup(camera):
    """调试相机设置"""
    # 检查相机是否初始化
    print(f"Camera initialized: {camera.is_initialized()}")
    
    # 检查渲染产品
    print(f"Render product: {camera.render_product_path}")
    
    # 确保等待一帧生成数据
    world.step(render=True)
    
    # 检查数据是否可用
    frame_data = camera.get_current_frame()
    print(f"Available data types: {list(frame_data.keys())}")

2. 标注器性能优化

# 优化标注器设置
def optimize_annotators(camera):
    # 减少不必要的标注器
    necessary_annotators = ["rgb", "depth"]
    
    # 降低分辨率
    camera.set_resolution((640, 480))
    
    # 限制频率
    camera.set_frequency(30)
    
    # 选择合适的设备
    camera.set_device("cuda")  # 使用GPU加速

3. 多相机同步问题

def synchronize_cameras(cameras):
    """确保多相机同步"""
    # 设置相同的频率
    for camera in cameras:
        camera.set_frequency(30)
        
    # 在相同时间点采集
    world.step(render=True)
    
    # 获取时间戳
    timestamp = world.current_time
    
    # 批量采集数据
    data = {}
    for i, camera in enumerate(cameras):
        frame = camera.get_current_frame()
        frame["timestamp"] = timestamp
        data[f"camera_{i}"] = frame
        
    return data

📊 标注器数据格式

标注器类型数据类型形状说明
rgbuint8(H, W, 3)RGB彩色图像
depthfloat32(H, W)深度图(米)
semantic_segmentationuint32(H, W)语义分割ID
instance_id_segmentationuint32(H, W)实例分割ID
bounding_box_2d_tightdict-2D边界框信息
bounding_box_3ddict-3D边界框信息
distance_to_camerafloat32(H, W)到相机距离
distance_to_image_planefloat32(H, W)到图像平面距离

📐 坐标变换常量

# 相机坐标系变换
R_U_TRANSFORM = np.array([    [ 1,  0,  0,  0],
    [ 0, -1,  0,  0],
    [ 0,  0, -1,  0],
    [ 0,  0,  0,  1]
])

U_R_TRANSFORM = np.array([    [ 1,  0,  0,  0],
    [ 0, -1,  0,  0],
    [ 0,  0, -1,  0],
    [ 0,  0,  0,  1]
])

U_W_TRANSFORM = np.array([    [ 0, -1,  0,  0],
    [ 0,  0,  1,  0],
    [-1,  0,  0,  0],
    [ 0,  0,  0,  1]
])

W_U_TRANSFORM = np.array([    [ 0,  0, -1,  0],
    [-1,  0,  0,  0],
    [ 0,  1,  0,  0],
    [ 0,  0,  0,  1]
])

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


Isaac Sim API - 对象与几何

📋 概述

3D对象和几何体,包括基本形状、关节对象等。涵盖从基础几何体到复杂对象的完整创建和管理功能。


📦 基础几何对象

🟦 立方体系列

动态立方体 - DynamicCuboid

位置: isaacsim.core.api.objects.DynamicCuboid

功能说明: 具有物理和碰撞的动态立方体。

代码示例:

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

# 创建动态立方体
dynamic_cube = DynamicCuboid(
    prim_path="/World/DynamicCube",
    name="dynamic_cube",
    position=np.array([0.5, 0.0, 0.5]),
    orientation=np.array([0.707, 0, 0, 0.707]),  # 45度旋转
    size=np.array([0.1, 0.1, 0.1]),
    scale=np.array([1.0, 1.0, 1.0]),
    color=np.array([1.0, 0.0, 0.0])  # 红色
)

# 应用材质
from isaacsim.core.api.materials import PhysicsMaterial
physics_material = PhysicsMaterial(
    prim_path="/World/Physics/CubeMaterial",
    static_friction=0.7,
    dynamic_friction=0.5,
    restitution=0.3
)
dynamic_cube.apply_physics_material(physics_material)

# 应用视觉材质
from isaacsim.core.api.materials import OmniPBR
visual_material = OmniPBR(
    prim_path="/World/Visual/CubeMaterial",
    color=np.array([0.8, 0.1, 0.1])
)
dynamic_cube.apply_visual_material(visual_material)

# 设置物理属性
dynamic_cube.set_mass(0.5)  # 设置质量
dynamic_cube.set_linear_velocity(np.array([0.1, 0, 0]))  # 设置线速度
dynamic_cube.set_angular_velocity(np.array([0, 0, 1]))   # 设置角速度

# 获取物理状态
position, orientation = dynamic_cube.get_world_pose()
linear_vel = dynamic_cube.get_linear_velocity()
angular_vel = dynamic_cube.get_angular_velocity()
固定立方体 - FixedCuboid

位置: isaacsim.core.api.objects.FixedCuboid

功能说明: 具有碰撞但无动力学的固定立方体。

代码示例:

from isaacsim.core.api.objects import FixedCuboid

# 创建固定立方体(作为地面障碍物)
fixed_cube = FixedCuboid(
    prim_path="/World/FixedCube",
    name="obstacle",
    position=np.array([1.0, 0.0, 0.0]),
    size=np.array([0.2, 0.2, 0.2]),
    color=np.array([0.5, 0.5, 0.5])
)

# 设置碰撞属性
fixed_cube.set_collision_approximation("convexHull")
fixed_cube.set_collision_enabled(True)

# 获取接触力数据
contact_force_data = fixed_cube.get_contact_force_data(dt=1.0)
contact_force_matrix = fixed_cube.get_contact_force_matrix(dt=1.0)
视觉立方体 - VisualCuboid

位置: isaacsim.core.api.objects.VisualCuboid

功能说明: 仅用于视觉显示的立方体,无物理碰撞。

代码示例:

from isaacsim.core.api.objects import VisualCuboid

# 创建纯视觉立方体(用作标记)
visual_cube = VisualCuboid(
    prim_path="/World/Marker",
    name="target_marker",
    position=np.array([2.0, 0.0, 0.5]),
    size=np.array([0.05, 0.05, 0.05]),
    color=np.array([0.0, 1.0, 0.0])  # 绿色标记
)

# 设置透明度
visual_cube.set_opacity(0.7)

🔵 球体系列

动态球体 - DynamicSphere

位置: isaacsim.core.api.objects.DynamicSphere

代码示例:

from isaacsim.core.api.objects import DynamicSphere

# 创建动态球体
dynamic_sphere = DynamicSphere(
    prim_path="/World/Ball",
    name="bouncing_ball",
    position=np.array([0.0, 0.0, 2.0]),
    radius=0.05,
    color=np.array([0.0, 0.0, 1.0])  # 蓝色
)

# 设置高弹性材质
bouncy_material = PhysicsMaterial(
    static_friction=0.3,
    dynamic_friction=0.2,
    restitution=0.9  # 高弹性
)
dynamic_sphere.apply_physics_material(bouncy_material)
固定球体 - FixedSphere

位置: isaacsim.core.api.objects.FixedSphere

视觉球体 - VisualSphere

位置: isaacsim.core.api.objects.VisualSphere

🔸 其他基础形状

圆锥体系列
from isaacsim.core.api.objects import DynamicCone, FixedCone, VisualCone

# 动态圆锥
cone = DynamicCone(
    prim_path="/World/Cone",
    name="traffic_cone",
    position=np.array([1.0, 1.0, 0.0]),
    radius=0.1,
    height=0.3,
    color=np.array([1.0, 0.5, 0.0])  # 橙色
)
圆柱体系列
from isaacsim.core.api.objects import DynamicCylinder, FixedCylinder, VisualCylinder

# 动态圆柱
cylinder = DynamicCylinder(
    prim_path="/World/Cylinder",
    name="barrel",
    position=np.array([0.5, 0.5, 0.0]),
    radius=0.1,
    height=0.4,
    color=np.array([0.8, 0.8, 0.8])  # 灰色
)
胶囊体系列
from isaacsim.core.api.objects import DynamicCapsule, FixedCapsule, VisualCapsule

# 动态胶囊
capsule = DynamicCapsule(
    prim_path="/World/Capsule",
    name="capsule",
    position=np.array([0.0, 0.0, 0.2]),
    radius=0.05,
    height=0.3,
    color=np.array([0.5, 0.0, 0.5])  # 紫色
)

🏗️ 特殊对象

🌍 地面平面 - GroundPlane

位置: isaacsim.core.api.objects.GroundPlane

功能说明: 创建地面平面,通常用作场景的基础。

代码示例:

from isaacsim.core.api.objects import GroundPlane

# 创建标准地面
ground_plane = GroundPlane(
    prim_path="/World/GroundPlane",
    name="main_ground",
    size=10.0,        # 地面尺寸 (10x10米)
    z_position=0.0,   # 地面高度
    scale=np.array([1.0, 1.0, 1.0]),
    color=np.array([0.5, 0.5, 0.5])
)

# 应用自定义物理材质
ground_material = PhysicsMaterial(
    static_friction=0.8,
    dynamic_friction=0.6,
    restitution=0.1
)
ground_plane.apply_physics_material(ground_material)

# 设置默认状态
ground_plane.set_default_state(
    position=np.array([0, 0, 0]),
    orientation=np.array([0, 0, 0, 1])
)

# 在重置时恢复到默认状态
ground_plane.post_reset()

关键方法:

  • set_default_state(position, orientation): 设置默认位姿
  • post_reset(): 重置到默认状态
  • apply_physics_material(material): 应用物理材质
  • get_world_pose(): 获取世界位姿

🔧 对象操作方法

通用属性和方法

所有几何对象都继承自基础类,具有以下通用方法:

# 位姿操作
object.set_world_pose(position, orientation)
position, orientation = object.get_world_pose()
object.set_local_pose(position, orientation)
position, orientation = object.get_local_pose()

# 缩放操作
object.set_world_scale(scale)
scale = object.get_world_scale()
object.set_local_scale(scale)
scale = object.get_local_scale()

# 可见性
object.set_visibility(visible=True)
is_visible = object.get_visibility()

# 材质应用
object.apply_visual_material(visual_material)
visual_material = object.get_applied_visual_material()
object.apply_physics_material(physics_material)
physics_material = object.get_applied_physics_material()

# 物理操作(仅动态对象)
object.set_mass(mass)
object.set_linear_velocity(velocity)
object.set_angular_velocity(angular_velocity)
object.set_inertia(inertia_tensor)

碰撞属性设置

# 设置碰撞形状
object.set_collision_approximation("convexHull")  # 选项: "none", "boundingBox", "boundingSphere", "convexHull", "mesh"

# 启用/禁用碰撞
object.set_collision_enabled(True)
is_enabled = object.get_collision_enabled()

# 设置碰撞偏移
object.set_contact_offset(0.02)
offset = object.get_contact_offset()

# 设置休息偏移
object.set_rest_offset(0.0)
rest_offset = object.get_rest_offset()

💡 实际应用示例

创建复杂场景

class SceneBuilder:
    def __init__(self, world):
        self.world = world
        self.scene = world.scene
        
    def create_warehouse_scene(self):
        """创建仓库场景"""
        # 地面
        ground = GroundPlane(
            prim_path="/World/Ground",
            name="warehouse_floor",
            size=20.0,
            color=np.array([0.7, 0.7, 0.7])
        )
        self.scene.add(ground)
        
        # 货架系列
        for i in range(5):
            for j in range(3):
                shelf = FixedCuboid(
                    prim_path=f"/World/Shelf_{i}_{j}",
                    name=f"shelf_{i}_{j}",
                    position=np.array([i * 2.0, j * 1.5, 1.0]),
                    size=np.array([0.8, 0.3, 2.0]),
                    color=np.array([0.8, 0.6, 0.4])
                )
                self.scene.add(shelf)
        
        # 货物
        cargo_positions = [
            [1.0, 0.5, 1.1], [3.0, 1.0, 1.1], [5.0, 2.0, 1.1]
        ]
        
        for i, pos in enumerate(cargo_positions):
            cargo = DynamicCuboid(
                prim_path=f"/World/Cargo_{i}",
                name=f"cargo_{i}",
                position=np.array(pos),
                size=np.array([0.5, 0.5, 0.5]),
                color=np.array([0.9, 0.7, 0.3])
            )
            self.scene.add(cargo)
        
        # 机器人工作台
        workbench = FixedCuboid(
            prim_path="/World/Workbench",
            name="workbench",
            position=np.array([0.0, 0.0, 0.5]),
            size=np.array([1.5, 1.0, 0.02]),
            color=np.array([0.3, 0.3, 0.3])
        )
        self.scene.add(workbench)
        
    def create_obstacle_course(self):
        """创建障碍物赛道"""
        # 起始平台
        start_platform = FixedCuboid(
            prim_path="/World/StartPlatform",
            position=np.array([0.0, 0.0, 0.1]),
            size=np.array([2.0, 2.0, 0.2]),
            color=np.array([0.0, 1.0, 0.0])
        )
        
        # 障碍物
        obstacles = [
            # 跳跃障碍
            {
                "type": DynamicCuboid,
                "position": [3.0, 0.0, 0.3],
                "size": [0.5, 2.0, 0.6],
                "color": [1.0, 0.0, 0.0]
            },
            # 圆柱障碍
            {
                "type": FixedCylinder,
                "position": [6.0, -1.0, 0.0],
                "radius": 0.3,
                "height": 2.0,
                "color": [0.0, 0.0, 1.0]
            },
            # 球形障碍
            {
                "type": DynamicSphere,
                "position": [9.0, 1.0, 1.0],
                "radius": 0.5,
                "color": [1.0, 1.0, 0.0]
            }
        ]
        
        for i, obs in enumerate(obstacles):
            obj_type = obs.pop("type")
            obj = obj_type(
                prim_path=f"/World/Obstacle_{i}",
                name=f"obstacle_{i}",
                **obs
            )
            self.scene.add(obj)
        
        # 终点平台
        end_platform = FixedCuboid(
            prim_path="/World/EndPlatform",
            position=np.array([12.0, 0.0, 0.1]),
            size=np.array([2.0, 2.0, 0.2]),
            color=np.array([0.0, 0.0, 1.0])
        )
        
    def create_physics_playground(self):
        """创建物理游乐场"""
        # 坡道
        ramp = FixedCuboid(
            prim_path="/World/Ramp",
            position=np.array([0.0, 0.0, 0.5]),
            rotation=np.array([0.0, 0.3, 0.0]),  # 倾斜角度
            size=np.array([2.0, 1.0, 0.1]),
            color=np.array([0.7, 0.7, 0.9])
        )
        
        # 滚球
        for i in range(10):
            ball = DynamicSphere(
                prim_path=f"/World/Ball_{i}",
                name=f"ball_{i}",
                position=np.array([
                    np.random.uniform(-0.5, 0.5),
                    np.random.uniform(-0.5, 0.5),
                    2.0 + i * 0.2
                ]),
                radius=0.05,
                color=np.random.uniform(0, 1, 3)
            )
            
            # 随机材质
            mat = PhysicsMaterial(
                static_friction=np.random.uniform(0.1, 1.0),
                dynamic_friction=np.random.uniform(0.1, 1.0),
                restitution=np.random.uniform(0.0, 0.9)
            )
            ball.apply_physics_material(mat)
        
        # 弹簧板
        trampoline = FixedCuboid(
            prim_path="/World/Trampoline",
            position=np.array([3.0, 0.0, 0.05]),
            size=np.array([1.0, 1.0, 0.1]),
            color=np.array([0.0, 1.0, 1.0])
        )
        
        # 高弹性材质
        bouncy_mat = PhysicsMaterial(
            static_friction=0.5,
            dynamic_friction=0.4,
            restitution=0.95
        )
        trampoline.apply_physics_material(bouncy_mat)

# 使用示例
builder = SceneBuilder(world)
builder.create_warehouse_scene()
builder.create_obstacle_course()
builder.create_physics_playground()

对象池管理器

class ObjectPoolManager:
    def __init__(self, world):
        self.world = world
        self.scene = world.scene
        self.pools = {}
        
    def create_pool(self, object_type, pool_name, size, **object_params):
        """创建对象池"""
        self.pools[pool_name] = {
            "objects": [],
            "available": [],
            "type": object_type,
            "params": object_params
        }
        
        # 预创建对象
        for i in range(size):
            obj = object_type(
                prim_path=f"/World/Pool/{pool_name}/{i}",
                name=f"{pool_name}_{i}",
                position=np.array([100, 100, 100]),  # 初始位置在远处
                **object_params
            )
            obj.set_visibility(False)  # 初始隐藏
            
            self.scene.add(obj)
            self.pools[pool_name]["objects"].append(obj)
            self.pools[pool_name]["available"].append(obj)
    
    def get_object(self, pool_name):
        """从池中获取对象"""
        if pool_name not in self.pools:
            return None
            
        pool = self.pools[pool_name]
        if not pool["available"]:
            return None
            
        obj = pool["available"].pop()
        obj.set_visibility(True)
        return obj
    
    def return_object(self, pool_name, obj):
        """归还对象到池"""
        if pool_name not in self.pools:
            return
            
        pool = self.pools[pool_name]
        if obj in pool["objects"] and obj not in pool["available"]:
            obj.set_visibility(False)
            obj.set_world_pose(np.array([100, 100, 100]))  # 移到远处
            pool["available"].append(obj)
    
    def clear_pool(self, pool_name):
        """清空池中所有对象"""
        if pool_name not in self.pools:
            return
            
        pool = self.pools[pool_name]
        for obj in pool["objects"]:
            self.return_object(pool_name, obj)

# 使用示例
pool_manager = ObjectPoolManager(world)

# 创建立方体池
pool_manager.create_pool(
    DynamicCuboid,
    "cubes",
    size=20,
    size=np.array([0.05, 0.05, 0.05]),
    color=np.array([1.0, 0.0, 0.0])
)

# 创建球体池
pool_manager.create_pool(
    DynamicSphere,
    "balls",
    size=30,
    radius=0.03,
    color=np.array([0.0, 1.0, 0.0])
)

# 使用对象
cube = pool_manager.get_object("cubes")
if cube:
    cube.set_world_pose(np.array([0.5, 0.0, 0.5]))
    
# 归还对象
pool_manager.return_object("cubes", cube)

动态场景生成器

class DynamicSceneGenerator:
    def __init__(self, world):
        self.world = world
        self.scene = world.scene
        
    def generate_random_scene(self, num_objects=20, scene_size=10.0):
        """生成随机场景"""
        object_types = [
            DynamicCuboid, DynamicSphere, DynamicCylinder, 
            DynamicCone, DynamicCapsule
        ]
        
        colors = [
            [1.0, 0.0, 0.0],  # 红
            [0.0, 1.0, 0.0],  # 绿
            [0.0, 0.0, 1.0],  # 蓝
            [1.0, 1.0, 0.0],  # 黄
            [1.0, 0.0, 1.0],  # 品红
            [0.0, 1.0, 1.0],  # 青
        ]
        
        for i in range(num_objects):
            # 随机选择对象类型
            obj_type = np.random.choice(object_types)
            
            # 随机位置
            position = np.array([
                np.random.uniform(-scene_size/2, scene_size/2),
                np.random.uniform(-scene_size/2, scene_size/2),
                np.random.uniform(0.1, 2.0)
            ])
            
            # 随机颜色
            color = np.array(np.random.choice(colors))
            
            # 创建对象
            if obj_type == DynamicCuboid:
                obj = obj_type(
                    prim_path=f"/World/Random/Cube_{i}",
                    name=f"random_cube_{i}",
                    position=position,
                    size=np.random.uniform(0.05, 0.2, 3),
                    color=color
                )
            elif obj_type == DynamicSphere:
                obj = obj_type(
                    prim_path=f"/World/Random/Sphere_{i}",
                    name=f"random_sphere_{i}",
                    position=position,
                    radius=np.random.uniform(0.03, 0.1),
                    color=color
                )
            elif obj_type in [DynamicCylinder, DynamicCone, DynamicCapsule]:
                obj = obj_type(
                    prim_path=f"/World/Random/{obj_type.__name__}_{i}",
                    name=f"random_{obj_type.__name__.lower()}_{i}",
                    position=position,
                    radius=np.random.uniform(0.03, 0.1),
                    height=np.random.uniform(0.1, 0.4),
                    color=color
                )
            
            # 应用随机物理材质
            mat = PhysicsMaterial(
                static_friction=np.random.uniform(0.1, 1.5),
                dynamic_friction=np.random.uniform(0.1, 1.2),
                restitution=np.random.uniform(0.0, 0.9)
            )
            obj.apply_physics_material(mat)
            
            self.scene.add(obj)
    
    def generate_maze(self, width=10, height=10, wall_height=1.0):
        """生成迷宫"""
        # 生成迷宫布局(简化算法)
        maze = np.ones((height, width), dtype=int)
        
        # 创建通道
        for i in range(1, height-1):
            for j in range(1, width-1):
                if np.random.random() < 0.3:  # 30%概率为空间
                    maze[i, j] = 0
        
        # 创建墙体
        for i in range(height):
            for j in range(width):
                if maze[i, j] == 1:
                    wall = FixedCuboid(
                        prim_path=f"/World/Maze/Wall_{i}_{j}",
                        name=f"wall_{i}_{j}",
                        position=np.array([j, i, wall_height/2]),
                        size=np.array([1.0, 1.0, wall_height]),
                        color=np.array([0.8, 0.8, 0.8])
                    )
                    self.scene.add(wall)
        
        # 添加起点和终点标记
        start_marker = VisualCuboid(
            prim_path="/World/Maze/Start",
            position=np.array([0, 0, wall_height + 0.1]),
            size=np.array([0.5, 0.5, 0.1]),
            color=np.array([0.0, 1.0, 0.0])
        )
        
        end_marker = VisualCuboid(
            prim_path="/World/Maze/End",
            position=np.array([width-1, height-1, wall_height + 0.1]),
            size=np.array([0.5, 0.5, 0.1]),
            color=np.array([1.0, 0.0, 0.0])
        )
        
        self.scene.add(start_marker)
        self.scene.add(end_marker)

# 使用示例
generator = DynamicSceneGenerator(world)

# 生成随机场景
generator.generate_random_scene(num_objects=50, scene_size=20.0)

# 生成迷宫
generator.generate_maze(width=20, height=20, wall_height=2.0)

🔧 常见问题解决

1. 物理对象不动问题

def debug_physics_object(obj):
    """调试物理对象"""
    # 检查是否有刚体
    if not hasattr(obj, 'get_linear_velocity'):
        print("Object is not a dynamic object")
        return
    
    # 检查质量
    mass = obj.get_mass()
    print(f"Mass: {mass}")
    
    # 检查碰撞
    collision_enabled = obj.get_collision_enabled()
    print(f"Collision enabled: {collision_enabled}")
    
    # 检查重力
    gravity_scale = obj.get_gravity_scale()
    print(f"Gravity scale: {gravity_scale}")
    
    # 检查是否被约束
    kinematic = obj.is_kinematic()
    print(f"Is kinematic: {kinematic}")
    
    # 设置初始速度
    obj.set_linear_velocity(np.array([0, 0, 0.1]))

2. 碰撞检测优化

class CollisionOptimizer:
    @staticmethod
    def optimize_collision_shapes(objects):
        """优化碰撞形状"""
        for obj in objects:
            # 根据对象类型选择最佳碰撞形状
            if isinstance(obj, DynamicSphere):
                obj.set_collision_approximation("boundingSphere")
            elif isinstance(obj, DynamicCuboid):
                obj.set_collision_approximation("boundingBox")
            else:
                obj.set_collision_approximation("convexHull")
            
            # 设置合适的碰撞边距
            obj.set_contact_offset(0.02)
            obj.set_rest_offset(0.001)
    
    @staticmethod
    def setup_collision_filters(obj1, obj2, should_collide=True):
        """设置碰撞过滤"""
        # 设置碰撞组
        obj1.set_collision_group(0 if should_collide else 1)
        obj2.set_collision_group(0 if should_collide else 2)
        
        # 设置碰撞掩码
        if not should_collide:
            obj1.set_collision_mask(0)
            obj2.set_collision_mask(0)

3. 性能优化

class ObjectPerformanceOptimizer:
    @staticmethod
    def optimize_visual_objects(objects):
        """优化视觉对象"""
        for obj in objects:
            # 减少LOD级别
            obj.set_lod_level(1)
            
            # 简化材质
            if hasattr(obj, 'apply_visual_material'):
                simple_material = PreviewSurface(
                    prim_path=f"{obj.prim_path}_simple_mat",
                    color=obj.get_color()
                )
                obj.apply_visual_material(simple_material)
    
    @staticmethod
    def batch_create_objects(object_configs):
        """批量创建对象"""
        # 关闭渲染更新
        from omni.kit.viewport.utility import get_active_viewport
        viewport = get_active_viewport()
        viewport.set_render_enabled(False)
        
        # 批量创建
        objects = []
        for config in object_configs:
            obj = config["type"](**config["params"])
            objects.append(obj)
        
        # 重新启用渲染
        viewport.set_render_enabled(True)
        
        return objects

📊 对象类型对比

对象类型物理碰撞刚体动力学适用场景
Dynamic*可移动的物体
Fixed*固定障碍物
Visual*视觉标记

🎯 最佳实践

  1. 选择合适的对象类型

    • 使用Dynamic对象用于需要物理交互的实体
    • 使用Fixed对象用于环境和障碍物
    • 使用Visual对象用于UI和标记
  2. 优化碰撞检测

    • 选择合适的碰撞近似形状
    • 为静态对象使用简单的碰撞形状
    • 合理设置碰撞边距
  3. 材质管理

    • 重用材质定义
    • 根据需求选择合适的材质类型
    • 批量应用材质
  4. 性能考虑

    • 使用对象池管理频繁创建/销毁的对象
    • 批量操作来减少渲染更新
    • 合理设置LOD级别

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


Isaac Sim API - 导入工具

📋 概述

资产导入工具,包括URDF、MJCF等格式导入。提供完整的机器人和场景资产导入解决方案。


📥 主要类

🔄 URDF导入器

🏷️ URDFCreateImportConfig

位置: isaacsim.asset.importer.urdf.URDFCreateImportConfig

功能说明: 返回用于解析和导入的ImportConfig对象。

使用示例:

# 创建URDF导入配置
config = URDFCreateImportConfig()

主要方法:

  • do() - 执行配置创建
  • undo() - 撤销操作
🤖 URDFImportRobot

位置: isaacsim.asset.importer.urdf.URDFImportRobot

功能说明: 解析并导入URDF文件,返回UrdfRobot对象。

参数说明:

参数类型描述
arg0strURDF文件的绝对路径
arg1UrdfRobot解析后的URDF机器人对象
arg2ImportConfig导入配置对象
arg3str目标USD路径(默认空串在内存中加载)

主要方法:

  • do() → str - 执行导入操作
  • undo() → None - 撤销导入

🎯 MJCF导入器

📦 MJCFCreateImportConfig

位置: isaacsim.asset.importer.mjcf.MJCFCreateImportConfig

功能说明: 创建MJCF格式的导入配置。

主要方法:

  • do() → ImportConfig - 返回MJCF导入配置
  • undo() → None - 撤销操作
🚀 MJCFCreateAsset

位置: isaacsim.asset.importer.mjcf.MJCFCreateAsset

功能说明: 解析并导入MJCF文件到场景。

参数说明:

参数类型描述
arg0strMJCF文件的绝对路径
arg1ImportConfig导入配置
arg2str机器人在USD场景中的路径
arg3str目标USD路径

主要方法:

  • do() → str - 执行导入操作
  • undo() → None - 撤销导入

🛠️ 重要函数

📝 UI构建函数

函数名描述示例用法
btn_builder()创建风格化按钮btn_builder(label="Import", onclick_fn=import_urdf)
cb_builder()创建复选框cb_builder(label="Fix Base", default_val=True)
dropdown_builder()创建下拉菜单dropdown_builder(label="Drive", items=["Position", "Velocity"])
float_builder()创建浮点数输入框float_builder(label="Scale", default_val=1.0)
str_builder()创建字符串输入框str_builder(label="Package Dir", use_folder_picker=True)

🔍 工具函数

# 检查文件类型
from isaacsim.asset.importer.urdf import is_urdf_file
from isaacsim.asset.importer.mjcf import is_mjcf_file

if is_urdf_file("robot.urdf"):
    print("这是一个URDF文件")
    
if is_mjcf_file("robot.xml"):
    print("这是一个MJCF文件")

# 目录检查
from isaacsim.asset.importer.urdf import dir_exists
if dir_exists("/path/to/directory"):
    print("目录存在")

📊 常量

常量名描述
EXTENSION_NAME (URDF)'URDF Importer'URDF扩展名称
EXTENSION_NAME (MJCF)'MJCF Importer'MJCF扩展名称

🔢 枚举

✅ Result枚举

位置: isaacsim.asset.importer.urdf.Result

枚举值数值描述
OK0操作成功
OK_LATEST1成功且为最新版本
ERROR3一般错误
ERROR_NOT_FOUND7文件未找到
ERROR_ACCESS_DENIED6访问被拒绝

💡 使用示例

导入URDF文件的完整流程

from isaacsim.asset.importer.urdf import URDFCreateImportConfig, URDFImportRobot
import omni

# 1. 创建导入配置
config_cmd = URDFCreateImportConfig()
config = config_cmd.do()

# 2. 设置配置参数
config.fix_base = True
config.use_gpu_dynamics = True
config.joint_drive_type = 0  # Position control

# 3. 导入URDF
import_cmd = URDFImportRobot(
    urdf_path="/path/to/robot.urdf",
    config=config,
    prim_path="/World/Robot"
)

# 4. 执行导入
result = import_cmd.do()
print(f"Robot imported at: {result}")

自定义MJCF导入

from isaacsim.asset.importer.mjcf import MJCFCreateImportConfig, MJCFCreateAsset

# 创建MJCF配置
config_cmd = MJCFCreateImportConfig()
config = config_cmd.do()

# 自定义配置
config.use_gpu_physics = True
config.self_collision = True

# 导入MJCF
asset_cmd = MJCFCreateAsset(
    mjcf_path="/path/to/robot.xml",
    config=config,
    prim_path="/World/MujocoRobot",
    usd_path=""  # 在内存中加载
)

# 执行导入
prim_path = asset_cmd.do()

🎨 UI扩展类

📁 FilePickerDialog

位置: isaacsim.asset.importer.mjcf.FilePickerDialog

功能说明: 文件选择器对话框,用于浏览文件系统。

主要方法:

方法名描述
get_current_directory()获取当前目录
get_current_selections()获取选中的文件
get_file_extension()获取文件扩展名
add_connections()添加服务器连接

🎚️ Extension类

基础扩展类,提供标准的启动和关闭接口

方法名描述
on_startup()扩展启动时调用
on_shutdown()扩展关闭时调用

Isaac Sim API - 仿真工具

📋 概述

仿真相关工具,包括数据生成、UI组件等。提供完整的仿真环境搭建和数据收集工具。


🎬 主要工具类

📹 SyntheticRecorder

📦 SyntheticRecorderExtension

位置: isaacsim.replicator.synthetic_recorder.SyntheticRecorderExtension

功能说明: 用于记录仿真数据的扩展,支持多种数据格式输出。

主要方法:

方法名描述
on_startup()扩展启动初始化
on_shutdown()扩展关闭清理
_destroy_window_async()异步销毁窗口
_visibility_changed_fn()处理可见性变化
🖥️ SyntheticRecorderWindow

位置: isaacsim.replicator.synthetic_recorder.SyntheticRecorderWindow

功能说明: 合成数据记录器的UI窗口。

界面组件:

# UI组件构建方法
- _build_control_ui()        # 控制面板
- _build_config_ui()         # 配置面板
- _build_rp_ui()            # 渲染产品UI
- _build_output_ui()        # 输出设置UI
- _build_basic_writer_ui()  # 基础写入器UI
- _build_custom_writer_ui() # 自定义写入器UI
- _build_s3_ui()           # S3存储UI

使用示例:

from isaacsim.replicator.synthetic_recorder import SyntheticRecorderWindow

# 创建记录器窗口
recorder = SyntheticRecorderWindow()

# 设置输出路径
recorder.set_output_path("/path/to/recordings")

# 添加渲染产品
recorder.add_render_product(camera_prim_path="/World/Camera")

# 开始记录
recorder.start_recording()

🎯 数据生成工具

📊 数据格式支持
格式描述用途
USD通用场景描述格式场景结构保存
JSON轻量级数据交换格式标注数据输出
HDF5分层数据格式大规模数据集存储
PNG/JPG图像格式相机数据记录
Parquet列式存储格式高效数据分析
🔧 记录配置选项
# 基础配置
config = {
    "output_dir": "/path/to/output",
    "file_format": "json",
    "compression": "gzip",
    "capture_interval": 1,  # 帧间隔
    "max_frames": 1000,
    "include_metadata": True
}

# 相机配置
camera_config = {
    "rgb": True,
    "depth": True,
    "semantic_segmentation": True,
    "instance_segmentation": True,
    "bounding_box_2d": True,
    "bounding_box_3d": True
}

# 传感器配置
sensor_config = {
    "lidar": {
        "enabled": True,
        "format": "pointcloud"
    },
    "imu": {
        "enabled": True,
        "frequency": 100
    }
}

🎨 UI辅助类

🔄 MenuHelperExtension

位置: isaacsim.replicator.synthetic_recorder.MenuHelperExtension

功能说明: 简化菜单创建和管理的辅助类。

使用方法:

from isaacsim.replicator.synthetic_recorder import MenuHelperExtension

class MyExtension(MenuHelperExtension):
    def on_startup(self, ext_id):
        # 创建菜单
        self.menu_startup(
            window_name="My Tool",
            menu_desc=[{
                "name": "Open My Tool",
                "onclick_fn": self._open_window
            }],
            menu_group="Tools",
            appear_after="Import"
        )
    
    def _open_window(self):
        # 打开窗口的逻辑
        pass

📊 实际应用示例

数据集生成流程

from isaacsim.replicator.synthetic_recorder import SyntheticRecorderExtension
from isaacsim.sensors.camera import Camera
import omni.replicator.core as rep

def generate_dataset():
    # 1. 设置场景
    rep.create.sphere(
        semantics=[('class', 'sphere')],
        position=rep.distribution.uniform((-1, -1, 0), (1, 1, 2)),
        count=10
    )
    
    # 2. 配置相机
    camera = Camera(prim_path="/World/Camera", frequency=30)
    camera.add_motion_vectors_to_frame()
    camera.add_instance_id_segmentation_to_frame()
    
    # 3. 设置记录器
    recorder = SyntheticRecorderWindow()
    recorder.add_render_product("/Render/Camera")
    
    # 4. 配置输出
    writer = rep.WriterRegistry.get("BasicWriter")
    writer.initialize(
        output_dir="/path/to/dataset",
        rgb=True,
        semantic_segmentation=True,
        instance_segmentation=True
    )
    
    # 5. 开始生成
    rep.orchestrator.step()

批量仿真处理

def batch_simulation(scenarios, output_base_dir):
    """批量运行仿真场景"""
    
    for i, scenario in enumerate(scenarios):
        # 加载场景
        load_scenario(scenario)
        
        # 配置记录器
        output_dir = f"{output_base_dir}/scenario_{i}"
        recorder = setup_recorder(output_dir)
        
        # 运行仿真
        for step in range(scenario.num_steps):
            # 应用场景变化
            apply_scenario_step(scenario, step)
            
            # 记录数据
            recorder.capture_frame()
            
            # 执行仿真步
            world.step(render=True)
        
        # 清理场景
        cleanup_scenario()
        
    print(f"完成 {len(scenarios)} 个场景的仿真")

自定义数据写入器

import json
from typing import Dict, Any

class CustomDataWriter:
    """自定义数据写入器"""
    
    def __init__(self, output_path: str):
        self.output_path = output_path
        self.frame_count = 0
        
    def write_frame(self, data: Dict[str, Any]):
        """写入单帧数据"""
        frame_data = {
            "frame_id": self.frame_count,
            "timestamp": time.time(),
            "robot_state": data.get("robot_state"),
            "camera_data": data.get("camera_data"),
            "annotations": data.get("annotations")
        }
        
        # 保存到JSON文件
        output_file = f"{self.output_path}/frame_{self.frame_count:06d}.json"
        with open(output_file, 'w') as f:
            json.dump(frame_data, f, indent=2)
            
        self.frame_count += 1
        
    def finalize(self):
        """完成数据写入"""
        metadata = {
            "total_frames": self.frame_count,
            "dataset_info": {
                "created_at": time.ctime(),
                "version": "1.0"
            }
        }
        
        with open(f"{self.output_path}/metadata.json", 'w') as f:
            json.dump(metadata, f, indent=2)

📈 性能优化技巧

高效数据记录

# 批量写入优化
class BatchWriter:
    def __init__(self, batch_size=100):
        self.batch_size = batch_size
        self.buffer = []
        
    def add_frame(self, frame_data):
        self.buffer.append(frame_data)
        
        if len(self.buffer) >= self.batch_size:
            self.flush()
            
    def flush(self):
        """批量写入磁盘"""
        if self.buffer:
            # 批量写入逻辑
            write_batch_to_disk(self.buffer)
            self.buffer.clear()

# 内存管理
@contextmanager
def memory_limit(max_memory_mb):
    """限制内存使用"""
    import psutil
    
    def check_memory():
        current = psutil.virtual_memory().percent
        if current > max_memory_mb:
            # 清理内存
            gc.collect()
            
    yield check_memory

并行处理

from concurrent.futures import ThreadPoolExecutor
import queue

class ParallelDataProcessor:
    """并行数据处理器"""
    
    def __init__(self, num_workers=4):
        self.num_workers = num_workers
        self.data_queue = queue.Queue()
        self.executor = ThreadPoolExecutor(max_workers=num_workers)
        
    def process_data_parallel(self, data_stream):
        """并行处理数据流"""
        futures = []
        
        for data in data_stream:
            future = self.executor.submit(self.process_single_frame, data)
            futures.append(future)
            
        # 等待所有任务完成
        for future in futures:
            result = future.result()
            self.save_result(result)

Isaac Sim API - ROS2集成

📋 概述

ROS2相关集成和桥接功能,提供与ROS2生态系统的完整互操作性。支持话题、服务、动作客户端等。


🌉 ROS2桥接

📡 话题桥接

from isaacsim.ros2.bridge import ROS2Bridge
from std_msgs.msg import String
from geometry_msgs.msg import Twist

# 初始化ROS2桥接
bridge = ROS2Bridge()

# 订阅ROS2话题
def cmd_vel_callback(msg):
    """处理速度命令"""
    linear_vel = msg.linear.x
    angular_vel = msg.angular.z
    
    # 应用到机器人
    robot.apply_action({
        "linear_velocity": linear_vel,
        "angular_velocity": angular_vel
    })

bridge.subscribe("cmd_vel", Twist, cmd_vel_callback)

# 发布ROS2话题
odom_pub = bridge.create_publisher("odom", Odometry, 10)

def publish_odometry():
    """发布里程计数据"""
    msg = Odometry()
    msg.header.stamp = bridge.get_clock().now().to_msg()
    msg.header.frame_id = "odom"
    
    # 填充位置信息
    pos = robot.get_world_pose()[0]
    msg.pose.pose.position.x = pos[0]
    msg.pose.pose.position.y = pos[1]
    msg.pose.pose.position.z = pos[2]
    
    odom_pub.publish(msg)

🔧 服务集成

from example_interfaces.srv import AddTwoInts

# 创建服务客户端
add_client = bridge.create_client(AddTwoInts, 'add_two_ints')

async def call_add_service(a, b):
    """调用ROS2服务"""
    req = AddTwoInts.Request()
    req.a = a
    req.b = b
    
    future = add_client.call_async(req)
    response = await future
    
    return response.sum

# 创建服务服务端
def handle_robot_command(request, response):
    """处理机器人命令服务"""
    command = request.command
    
    if command == "home":
        robot.move_to_home_position()
        response.success = True
        response.message = "Robot moved to home position"
    else:
        response.success = False
        response.message = f"Unknown command: {command}"
        
    return response

bridge.create_service(
    srv_type=RobotCommand,
    srv_name='robot_command',
    callback=handle_robot_command
)

🎮 动作集成

from control_msgs.action import FollowJointTrajectory

# 创建动作客户端
action_client = bridge.create_action_client(
    FollowJointTrajectory,
    'follow_joint_trajectory'
)

async def execute_trajectory(joint_trajectory):
    """执行关节轨迹"""
    goal_msg = FollowJointTrajectory.Goal()
    goal_msg.trajectory = joint_trajectory
    
    # 发送目标
    future = action_client.send_goal_async(goal_msg)
    goal_handle = await future
    
    if not goal_handle.accepted:
        print("Goal rejected!")
        return
    
    # 等待结果
    result_future = goal_handle.get_result_async()
    result = await result_future
    
    return result.result

🤖 机器人描述集成

📄 URDF/XACRO支持

from isaacsim.ros2.robot_description import RobotDescription

# 加载机器人描述
robot_desc = RobotDescription.from_param("robot_description")

# 创建机器人
robot = robot_desc.create_robot(
    prim_path="/World/RoboROS",
    position=[0, 0, 0]
)

# 同步关节状态
def sync_joint_states():
    """同步关节状态到ROS2"""
    joint_states = JointState()
    joint_states.header.stamp = bridge.get_clock().now().to_msg()
    
    positions = robot.get_joint_positions()
    velocities = robot.get_joint_velocities()
    
    joint_states.name = robot.get_joint_names()
    joint_states.position = positions.tolist()
    joint_states.velocity = velocities.tolist()
    
    joint_state_pub.publish(joint_states)

🗺️ TF变换发布

from tf2_ros import TransformBroadcaster
from geometry_msgs.msg import TransformStamped

# 创建TF广播器
tf_broadcaster = TransformBroadcaster(bridge.node)

def publish_transforms():
    """发布机器人变换树"""
    links = robot.get_all_links()
    
    for link in links:
        if link.parent:
            t = TransformStamped()
            
            # 设置头信息
            t.header.stamp = bridge.get_clock().now().to_msg()
            t.header.frame_id = link.parent.name
            t.child_frame_id = link.name
            
            # 设置变换
            pos, quat = link.get_world_pose()
            t.transform.translation.x = pos[0]
            t.transform.translation.y = pos[1]
            t.transform.translation.z = pos[2]
            t.transform.rotation.x = quat[0]
            t.transform.rotation.y = quat[1]
            t.transform.rotation.rotation.z = quat[2]
            t.transform.rotation.w = quat[3]
            
            tf_broadcaster.sendTransform(t)

📡 传感器数据桥接

📷 相机数据流

from sensor_msgs.msg import Image, PointCloud2
from cv_bridge import CvBridge

# 创建图像桥接器
cv_bridge = CvBridge()

# 设置相机回调
def camera_callback(frame):
    """处理相机帧数据"""
    # RGB图像
    rgb_msg = cv_bridge.cv2_to_imgmsg(frame.rgb, encoding="bgr8")
    rgb_msg.header.stamp = bridge.get_clock().now().to_msg()
    rgb_msg.header.frame_id = "camera_link"
    rgb_pub.publish(rgb_msg)
    
    # 深度图像
    depth_msg = cv_bridge.cv2_to_imgmsg(frame.depth, encoding="32FC1")
    depth_msg.header = rgb_msg.header
    depth_pub.publish(depth_msg)
    
    # 点云数据
    if frame.pointcloud is not None:
        pc_msg = create_pointcloud2_msg(frame.pointcloud)
        pc_msg.header = rgb_msg.header
        pc_pub.publish(pc_msg)

# 注册相机回调
camera.register_callback(camera_callback)

🌐 激光雷达数据

from sensor_msgs.msg import LaserScan

def lidar_callback(scan_data):
    """处理激光雷达数据"""
    scan_msg = LaserScan()
    
    # 设置头信息
    scan_msg.header.stamp = bridge.get_clock().now().to_msg()
    scan_msg.header.frame_id = "laser_link"
    
    # 设置扫描参数
    scan_msg.angle_min = scan_data.angle_min
    scan_msg.angle_max = scan_data.angle_max
    scan_msg.angle_increment = scan_data.angle_increment
    scan_msg.time_increment = scan_data.time_increment
    scan_msg.scan_time = scan_data.scan_time
    scan_msg.range_min = scan_data.range_min
    scan_msg.range_max = scan_data.range_max
    
    # 设置距离数据
    scan_msg.ranges = scan_data.ranges.tolist()
    scan_msg.intensities = scan_data.intensities.tolist()
    
    laser_pub.publish(scan_msg)

# 配置激光雷达
lidar.register_callback(lidar_callback)

🎮 导航集成

🗺️ 导航2集成

from nav2_simple_commander.robot_navigator import BasicNavigator
from geometry_msgs.msg import PoseStamped

# 初始化导航器
navigator = BasicNavigator()

def set_initial_pose(x, y, theta):
    """设置机器人初始位置"""
    initial_pose = PoseStamped()
    initial_pose.header.frame_id = 'map'
    initial_pose.header.stamp = navigator.get_clock().now().to_msg()
    
    initial_pose.pose.position.x = x
    initial_pose.pose.position.y = y
    
    # 设置方向(四元数)
    q = tf_transformations.quaternion_from_euler(0, 0, theta)
    initial_pose.pose.orientation.x = q[0]
    initial_pose.pose.orientation.y = q[1]
    initial_pose.pose.orientation.z = q[2]
    initial_pose.pose.orientation.w = q[3]
    
    navigator.setInitialPose(initial_pose)

def navigate_to_pose(goal_pose):
    """导航到目标位置"""
    goal = PoseStamped()
    goal.header.frame_id = 'map'
    goal.header.stamp = navigator.get_clock().now().to_msg()
    goal.pose = goal_pose
    
    # 开始导航
    navigator.goToPose(goal)
    
    # 等待导航完成
    while not navigator.isTaskComplete():
        feedback = navigator.getFeedback()
        
        # 更新进度
        if feedback:
            print(f"Distance remaining: {feedback.distance_remaining:.2f}")
    
    # 处理导航结果
    result = navigator.getResult()
    if result == TaskResult.SUCCEEDED:
        print("Goal reached!")
    else:
        print(f"Navigation failed: {result}")

🛤️ 路径规划集成

from nav_msgs.msg import Path
from nav_msgs.srv import GetPlan

# 创建路径规划服务客户端
planner_client = bridge.create_client(GetPlan, 'plan_route')

async def plan_path(start, goal):
    """规划路径"""
    req = GetPlan.Request()
    req.start = start
    req.goal = goal
    req.tolerance = 0.5
    
    # 调用规划服务
    future = planner_client.call_async(req)
    response = await future
    
    if response.plan.poses:
        # 可视化路径
        visualize_path(response.plan)
        
        # 执行路径
        follow_path(response.plan)
        
    return response.plan

def follow_path(path):
    """跟随规划的路径"""
    for i, pose_stamped in enumerate(path.poses):
        # 计算机器人到当前目标点的距离
        current_pose = robot.get_world_pose()
        target_pose = extract_pose(pose_stamped.pose)
        
        distance = calculate_distance(current_pose, target_pose)
        
        # 控制机器人移动
        while distance > 0.1:  # 到达阈值
            cmd_vel = calculate_velocity_command(current_pose, target_pose)
            robot.apply_velocity(cmd_vel)
            
            # 更新位置
            current_pose = robot.get_world_pose()
            distance = calculate_distance(current_pose, target_pose)
            
        print(f"Reached waypoint {i+1}/{len(path.poses)}")

🔧 高级功能

📊 诊断系统集成

from diagnostic_msgs.msg import DiagnosticArray, DiagnosticStatus

def publish_diagnostics():
    """发布系统诊断信息"""
    diag_array = DiagnosticArray()
    diag_array.header.stamp = bridge.get_clock().now().to_msg()
    
    # 机器人状态诊断
    robot_status = DiagnosticStatus()
    robot_status.name = "Robot Hardware"
    robot_status.level = DiagnosticStatus.OK
    robot_status.message = "All systems operational"
    
    # 添加详细信息
    robot_status.values.append(KeyValue("Battery", f"{robot.get_battery_level():.1f}%"))
    robot_status.values.append(KeyValue("Temperature", f"{robot.get_temperature():.1f}°C"))
    robot_status.values.append(KeyValue("Uptime", f"{robot.get_uptime():.1f}s"))
    
    diag_array.status.append(robot_status)
    
    # 传感器状态诊断
    sensor_status = DiagnosticStatus()
    sensor_status.name = "Sensors"
    sensor_status.level = check_sensor_health()
    sensor_status.message = "Sensor diagnostics"
    
    diag_array.status.append(sensor_status)
    
    # 发布诊断信息
    diag_pub.publish(diag_array)

🔄 参数服务器集成

# 声明参数
bridge.node.declare_parameter('robot.max_speed', 1.0)
bridge.node.declare_parameter('robot.max_angular_speed', 1.0)
bridge.node.declare_parameter('camera.fps', 30)

# 读取参数
max_speed = bridge.node.get_parameter('robot.max_speed').value
camera_fps = bridge.node.get_parameter('camera.fps').value

# 参数回调
def parameter_callback(params):
    """处理参数变化"""
    for param in params:
        if param.name == 'robot.max_speed':
            robot.set_max_speed(param.value)
        elif param.name == 'camera.fps':
            camera.set_fps(param.value)
            
    return SetParametersResult(successful=True)

# 注册参数回调
bridge.node.add_on_set_parameters_callback(parameter_callback)

🔍 ROS2工具集成

# 与ROS2命令行工具交互
def integrate_with_ros2_tools():
    """集成ROS2工具"""
    
    # 1. 话题列表
    topics = bridge.get_topic_names_and_types()
    print("Available topics:")
    for topic, msg_type in topics:
        print(f"  {topic}: {msg_type}")
    
    # 2. 服务列表
    services = bridge.get_service_names_and_types()
    print("\nAvailable services:")
    for service, srv_type in services:
        print(f"  {service}: {srv_type}")
    
    # 3. 节点信息
    nodes = bridge.get_node_names()
    print(f"\nActive nodes: {nodes}")
    
    # 4. QoS配置
    from rclpy.qos import QoSProfile, ReliabilityPolicy, DurabilityPolicy
    
    custom_qos = QoSProfile(
        reliability=ReliabilityPolicy.RELIABLE,
        durability=DurabilityPolicy.TRANSIENT_LOCAL,
        depth=10
    )
    
    # 使用自定义QoS
    reliable_pub = bridge.create_publisher(
        msg_type=CustomMsg,
        topic='reliable_topic',
        qos_profile=custom_qos
    )

📚 完整示例

🤖 ROS2控制的移动机器人

import rclpy
from isaacsim.ros2.bridge import ROS2Bridge
from isaacsim.robot.wheeled_robots import DifferentialController

class ROS2MobileRobot:
    def __init__(self):
        # 初始化ROS2
        rclpy.init()
        self.bridge = ROS2Bridge()
        
        # 创建机器人
        self.robot = create_differential_robot()
        self.controller = DifferentialController()
        
        # 设置订阅和发布
        self.setup_ros2_interface()
        
    def setup_ros2_interface(self):
        """设置ROS2接口"""
        # 订阅控制命令
        self.bridge.subscribe("cmd_vel", Twist, self.cmd_vel_callback)
        
        # 发布状态信息
        self.odom_pub = self.bridge.create_publisher("odom", Odometry, 10)
        self.joint_pub = self.bridge.create_publisher("joint_states", JointState, 10)
        
        # 创建TF广播器
        self.tf_broadcaster = TransformBroadcaster(self.bridge.node)
        
    def cmd_vel_callback(self, msg):
        """处理速度命令"""
        action = self.controller.forward([msg.linear.x, msg.angular.z])
        self.robot.apply_action(action)
        
    def update(self):
        """更新循环"""
        # 更新仿真
        world.step(render=True)
        
        # 发布里程计
        self.publish_odometry()
        
        # 发布关节状态
        self.publish_joint_states()
        
        # 发布TF
        self.publish_tf()
        
    def run(self):
        """运行机器人"""
        while rclpy.ok():
            self.update()
            rclpy.spin_once(self.bridge.node, timeout_sec=0.01)

# 启动机器人
if __name__ == '__main__':
    robot = ROS2MobileRobot()
    robot.run()