参考

前言

由于之前一直在用 Mujoco,现在由于某些原因切换到使用 Isaac Sim中,刚刚接触,记录摸索 Isaac Sim 实现机器人仿真中的一些笔记,供参考。

本次实现机器人逆运动学控制,由于示例中给了关节控制的例程,非常简单,但是当我想实现笛卡尔空间控制时,查阅文档找到了ArticulationKinematicsSolver🔗,但这里的参数需要传入一个kinematics_solver的实例对象,因此又找到了 KinematicsSolver🔗,进而知道需要先创建一个 Lula Kinematics Solver,本文就以Lula Kinematics Solver为基础,实现机械臂逆运动学控制

前提需求

  • 需要安装 WorkStation 版本的 Isaac Sim 4.5.0(Python 版本的 Isaac Sim 似乎确实某些功能,没有【Tool-Robotics-Lula Robot Description Editor】)
  • 已经有机械臂的 urdfusd 模型

1. Lula Robot Description 创建

Lula Kinematics Solver 的文档中可以知道,要想配置 Lula Kinematics Solver,需要有robot_descriptor.yaml 和机器人 urdf 这两个文件。其中 urdf 肯定已经都有了,本节从使用 Isaac Sim 的 Robot Description Editor 创建 robot_descriptor.yaml 开始。

以本文的 UR + 灵巧手为例,共有 6+6=12个关节是可控关节,但 Lula 关注将机器人移动到指定位置,不涉及末端执行器,因此只考虑 UR 的6个关节为活动关节,灵巧手关节视为固定关节。

(1)打开 Lula Robot Description Editor

启动 Isaac Sim:

1
2
cd ~/isaacsim
./isaac-sim.sh

将机器人USD文件拖入到 World 坐标系下。

image.png

打开【Tools -> Robotics -> Lula Robot Description Editor】,会发现窗口左侧出现Lula Robot Description Editor的面板。

然后点击【播放】按钮,Lula Robot Description Editor中会出现【Selection Panel】,在其中的 Select Articulation 位置选择自己的机器人,下方会展开一个 Set Joint Properties 面板。

(2)设置关节属性

按照 UR 机器人的活动关节,依次将 6 个 Joint Status 设置为 Active Joint,默认的关节位置,加速度限制等可以先不修改,后续熟悉了各参数含义再修改也没问题。

灵巧手/夹爪所包含的关节都设置为 Fixed Joint。

image.png

(3)碰撞球(只做运动学可省略)

需要再 Robot Description 文件中添加碰撞球,才能进行RMPFlow运动规划等,具体方法可以参考 Adding Collision Spheres,理论上对于六自由度机械臂,只需要添加Link2和Link4的碰撞就足够了

所有过程还是在Lula Robot Description Editor中完成。

  • 首先在【Selection Panel-Select Link】,选择Link2。
  • 然后再【Link Sphere Editor-Add Sphere】,添加碰撞球,可以拖动位置,右下角属性调整半径,直到全部覆盖当前link为止。

重复以上过程,添加Link4的碰撞球,效果如下:

image.png

(4)导出配置文件

保存 Lula Robot Description 文件:在【Export To File -> Export to Lula Robot Description File】,输入一个本地路径(必须以.yaml结尾),例如/home/mahaofei/Downloads/ur5e_hand.yaml,YAML文件会被保存在目标位置。

保存 XRDF 文件:虽然不知道有什么用,但是也是同样的保存方法。

image.png

2. 笛卡尔空间运动控制代码

参考代码:作用为设置机器人笛卡尔空间位置为position: [0.5, 0, 0.5], orientation: [0, 0, 0]。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import sys
import numpy as np
import argparse
from typing import Optional

# Isaac Sim 相关依赖库
from isaacsim import SimulationApp
simulation_app = SimulationApp({"headless": False}) # start the simulation app, with GUI open
from isaacsim.core.api import World
from isaacsim.core.prims import Articulation
from isaacsim.core.utils.stage import add_reference_to_stage, get_stage_units
from isaacsim.core.utils.viewports import set_camera_view
from isaacsim.storage.native import get_assets_root_path
from isaacsim.robot_motion.motion_generation import ArticulationKinematicsSolver, LulaKinematicsSolver
from isaacsim.core.utils.numpy.rotations import euler_angles_to_quats

from isaacsim.core.utils.types import ArticulationAction
from isaacsim.robot.manipulators.manipulators import SingleManipulator
import isaacsim.core.api.tasks as tasks

class KinematicsSolver(ArticulationKinematicsSolver):
def __init__(self, robot_articulation: Articulation, end_effector_frame_name: Optional[str] = None) -> None:
#TODO: change the config path
self._kinematics = LulaKinematicsSolver(robot_description_path="asset/isaac_sim/ur5e_hand/ur5e_hand.yaml",
urdf_path="asset/urdf_ros2/ur5e_hand/urdf/ur5e_hand.urdf")
if end_effector_frame_name is None:
end_effector_frame_name = "wrist_3_link"
ArticulationKinematicsSolver.__init__(self, robot_articulation, self._kinematics, end_effector_frame_name)
return

# 1. 创建一个World对象
world = World(stage_units_in_meters=1.0)
world.initialize_physics()
world.scene.add_default_ground_plane()
set_camera_view(
eye=[2.0, 1.5, 1.8], target=[0.00, 0.00, 0.81], camera_prim_path="/OmniverseKit_Persp"
)

# 2. 添加一个UR5e机器人
add_reference_to_stage(usd_path="asset/isaac_sim/ur5e_hand/ur5e_hand.usd", prim_path="/World/ur5e_hand")
ur5e_hand = SingleManipulator(
prim_path="/World/ur5e_hand",
name="ur5e_hand",
end_effector_prim_path="/World/ur5e_hand/wrist_3_link")
init_joint_positions=np.array([0.0, -np.pi/2, np.pi/2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
ur5e_hand.set_joints_default_state([init_joint_positions])
ur5e_hand.initialize()
ur5e_hand.post_reset()
world.scene.add(ur5e_hand)

# 3. 设置逆运动学求解器
controller = KinematicsSolver(ur5e_hand)
articulation_controller = ur5e_hand.get_articulation_controller()

# 4. 控制机器人运动
while simulation_app.is_running():
world.step(render=True)
if world.is_playing():
if world.current_time_step_index == 0:
world.reset()
actions, succ = controller.compute_inverse_kinematics(
target_position=np.array([0.5, 0, 0.5]),
target_orientation=euler_angles_to_quats(np.array([0, 0, 0])),
)
if succ:
articulation_controller.apply_action(actions)
else:
print("IK did not converge to a solution. No action is being taken.")
simulation_app.close()