5. isaac sim4.2 教程-Core API-操作机械臂

发布于:2025-07-11 ⋅ 阅读:(22) ⋅ 点赞:(0)

本教程将向仿真场景中引入第二个机器人——Franka Panda机械臂,详细讲解如何将其添加到场景中,并演示如何使用其PickAndPlaceController(抓放控制器)。通过本教程的学习,您将积累更多在Omniverse Isaac Sim中使用不同机器人及控制器类的实践经验。

1. 创建场景

# 机械臂
from omni.isaac.examples.base_sample import BaseSample
# This extension has franka related tasks and controllers as well
from omni.isaac.franka import Franka
from omni.isaac.core.objects import DynamicCuboid
import numpy as np

class MyHelloWorld(BaseSample): # 继承自basesample
    def __init__(self) -> None:
        super().__init__()
        return

    def setup_scene(self):
        world = self.get_world()
        world.scene.add_default_ground_plane()
        # adding a Franka robot 
        franka = world.scene.add(Franka(prim_path="/World/Fancy_Franka", name="fancy_franka"))

        world.scene.add(
            DynamicCuboid(
                prim_path="/World/random_cube",
                name="fancy_cube",
                position=np.array([0.3, 0.3, 0.3]),
                scale=np.array([0.0515, 0.0515, 0.0515]),
                color=np.array([0, 0, 1.0]),
            )
        )
        return

2. Using the PickAndPlace Controller

可以看到franka带了3个控制器,我们这里用第一个

# 机械臂
from omni.isaac.examples.base_sample import BaseSample
# This extension has franka related tasks and controllers as well
from omni.isaac.franka import Franka
from omni.isaac.core.objects import DynamicCuboid
from omni.isaac.franka.controllers import PickPlaceController
import numpy as np


class MyHelloWorld(BaseSample): # 继承自basesample
    def __init__(self) -> None:
        super().__init__()
        return

    def setup_scene(self):
        world = self.get_world()
        world.scene.add_default_ground_plane()
        # adding a Franka robot 
        franka = world.scene.add(Franka(prim_path="/World/Fancy_Franka", name="fancy_franka"))

        world.scene.add(
            DynamicCuboid(
                prim_path="/World/random_cube",
                name="fancy_cube",
                position=np.array([0.3, 0.3, 0.3]),
                scale=np.array([0.0515, 0.0515, 0.0515]),
                color=np.array([0, 0, 1.0]),
            )
        )
        return
    
    async def setup_post_load(self):
        self._world = self.get_world()
        self._franka = self._world.scene.get_object("fancy_franka")
        self._fancy_cube = self._world.scene.get_object("fancy_cube")
        # 初始化自己的控制器
        self._controller = PickPlaceController(
            name="pick_place_controller",
            gripper=self._franka.gripper,
            robot_articulation=self._franka,
        )
        # 设置自动执行的任务--通过回调函数
        self._world.add_physics_callback("sim_step", callback_fn=self.physics_step)
        # load之后要设置夹爪初始位置,确定仿真启动之后机器人从同一个已知状态开始
        self._franka.gripper.set_joint_positions(self._franka.gripper.joint_opened_positions)
        await self._world.play_async()
        return
    
    # 重置之后要做的事情
    async def setup_post_reset(self):
        self._controller.reset()
        # 重启之后也要重置夹爪位置/打开夹爪
        self._franka.gripper.set_joint_positions(self._franka.gripper.joint_opened_positions)
        await self._world.play_async()
        return
    
    def physics_step(self, step_size):
        cube_position, _ = self._fancy_cube.get_world_pose()
        goal_position = np.array([-0.3, -0.3, 0.0515 / 2.0])
        current_joint_positions = self._franka.get_joint_positions()
        # 生成action
        actions = self._controller.forward(
            picking_position=cube_position,
            placing_position=goal_position,
            current_joint_positions=current_joint_positions,
        )
        self._franka.apply_action(actions)
        if self._controller.is_done():
            self._world.pause()
        return
    

    def world_cleanup(self):# 释放内存等
        return

3. 什么是task

在 Omniverse Isaac Sim 中,Task 类提供了一种模块化的方式,用于管理场景创建、信息检索和指标计算。它适用于构建具有高级逻辑的更复杂场景。在本教程中,你将需要基于 Task 类重构之前的代码。

3.1 定义自己的task

# 自己定义task
from omni.isaac.examples.base_sample import BaseSample
from omni.isaac.franka import Franka
from omni.isaac.core.objects import DynamicCuboid
from omni.isaac.franka.controllers import PickPlaceController
from omni.isaac.core.tasks import BaseTask # 任务基类
import numpy as np

