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(api): allow labware calibration on non liquid handling events #7812

Merged
merged 2 commits into from
May 17, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
15 changes: 15 additions & 0 deletions api/src/opentrons/commands/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,18 @@ def drop_tip(
'text': text
}
}


def move_to(
instrument: InstrumentContext,
location: Union[Location, Well]) -> command_types.MoveToCommand:
location_text = stringify_location(location)
text = 'Moving to {location}'.format(location=location_text)
return {
'name': command_types.MOVE_TO,
'payload': {
'instrument': instrument,
'location': location,
'text': text
}
}
15 changes: 15 additions & 0 deletions api/src/opentrons/commands/paired_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,18 @@ def paired_drop_tip(
'text': text
}
}


def paired_move_to(
instruments: Apiv2Instruments,
locations: Apiv2Locations, pub_type: str) -> command_types.MoveToCommand:
location_text = combine_locations(locations)
text = f'{pub_type}: Moving to {location_text}'
return {
'name': command_types.MOVE_TO,
'payload': {
'instruments': instruments,
'locations': locations,
'text': text
}
}
27 changes: 24 additions & 3 deletions api/src/opentrons/commands/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
AIR_GAP: Final = 'command.AIR_GAP'
TOUCH_TIP: Final = 'command.TOUCH_TIP'
RETURN_TIP: Final = 'command.RETURN_TIP'
MOVE_TO: Final = 'command.MOVE_TO'

# Modules #

Expand Down Expand Up @@ -450,6 +451,21 @@ class DropTipCommand(TypedDict):
payload: Union[DropTipCommandPayload, PairedDropTipCommandPayload]


class MoveToCommand(TypedDict):
name: Literal['command.MOVE_TO']
payload: Union[MoveToCommandPayload, PairedMoveToCommandPayload]


class MoveToCommandPayload(
TextOnlyPayload, SingleLocationPayload, SingleInstrumentPayload):
pass


class PairedMoveToCommandPayload(
TextOnlyPayload, MultiLocationPayload, MultiInstrumentPayload):
pass


Command = Union[
DropTipCommand, PickUpTipCommand, ReturnTipCommand, AirGapCommand,
TouchTipCommand, BlowOutCommand, MixCommand, TransferCommand,
Expand All @@ -463,7 +479,7 @@ class DropTipCommand(TypedDict):
TempdeckDeactivateCommand, TempdeckAwaitTempCommand,
TempdeckSetTempCommand, MagdeckCalibrateCommand, MagdeckDisengageCommand,
MagdeckEngageCommand, ResumeCommand, PauseCommand, DelayCommand,
CommentCommand]
CommentCommand, MoveToCommand]


CommandPayload = Union[
Expand Down Expand Up @@ -492,7 +508,8 @@ class DropTipCommand(TypedDict):
ThermocyclerSetBlockTempCommandPayload,
TempdeckAwaitTempCommandPayload,
TempdeckSetTempCommandPayload,
PauseCommandPayload, DelayCommandPayload
PauseCommandPayload, DelayCommandPayload,
MoveToCommandPayload, PairedMoveToCommandPayload
]


Expand All @@ -510,6 +527,10 @@ class CommandMessageFields(CommandMessageMeta, CommandMessageSequence):
pass


class MoveToMessage(CommandMessageFields, MoveToCommand):
pass


class DropTipMessage(CommandMessageFields, DropTipCommand):
pass

