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): replace format with quirks for rectangular well behavior #4027

Merged
merged 2 commits into from
Sep 16, 2019
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
26 changes: 21 additions & 5 deletions api/src/opentrons/legacy_api/containers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging
import json
from opentrons.config import CONFIG
from opentrons.config.pipette_config import Y_OFFSET_MULTI
from opentrons.data_storage import database
from opentrons.util.vector import Vector
from opentrons.types import Point
Expand Down Expand Up @@ -152,30 +153,45 @@ def save_custom_container(data):
"labware, please use opentrons.containers.create()")


def _load_new_well(well_data, saved_offset, lw_format):
def _load_new_well(well_data, saved_offset, lw_quirks):
# We assume a labware is a trough (a.k.a. a reservoir)
# if it has the "centerMultichannelOnWells" quirk, and does
# *not* have the "fixedTrash" quirk.
#
# There are two key hacks in here to make troughs work:
# - do not specify the size of the well
# - specify the center without subtracting the size (since
# the size is 0) in x, and _add_ 7/16 of the size in y
# so that the nominal center leaves the nozzle centered in
# an imaginary well instead of centering itself over the
# top wall of the trough.
#
# If a labware does have the "fixedTrash" quirk, we shift
# the center position back by the y-offset of multi-channel
# pipettes so that the pipettes get as close as they can
# reach to the center of the trash, without colliding with
# the back of the frame.
props = {
'depth': well_data['depth'],
'total-liquid-volume': well_data['totalLiquidVolume'],
}
if well_data['shape'] == 'circular':
props['diameter'] = well_data['diameter']
elif well_data['shape'] == 'rectangular':
if lw_format != 'trough':
if "centerMultichannelOnWells" not in lw_quirks:
props['length'] = well_data['yDimension']
props['width'] = well_data['xDimension']
else:
raise ValueError(
f"Bad definition for well shape: {well_data['shape']}")
well = Well(properties=props)

if lw_format == 'trough':
if "fixedTrash" in lw_quirks:
well_tuple = (
well_data['x'] + saved_offset.x,
well_data['y'] + Y_OFFSET_MULTI + saved_offset.y,
well_data['z'] + saved_offset.z)
elif "centerMultichannelOnWells" in lw_quirks:
well_tuple = (
well_data['x'] + saved_offset.x,
well_data['y'] + 7 * well_data['yDimension'] / 16 + saved_offset.y,
Expand Down Expand Up @@ -231,11 +247,11 @@ def load_new_labware_def(definition):
log.info(f"Container name {container_name}, hash {labware_hash}")
container.properties['labware_hash'] = labware_hash
container.properties['type'] = container_name
lw_format = definition['parameters']['format']
lw_quirks = definition['parameters'].get('quirks', [])

container._coordinates = Vector(definition['cornerOffsetFromSlot'])
for well_name in itertools.chain(*definition['ordering']):
well_obj, well_pos = _load_new_well(
definition['wells'][well_name], saved_offset, lw_format)
definition['wells'][well_name], saved_offset, lw_quirks)
container.add(well_obj, well_name, well_pos)
return container
6 changes: 4 additions & 2 deletions api/src/opentrons/legacy_api/robot/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -780,9 +780,11 @@ def setup_deck(self):
# @TODO (Laura & Andy) Slot and type of trash
# needs to be pulled from config file
if fflags.short_fixed_trash():
self._fixed_trash = self.add_container('fixed-trash', '12')
self._fixed_trash = self.add_container(
'opentrons_1_trash_850ml_fixed', '12')
else:
self._fixed_trash = self.add_container('tall-fixed-trash', '12')
self._fixed_trash = self.add_container(
'opentrons_1_trash_1100ml_fixed', '12')

@property
def deck(self):
Expand Down
7 changes: 4 additions & 3 deletions api/tests/opentrons/api/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ def test_get_labware(labware_setup):
async def test_session_model_functional(session_manager, protocol):
session = session_manager.create(name='<blank>', text=protocol.text)
assert [container.name for container in session.containers] == \
['tiprack', 'trough', 'plate', 'tall-fixed-trash']
['tiprack', 'trough', 'plate', 'opentrons_1_trash_1100ml_fixed']
names = [instrument.name for instrument in session.instruments]
assert names == ['p300_single_v1']