# FrankaPlaying 任务子类
class FrankaPlaying(BaseTask):
    #NOTE: 这里只有basetask任务类中的一部分,还有更多可以查看原本实现
    def __init__(self, name):
        super().__init__(name=name, offset=None)
        self._goal_position = np.array([-0.3, -0.3, 0.0515 / 2.0]) # 立方体目标位置
        self._task_achieved = False # 任务完成标志
        return

    # setup all 在任务中的 assets
    def set_up_scene(self, scene):
        super().set_up_scene(scene)
        scene.add_default_ground_plane()
        # 创建蓝色立方体 (可移动目标)
        self._cube = scene.add(DynamicCuboid(
            prim_path="/World/random_cube",
            name="fancy_cube",
            position=np.array([0.3, 0.3, 0.3]),
            scale=np.array([0.0515, 0.0515, 0.0515]),
            color=np.array([0, 0, 1.0])
        ))
        # 添加Franka机械臂
        self._franka = scene.add(
            Franka(
                prim_path="/World/Fancy_Franka",
                name="fancy_franka"
            )
        )
        return

    # 任务中需要的信息通过 get_observations
    def get_observations(self):
        cube_position, _ = self._cube.get_world_pose() # 获取立方体世界坐标
        current_joint_positions = self._franka.get_joint_positions() # 获取机械臂关节角度
        # 构建观察值字典 (供控制器使用)
        observations = {
            self._franka.name: {
                "joint_positions": current_joint_positions,
            },
            self._cube.name: {
                "position": cube_position,
                "goal_position": self._goal_position
            }
        }
        return observations


    # for instance we can check here if the task was accomplished by
    # changing the color of the cube once its accomplished
    # 每物理步模拟前调用
    def pre_step(self, control_index, simulation_time):
        cube_position, _ = self._cube.get_world_pose()
        # 检查立方体是否到达目标位置(误差<2cm)
        if not self._task_achieved and np.mean(np.abs(self._goal_position - cube_position)) < 0.02:
            # PreviewSurface, we can set its color once the target is reached.
            self._cube.get_applied_visual_material().set_color(color=np.array([0, 1.0, 0]))# 变绿色
            self._task_achieved = True # 标记任务完成
        return


    # 每次重置后调用
    def post_reset(self):
        self._franka.gripper.set_joint_positions(self._franka.gripper.joint_opened_positions) # 打开夹爪
        self._cube.get_applied_visual_material().set_color(color=np.array([0, 0, 1.0])) # 重置为蓝色
        self._task_achieved = False # 重置任务状态
        return
    
class MyHelloWorld(BaseSample): # 继承自basesample
    def __init__(self) -> None:
        super().__init__()
        return

    def setup_scene(self):
        world = self.get_world()
        world.add_task(FrankaPlaying(name="my_first_task"))  # 添加自定义任务
        return
    
    async def setup_post_load(self):
        self._world = self.get_world()
        self._franka = self._world.scene.get_object("fancy_franka")  # 获取机械臂对象
        
        # 初始化抓放控制器
        self._controller = PickPlaceController(
            name="pick_place_controller",
            gripper=self._franka.gripper,  # 夹爪对象
            robot_articulation=self._franka  # 机械臂对象
        )
        
        # 注册物理步进回调
        self._world.add_physics_callback("sim_step", callback_fn=self.physics_step)
        await self._world.play_async()  # 开始仿真
    
    # 重置之后要做的事情
    async def setup_post_reset(self):
        self._controller.reset()
        # 重启之后也要重置夹爪位置/打开夹爪
        self._franka.gripper.set_joint_positions(self._franka.gripper.joint_opened_positions)
        await self._world.play_async()
        return
    
    def physics_step(self, step_size):
        # 1. 获取当前观察值(立方体位置/目标位置/关节角度)
        current_observations = self._world.get_observations()
        
        # 2. 控制器计算动作指令
        actions = self._controller.forward(
            picking_position=current_observations["fancy_cube"]["position"],
            placing_position=current_observations["fancy_cube"]["goal_position"],
            current_joint_positions=current_observations["fancy_franka"]["joint_positions"]
        )
        
        # 3. 应用动作到机械臂
        self._franka.apply_action(actions)
        
        # 4. 检查任务完成状态
        if self._controller.is_done():
            self._world.pause()  # 暂停仿真
        return
    
    def world_cleanup(self):# 释放内存等
        return

最后成功了cube就有蓝变绿.

3.2 使用Pick and Place Task

Omniverse Isaac Sim 也提供了不同的任务类在许多的机器人扩展中,我们这里重写提供的pickplace

# Use the Pick and Place Task
from omni.isaac.examples.base_sample import BaseSample
from omni.isaac.franka.controllers import PickPlaceController
from omni.isaac.franka.tasks import PickPlace
import numpy as np


class MyHelloWorld(BaseSample): # 继承自basesample
    def __init__(self) -> None:
        super().__init__()
        return

    def setup_scene(self):
        world = self.get_world()
        world.add_task(PickPlace(name="awesome_task"))  # 添加自带的任务,包含了机械臂方块等
        return
    
    async def setup_post_load(self):
        self._world = self.get_world()
        # 每个被定义好的任务都有一个 get_params()和set_params()方法
        # 通过 get_params() 获取任务参数
        task_params = self._world.get_task("awesome_task").get_params()
        self._franka = self._world.scene.get_object(task_params["robot_name"]["value"])
        self._cube_name = task_params["cube_name"]["value"]

        self._controller = PickPlaceController(
            name="pick_place_controller",
            gripper=self._franka.gripper,
            robot_articulation=self._franka,
        )
        # 注册物理步进回调
        self._world.add_physics_callback("sim_step", callback_fn=self.physics_step)
        await self._world.play_async()  # 开始仿真
        return
    
    # 重置之后要做的事情
    async def setup_post_reset(self):
        self._controller.reset()
        # 重启之后也要重置夹爪位置/打开夹爪
        self._franka.gripper.set_joint_positions(self._franka.gripper.joint_opened_positions)
        await self._world.play_async()
        return
    
    def physics_step(self, step_size):
        # 1. 获取当前观察值(立方体位置/目标位置/关节角度)
        current_observations = self._world.get_observations()
        
        # 2. 控制器计算动作指令
        actions = self._controller.forward(
            picking_position=current_observations[self._cube_name]["position"],
            placing_position=current_observations[self._cube_name]["target_position"],
            current_joint_positions=current_observations[self._franka.name]["joint_positions"],
        )
        
        # 3. 应用动作到机械臂
        self._franka.apply_action(actions)
        
        # 4. 检查任务完成状态
        if self._controller.is_done():
            self._world.pause()  # 暂停仿真
        return
    

整体来说更简单,直接调用人家封装好的就可以,不用我们自己设置各种各样的东西。


网站公告

今日签到

点亮在社区的每一天
去签到