Mujoco KDL Wrapper  0.2.2
MuJoCo + KDL bridge for robot kinematics and dynamics
Loading...
Searching...
No Matches
ex_dual_arm.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""Dual-arm example ported from src/examples/ex_dual_arm.cpp.
3
4Two Kinova GEN3 arms, each with a Robotiq 2F-85 gripper, in one scene. Both run
5joint-space impedance to the home pose. An Env on_reset hook re-homes both arms.
6"""
7
8from __future__ import annotations
9
10import argparse
11import math
12
13import mj_kdl_wrapper as mjk
14
15HOME_POSE = [0.0, 0.2618, 3.1416, -2.2689, 0.0, 0.9599, 1.5708]
16
17KP = [100, 200, 100, 200, 100, 200, 100]
18KD = [10, 20, 10, 20, 10, 20, 10]
19
20
21def attachment_gripper(path: str, prefix: str = "g_") -> mjk.AttachmentSpec:
22 spec = mjk.AttachmentSpec()
23 spec.mjcf_path = path
24 spec.attach_to = mjk.AttachTarget(mjk.AttachKind.Site, "pinch_site")
25 spec.prefix = prefix
26 return spec
27
28
29def apply(robot: mjk.Robot, target: list[float]) -> None:
30 robot.update()
31 grav = robot.gravity_torques(-9.81)
32 robot.jnt_trq_cmd = [
33 KP[i] * (target[i] - robot.jnt_pos_msr[i]) - KD[i] * robot.jnt_vel_msr[i] + grav[i]
34 for i in range(robot.n_joints)
35 ]
36
37
38def main() -> int:
39 parser = argparse.ArgumentParser()
40 parser.add_argument("--gui", action="store_true")
41 args = parser.parse_args()
42
43 arm_path = mjk.menagerie.model_path("kinova_gen3", env_var="MJ_KDL_MODEL")
44 gripper_path = mjk.menagerie.asset_path("robotiq_2f85/2f85.xml", env_var="MJ_KDL_GRIPPER")
45 attach = attachment_gripper(gripper_path)
46
47 spec = mjk.SceneSpec()
48 spec.timestep = 0.002
49 spec.add_floor = True
50 spec.add_skybox = True
51 left = mjk.RobotSpec()
52 left.path = arm_path
53 left.pos = [-1.0, 0.0, 0.0]
54 left.attachments = [attach]
55 right = mjk.RobotSpec()
56 right.path = arm_path
57 right.prefix = "r2_"
58 right.pos = [1.0, 0.0, 0.0]
59 right.attachments = [attach]
60 spec.robots = [left, right]
61
62 env = mjk.Env.build(spec)
63 try:
64 tool1 = mjk.ToolFrameSpec()
65 tool1.tool_body = "g_base"
66 tool1.tcp_site = "g_pinch"
67 tool2 = mjk.ToolFrameSpec()
68 tool2.tool_body = "r2_g_base"
69 tool2.tcp_site = "r2_g_pinch"
70 arm1 = env.create_robot("base_link", "bracelet_link", tool=tool1)
71 arm2 = env.create_robot("r2_base_link", "r2_bracelet_link", tool=tool2)
72 for robot in (arm1, arm2):
73 robot.ctrl_mode = mjk.CtrlMode.TORQUE
74
75 def on_reset(ctx):
76 arm1.set_joint_pos(HOME_POSE, call_forward=False)
77 arm2.set_joint_pos(HOME_POSE, call_forward=False)
78
79 env.on_reset = on_reset
80 env.reset()
81
82 def step():
83 apply(arm1, HOME_POSE)
84 apply(arm2, HOME_POSE)
85 grip = 255.0 if math.fmod(env.time(), 6.0) < 3.0 else 0.0
86 for name in ("g_fingers_actuator", "r2_g_fingers_actuator"):
87 if env.has_actuator(name):
88 env.set_actuator_ctrl(name, grip)
89
90 if args.gui:
91 viewer = mjk.SimulateViewer.open(arm1, "ex_dual_arm.py")
92 prev = env.time()
93 try:
94 while viewer.is_running():
95 if env.time() < prev - 1e-6:
96 env.reset()
97 prev = env.time()
98 step()
99 if not viewer.step():
100 break
101 finally:
102 viewer.close()
103 else:
104 end = env.time() + 1.2
105 while env.time() < end:
106 step()
107 arm1.step()
108 arm1_frame = arm1.fk_frame()
109 arm2_frame = arm2.fk_frame()
110 arm1_pos = [arm1_frame.p.x(), arm1_frame.p.y(), arm1_frame.p.z()]
111 arm2_pos = [arm2_frame.p.x(), arm2_frame.p.y(), arm2_frame.p.z()]
112 print(f"arm1 EE: {[round(x, 4) for x in arm1_pos]}")
113 print(f"arm2 EE: {[round(x, 4) for x in arm2_pos]}")
114 finally:
115 env.close()
116 return 0
117
118
119if __name__ == "__main__":
120 raise SystemExit(main())
None apply(mjk.Robot robot, list[float] target)
mjk.AttachmentSpec attachment_gripper(str path, str prefix="g_")