Skip to content

Commit 94265ff

Browse files
authored
Add joint bias for IK (#10)
* Add joint bias for IK * version
1 parent d8aef45 commit 94265ff

File tree

3 files changed

+125
-19
lines changed

3 files changed

+125
-19
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
setup(
1818
name="teleop",
19-
version="0.1.0",
19+
version="0.1.1",
2020
packages=["teleop", "teleop.basic", "teleop.ros2", "teleop.utils", "teleop.ros2_ik", "teleop.xarm"],
2121
long_description=long_description,
2222
long_description_content_type="text/markdown",

teleop/index.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,14 @@ <h1>Teleop</h1>
127127
this.gripper = (this.gripper === 'open') ? 'close' : 'open';
128128
}
129129
gamepad.buttons[0].wasPressed = gamepad.buttons[0].pressed;
130+
131+
this.reservedButtonA = gamepad.buttons[4] && gamepad.buttons[4].pressed;
132+
this.reservedButtonB = gamepad.buttons[5] && gamepad.buttons[5].pressed;
133+
134+
const gamepadAxis = gamepad.axes[0];
135+
if (gamepadAxis !== undefined && Math.abs(gamepadAxis) > 0.1) {
136+
this.scale = Math.max(0.2, Math.min(1.0, this.scale + gamepadAxis * 0.1));
137+
}
130138
}
131139
}
132140
}

teleop/utils/jacobi_robot.py

Lines changed: 116 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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

467565
if __name__ == "__main__":
468566
import time

0 commit comments

Comments
 (0)