5. isaac sim4.2 教程-Core API-操作机械臂
本教程将向仿真场景中引入第二个机器人——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 npclass MyHelloWorld(BaseSample): # 继承自basesampledef __init__(self) -> None:super().__init__()returndef 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 npclass MyHelloWorld(BaseSample): # 继承自basesampledef __init__(self) -> None:super().__init__()returndef 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]),))returnasync 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()returndef 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()# 生成actionactions = 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()returndef 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 在任务中的 assetsdef 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_observationsdef 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 # 重置任务状态returnclass MyHelloWorld(BaseSample): # 继承自basesampledef __init__(self) -> None:super().__init__()returndef setup_scene(self):world = self.get_world()world.add_task(FrankaPlaying(name="my_first_task")) # 添加自定义任务returnasync 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()returndef 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() # 暂停仿真returndef 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 npclass MyHelloWorld(BaseSample): # 继承自basesampledef __init__(self) -> None:super().__init__()returndef setup_scene(self):world = self.get_world()world.add_task(PickPlace(name="awesome_task")) # 添加自带的任务,包含了机械臂方块等returnasync 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()returndef 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
整体来说更简单,直接调用人家封装好的就可以,不用我们自己设置各种各样的东西。