mirror of
https://github.com/huggingface/lerobot.git
synced 2026-07-27 19:56:09 +00:00
feat(rollout): add smooth_handover flag to episodic strategy config
Follow-up to #3985, which added the same flag to the DAgger strategy. The episodic strategy's reset-phase handover had two gaps: - Non-actuated teleops could not skip the blocking follower slide at all. - Setting smooth_leader_to_follower_handover=false on an actuated teleop swapped which arm moves instead of skipping the handover. Add --strategy.smooth_handover (default true, existing behavior unchanged) as a master switch that skips the interpolation entirely, for clutch-style teleops that re-reference at the current robot pose on engage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
committed by
Maxime Ellerbach
parent
0d383d09f2
commit
360e619e18
@@ -194,6 +194,7 @@ Teleop is optional — if omitted the robot holds its position during the reset
|
|||||||
| `--teleop.type` | Optional. Teleoperator to drive the robot during resets |
|
| `--teleop.type` | Optional. Teleoperator to drive the robot during resets |
|
||||||
| `--strategy.reset_to_initial_position` | Whether to reset the robot to its initial position between episodes |
|
| `--strategy.reset_to_initial_position` | Whether to reset the robot to its initial position between episodes |
|
||||||
| `--strategy.smooth_leader_to_follower_handover` | Whether to turn on or off the leader -> follower smooth handover behavior. |
|
| `--strategy.smooth_leader_to_follower_handover` | Whether to turn on or off the leader -> follower smooth handover behavior. |
|
||||||
|
| `--strategy.smooth_handover` | Smoothly hand control to the teleop at reset start (default: true). Disable for clutch-style teleops that re-reference at the current robot pose on engage |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,15 @@ class EpisodicStrategyConfig(RolloutStrategyConfig):
|
|||||||
# Note that leader -> follower handover is only supported when the leader has `send_feedback` capability.
|
# Note that leader -> follower handover is only supported when the leader has `send_feedback` capability.
|
||||||
smooth_leader_to_follower_handover: bool = True
|
smooth_leader_to_follower_handover: bool = True
|
||||||
|
|
||||||
|
# Whether to turn on or off the smooth handover behavior at the start of the
|
||||||
|
# reset phase: the leader is driven to the follower position (actuated
|
||||||
|
# teleops, see `smooth_leader_to_follower_handover`), or the follower is
|
||||||
|
# slid to the teleop pose (non-actuated teleops). Disable for clutch-style
|
||||||
|
# teleoperators (e.g. VR controllers) that re-reference at the current robot
|
||||||
|
# pose on engage: the handover is already continuous there, and the blocking
|
||||||
|
# interpolation only delays the start of the reset phase.
|
||||||
|
smooth_handover: bool = True
|
||||||
|
|
||||||
|
|
||||||
@RolloutStrategyConfig.register_subclass("dagger")
|
@RolloutStrategyConfig.register_subclass("dagger")
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@@ -143,21 +143,25 @@ class EpisodicStrategy(RolloutStrategy):
|
|||||||
# position so the operator takes over without fighting the arm.
|
# position so the operator takes over without fighting the arm.
|
||||||
# For non-actuated teleops: slide the follower to the teleop's current
|
# For non-actuated teleops: slide the follower to the teleop's current
|
||||||
# pose instead, since the leader cannot be driven.
|
# pose instead, since the leader cannot be driven.
|
||||||
obs = robot.get_observation()
|
# Disabled entirely with --strategy.smooth_handover=false (useful for
|
||||||
current_pos = {k: v for k, v in obs.items() if k.endswith(".pos")}
|
# clutch-style teleops that re-reference at the current robot pose on
|
||||||
if (
|
# engage).
|
||||||
teleop_supports_feedback(teleop)
|
if self.config.smooth_handover:
|
||||||
and self.config.smooth_leader_to_follower_handover
|
obs = robot.get_observation()
|
||||||
):
|
current_pos = {k: v for k, v in obs.items() if k.endswith(".pos")}
|
||||||
logger.info("Smooth handover: moving leader arm to follower position")
|
if (
|
||||||
teleop_smooth_move_to(teleop, current_pos, duration_s=2)
|
teleop_supports_feedback(teleop)
|
||||||
teleop.disable_torque()
|
and self.config.smooth_leader_to_follower_handover
|
||||||
else:
|
):
|
||||||
logger.info("Smooth handover: sliding follower to teleop position")
|
logger.info("Smooth handover: moving leader arm to follower position")
|
||||||
teleop_action = teleop.get_action()
|
teleop_smooth_move_to(teleop, current_pos, duration_s=2)
|
||||||
processed = ctx.processors.teleop_action_processor((teleop_action, obs))
|
teleop.disable_torque()
|
||||||
target = ctx.processors.robot_action_processor((processed, obs))
|
else:
|
||||||
follower_smooth_move_to(robot, current_pos, target, duration_s=1)
|
logger.info("Smooth handover: sliding follower to teleop position")
|
||||||
|
teleop_action = teleop.get_action()
|
||||||
|
processed = ctx.processors.teleop_action_processor((teleop_action, obs))
|
||||||
|
target = ctx.processors.robot_action_processor((processed, obs))
|
||||||
|
follower_smooth_move_to(robot, current_pos, target, duration_s=1)
|
||||||
|
|
||||||
elif self.config.reset_to_initial_position:
|
elif self.config.reset_to_initial_position:
|
||||||
# No teleop: return the robot to its startup position.
|
# No teleop: return the robot to its startup position.
|
||||||
|
|||||||
Reference in New Issue
Block a user