🦾 逆运动学与运动规划#

在本教程中,我们将通过几个示例演示如何在 Genesis 中使用逆运动学(IK)和运动规划求解器,并执行一个简单的抓取任务。

首先,让我们创建一个场景,加载你最喜欢的机械臂和一个小立方体,构建场景,然后设置控制增益:

import numpy as np
import genesis as gs

########################## init ##########################
gs.init(backend=gs.gpu)

########################## create a scene ##########################
scene = gs.Scene(
    sim_options = gs.options.SimOptions(
        dt = 0.01,
    ),
    viewer_options = gs.options.ViewerOptions(
        camera_pos    = (3, -1, 1.5),
        camera_lookat = (0.0, 0.0, 0.5),
        camera_fov    = 30,
        max_FPS       = 60,
    ),
    show_viewer = True,
)

########################## entities ##########################
plane = scene.add_entity(
    gs.morphs.Plane(),
)
cube = scene.add_entity(
    gs.morphs.Box(
        size = (0.04, 0.04, 0.04),
        pos  = (0.65, 0.0, 0.02),
    )
)
franka = scene.add_entity(
    gs.morphs.MJCF(file='xml/franka_emika_panda/panda.xml'),
)
########################## build ##########################
scene.build()

motors_dof = np.arange(7)
fingers_dof = np.arange(7, 9)

# 设置控制增益
# 注意:以下值是针对 Franka 实现最佳行为而调整的
# 通常,每个新机器人都会有一组不同的参数。
# 有时高质量的 URDF 或 XML 文件也会提供这些参数并会被解析。
franka.set_dofs_kp(
    np.array([4500, 4500, 3500, 3500, 2000, 2000, 2000, 100, 100]),
)
franka.set_dofs_kv(
    np.array([450, 450, 350, 350, 200, 200, 200, 10, 10]),
)
franka.set_dofs_force_range(
    np.array([-87, -87, -87, -87, -12, -12, -12, -100, -100]),
    np.array([ 87,  87,  87,  87,  12,  12,  12,  100,  100]),
)
../../_images/IK_mp_grasp.png

接下来,让我们将机器人的末端执行器移动到预抓取姿态。这通过两个步骤完成:

  • 使用 IK 求解给定目标末端执行器姿态的关节位置

  • 使用运动规划器到达目标位置

Genesis 中的运动规划使用 OMPL 库。你可以按照安装页面中的说明进行安装。

Genesis 中的 IK 和运动规划尽可能简单:每个都可以通过单个函数调用来完成。


# 获取末端执行器连杆
end_effector = franka.get_link('hand')

# 移动到预抓取姿态
qpos = franka.inverse_kinematics(
    link = end_effector,
    pos  = np.array([0.65, 0.0, 0.25]),
    quat = np.array([0, 1, 0, 0]),
)
# 夹爪打开位置
qpos[-2:] = 0.04
path = franka.plan_path(
    qpos_goal     = qpos,
    num_waypoints = 200, # 2 秒持续时间
)
# 执行规划的路径
for waypoint in path:
    franka.control_dofs_position(waypoint)
    scene.step()

# 允许机器人到达最后一个路径点
for i in range(100):
    scene.step()

如你所见,IK 求解和运动规划都是机器人实体的集成方法。对于 IK 求解,你只需告诉机器人的 IK 求解器哪个连杆是末端执行器,并指定目标姿态。然后,你告诉运动规划器目标关节位置(qpos),它将返回一个规划并平滑的路径点列表。注意,在执行路径后,我们让控制器再运行 100 步。这是因为我们使用 PD 控制器,期望目标位置与当前位置之间会存在差距。因此,我们让控制器运行更长时间,以便机器人能够到达规划轨迹中的最后一个路径点。

接下来,我们向下移动机器人夹爪,抓取立方体,并将其抬起:

# 到达
qpos = franka.inverse_kinematics(
    link = end_effector,
    pos  = np.array([0.65, 0.0, 0.130]),
    quat = np.array([0, 1, 0, 0]),
)
franka.control_dofs_position(qpos[:-2], motors_dof)
for i in range(100):
    scene.step()

# 抓取
franka.control_dofs_position(qpos[:-2], motors_dof)
franka.control_dofs_force(np.array([-0.5, -0.5]), fingers_dof)

for i in range(100):
    scene.step()

# 抬起
qpos = franka.inverse_kinematics(
    link=end_effector,
    pos=np.array([0.65, 0.0, 0.28]),
    quat=np.array([0, 1, 0, 0]),
)
franka.control_dofs_position(qpos[:-2], motors_dof)
for i in range(200):
    scene.step()

抓取物体时,我们对 2 个夹爪自由度使用了力控制,并施加了 0.5N 的抓取力。如果一切正常,你会看到物体被抓取并抬起。