@@ -39,15 +39,15 @@ def __init__(
3939 self ,
4040 urdf_path : str ,
4141 ee_link : str = "end_effector" ,
42- max_linear_vel : float = 0.4 ,
43- max_angular_vel : float = 1.8 ,
44- max_linear_acc : float = 3 .0 ,
45- max_angular_acc : float = 6 .0 ,
42+ max_linear_vel : float = 0.8 ,
43+ max_angular_vel : float = 3.0 ,
44+ max_linear_acc : float = 6 .0 ,
45+ max_angular_acc : float = 8 .0 ,
4646 max_joint_vel : float = 5.0 ,
4747 min_linear_vel : float = 0.03 ,
4848 min_angular_vel : float = 0.1 ,
4949 linear_gain : float = 20.0 ,
50- angular_gain : float = 8 .0 ,
50+ angular_gain : float = 12 .0 ,
5151 ):
5252 """
5353 Initialize the Pinocchio robot with servo control capabilities.
@@ -93,6 +93,16 @@ def __init__(
9393 self .max_iter = 100
9494 self .damping = 1e-4 # Increased damping for stability
9595
96+ # IK regularization parameters
97+ self .joint_regularization = 0.01 # Joint position regularization weight
98+ self .velocity_regularization = 0.001 # Joint velocity regularization weight
99+ self .manipulability_threshold = (
100+ 0.01 # Threshold for manipulability-based regularization
101+ )
102+ self .desired_joint_config = pin .neutral (
103+ self .model
104+ ).copy () # Target joint configuration for regularization
105+
96106 # Previous velocities for acceleration limiting
97107 self .prev_linear_vel = np .zeros (3 )
98108 self .prev_angular_vel = np .zeros (3 )
@@ -139,11 +149,11 @@ def twist(
139149 J = self .__compute_jacobian ()
140150 # Create desired spatial velocity vector
141151 desired_spatial_vel = np .concatenate ([linear_velocity , angular_velocity_rpy ])
142- # Use SVD for more stable pseudo-inverse
143- U , s , Vt = np . linalg . svd ( J , full_matrices = False )
144- s_inv = np . where ( s > 1e-6 , 1.0 / s , 0.0 ) # Threshold small singular values
145- J_pinv = Vt . T @ np . diag ( s_inv ) @ U . T
146- joint_velocities = J_pinv @ desired_spatial_vel
152+
153+ # Use regularized pseudo-inverse
154+ J_pinv , joint_bias = self . __compute_regularized_jacobian_pinv ( J )
155+ joint_velocities = J_pinv @ desired_spatial_vel + joint_bias
156+
147157 # Apply joint velocity limits
148158 for i in range (len (joint_velocities )):
149159 if i < len (self .dq_max ) and self .dq_max [i ] > 0 :
@@ -268,15 +278,12 @@ def servo_to_pose(
268278 current_spatial_vel = self .__get_ee_velocity ()
269279 desired_spatial_vel -= damping_factor * current_spatial_vel
270280
271- # Compute joint velocities using damped pseudo-inverse
281+ # Compute joint velocities using regularized pseudo-inverse
272282 J = self .__compute_jacobian ()
273283
274- # Use SVD for more stable pseudo-inverse
275- U , s , Vt = np .linalg .svd (J , full_matrices = False )
276- s_inv = np .where (s > 1e-6 , 1.0 / s , 0.0 ) # Threshold small singular values
277- J_pinv = Vt .T @ np .diag (s_inv ) @ U .T
278-
279- joint_velocities = J_pinv @ desired_spatial_vel
284+ # Use regularized pseudo-inverse with multiple regularization terms
285+ J_pinv , joint_bias = self .__compute_regularized_jacobian_pinv (J )
286+ joint_velocities = J_pinv @ desired_spatial_vel + joint_bias
280287
281288 # Apply joint velocity limits
282289 for i in range (len (joint_velocities )):
@@ -418,7 +425,7 @@ def stop_visualization(self):
418425 plt .close (self .fig )
419426
420427 def print_status (self ):
421- """Print current robot status."""
428+ """Print current robot status including IK diagnostics ."""
422429 ee_pose = self .get_ee_pose ()
423430
424431 print (f"\n --- Robot Status ---" )
@@ -463,6 +470,97 @@ def get_joint_velocity(self, joint_name: str) -> float:
463470 raise ValueError (f"Joint '{ joint_name } ' not found in model." )
464471 return self .dq [joint_index ]
465472
473+ def __compute_regularized_jacobian_pinv (self , J : np .ndarray ) -> np .ndarray :
474+ """
475+ Compute regularized pseudo-inverse of Jacobian with multiple regularization terms.
476+
477+ Args:
478+ J: Jacobian matrix
479+
480+ Returns:
481+ Regularized pseudo-inverse of Jacobian
482+ """
483+ n_joints = J .shape [1 ]
484+
485+ # Compute manipulability measure
486+ manipulability = np .sqrt (np .linalg .det (J @ J .T ))
487+
488+ # Adaptive damping based on manipulability
489+ adaptive_damping = self .damping
490+ if manipulability < self .manipulability_threshold :
491+ # Increase damping near singularities
492+ damping_factor = self .manipulability_threshold / (manipulability + 1e-8 )
493+ adaptive_damping = self .damping * min (damping_factor , 10.0 )
494+
495+ # Joint position regularization (bias towards desired joint configuration)
496+ joint_position_error = self .q - self .desired_joint_config
497+ W_joint = np .eye (n_joints ) * self .joint_regularization
498+
499+ # Joint velocity regularization (bias towards zero velocity)
500+ W_velocity = np .eye (n_joints ) * self .velocity_regularization
501+
502+ # Combined regularization matrix
503+ W_reg = W_joint + W_velocity
504+
505+ # Damped least squares with regularization
506+ # J_pinv = (J^T J + λI + W_reg)^(-1) J^T
507+ JTJ = J .T @ J
508+ regularization_matrix = adaptive_damping * np .eye (n_joints ) + W_reg
509+
510+ try :
511+ # Primary method: Regularized normal equation
512+ J_pinv = np .linalg .solve (JTJ + regularization_matrix , J .T )
513+ except np .linalg .LinAlgError :
514+ # Fallback: SVD-based regularized pseudo-inverse
515+ U , s , Vt = np .linalg .svd (J , full_matrices = False )
516+ s_reg = s / (s ** 2 + adaptive_damping ) # Regularized singular values
517+ J_pinv = Vt .T @ np .diag (s_reg ) @ U .T
518+
519+ # Add joint position bias term
520+ joint_bias = - self .joint_regularization * joint_position_error
521+
522+ return J_pinv , joint_bias
523+
524+ def set_regularization_params (
525+ self ,
526+ joint_regularization : float = None ,
527+ velocity_regularization : float = None ,
528+ manipulability_threshold : float = None ,
529+ damping : float = None ,
530+ desired_joint_config : np .ndarray = None ,
531+ ):
532+ """
533+ Set IK regularization parameters.
534+
535+ Args:
536+ joint_regularization: Weight for joint position regularization (bias towards desired config)
537+ velocity_regularization: Weight for joint velocity regularization (bias towards zero)
538+ manipulability_threshold: Threshold for manipulability-based adaptive damping
539+ damping: Base damping factor for singularity avoidance
540+ desired_joint_config: Target joint configuration for regularization (bias towards these angles)
541+ """
542+ if joint_regularization is not None :
543+ self .joint_regularization = joint_regularization
544+ if velocity_regularization is not None :
545+ self .velocity_regularization = velocity_regularization
546+ if manipulability_threshold is not None :
547+ self .manipulability_threshold = manipulability_threshold
548+ if damping is not None :
549+ self .damping = damping
550+ if desired_joint_config is not None :
551+ if len (desired_joint_config ) != self .model .nq :
552+ raise ValueError (
553+ f"desired_joint_config must have { self .model .nq } elements, got { len (desired_joint_config )} "
554+ )
555+ self .desired_joint_config = np .array (desired_joint_config )
556+
557+ print (f"Regularization parameters updated:" )
558+ print (f" Joint regularization: { self .joint_regularization } " )
559+ print (f" Velocity regularization: { self .velocity_regularization } " )
560+ print (f" Manipulability threshold: { self .manipulability_threshold } " )
561+ print (f" Damping: { self .damping } " )
562+ print (f" Desired joint config: { np .round (self .desired_joint_config , 3 )} " )
563+
466564
467565if __name__ == "__main__" :
468566 import time
0 commit comments