Skip to content

Commit

Permalink
fix(api): Switch plunger backlash to pre-load for aspirations (#13076)
Browse files Browse the repository at this point in the history
  • Loading branch information
andySigler authored Jul 11, 2023
1 parent 9e7c35c commit 11b4775
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 25 deletions.
20 changes: 6 additions & 14 deletions api/src/opentrons/hardware_control/ot3api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1467,10 +1467,13 @@ async def _move_to_plunger_bottom(
# save time by using max speed
max_speeds = self.config.motion_settings.default_max_speed
speed = max_speeds[self.gantry_load][OT3AxisKind.P]
if current_pos > target_pos[pip_ax]:
# IMPORTANT: Here is our backlash compensation.
# The plunger is pre-loaded in the "aspirate" direction
# NOTE: plunger position (mm) decreases up towards homing switch
if current_pos < target_pos[pip_ax]:
# move down below "bottom", before moving back up to "bottom"
backlash_pos = target_pos.copy()
backlash_pos[pip_ax] -= instrument.backlash_distance

backlash_pos[pip_ax] += instrument.backlash_distance
await self._move(
backlash_pos,
speed=(speed * rate),
Expand Down Expand Up @@ -1511,10 +1514,6 @@ async def aspirate(
if not aspirate_spec:
return

checked_mount = OT3Mount.from_mount(mount)
instrument = self._pipette_handler.get_pipette(checked_mount)
pip_ax = OT3Axis.of_main_tool_actuator(mount)

target_pos = target_position_from_plunger(
realmount,
aspirate_spec.plunger_distance,
Expand All @@ -1525,13 +1524,6 @@ async def aspirate(
await self._backend.set_active_current(
{OT3Axis.from_axis(aspirate_spec.axis): aspirate_spec.current}
)
backlash_pos = target_pos.copy()
backlash_pos[pip_ax] -= instrument.backlash_distance
await self._move(
backlash_pos,
speed=aspirate_spec.speed,
home_flagged_axes=False,
)
await self._move(
target_pos,
speed=aspirate_spec.speed,
Expand Down
26 changes: 15 additions & 11 deletions api/tests/opentrons/hardware_control/test_ot3_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1106,13 +1106,16 @@ async def test_move_to_plunger_bottom(
await ot3_hardware.cache_pipette(mount, instr_data, None)
pipette = ot3_hardware.hardware_pipettes[mount.to_mount()]
assert pipette
pip_ax = OT3Axis.of_main_tool_actuator(mount)

max_speeds = ot3_hardware.config.motion_settings.default_max_speed
target_pos = target_position_from_plunger(
OT3Mount.from_mount(mount),
pipette.plunger_positions.bottom,
ot3_hardware._current_position,
)
backlash_pos = target_pos.copy()
backlash_pos[pip_ax] += pipette.backlash_distance

# plunger will move at different speeds, depending on if:
# - no tip attached (max speed)
Expand All @@ -1130,7 +1133,12 @@ async def test_move_to_plunger_bottom(
await ot3_hardware.home()
mock_move.reset_mock()
await ot3_hardware.home_plunger(mount)
mock_move.assert_called_once_with(
# make sure we've done the backlash compensation
mock_move.assert_any_call(
backlash_pos, speed=expected_speed_no_tip, acquire_lock=False
)
# make sure the final move is to our target position
mock_move.assert_called_with(
target_pos, speed=expected_speed_no_tip, acquire_lock=False
)

Expand All @@ -1139,25 +1147,21 @@ async def test_move_to_plunger_bottom(
await ot3_hardware.add_tip(mount, 100)
mock_move.reset_mock()
await ot3_hardware.prepare_for_aspirate(mount)
# make sure when plunger is going down that only one move is called,
# and there's no backlash move queued
mock_move.assert_called_once_with(
# make sure we've done the backlash compensation
mock_move.assert_any_call(
backlash_pos, speed=expected_speed_moving_down, acquire_lock=True
)
# make sure the final move is to our target position
mock_move.assert_called_with(
target_pos, speed=expected_speed_moving_down, acquire_lock=True
)

# tip attached, moving UP towards "bottom" position
# NOTE: _move() is mocked, so we need to update the OT3API's
# cached coordinates in the test
pip_ax = OT3Axis.of_main_tool_actuator(mount)
ot3_hardware._current_position[pip_ax] = target_pos[pip_ax] + 1
mock_move.reset_mock()
await ot3_hardware.prepare_for_aspirate(mount)
# make sure we've done the backlash compensation
backlash_pos = target_pos.copy()
backlash_pos[pip_ax] -= pipette.backlash_distance
mock_move.assert_any_call(
backlash_pos, speed=expected_speed_moving_up, acquire_lock=True
)
# make sure the final move is to our target position
mock_move.assert_called_with(
target_pos, speed=expected_speed_moving_up, acquire_lock=True
Expand Down

0 comments on commit 11b4775

Please sign in to comment.