Isaac Sim API 文档索引
📚 本文档集合概述
本文档集合按功能分类整理了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_articulation | SingleArticulation | UR10机器人对象 |
end_effector_frame_name | Optional[str] | 末端执行器坐标系名称 |
attach_gripper | Optional[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
📊 标注器数据格式
| 标注器类型 | 数据类型 | 形状 | 说明 |
|---|---|---|---|
rgb | uint8 | (H, W, 3) | RGB彩色图像 |
depth | float32 | (H, W) | 深度图(米) |
semantic_segmentation | uint32 | (H, W) | 语义分割ID |
instance_id_segmentation | uint32 | (H, W) | 实例分割ID |
bounding_box_2d_tight | dict | - | 2D边界框信息 |
bounding_box_3d | dict | - | 3D边界框信息 |
distance_to_camera | float32 | (H, W) | 到相机距离 |
distance_to_image_plane | float32 | (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* | ✗ | ✗ | 视觉标记 |
🎯 最佳实践
-
选择合适的对象类型
- 使用
Dynamic对象用于需要物理交互的实体 - 使用
Fixed对象用于环境和障碍物 - 使用
Visual对象用于UI和标记
- 使用
-
优化碰撞检测
- 选择合适的碰撞近似形状
- 为静态对象使用简单的碰撞形状
- 合理设置碰撞边距
-
材质管理
- 重用材质定义
- 根据需求选择合适的材质类型
- 批量应用材质
-
性能考虑
- 使用对象池管理频繁创建/销毁的对象
- 批量操作来减少渲染更新
- 合理设置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对象。
参数说明:
| 参数 | 类型 | 描述 |
|---|---|---|
| arg0 | str | URDF文件的绝对路径 |
| arg1 | UrdfRobot | 解析后的URDF机器人对象 |
| arg2 | ImportConfig | 导入配置对象 |
| arg3 | str | 目标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文件到场景。
参数说明:
| 参数 | 类型 | 描述 |
|---|---|---|
| arg0 | str | MJCF文件的绝对路径 |
| arg1 | ImportConfig | 导入配置 |
| arg2 | str | 机器人在USD场景中的路径 |
| arg3 | str | 目标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
| 枚举值 | 数值 | 描述 |
|---|---|---|
OK | 0 | 操作成功 |
OK_LATEST | 1 | 成功且为最新版本 |
ERROR | 3 | 一般错误 |
ERROR_NOT_FOUND | 7 | 文件未找到 |
ERROR_ACCESS_DENIED | 6 | 访问被拒绝 |
💡 使用示例
导入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()