用Python控制Isaac Sim机器人

深入学习Isaac Sim的Python API,掌握机械臂运动控制、轨迹规划和传感器数据读取。

Isaac Sim Python 机器人控制 API 运动规划
用Python控制Isaac Sim机器人

用Python控制Isaac Sim机器人

Isaac Sim提供了强大的Python API来控制仿真中的机器人。本文深入讲解运动控制、轨迹规划和传感器数据读取。

关节空间控制

import numpy as np
from isaacsim.core import World
from isaacsim.assets import FrankaRobot

world = World()
franka = FrankaRobot(prim_path="/World/Franka", name="franka")
world.scene.add(franka)
world.reset()

# 获取当前关节角度
current_joints = franka.get_joint_positions()
print(f"当前关节角度: {current_joints}")

# 设置目标关节角度
target_joints = np.array([0.0, -0.5, 0.0, -1.5, 0.0, 1.0, 0.0])
franka.set_joint_positions(target_joints)

# 等待运动完成
while not franka.reached_target():
    world.step(render=True)

笛卡尔空间控制

# 获取末端执行器位姿
end_effector_pose = franka.get_end_effector_pose()
position = end_effector_pose[:3]  # [x, y, z]
orientation = end_effector_pose[3:]  # [qx, qy, qz, qw]

# 移动到目标位置
target_position = np.array([0.5, 0.0, 0.3])
target_orientation = np.array([0.0, 0.0, 0.0, 1.0])  # 单位四元数

franka.move_to_position(target_position)
franka.move_to_orientation(target_orientation)

# 同时移动位置和方向
franka.move_to_pose(position=target_position, orientation=target_orientation)

轨迹规划

class TrajectoryPlanner:
    def __init__(self, robot):
        self.robot = robot

    def plan_linear_path(self, start, end, steps=100):
        """规划直线路径"""
        trajectory = np.linspace(start, end, steps)
        return trajectory

    def plan_circular_path(self, center, radius, steps=100):
        """规划圆形路径"""
        angles = np.linspace(0, 2*np.pi, steps)
        trajectory = []
        for angle in angles:
            x = center[0] + radius * np.cos(angle)
            y = center[1] + radius * np.sin(angle)
            z = center[2]
            trajectory.append([x, y, z])
        return np.array(trajectory)

    def execute_trajectory(self, trajectory, speed=0.1):
        """执行轨迹"""
        for point in trajectory:
            self.robot.move_to_position(point)
            # 等待到达
            while np.linalg.norm(
                self.robot.get_end_effector_pose()[:3] - point
            ) > 0.01:
                world.step(render=True)

# 使用示例
planner = TrajectoryPlanner(franka)

# 直线运动
start = np.array([0.3, 0.0, 0.2])
end = np.array([0.5, 0.2, 0.3])
trajectory = planner.plan_linear_path(start, end)
planner.execute_trajectory(trajectory)

# 圆形运动
center = np.array([0.4, 0.0, 0.25])
radius = 0.1
trajectory = planner.plan_circular_path(center, radius)
planner.execute_trajectory(trajectory)

读取传感器数据

class SensorReader:
    def __init__(self, camera, lidar=None):
        self.camera = camera
        self.lidar = lidar

    def get_camera_data(self):
        """获取相机数据"""
        rgb = self.camera.get_rgb()          # RGB图像
        depth = self.camera.get_depth()      # 深度图
        normals = self.camera.get_normals()  # 法线图

        # 获取相机内参
        intrinsics = self.camera.get_intrinsics()
        fx, fy = intrinsics[0, 0], intrinsics[1, 1]
        cx, cy = intrinsics[0, 2], intrinsics[1, 2]

        return {
            "rgb": rgb,
            "depth": depth,
            "normals": normals,
            "intrinsics": {"fx": fx, "fy": fy, "cx": cx, "cy": cy}
        }

    def get_lidar_data(self):
        """获取激光雷达数据"""
        if self.lidar is None:
            return None

        points = self.lidar.get_point_cloud()  # 点云数据
        intensities = self.lidar.get_intensities()  # 反射强度

        return {
            "points": points,
            "intensities": intensities
        }

    def depth_to_pointcloud(self, depth, intrinsics):
        """将深度图转换为点云"""
        h, w = depth.shape
        fx, fy = intrinsics["fx"], intrinsics["fy"]
        cx, cy = intrinsics["cx"], intrinsics["cy"]

        # 创建像素坐标网格
        u, v = np.meshgrid(np.arange(w), np.arange(h))

        # 反投影到3D空间
        z = depth
        x = (u - cx) * z / fx
        y = (v - cy) * z / fy

        # 组合成点云
        points = np.stack([x, y, z], axis=-1)
        points = points.reshape(-1, 3)

        # 过滤无效点
        valid = (z > 0) & (z < 5.0)  # 0-5米范围
        points = points[valid.flatten()]

        return points

# 使用示例
sensor = SensorReader(camera)
data = sensor.get_camera_data()

# 深度图转点云
point_cloud = sensor.depth_to_pointcloud(data["depth"], data["intrinsics"])
print(f"点云点数: {len(point_cloud)}")

力/力矩控制

class ForceController:
    def __init__(self, robot):
        self.robot = robot

    def apply_force(self, force_vector):
        """在末端执行器施加力"""
        self.robot.apply_end_effector_force(force_vector)

    def compliant_control(self, target_position, stiffness=100, damping=10):
        """柔顺控制"""
        current_pos = self.robot.get_end_effector_pose()[:3]
        current_vel = self.robot.get_end_effector_velocity()[:3]

        # 计算力
        position_error = target_position - current_pos
        force = stiffness * position_error - damping * current_vel

        # 施加力
        self.apply_force(force)

        return force

# 使用示例
controller = ForceController(franka)

# 柔顺移动到目标位置
target = np.array([0.5, 0.0, 0.2])
for _ in range(1000):
    world.step(render=True)
    force = controller.compliant_control(target)
    if np.linalg.norm(force) < 0.1:
        break

FAQ

如何控制机械臂的速度?

使用set_joint_velocities()设置关节速度,或在轨迹规划中调整时间参数。

传感器数据有延迟怎么办?

Isaac Sim的传感器数据是同步的。如果感觉有延迟,检查仿真步长设置。

如何实现多机器人协同控制?

每个机器人作为独立的Prim对象,通过共享的状态变量或ROS2话题进行协调。