Skip to content

Commit 885464d

Browse files
committed
Commit changes
1 parent db45191 commit 885464d

1 file changed

Lines changed: 12 additions & 146 deletions

File tree

examples/example_5_tsid_com_shift.py

Lines changed: 12 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -25,130 +25,6 @@ class GeneralParams:
2525
n_solver_iter: int = 1000
2626

2727

28-
def _parse_xyz(text: str | None) -> np.ndarray:
29-
if text is None:
30-
return np.zeros(3)
31-
return np.array([float(v) for v in text.split()], dtype=float)
32-
33-
34-
def _rpy_to_matrix(rpy: np.ndarray) -> np.ndarray:
35-
roll, pitch, yaw = rpy
36-
cr, sr = math.cos(roll), math.sin(roll)
37-
cp, sp = math.cos(pitch), math.sin(pitch)
38-
cy, sy = math.cos(yaw), math.sin(yaw)
39-
40-
rot_x = np.array([[1.0, 0.0, 0.0], [0.0, cr, -sr], [0.0, sr, cr]])
41-
rot_y = np.array([[cp, 0.0, sp], [0.0, 1.0, 0.0], [-sp, 0.0, cp]])
42-
rot_z = np.array([[cy, -sy, 0.0], [sy, cy, 0.0], [0.0, 0.0, 1.0]])
43-
44-
return rot_z @ rot_y @ rot_x
45-
46-
47-
def _origin_to_transform(origin: ET.Element | None) -> np.ndarray:
48-
transform = np.eye(4)
49-
if origin is None:
50-
return transform
51-
52-
xyz = _parse_xyz(origin.attrib.get("xyz"))
53-
rpy = _parse_xyz(origin.attrib.get("rpy"))
54-
transform[:3, :3] = _rpy_to_matrix(rpy)
55-
transform[:3, 3] = xyz
56-
return transform
57-
58-
59-
def _find_link(root: ET.Element, link_name: str) -> ET.Element:
60-
for link in root.findall("link"):
61-
if link.attrib.get("name") == link_name:
62-
return link
63-
raise ValueError(f"Link '{link_name}' not found in URDF")
64-
65-
66-
def _find_parent_link_and_transform(root: ET.Element, child_link_name: str):
67-
for joint in root.findall("joint"):
68-
child = joint.find("child")
69-
if child is None or child.attrib.get("link") != child_link_name:
70-
continue
71-
72-
parent = joint.find("parent")
73-
if parent is None:
74-
break
75-
76-
return parent.attrib["link"], _origin_to_transform(joint.find("origin"))
77-
78-
return child_link_name, np.eye(4)
79-
80-
81-
def contact_points_from_urdf_box(urdf_path: Path, contact_frame_name: str) -> np.ndarray:
82-
"""
83-
Read the rectangular foot contact patch from a URDF collision box.
84-
85-
Talos stores the foot collision box on ``leg_*_6_link`` and attaches the
86-
``*_sole_link`` contact frame with a fixed joint. This function transforms
87-
that box into the sole frame and returns its XY footprint at z=0.
88-
"""
89-
root = ET.parse(urdf_path).getroot()
90-
collision_link_name, parent_to_contact = _find_parent_link_and_transform(
91-
root, contact_frame_name
92-
)
93-
collision_link = _find_link(root, collision_link_name)
94-
contact_to_parent = np.linalg.inv(parent_to_contact)
95-
96-
best_points = None
97-
best_area = -np.inf
98-
99-
for collision in collision_link.findall("collision"):
100-
box = collision.find("geometry/box")
101-
if box is None:
102-
continue
103-
104-
size = _parse_xyz(box.attrib["size"])
105-
half_size = 0.5 * size
106-
parent_to_box = _origin_to_transform(collision.find("origin"))
107-
108-
local_corners = np.array(
109-
[
110-
[sx * half_size[0], sy * half_size[1], sz * half_size[2], 1.0]
111-
for sx in (-1.0, 1.0)
112-
for sy in (-1.0, 1.0)
113-
for sz in (-1.0, 1.0)
114-
]
115-
).T
116-
contact_corners = (contact_to_parent @ parent_to_box @ local_corners)[:3].T
117-
118-
min_xy = contact_corners[:, :2].min(axis=0)
119-
max_xy = contact_corners[:, :2].max(axis=0)
120-
area = np.prod(max_xy - min_xy)
121-
if area <= best_area:
122-
continue
123-
124-
best_area = area
125-
best_points = np.array(
126-
[
127-
[max_xy[0], max_xy[1], 0.0],
128-
[max_xy[0], min_xy[1], 0.0],
129-
[min_xy[0], min_xy[1], 0.0],
130-
[min_xy[0], max_xy[1], 0.0],
131-
]
132-
).T
133-
134-
if best_points is None:
135-
raise ValueError(
136-
f"No collision box found for contact frame '{contact_frame_name}' "
137-
f"through link '{collision_link_name}'"
138-
)
139-
140-
return best_points
141-
142-
143-
def _contact_patch_summary(contact_points: np.ndarray) -> str:
144-
x_min, x_max = contact_points[0].min(), contact_points[0].max()
145-
y_min, y_max = contact_points[1].min(), contact_points[1].max()
146-
return (
147-
f"x=[{x_min:.3f}, {x_max:.3f}], y=[{y_min:.3f}, {y_max:.3f}] "
148-
f"(half extents {0.5 * (x_max - x_min):.3f}, {0.5 * (y_max - y_min):.3f})"
149-
)
150-
151-
15228
class TSIDController:
15329
def __init__(
15430
self,
@@ -157,8 +33,6 @@ def __init__(
15733
q0: np.ndarray,
15834
left_foot_frame: str,
15935
right_foot_frame: str,
160-
left_contact_points: np.ndarray,
161-
right_contact_points: np.ndarray,
16236
):
16337
self.robot = tsid.RobotWrapper(
16438
str(urdf_path), [str(package_root)], pin.JointModelFreeFlyer(), False
@@ -168,17 +42,16 @@ def __init__(
16842

16943
self.left_foot_frame = "leg_left_6_joint"
17044
self.right_foot_frame = "leg_right_6_joint"
171-
self.left_contact_points = left_contact_points
172-
self.right_contact_points = right_contact_points
17345
self.left_foot_id = self._get_frame_id(left_foot_frame)
17446
self.right_foot_id = self._get_frame_id(right_foot_frame)
17547

17648
self.invdyn = tsid.InverseDynamicsFormulationAccForce("tsid", self.robot, False)
17749
self.invdyn.computeProblemData(0.0, q0, self.v0)
50+
self.data = self.invdyn.data()
17851

17952
self._add_foot_contacts()
18053
self._add_com_task()
181-
self._add_waist_task()
54+
# self._add_waist_task()
18255
self._add_posture_task(q0)
18356

18457
# Use EiquadprogFast: dynamic matrix sizes (memory allocation performed only when resizing)
@@ -231,7 +104,7 @@ def _add_foot_contacts(self):
231104
self.contact_left.setReference(
232105
self.robot.position(self.data, self.model.getJointId(self.left_foot_frame))
233106
)
234-
self.invdyn.addRigidContact(self.contact_left, w_force_reg, 1.0, 0)
107+
self.invdyn.addRigidContact(self.contact_left, w_force_reg, 1.0, 1)
235108

236109
self.contact_right = tsid.Contact6d(
237110
"contact-right",
@@ -248,7 +121,7 @@ def _add_foot_contacts(self):
248121
self.contact_right.setReference(
249122
self.robot.position(self.data, self.model.getJointId(self.right_foot_frame))
250123
)
251-
self.invdyn.addRigidContact(self.contact_right, w_force_reg, 1.0, 0)
124+
self.invdyn.addRigidContact(self.contact_right, w_force_reg, 1.0, 1)
252125

253126
def _add_com_task(self):
254127
kp_com = 20.0
@@ -258,7 +131,7 @@ def _add_com_task(self):
258131
self.com_task = tsid.TaskComEquality("task-com", self.robot)
259132
self.com_task.setKp(kp_com * np.ones(3))
260133
self.com_task.setKd(kd_com * np.ones(3))
261-
self.invdyn.addMotionTask(self.com_task, w_com, 0, 0.0)
134+
self.invdyn.addMotionTask(self.com_task, w_com, 1, 0.0)
262135

263136
def _add_waist_task(self):
264137
kp_waist = 500.0
@@ -267,7 +140,7 @@ def _add_waist_task(self):
267140

268141
self.waist_task = tsid.TaskSE3Equality("task-waist", self.robot, "root_joint")
269142
self.waist_task.setKp(kp_waist * np.ones(6))
270-
self.waist_task.setKd(kd_waist * np.ones(3))
143+
self.waist_task.setKd(kd_waist * np.ones(6))
271144

272145
# Add a Mask to the task which will select the vector dimensions on which the task will act.
273146
# In this case the waist configuration is a vector 6d (position and orientation -> SE3)
@@ -324,7 +197,7 @@ def _add_posture_task(self, q0: np.ndarray):
324197
self.invdyn.addMotionTask(self.posture_task, w_posture, 1, 0.0)
325198

326199
self.posture_sample = tsid.TrajectorySample(self.robot.nv - 6)
327-
self.posture_sample.pos(q0[7:])
200+
self.posture_sample.value(q0[7:])
328201

329202
def compute(
330203
self,
@@ -334,9 +207,9 @@ def compute(
334207
com_ref: np.ndarray,
335208
) -> np.ndarray:
336209
com_sample = tsid.TrajectorySample(3)
337-
com_sample.pos(com_ref)
338-
com_sample.vel(np.zeros(3))
339-
com_sample.acc(np.zeros(3))
210+
com_sample.value(com_ref)
211+
com_sample.derivative(np.zeros(3))
212+
com_sample.second_derivative(np.zeros(3))
340213

341214
self.com_task.setReference(com_sample)
342215
self.posture_task.setReference(self.posture_sample)
@@ -371,7 +244,7 @@ def main():
371244
np.set_printoptions(suppress=True, precision=3)
372245

373246
package_root = args.path_talos_data.expanduser().resolve()
374-
urdf_path = package_root / "talos_data" / "urdf" / "talos_full.urdf"
247+
urdf_path = package_root / "talos_data" / "urdf" / "talos_reduced.urdf"
375248
if not urdf_path.is_file():
376249
raise FileNotFoundError(f"URDF file not found: {urdf_path}")
377250

@@ -382,7 +255,7 @@ def main():
382255
dt=params.dt,
383256
path_to_robot_urdf=urdf_path,
384257
model=talos,
385-
launch_gui=args.launch_gui,
258+
launch_gui=True,
386259
n_solver_iter=params.n_solver_iter,
387260
)
388261

@@ -402,19 +275,12 @@ def main():
402275
simulator.reset_robot_configuration(q_init)
403276
simulator.disable_joint_motors()
404277

405-
left_contact_points = contact_points_from_urdf_box(urdf_path, "left_sole_link")
406-
right_contact_points = contact_points_from_urdf_box(urdf_path, "right_sole_link")
407-
print(f"Left TSID contact patch from URDF: {_contact_patch_summary(left_contact_points)}")
408-
print(f"Right TSID contact patch from URDF: {_contact_patch_summary(right_contact_points)}")
409-
410278
controller = TSIDController(
411279
urdf_path=urdf_path,
412280
package_root=package_root,
413281
q0=q_init,
414282
left_foot_frame="left_sole_link",
415283
right_foot_frame="right_sole_link",
416-
left_contact_points=left_contact_points,
417-
right_contact_points=right_contact_points,
418284
)
419285

420286
com0 = pin.centerOfMass(talos.model, talos.data, q_init)

0 commit comments

Comments
 (0)