@@ -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-
15228class 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