Expand All @@ -331,9 +331,10 @@ async def test_drop_tip_with_trash(session_manager, protocol, protocol_file):
"""
session = session_manager.create(name='<blank>', text=protocol.text)

assert 'tall-fixed-trash' in [c.name for c in session.get_containers()]
assert 'opentrons_1_trash_1100ml_fixed' in [
c.name for c in session.get_containers()]
containers = sum([i.containers for i in session.get_instruments()], [])
assert 'tall-fixed-trash' in [c.name for c in containers]
assert 'opentrons_1_trash_1100ml_fixed' in [c.name for c in containers]


@pytest.mark.api1_only
Expand Down
6 changes: 6 additions & 0 deletions api/tests/opentrons/containers/test_containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ def test_load_new_trough(robot):
== (13.94, 42.9 + 31.4475, 2.29)


def test_load_fixed_trash(robot):
from opentrons.config.pipette_config import Y_OFFSET_MULTI
assert robot.fixed_trash[0]._coordinates == (
82.84, 53.56 + Y_OFFSET_MULTI, 82)


def test_containers_list(robot):
res = containers_list()
assert res
Expand Down
2 changes: 1 addition & 1 deletion api/tests/opentrons/integration/test_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@ def test_deck_setup(robot):
assert isinstance(tiprack, Container)
assert isinstance(deck, Deck)
# Check that well location is the same on the robot as the pipette
assert robot._deck['12']['tall-fixed-trash'][0] == trash
assert robot._deck['12']['opentrons_1_trash_1100ml_fixed'][0] == trash
assert deck.has_container(tiprack)
2 changes: 1 addition & 1 deletion api/tests/opentrons/robot/test_robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def test_calibrated_max_z(virtual_smoothie_env):
robot.reset()

instruments.P300_Single(mount='left')
assert robot.max_deck_height() == 85
assert robot.max_deck_height() == 82


def test_get_serial_ports_list(monkeypatch):
Expand Down
31 changes: 0 additions & 31 deletions api/tests/opentrons/server/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,34 +436,3 @@ def message_key(message):
meta = message['$']
data = message.get('data', '')
return str(meta.get('type')) + meta.get('token', '') + str(data)


@pytest.mark.api1_only
@pytest.mark.parametrize('root', [TickTock()])
async def test_concurrent_and_disconnect(loop, root, session, connect): # noqa C901
n_sockets = 20
sockets = await async_iterate([connect() for _ in range(n_sockets)])

# TODO (artyom, 20170920): look for pattern to call several coroutines
# and collect results in one line
tokens = await async_iterate([
call(socket, id=id(root), name='start', args=[])
for socket in sockets])

await sockets.pop(1).close()

stop_messages = [result_message(token, 'Done!') for token in tokens]
results = await async_iterate(
[read_until(socket, stop_messages) for socket in sockets])

for res in results:
# First message is root info
assert res.pop(0)['$'] == {'type': 3, 'monitor': True}
expected = []
# All acks received
expected.extend([ack_message(token) for token in tokens])
# All results received
expected.extend([result_message(token, 'Done!') for token in tokens])
# All notifications received. 5 ticks per notifications
expected.extend([notification_message(i) for i in range(5)] * n_sockets) # noqa
assert sorted(res, key=message_key) == sorted(expected, key=message_key) # noqa
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
"yDimension": 165.67,
"xDimension": 107.11,
"totalLiquidVolume": 1100000,
"depth": 77,
"depth": 0,
"x": 82.84,
"y": 53.56,
"z": 5
"z": 82
}
},
"brand": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
"yDimension": 165.67,
"xDimension": 107.11,
"totalLiquidVolume": 850000,
"depth": 53,
"depth": 0,
"x": 82.84,
"y": 53.56,
"z": 5
"z": 58
}
},
"brand": {
Expand Down