Refactor UR5 environment to enhance target setting and joint control
Browse files- Updated target position and orientation initialization to use forward kinematics from the home pose.
- Enhanced `set_target` and `set_target_orientation` methods to include an option for updating joint targets via inverse kinematics.
- Modified `set_joint_positions` to optionally update the IK target based on the new end-effector pose.
- Improved the reset logic to compute the target from the end-effector's position and orientation after initialization.
- robots/ur5/ur5_env.py +78 -15
robots/ur5/ur5_env.py
CHANGED
|
@@ -110,11 +110,18 @@ class UR5Env(gym.Env):
|
|
| 110 |
arm_joint_names=self.JOINT_NAMES
|
| 111 |
)
|
| 112 |
|
| 113 |
-
#
|
| 114 |
-
self.
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
# Whether to use orientation in IK (user can toggle this)
|
| 119 |
self._use_orientation = True
|
| 120 |
# Gripper target: Robotiq 2F-85 uses 0=open, 255=closed
|
|
@@ -125,20 +132,49 @@ class UR5Env(gym.Env):
|
|
| 125 |
# Direct joint targets (used when control_mode is 'joint')
|
| 126 |
self._joint_targets = self.DEFAULT_HOME_POSE.copy()
|
| 127 |
|
| 128 |
-
def set_target(self, x: float, y: float, z: float):
|
| 129 |
-
"""Set target position for IK controller.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
self._target_pos = np.array([x, y, z], dtype=np.float32)
|
| 131 |
# Update mocap body position for visualization
|
| 132 |
self.data.mocap_pos[0] = self._target_pos
|
| 133 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
def get_target(self):
|
| 135 |
"""Get current target position."""
|
| 136 |
return self._target_pos.copy()
|
| 137 |
|
| 138 |
-
def set_target_orientation(self, roll: float, pitch: float, yaw: float):
|
| 139 |
-
"""Set target orientation as Euler angles (radians).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
self._target_euler = np.array([roll, pitch, yaw], dtype=np.float32)
|
| 141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
def get_target_orientation(self):
|
| 143 |
"""Get target orientation as Euler angles (radians)."""
|
| 144 |
return self._target_euler.copy()
|
|
@@ -168,17 +204,36 @@ class UR5Env(gym.Env):
|
|
| 168 |
"""Get current control mode."""
|
| 169 |
return self._control_mode
|
| 170 |
|
| 171 |
-
def set_joint_positions(self, positions):
|
| 172 |
"""Set target joint positions directly (bypasses IK).
|
| 173 |
|
| 174 |
Args:
|
| 175 |
positions: Array of 6 joint angles in radians
|
|
|
|
| 176 |
"""
|
| 177 |
positions = np.array(positions, dtype=np.float32)
|
| 178 |
# Clamp to joint limits
|
| 179 |
positions = np.clip(positions, self.action_space.low[:6], self.action_space.high[:6])
|
| 180 |
self._joint_targets = positions
|
| 181 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 182 |
def get_joint_positions(self):
|
| 183 |
"""Get current joint positions."""
|
| 184 |
return self.data.qpos[:6].copy()
|
|
@@ -250,13 +305,21 @@ class UR5Env(gym.Env):
|
|
| 250 |
self.data.qpos[box_qpos_start:box_qpos_start+3] = [0.5, 0.2, 0.45]
|
| 251 |
self.data.qpos[box_qpos_start+3:box_qpos_start+7] = [1, 0, 0, 0]
|
| 252 |
|
| 253 |
-
#
|
| 254 |
-
|
| 255 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 256 |
self.data.mocap_pos[0] = self._target_pos
|
| 257 |
self._gripper_target = 0.0 # Open gripper
|
| 258 |
-
|
| 259 |
-
mujoco.mj_forward(self.model, self.data)
|
| 260 |
|
| 261 |
self.steps = 0
|
| 262 |
|
|
|
|
| 110 |
arm_joint_names=self.JOINT_NAMES
|
| 111 |
)
|
| 112 |
|
| 113 |
+
# Set initial joint positions to home pose and compute FK
|
| 114 |
+
self.data.qpos[:6] = self.DEFAULT_HOME_POSE.copy()
|
| 115 |
+
self.data.ctrl[:6] = self.DEFAULT_HOME_POSE.copy()
|
| 116 |
+
mujoco.mj_forward(self.model, self.data)
|
| 117 |
+
|
| 118 |
+
# Target position/orientation from FK of home pose
|
| 119 |
+
ee_pos = self.get_end_effector_pos()
|
| 120 |
+
ee_quat = self.get_end_effector_quat()
|
| 121 |
+
self._target_pos = ee_pos.astype(np.float32)
|
| 122 |
+
roll, pitch, yaw = IKController.quat_to_euler(ee_quat)
|
| 123 |
+
self._target_euler = np.array([roll, pitch, yaw], dtype=np.float32)
|
| 124 |
+
|
| 125 |
# Whether to use orientation in IK (user can toggle this)
|
| 126 |
self._use_orientation = True
|
| 127 |
# Gripper target: Robotiq 2F-85 uses 0=open, 255=closed
|
|
|
|
| 132 |
# Direct joint targets (used when control_mode is 'joint')
|
| 133 |
self._joint_targets = self.DEFAULT_HOME_POSE.copy()
|
| 134 |
|
| 135 |
+
def set_target(self, x: float, y: float, z: float, update_joint_targets=True):
|
| 136 |
+
"""Set target position for IK controller.
|
| 137 |
+
|
| 138 |
+
Args:
|
| 139 |
+
x, y, z: Target position in meters
|
| 140 |
+
update_joint_targets: If True, compute IK and update joint targets
|
| 141 |
+
"""
|
| 142 |
self._target_pos = np.array([x, y, z], dtype=np.float32)
|
| 143 |
# Update mocap body position for visualization
|
| 144 |
self.data.mocap_pos[0] = self._target_pos
|
| 145 |
|
| 146 |
+
# Update joint targets via IK
|
| 147 |
+
if update_joint_targets:
|
| 148 |
+
if self._use_orientation:
|
| 149 |
+
target_quat = IKController.euler_to_quat(
|
| 150 |
+
self._target_euler[0], self._target_euler[1], self._target_euler[2]
|
| 151 |
+
)
|
| 152 |
+
self._joint_targets = self.controller.compute_ik_with_orientation(
|
| 153 |
+
self._target_pos, target_quat
|
| 154 |
+
)
|
| 155 |
+
else:
|
| 156 |
+
self._joint_targets = self.controller.compute_ik(self._target_pos)
|
| 157 |
+
|
| 158 |
def get_target(self):
|
| 159 |
"""Get current target position."""
|
| 160 |
return self._target_pos.copy()
|
| 161 |
|
| 162 |
+
def set_target_orientation(self, roll: float, pitch: float, yaw: float, update_joint_targets=True):
|
| 163 |
+
"""Set target orientation as Euler angles (radians).
|
| 164 |
+
|
| 165 |
+
Args:
|
| 166 |
+
roll, pitch, yaw: Target orientation in radians
|
| 167 |
+
update_joint_targets: If True, compute IK and update joint targets
|
| 168 |
+
"""
|
| 169 |
self._target_euler = np.array([roll, pitch, yaw], dtype=np.float32)
|
| 170 |
|
| 171 |
+
# Update joint targets via IK
|
| 172 |
+
if update_joint_targets and self._use_orientation:
|
| 173 |
+
target_quat = IKController.euler_to_quat(roll, pitch, yaw)
|
| 174 |
+
self._joint_targets = self.controller.compute_ik_with_orientation(
|
| 175 |
+
self._target_pos, target_quat
|
| 176 |
+
)
|
| 177 |
+
|
| 178 |
def get_target_orientation(self):
|
| 179 |
"""Get target orientation as Euler angles (radians)."""
|
| 180 |
return self._target_euler.copy()
|
|
|
|
| 204 |
"""Get current control mode."""
|
| 205 |
return self._control_mode
|
| 206 |
|
| 207 |
+
def set_joint_positions(self, positions, update_ik_target=True):
|
| 208 |
"""Set target joint positions directly (bypasses IK).
|
| 209 |
|
| 210 |
Args:
|
| 211 |
positions: Array of 6 joint angles in radians
|
| 212 |
+
update_ik_target: If True, update IK target to match new EE pose
|
| 213 |
"""
|
| 214 |
positions = np.array(positions, dtype=np.float32)
|
| 215 |
# Clamp to joint limits
|
| 216 |
positions = np.clip(positions, self.action_space.low[:6], self.action_space.high[:6])
|
| 217 |
self._joint_targets = positions
|
| 218 |
|
| 219 |
+
# Update IK target to match the FK of new joint positions
|
| 220 |
+
if update_ik_target:
|
| 221 |
+
# Temporarily set joints to compute FK
|
| 222 |
+
old_qpos = self.data.qpos[:6].copy()
|
| 223 |
+
self.data.qpos[:6] = positions
|
| 224 |
+
mujoco.mj_forward(self.model, self.data)
|
| 225 |
+
|
| 226 |
+
# Get EE pose from FK
|
| 227 |
+
ee_pos = self.get_end_effector_pos()
|
| 228 |
+
ee_quat = self.get_end_effector_quat()
|
| 229 |
+
self._target_pos = ee_pos.astype(np.float32)
|
| 230 |
+
roll, pitch, yaw = IKController.quat_to_euler(ee_quat)
|
| 231 |
+
self._target_euler = np.array([roll, pitch, yaw], dtype=np.float32)
|
| 232 |
+
self.data.mocap_pos[0] = self._target_pos
|
| 233 |
+
|
| 234 |
+
# Restore original qpos (simulation will move towards target)
|
| 235 |
+
self.data.qpos[:6] = old_qpos
|
| 236 |
+
|
| 237 |
def get_joint_positions(self):
|
| 238 |
"""Get current joint positions."""
|
| 239 |
return self.data.qpos[:6].copy()
|
|
|
|
| 305 |
self.data.qpos[box_qpos_start:box_qpos_start+3] = [0.5, 0.2, 0.45]
|
| 306 |
self.data.qpos[box_qpos_start+3:box_qpos_start+7] = [1, 0, 0, 0]
|
| 307 |
|
| 308 |
+
# Compute forward kinematics to get EE pose from home joints
|
| 309 |
+
mujoco.mj_forward(self.model, self.data)
|
| 310 |
+
|
| 311 |
+
# Set target to current EE position (computed from FK)
|
| 312 |
+
ee_pos = self.get_end_effector_pos()
|
| 313 |
+
ee_quat = self.get_end_effector_quat()
|
| 314 |
+
self._target_pos = ee_pos.astype(np.float32)
|
| 315 |
+
|
| 316 |
+
# Convert EE quaternion to euler for target orientation
|
| 317 |
+
roll, pitch, yaw = IKController.quat_to_euler(ee_quat)
|
| 318 |
+
self._target_euler = np.array([roll, pitch, yaw], dtype=np.float32)
|
| 319 |
+
|
| 320 |
self.data.mocap_pos[0] = self._target_pos
|
| 321 |
self._gripper_target = 0.0 # Open gripper
|
| 322 |
+
self._joint_targets = self.DEFAULT_HOME_POSE.copy()
|
|
|
|
| 323 |
|
| 324 |
self.steps = 0
|
| 325 |
|