yqi19's picture
YAM bimanual task suite: env, solvers, tasks, converters
7399b6f verified
Raw
History Blame Contribute Delete
3.34 kB
"""Two arms pinch a rope at both ends and pull it taut.
The rope is a CHAIN: many short rigid links joined by universal joints. Isaac Lab does have FEM
deformables, but a rope you have to pinch and pull is far better served by a chain -- a soft body
slips out of a parallel jaw, and the thing being measured here (end-to-end span versus the rope's
own length) is exactly what a chain represents faithfully.
Nothing here goes through approach_and_grasp: that works on rigid bodies in `scene.objects`, and
a rope link lives in `scene.articulations`. The end links are located with link_pos() instead.
"""
import numpy as np
from ..motion.arm import OPEN, CLOSE, grasp_quat
from ..envs.scene import TABLE_TOP
def solve(env, rope, n_links, pull_to=0.30, lift=0.10, grip_inset=1):
"""Pinch link `grip_inset` from each end, lift, then draw the hands apart to `pull_to`."""
rec = env.recorder
L, R = env.arms["left"], env.arms["right"]
lo, hi = grip_inset, n_links-1-grip_inset
a_xyz = env.scene.link_pos(rope, lo)
b_xyz = env.scene.link_pos(rope, hi)
# whichever end is on each arm's side, so the arms never cross
if a_xyz[1] < b_xyz[1]:
a_xyz, b_xyz = b_xyz, a_xyz
print(f"[solver] rope ends at {a_xyz.round(3)} (left) and {b_xyz.round(3)} (right), "
f"apart {np.linalg.norm(a_xyz-b_xyz):.3f} m", flush=True)
for arm in (L, R):
arm.quat = grasp_quat("y")
above = 0.11
Lg = np.array([a_xyz[0], a_xyz[1], TABLE_TOP+0.012], np.float32)
Rg = np.array([b_xyz[0], b_xyz[1], TABLE_TOP+0.012], np.float32)
rec.phase = "1. BOTH HANDS reach over their end of the rope"
for k in range(120):
t = (k+1)/120.0
env.drive_both(L.to_root(Lg+np.array([0, 0, above*(1-t)+0.10*t], np.float32)),
R.to_root(Rg+np.array([0, 0, above*(1-t)+0.10*t], np.float32)), OPEN, OPEN)
rec.phase = "2. LOWER onto the rope ends"
for k in range(140):
t = (k+1)/140.0
env.drive_both(L.to_root(Lg+np.array([0, 0, 0.10*(1-t)], np.float32)),
R.to_root(Rg+np.array([0, 0, 0.10*(1-t)], np.float32)), OPEN, OPEN)
rec.phase = "3. PINCH both ends"
for _ in range(70):
env.drive_both(L.to_root(Lg), R.to_root(Rg), CLOSE, CLOSE)
rec.phase = "4. LIFT the rope clear of the table"
for k in range(110):
t = (k+1)/110.0
env.drive_both(L.to_root(Lg+np.array([0, 0, lift*t], np.float32)),
R.to_root(Rg+np.array([0, 0, lift*t], np.float32)), CLOSE, CLOSE)
rec.phase = f"5. PULL APART until the rope is straight ({pull_to*100:.0f} cm)"
mid_y = (Lg[1]+Rg[1])/2.0
for k in range(200):
t = (k+1)/200.0
ly = mid_y+(pull_to/2.0)*t+(Lg[1]-mid_y)*(1-t)
ry = mid_y-(pull_to/2.0)*t+(Rg[1]-mid_y)*(1-t)
env.drive_both(L.to_root(np.array([Lg[0], ly, TABLE_TOP+lift], np.float32)),
R.to_root(np.array([Rg[0], ry, TABLE_TOP+lift], np.float32)), CLOSE, CLOSE)
rec.phase = "6. HOLD it taut"
for _ in range(50):
env.drive_both(L._seg_start(), R._seg_start(), CLOSE, CLOSE)
a2 = env.scene.link_pos(rope, 0)
b2 = env.scene.link_pos(rope, n_links-1)
span = float(np.linalg.norm(a2-b2))
print(f"[solver] rope end-to-end span {span:.3f} m", flush=True)
return {"span": span}