Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gripper): specify whether or not a gripper move should stay engaged after an error #13214

Merged
merged 3 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion api/src/opentrons/hardware_control/backends/ot3controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,8 +660,11 @@ async def gripper_grip_jaw(
self,
duty_cycle: float,
stop_condition: MoveStopCondition = MoveStopCondition.none,
stay_engaged: bool = True,
) -> None:
move_group = create_gripper_jaw_grip_group(duty_cycle, stop_condition)
move_group = create_gripper_jaw_grip_group(
duty_cycle, stop_condition, stay_engaged
)
runner = MoveGroupRunner(move_groups=[move_group])
positions = await runner.run(can_messenger=self._messenger)
self._handle_motor_status_response(positions)
Expand Down
3 changes: 2 additions & 1 deletion api/src/opentrons/hardware_control/backends/ot3simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,9 +353,10 @@ async def gripper_grip_jaw(
self,
duty_cycle: float,
stop_condition: MoveStopCondition = MoveStopCondition.none,
stay_engaged: bool = True,
) -> None:
"""Move gripper inward."""
_ = create_gripper_jaw_grip_group(duty_cycle, stop_condition)
_ = create_gripper_jaw_grip_group(duty_cycle, stop_condition, stay_engaged)

@ensure_yield
async def gripper_home_jaw(self, duty_cycle: float) -> None:
Expand Down
2 changes: 2 additions & 0 deletions api/src/opentrons/hardware_control/backends/ot3utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,12 +428,14 @@ def create_gear_motor_home_group(
def create_gripper_jaw_grip_group(
duty_cycle: float,
stop_condition: MoveStopCondition = MoveStopCondition.none,
stay_engaged: bool = True,
) -> MoveGroup:
step = create_gripper_jaw_step(
duration=np.float64(GRIPPER_JAW_GRIP_TIME),
duty_cycle=np.float32(round(duty_cycle)),
stop_condition=stop_condition,
move_type=MoveType.grip,
stay_engaged=stay_engaged,
)
move_group: MoveGroup = [step]
return move_group
Expand Down
12 changes: 8 additions & 4 deletions api/src/opentrons/hardware_control/ot3api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1395,10 +1395,12 @@ async def update_config(self, **kwargs: Any) -> None:
self._config = replace(self._config, **kwargs)

@ExecutionManagerProvider.wait_for_running
async def _grip(self, duty_cycle: float) -> None:
async def _grip(self, duty_cycle: float, stay_engaged: bool = True) -> None:
"""Move the gripper jaw inward to close."""
try:
await self._backend.gripper_grip_jaw(duty_cycle=duty_cycle)
await self._backend.gripper_grip_jaw(
duty_cycle=duty_cycle, stay_engaged=stay_engaged
)
await self._cache_encoder_position()
except Exception:
self._log.exception(
Expand Down Expand Up @@ -1431,12 +1433,14 @@ async def _hold_jaw_width(self, jaw_width_mm: float) -> None:
self._log.exception("Gripper set width failed")
raise

async def grip(self, force_newtons: Optional[float] = None) -> None:
async def grip(
self, force_newtons: Optional[float] = None, stay_engaged: bool = True
) -> None:
self._gripper_handler.check_ready_for_jaw_move()
dc = self._gripper_handler.get_duty_cycle_by_grip_force(
force_newtons or self._gripper_handler.get_gripper().default_grip_force
)
await self._grip(duty_cycle=dc)
await self._grip(duty_cycle=dc, stay_engaged=stay_engaged)
self._gripper_handler.set_jaw_state(GripperJawState.GRIPPING)

async def ungrip(self, force_newtons: Optional[float] = None) -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ async def move_labware_with_gripper(

# Keep the gripper in idly gripped position to avoid colliding with
# things like the thermocycler latches
await ot3api.grip(force_newtons=IDLE_STATE_GRIP_FORCE)
await ot3api.grip(force_newtons=IDLE_STATE_GRIP_FORCE, stay_engaged=False)

async def ensure_movement_not_obstructed_by_module(
self, labware_id: str, new_location: LabwareLocation
Expand Down
1 change: 1 addition & 0 deletions api/tests/opentrons/hardware_control/test_ot3_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,7 @@ async def test_gripper_action_works_with_gripper(
await ot3_hardware.grip(5.0)
mock_grip.assert_called_once_with(
gc.duty_cycle_by_force(5.0, gripper_config.grip_force_profile),
stay_engaged=True,
)

await ot3_hardware.ungrip()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,9 @@ async def test_move_labware_with_gripper(
await ot3_hardware_api.move_to(
mount=gripper, abs_position=expected_waypoints[5]
),
await ot3_hardware_api.grip(force_newtons=IDLE_STATE_GRIP_FORCE),
await ot3_hardware_api.grip(
force_newtons=IDLE_STATE_GRIP_FORCE, stay_engaged=False
),
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,7 @@ class GripperMoveRequestPayload(AddToMoveGroupRequestPayload):

duty_cycle: utils.UInt32Field
encoder_position_um: utils.Int32Field
stay_engaged: utils.UInt8Field


@dataclass(eq=False)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ async def grip(
seq_id: int,
duration_sec: float,
duty_cycle: int,
stay_engaged: bool = False,
) -> None:
"""Start grip motion."""
await can_messenger.send(
Expand All @@ -141,6 +142,7 @@ async def grip(
),
duty_cycle=UInt32Field(duty_cycle),
encoder_position_um=Int32Field(0),
stay_engaged=UInt8Field(int(stay_engaged)),
)
),
)
Expand All @@ -162,6 +164,7 @@ async def home(
duration=UInt32Field(0),
duty_cycle=UInt32Field(duty_cycle),
encoder_position_um=Int32Field(0),
stay_engaged=UInt8Field(0),
)
),
)
Expand All @@ -173,6 +176,7 @@ async def move(
seq_id: int,
duty_cycle: int,
encoder_position_um: int,
stay_engaged: bool = False,
) -> None:
"""Start linear motion."""
await can_messenger.send(
Expand All @@ -184,6 +188,7 @@ async def move(
duration=UInt32Field(0),
duty_cycle=UInt32Field(duty_cycle),
encoder_position_um=Int32Field(encoder_position_um),
stay_engaged=UInt8Field(int(stay_engaged)),
)
),
)
3 changes: 3 additions & 0 deletions hardware/opentrons_hardware/hardware_control/motion.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class MoveGroupSingleGripperStep:
pwm_duty_cycle: np.float32
encoder_position_um: np.int32
pwm_frequency: np.float32 = np.float32(320000)
stay_engaged: bool = False
stop_condition: MoveStopCondition = MoveStopCondition.gripper_force
move_type: MoveType = MoveType.grip

Expand Down Expand Up @@ -214,6 +215,7 @@ def create_gripper_jaw_step(
duty_cycle: np.float32,
encoder_position_um: np.int32 = np.int32(0),
frequency: np.float32 = np.float32(320000),
stay_engaged: bool = False,
stop_condition: MoveStopCondition = MoveStopCondition.gripper_force,
move_type: MoveType = MoveType.grip,
) -> MoveGroupStep:
Expand All @@ -223,6 +225,7 @@ def create_gripper_jaw_step(
duration_sec=duration,
pwm_frequency=frequency,
pwm_duty_cycle=duty_cycle,
stay_engaged=stay_engaged,
stop_condition=stop_condition,
move_type=move_type,
encoder_position_um=encoder_position_um,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ def _get_brushed_motor_message(
),
duty_cycle=UInt32Field(int(step.pwm_duty_cycle)),
encoder_position_um=Int32Field(int(step.encoder_position_um)),
stay_engaged=UInt8Field(int(step.stay_engaged)),
)
if step.move_type == MoveType.home:
return GripperHomeRequest(payload=payload)
Expand Down
1 change: 1 addition & 0 deletions hardware/opentrons_hardware/scripts/gripper_lifetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ async def run(args: argparse.Namespace) -> None:
pwm_frequency=float32(pwm_freq),
pwm_duty_cycle=float32(pwm_duty),
encoder_position_um=int32(0),
stay_engaged=True,
)
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ def move_group_gripper_multiple() -> MoveGroups:
duration_sec=float64(1),
pwm_duty_cycle=float32(50),
encoder_position_um=int32(0),
stay_engaged=True,
stop_condition=MoveStopCondition.gripper_force,
move_type=MoveType.grip,
),
Expand All @@ -203,6 +204,7 @@ def move_group_gripper_multiple() -> MoveGroups:
duration_sec=float64(1),
pwm_duty_cycle=float32(50),
encoder_position_um=int32(80000),
stay_engaged=False,
stop_condition=MoveStopCondition.encoder_position,
move_type=MoveType.linear,
),
Expand Down