Expand Down Expand Up @@ -673,4 +694,4 @@ class CommentMessage(CommandMessageFields, CommentCommand):
ThermocyclerExecuteProfileMessage, ThermocyclerSetBlockTempMessage,
ThermocyclerOpenMessage, TempdeckSetTempMessage, TempdeckDeactivateMessage,
MagdeckEngageMessage, MagdeckDisengageMessage, MagdeckCalibrateMessage,
CommentMessage, DelayMessage, PauseMessage, ResumeMessage]
CommentMessage, DelayMessage, PauseMessage, ResumeMessage, MoveToMessage]
4 changes: 4 additions & 0 deletions api/src/opentrons/protocol_api/instrument_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -1110,12 +1110,16 @@ def move_to(self,
if isinstance(mod, ThermocyclerContext):
mod.flag_unsafe_move(to_loc=location, from_loc=from_loc)

do_publish(self.broker, cmds.move_to, self.move_to, 'before',
None, None, self, location or self._ctx.location_cache)
self._implementation.move_to(
location=location,
force_direct=force_direct,
minimum_z_height=minimum_z_height,
speed=speed
)
do_publish(self.broker, cmds.move_to, self.move_to, 'after',
None, None, self, location or self._ctx.location_cache)
return self

@property # type: ignore
Expand Down
8 changes: 8 additions & 0 deletions api/src/opentrons/protocol_api/paired_instrument_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -808,8 +808,16 @@ def move_to(self, location: types.Location, force_direct: bool = False,
to limit individual axis speeds, you can use
:py:attr:`.ProtocolContext.max_speeds`.
"""
instruments = list(self._instruments.values())
locations: Optional[List] = None
if location:
locations = self._get_locations(location)
publish_paired(self.broker, cmds.paired_move_to,
'before', None, instruments, locations)
self.paired_instrument_obj.move_to(
location, force_direct, minimum_z_height, speed)
publish_paired(self.broker, cmds.paired_move_to,
'after', None, instruments, locations)
return self

def _next_available_tip(self) -> Tuple[Labware, Well]:
Expand Down
25 changes: 23 additions & 2 deletions api/tests/opentrons/api/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ def run(ctx):
contents=proto)


@pytest.mark.api2_only
async def test_session_extra_labware(main_router, get_labware_fixture,
virtual_smoothie_env):
proto = '''
Expand Down Expand Up @@ -205,7 +204,6 @@ def run(ctx):
contents=proto)


@pytest.mark.api2_only
async def test_session_bundle(main_router, get_bundle_fixture,
virtual_smoothie_env):
bundle = get_bundle_fixture('simple_bundle')
Expand Down Expand Up @@ -257,6 +255,29 @@ def run(ctx):
assert 'p10_single_v1' in [pip.name for pip in session2.instruments]


async def test_session_move_to_labware(main_router,
virtual_smoothie_env):
proto = '''
metadata = {"apiLevel": "2.0"}
def run(ctx):
rack1 = ctx.load_labware('opentrons_96_tiprack_300ul', '1')
rack2 = ctx.load_labware('opentrons_96_tiprack_300ul', '2')
left = ctx.load_instrument('p300_single', 'left', tip_racks=[rack1])
plate = ctx.load_labware('corning_96_wellplate_360ul_flat', '4')
left.pick_up_tip()
left.move_to(plate['A1'].top())
left.move_to(plate['A2'].top())
left.drop_tip()
'''
session = main_router.session_manager.create('dummy-pipette',
proto)
assert 'p300_single_v1' in [pip.name for pip in session.instruments]

# Labware that does not have a liquid handling event, but is interacted
# with using a pipette should still show up in the list of labware.
assert 'corning_96_wellplate_360ul_flat' in [lw.type for lw in session.containers]


async def test_session_run_concurrently(
main_router,
get_labware_fixture,
Expand Down
3 changes: 0 additions & 3 deletions api/tests/opentrons/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,6 @@ def model(request, hardware, loop):
# Use with pytest.mark.parametrize(’labware’, [some-labware-name])
# to have a different labware loaded as .container. If not passed,
# defaults to the version-appropriate way to do 96 flat
if request.node.get_closest_marker('api2_only')\
and request.param != build_v2_model:
pytest.skip('only works with hardware controller')
try:
lw_name = request.getfixturevalue('labware_name')
except Exception:
Expand Down