Georg commited on
Commit ·
d5b839c
1
Parent(s): c1222b2
Enhance UR5 environment jogging functionality with internal fallback
Browse files- Introduced an internal jogging mechanism for cartesian and joint movements when Nova jogging is unavailable.
- Updated the start_jog method to handle both Nova and internal jogging commands, improving robustness.
- Enhanced stop_jog method to manage both Nova and internal jogging states.
- Modified the step function to apply internal jogging updates to target positions and joint targets, ensuring smooth operation.
- robots/ur5/model/scene_t_push.xml +2 -2
- robots/ur5/ur5_env.py +115 -41
robots/ur5/model/scene_t_push.xml
CHANGED
|
@@ -188,8 +188,8 @@
|
|
| 188 |
<!-- Movable T-shaped object to push into target -->
|
| 189 |
<body name="t_object" pos="0.45 0.2 0.43">
|
| 190 |
<freejoint name="t_object_joint"/>
|
| 191 |
-
<geom name="t_object_stem" type="box" pos="0 -0.05 0" size="0.02 0.07 0.
|
| 192 |
-
<geom name="t_object_cap" type="box" pos="0 0.03 0" size="0.08 0.02 0.
|
| 193 |
</body>
|
| 194 |
</worldbody>
|
| 195 |
|
|
|
|
| 188 |
<!-- Movable T-shaped object to push into target -->
|
| 189 |
<body name="t_object" pos="0.45 0.2 0.43">
|
| 190 |
<freejoint name="t_object_joint"/>
|
| 191 |
+
<geom name="t_object_stem" type="box" pos="0 -0.05 0" size="0.02 0.07 0.03" material="t_object_mat" mass="3.0" friction="0.3 0.005 0.005"/>
|
| 192 |
+
<geom name="t_object_cap" type="box" pos="0 0.03 0" size="0.08 0.02 0.03" material="t_object_mat" mass="2.0" friction="0.3 0.005 0.005"/>
|
| 193 |
</body>
|
| 194 |
</worldbody>
|
| 195 |
|
robots/ur5/ur5_env.py
CHANGED
|
@@ -140,6 +140,7 @@ class UR5Env(gym.Env):
|
|
| 140 |
self._use_nova_jogging = False
|
| 141 |
self._last_nova_sequence = None
|
| 142 |
self._latest_nova_joints = None
|
|
|
|
| 143 |
|
| 144 |
# IK controller for end-effector control
|
| 145 |
self.controller = IKController(
|
|
@@ -338,7 +339,7 @@ class UR5Env(gym.Env):
|
|
| 338 |
return self._control_mode
|
| 339 |
|
| 340 |
def start_jog(self, jog_type: str, **kwargs) -> bool:
|
| 341 |
-
"""Start
|
| 342 |
|
| 343 |
Args:
|
| 344 |
jog_type: 'joint', 'cartesian_translation', or 'cartesian_rotation'
|
|
@@ -347,50 +348,102 @@ class UR5Env(gym.Env):
|
|
| 347 |
Returns:
|
| 348 |
True if command sent successfully
|
| 349 |
"""
|
| 350 |
-
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
|
|
|
| 379 |
return False
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 383 |
|
| 384 |
def stop_jog(self) -> bool:
|
| 385 |
-
"""Stop any active
|
| 386 |
-
|
| 387 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 388 |
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
print(
|
| 393 |
-
return
|
|
|
|
|
|
|
| 394 |
|
| 395 |
def set_joint_positions(self, positions, update_ik_target=True):
|
| 396 |
"""Set target joint positions directly (bypasses IK).
|
|
@@ -575,6 +628,27 @@ class UR5Env(gym.Env):
|
|
| 575 |
self.steps += 1
|
| 576 |
return self._get_obs()
|
| 577 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 578 |
if self._control_mode == 'ik':
|
| 579 |
joint_targets = self._compute_joint_targets()
|
| 580 |
else:
|
|
|
|
| 140 |
self._use_nova_jogging = False
|
| 141 |
self._last_nova_sequence = None
|
| 142 |
self._latest_nova_joints = None
|
| 143 |
+
self._active_jog = None # Internal jogging state
|
| 144 |
|
| 145 |
# IK controller for end-effector control
|
| 146 |
self.controller = IKController(
|
|
|
|
| 339 |
return self._control_mode
|
| 340 |
|
| 341 |
def start_jog(self, jog_type: str, **kwargs) -> bool:
|
| 342 |
+
"""Start jogging command (Nova or internal IK fallback).
|
| 343 |
|
| 344 |
Args:
|
| 345 |
jog_type: 'joint', 'cartesian_translation', or 'cartesian_rotation'
|
|
|
|
| 348 |
Returns:
|
| 349 |
True if command sent successfully
|
| 350 |
"""
|
| 351 |
+
# Try Nova jogging first if available
|
| 352 |
+
if self._use_nova_jogging and self._nova_jogger is not None:
|
| 353 |
+
try:
|
| 354 |
+
if jog_type == 'joint':
|
| 355 |
+
return self._nova_jogger.start_joint_jog(
|
| 356 |
+
joint=kwargs.get('joint', 0),
|
| 357 |
+
direction=kwargs.get('direction', '+'),
|
| 358 |
+
velocity_rads_per_sec=kwargs.get('velocity', 0.5)
|
| 359 |
+
)
|
| 360 |
+
elif jog_type == 'cartesian_translation':
|
| 361 |
+
return self._nova_jogger.start_cartesian_translation(
|
| 362 |
+
axis=kwargs.get('axis', 'x'),
|
| 363 |
+
direction=kwargs.get('direction', '+'),
|
| 364 |
+
velocity_mm_per_sec=kwargs.get('velocity', 50.0),
|
| 365 |
+
tcp_id=kwargs.get('tcp_id', 'Flange'),
|
| 366 |
+
coord_system_id=kwargs.get('coord_system_id', 'world')
|
| 367 |
+
)
|
| 368 |
+
elif jog_type == 'cartesian_rotation':
|
| 369 |
+
return self._nova_jogger.start_cartesian_rotation(
|
| 370 |
+
axis=kwargs.get('axis', 'x'),
|
| 371 |
+
direction=kwargs.get('direction', '+'),
|
| 372 |
+
velocity_rads_per_sec=kwargs.get('velocity', 0.3),
|
| 373 |
+
tcp_id=kwargs.get('tcp_id', 'Flange'),
|
| 374 |
+
coord_system_id=kwargs.get('coord_system_id', 'world')
|
| 375 |
+
)
|
| 376 |
+
else:
|
| 377 |
+
print(f"[Nova] Unknown jog type: {jog_type}")
|
| 378 |
+
return False
|
| 379 |
+
except Exception as e:
|
| 380 |
+
print(f"[Nova] Error starting jog: {e}")
|
| 381 |
return False
|
| 382 |
+
|
| 383 |
+
# Fallback to internal IK for cartesian movements
|
| 384 |
+
print(f"[Internal] Using internal IK for jogging: {jog_type}")
|
| 385 |
+
if jog_type in ('cartesian_translation', 'cartesian_rotation'):
|
| 386 |
+
axis = kwargs.get('axis', 'x')
|
| 387 |
+
direction = kwargs.get('direction', '+')
|
| 388 |
+
|
| 389 |
+
# Calculate step size (velocity * dt where dt ~= 0.002s per step)
|
| 390 |
+
# For translation: velocity in mm/s, convert to m/s and multiply by step time
|
| 391 |
+
# For rotation: velocity in rad/s, multiply by step time
|
| 392 |
+
if jog_type == 'cartesian_translation':
|
| 393 |
+
velocity_mm_per_sec = kwargs.get('velocity', 50.0)
|
| 394 |
+
step_size = (velocity_mm_per_sec / 1000.0) * 0.02 # m per update (10 Hz updates)
|
| 395 |
+
else: # rotation
|
| 396 |
+
velocity_rad_per_sec = kwargs.get('velocity', 0.3)
|
| 397 |
+
step_size = velocity_rad_per_sec * 0.02 # radians per update (10 Hz updates)
|
| 398 |
+
|
| 399 |
+
# Apply direction
|
| 400 |
+
if direction == '-':
|
| 401 |
+
step_size = -step_size
|
| 402 |
+
|
| 403 |
+
self._active_jog = {
|
| 404 |
+
'type': jog_type,
|
| 405 |
+
'axis': axis,
|
| 406 |
+
'step_size': step_size
|
| 407 |
+
}
|
| 408 |
+
return True
|
| 409 |
+
|
| 410 |
+
# For joint jogging with internal control
|
| 411 |
+
elif jog_type == 'joint':
|
| 412 |
+
joint = kwargs.get('joint', 0)
|
| 413 |
+
direction = kwargs.get('direction', '+')
|
| 414 |
+
velocity_rad_per_sec = kwargs.get('velocity', 0.5)
|
| 415 |
+
|
| 416 |
+
step_size = velocity_rad_per_sec * 0.02 # radians per update (10 Hz updates)
|
| 417 |
+
if direction == '-':
|
| 418 |
+
step_size = -step_size
|
| 419 |
+
|
| 420 |
+
self._active_jog = {
|
| 421 |
+
'type': 'joint',
|
| 422 |
+
'joint': joint,
|
| 423 |
+
'step_size': step_size
|
| 424 |
+
}
|
| 425 |
+
return True
|
| 426 |
+
|
| 427 |
+
print(f"[Internal] Unknown jog type: {jog_type}")
|
| 428 |
+
return False
|
| 429 |
|
| 430 |
def stop_jog(self) -> bool:
|
| 431 |
+
"""Stop any active jogging movement (Nova or internal)."""
|
| 432 |
+
# Stop Nova jogging if active
|
| 433 |
+
if self._use_nova_jogging and self._nova_jogger is not None:
|
| 434 |
+
try:
|
| 435 |
+
return self._nova_jogger.stop()
|
| 436 |
+
except Exception as e:
|
| 437 |
+
print(f"[Nova] Error stopping jog: {e}")
|
| 438 |
+
return False
|
| 439 |
|
| 440 |
+
# Stop internal jogging
|
| 441 |
+
if hasattr(self, '_active_jog'):
|
| 442 |
+
self._active_jog = None
|
| 443 |
+
print("[Internal] Stopped internal jogging")
|
| 444 |
+
return True
|
| 445 |
+
|
| 446 |
+
return False
|
| 447 |
|
| 448 |
def set_joint_positions(self, positions, update_ik_target=True):
|
| 449 |
"""Set target joint positions directly (bypasses IK).
|
|
|
|
| 628 |
self.steps += 1
|
| 629 |
return self._get_obs()
|
| 630 |
|
| 631 |
+
# Apply internal jogging if active
|
| 632 |
+
if hasattr(self, '_active_jog') and self._active_jog is not None:
|
| 633 |
+
jog = self._active_jog
|
| 634 |
+
if jog['type'] == 'cartesian_translation':
|
| 635 |
+
# Update target position along specified axis
|
| 636 |
+
axis_idx = {'x': 0, 'y': 1, 'z': 2}[jog['axis']]
|
| 637 |
+
self._target_pos[axis_idx] += jog['step_size']
|
| 638 |
+
elif jog['type'] == 'cartesian_rotation':
|
| 639 |
+
# Update target orientation around specified axis
|
| 640 |
+
axis_idx = {'x': 0, 'y': 1, 'z': 2}[jog['axis']]
|
| 641 |
+
self._target_euler[axis_idx] += jog['step_size']
|
| 642 |
+
elif jog['type'] == 'joint':
|
| 643 |
+
# Update target joint position directly
|
| 644 |
+
self._joint_targets[jog['joint']] += jog['step_size']
|
| 645 |
+
# Clamp to joint limits
|
| 646 |
+
self._joint_targets = np.clip(
|
| 647 |
+
self._joint_targets,
|
| 648 |
+
self.action_space.low[:6],
|
| 649 |
+
self.action_space.high[:6]
|
| 650 |
+
)
|
| 651 |
+
|
| 652 |
if self._control_mode == 'ik':
|
| 653 |
joint_targets = self._compute_joint_targets()
|
| 654 |
else:
|