GLIDE iconGLIDE: Guardrails for Learning from Infeasible Demonstrations Efficiently

Anonymous Authors

TL;DR: GLIDE uses closed-loop, self-refined guardrails to make infeasible robot manipulation tasks demonstrable, learnable, and the trained policies more reliable to deploy.

GLIDE Methodology

(A) From task description, GLIDE infers task-specific failure points and generates an initial executable guardrail. (B) During data collection, the guardrail filters human commands while logging system states, human commands, and executed commands. (C) GLIDE diagnoses real-world dataset using visual feedback to determine successes or failure modes and self-refines the guardrail. (D) This rollout-driven loop repeats across iterations; the final guardrail improves demonstration collection and can also guard learned policies at deployment.

Task Descriptions

Tomato Plate Transfer

The robot must use both grippers to grasp and transport a plate containing tomatoes from tabletop to an elevated surface. Successful execution requires maintaining plate stability throughout the lift and placement so that no tomatoes are spilled.

Tomato plate transfer task description.

Note: visual outlines in the images are added only for readability; the underlying robot observations are otherwise unedited.

GLIDE-Teleoperation

Tomato Plate Transfer

OpenTV (Cheng et al. CoRL 2024)

Raw teleoperation treats the two arms independently. During loaded transport, controller mismatch can create height differences between grippers, tilt the plate, and spill tomatoes.

GLIDE (Ours)

GLIDE treats both grippers as a coupled tray: it keep the plate level, preserve grasp width, restrain wrist tilt, and coordinates gripper open/close.

Case Study (GLIDE keeps grippers at matching heights to avoid side-to-side tilt)

GLIDE Guardrail Generation

Task Prompt

I have a bimanual teleoperation script at <script_name>, where the readings of two controllers from VR headset are mapped to the robot commands through inverse kinematics. I am now collecting data for a new task, that bimanually picking up and lifting a plate full of cherry tomatoes onto a box. Please identify the potential failure cases in the teleoperation process, design constraints and apply the filter that will help to make the human teleoperation easier.

GLIDE Guardrail Code generating

                  class PlateLiftTeleopFilter:
                      # Task-space filter inserted between raw VR target poses and IK.

                      def _filter_carry_midpoint(self, raw_mid, prev_mid):
                          # Move the shared plate center. XY can move faster for
                          # transport, while Z is slower to avoid drops and spills.
                          filtered = prev_mid + pos_alpha * (raw_mid - prev_mid)
                          step = filtered - prev_mid
                          step[:2] = clamp_vector_norm(step[:2], carry_max_xy_speed * dt)
                          step[2] = clip(step[2], -carry_max_z_speed * dt, carry_max_z_speed * dt)
                          step_delta = clamp_accel(step - self.prev_mid_step)
                          self.prev_mid_step = step
                          return prev_mid + step

                      def filter_pair(self, left_target_pose, right_target_pose, stabilize=False):
                          if not stabilize:
                              return filter_single(left), filter_single(right)
                          self._ensure_carry_reference(left_target_pose, right_target_pose)
                          raw_mid = 0.5 * (raw_left_pos + raw_right_pos)
                          raw_mid[2] = max(raw_mid[2], init_mid[2] - carry_down_margin)
                          half_delta = carry_differential_gain * (raw_half_sep - init_half_sep)
                          half_delta[2] = clip(
                              half_delta[2], -0.5 * carry_max_height_diff, 0.5 * carry_max_height_diff)
                          filtered_mid = self._filter_carry_midpoint(raw_mid, prev_mid)
                          left_rot = self._filter_rotation(carry_left_rot, left_target_rot, carry_orientation_weight)
                          right_rot = self._filter_rotation(carry_right_rot, right_target_rot, carry_orientation_weight)
                          return left_filtered, right_filtered


                  def should_stabilize_plate(left_arm, right_arm, left_state, right_state, args):
                      # Enter paired carry when both triggers are pressed or both grippers close.
                      return both_triggers or (left_closed and right_closed)


                  def toggle_plate_grippers_from_triggers(left_arm, right_arm, args):
                      target_label = "open" if min(left_closed, right_closed) >= reopen_threshold else "close"
                      set_gripper_target_label(left_arm, target_label)
                      set_gripper_target_label(right_arm, target_label)
                

Iterative Self-Refinement

iteration1: make loaded carry gentler after spill episodes

Log diagnosis: Hover to play episodes 6-9 spilled after the plate was already grasped; failed runs had faster loaded transport and larger height mismatch.
Before After
Category: Motion limits during carry (plate guardrail restrictions) - Changing speed limits; adding acceleration guard
Category: Motion limits during carry (plate guardrail restrictions) - Changing speed limits; adding acceleration guard
1222-parser.add_argument("--plate-filter-alpha", type=float, default=0.45)
1222+parser.add_argument("--plate-filter-alpha", type=float, default=0.40)
1224-parser.add_argument("--plate-carry-max-ee-speed", type=float, default=0.18)
1224+parser.add_argument("--plate-carry-max-ee-speed", type=float, default=0.14)
1225+parser.add_argument("--plate-carry-max-ee-accel", type=float, default=0.45)
1350left_pos = self._filter_position(
1350left_pos = self._filter_position(
1351 left_pos, left_prev,
1351 left_pos, left_prev,
1352- self.config.carry_max_speed,
1352+ self.prev_left_step,
1353+ self.config.carry_max_accel,
Category: Keep the plate level (plate guardrail restrictions) - Tightening shared stability bound
Category: Keep the plate level (plate guardrail restrictions) - Tightening shared stability bound
1231-parser.add_argument("--plate-carry-max-height-diff", type=float, default=0.012)
1232+parser.add_argument("--plate-carry-max-height-diff", type=float, default=0.008)

iteration2: make transport faster without relaxing vertical safety

Log diagnosis: Hover to play episode 7 fully closed but spilled during carry; one isotropic filter throttled horizontal and vertical motion together.
Before After
Category: Motion limits during carry (plate guardrail restrictions) - Move the plate as one object
Category: Motion limits during carry (plate guardrail restrictions) - Move the plate as one object
1224-parser.add_argument("--plate-carry-max-ee-speed", type=float, default=0.14)
1224+parser.add_argument("--plate-carry-max-ee-speed", type=float, default=0.22)
1225+parser.add_argument("--plate-carry-max-xy-speed", type=float, default=0.24)
1226+parser.add_argument("--plate-carry-max-z-speed", type=float, default=0.055)
1227+parser.add_argument("--plate-carry-max-xy-accel", type=float, default=0.85)
1228+parser.add_argument("--plate-carry-max-z-accel", type=float, default=0.18)
1361-left_pos = self._filter_position(
1361+prev_mid = 0.5 * (left_prev + right_prev)
1364- self.config.carry_max_speed,
1362+filtered_mid = self._filter_carry_midpoint(raw_mid, prev_mid)
1365- self.prev_left_step,
1363+left_pos = filtered_mid + filtered_half_sep
1366- self.config.carry_max_accel,
1364+right_pos = filtered_mid - filtered_half_sep
Category: Restrain wrist/plate tilt (plate guardrail restrictions) - Relaxing an over-strict orientation lock
Category: Restrain wrist/plate tilt (plate guardrail restrictions) - Relaxing an over-strict orientation lock
1235-parser.add_argument("--plate-carry-orientation-weight", type=float, default=1.0)
1239+parser.add_argument("--plate-carry-orientation-weight", type=float, default=0.9)

GLIDE-π0.5 Policy

Rollout 1

Rollout 2

Rollout 3

Results

Expert Demonstration Collection

GLIDE raises best demonstration success to 70%, 90%, and 90% on Tomato plate transfer, Marker handover & stand, and Wine serving, compared with 0%, 10%, and 0% for unguarded OpenTV teleoperation.

Guarded Policy Execution

Guarded deployment improves autonomous execution where raw policy outputs are brittle. The best deployment results use mixed-quality data with guardrail filtering, reaching 70% success on Tomato plate transfer, 60% on Marker handover & stand, and 60% on Wine serving.

Abstract

Behavior cloning for robot manipulation relies on expert demonstrations. However, for tasks that require dynamic stability, precise contact timing, or dexterous coordination, human teleoperators may find it hard or evenimpossible to collect data. We study this infeasible-demonstration regime and propose GLIDE, a framework that infers task-specific failure modes and converts them into executable guardrails for data collection and policy deployment. Given a task description, GLIDE writes guardrails that use robot states to filter teleoperation and policy commands, constrain failure-prone actions, and iteratively improve from closed-loop dataset feedback. Across Tomato plate transfer, Marker handover & stand, and Wine serving tasks, GLIDE improves data collection over raw VR teleoperation and manually designed guardrails. After refinement, GLIDE raises data-collection efficiency from 0-10% to 70-90% across the three tasks. During policy execution, guarded deployment raises Tomato plate transfer policy success from 0% to 60-70%, enabling efficient learning on mixed-quality demonstrations. These results show that GLIDE can support policy learning when direct demonstrations are infeasible.