opentrons 8.4.1a2__py2.py3-none-any.whl → 8.5.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- opentrons/config/defaults_ot3.py +1 -1
- opentrons/hardware_control/backends/flex_protocol.py +25 -0
- opentrons/hardware_control/backends/ot3controller.py +76 -1
- opentrons/hardware_control/backends/ot3simulator.py +27 -0
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +1 -0
- opentrons/hardware_control/ot3api.py +32 -0
- opentrons/legacy_commands/commands.py +16 -4
- opentrons/legacy_commands/robot_commands.py +51 -0
- opentrons/legacy_commands/types.py +91 -2
- opentrons/protocol_api/_liquid.py +60 -15
- opentrons/protocol_api/_liquid_properties.py +149 -90
- opentrons/protocol_api/_transfer_liquid_validation.py +43 -14
- opentrons/protocol_api/core/engine/instrument.py +367 -221
- opentrons/protocol_api/core/engine/protocol.py +14 -15
- opentrons/protocol_api/core/engine/robot.py +2 -2
- opentrons/protocol_api/core/engine/transfer_components_executor.py +275 -163
- opentrons/protocol_api/core/engine/well.py +16 -0
- opentrons/protocol_api/core/instrument.py +11 -5
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +11 -5
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +2 -2
- opentrons/protocol_api/core/legacy/legacy_well_core.py +8 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +11 -5
- opentrons/protocol_api/core/protocol.py +3 -3
- opentrons/protocol_api/core/well.py +8 -0
- opentrons/protocol_api/instrument_context.py +478 -111
- opentrons/protocol_api/labware.py +10 -0
- opentrons/protocol_api/module_contexts.py +5 -2
- opentrons/protocol_api/protocol_context.py +76 -11
- opentrons/protocol_api/robot_context.py +48 -6
- opentrons/protocol_api/validation.py +15 -8
- opentrons/protocol_engine/commands/command_unions.py +10 -10
- opentrons/protocol_engine/commands/generate_command_schema.py +1 -1
- opentrons/protocol_engine/commands/get_next_tip.py +2 -2
- opentrons/protocol_engine/commands/load_labware.py +0 -19
- opentrons/protocol_engine/commands/pick_up_tip.py +9 -3
- opentrons/protocol_engine/commands/robot/__init__.py +20 -20
- opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +34 -24
- opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +29 -20
- opentrons/protocol_engine/commands/seal_pipette_to_tip.py +1 -1
- opentrons/protocol_engine/commands/unsafe/__init__.py +17 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +1 -2
- opentrons/protocol_engine/execution/labware_movement.py +9 -2
- opentrons/protocol_engine/execution/movement.py +12 -9
- opentrons/protocol_engine/execution/queue_worker.py +8 -1
- opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +52 -19
- opentrons/protocol_engine/resources/labware_validation.py +7 -1
- opentrons/protocol_engine/state/_well_math.py +2 -2
- opentrons/protocol_engine/state/commands.py +14 -28
- opentrons/protocol_engine/state/frustum_helpers.py +11 -7
- opentrons/protocol_engine/state/labware.py +12 -0
- opentrons/protocol_engine/state/modules.py +1 -1
- opentrons/protocol_engine/state/pipettes.py +8 -0
- opentrons/protocol_engine/state/tips.py +46 -83
- opentrons/protocol_engine/state/update_types.py +8 -23
- opentrons/protocol_engine/types/liquid_level_detection.py +68 -8
- opentrons/protocol_runner/legacy_command_mapper.py +12 -6
- opentrons/protocol_runner/run_orchestrator.py +1 -1
- opentrons/protocols/advanced_control/transfers/common.py +54 -11
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +55 -28
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/types.py +6 -6
- {opentrons-8.4.1a2.dist-info → opentrons-8.5.0.dist-info}/METADATA +4 -4
- {opentrons-8.4.1a2.dist-info → opentrons-8.5.0.dist-info}/RECORD +67 -66
- {opentrons-8.4.1a2.dist-info → opentrons-8.5.0.dist-info}/LICENSE +0 -0
- {opentrons-8.4.1a2.dist-info → opentrons-8.5.0.dist-info}/WHEEL +0 -0
- {opentrons-8.4.1a2.dist-info → opentrons-8.5.0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.4.1a2.dist-info → opentrons-8.5.0.dist-info}/top_level.txt +0 -0
opentrons/config/defaults_ot3.py
CHANGED
|
@@ -158,7 +158,7 @@ DEFAULT_HOLD_CURRENT: Final[ByGantryLoad[Dict[OT3AxisKind, float]]] = ByGantryLo
|
|
|
158
158
|
OT3AxisKind.X: 0.5,
|
|
159
159
|
OT3AxisKind.Y: 0.5,
|
|
160
160
|
OT3AxisKind.Z: 0.5,
|
|
161
|
-
OT3AxisKind.P: 0.
|
|
161
|
+
OT3AxisKind.P: 0.8,
|
|
162
162
|
OT3AxisKind.Z_G: 0.2,
|
|
163
163
|
OT3AxisKind.Q: 0.3,
|
|
164
164
|
},
|
|
@@ -42,6 +42,7 @@ from opentrons.hardware_control.module_control import AttachedModulesControl
|
|
|
42
42
|
from ..dev_types import OT3AttachedInstruments
|
|
43
43
|
from .types import HWStopCondition
|
|
44
44
|
|
|
45
|
+
|
|
45
46
|
Cls = TypeVar("Cls")
|
|
46
47
|
|
|
47
48
|
|
|
@@ -466,3 +467,27 @@ class FlexBackend(Protocol):
|
|
|
466
467
|
async def increase_evo_disp_count(self, mount: OT3Mount) -> None:
|
|
467
468
|
"""Tell a pipette to increase it's evo-tip-dispense-count in eeprom."""
|
|
468
469
|
...
|
|
470
|
+
|
|
471
|
+
async def read_env_temp_sensor(
|
|
472
|
+
self, mount: OT3Mount, primary: bool
|
|
473
|
+
) -> Optional[float]:
|
|
474
|
+
"""Read and return the current sensor information."""
|
|
475
|
+
...
|
|
476
|
+
|
|
477
|
+
async def read_env_hum_sensor(
|
|
478
|
+
self, mount: OT3Mount, primary: bool
|
|
479
|
+
) -> Optional[float]:
|
|
480
|
+
"""Read and return the current sensor information."""
|
|
481
|
+
...
|
|
482
|
+
|
|
483
|
+
async def read_pressure_sensor(
|
|
484
|
+
self, mount: OT3Mount, primary: bool
|
|
485
|
+
) -> Optional[float]:
|
|
486
|
+
"""Read and return the current sensor information."""
|
|
487
|
+
...
|
|
488
|
+
|
|
489
|
+
async def read_capacitive_sensor(
|
|
490
|
+
self, mount: OT3Mount, primary: bool
|
|
491
|
+
) -> Optional[float]:
|
|
492
|
+
"""Read and return the current sensor information."""
|
|
493
|
+
...
|
|
@@ -215,7 +215,13 @@ from ..types import HepaFanState, HepaUVState, StatusBarState
|
|
|
215
215
|
from .types import HWStopCondition
|
|
216
216
|
from .flex_protocol import FlexBackend
|
|
217
217
|
from .status_bar_state import StatusBarStateController
|
|
218
|
-
from opentrons_hardware.sensors.
|
|
218
|
+
from opentrons_hardware.sensors.sensor_types import (
|
|
219
|
+
EnvironmentSensor,
|
|
220
|
+
CapacitiveSensor,
|
|
221
|
+
PressureSensor,
|
|
222
|
+
)
|
|
223
|
+
from opentrons_hardware.sensors.types import SensorDataType, EnvironmentSensorDataType
|
|
224
|
+
from opentrons_hardware.sensors.sensor_driver import SensorDriver
|
|
219
225
|
from opentrons_hardware.sensors.utils import send_evo_dispense_count_increase
|
|
220
226
|
|
|
221
227
|
log = logging.getLogger(__name__)
|
|
@@ -1835,3 +1841,72 @@ class OT3Controller(FlexBackend):
|
|
|
1835
1841
|
await send_evo_dispense_count_increase(
|
|
1836
1842
|
self._messenger, sensor_node_for_pipette(OT3Mount(mount.value))
|
|
1837
1843
|
)
|
|
1844
|
+
|
|
1845
|
+
async def _read_env_sensor(
|
|
1846
|
+
self, mount: OT3Mount, primary: bool
|
|
1847
|
+
) -> Optional[EnvironmentSensorDataType]:
|
|
1848
|
+
"""Read and return the current sensor information."""
|
|
1849
|
+
sensor = EnvironmentSensor.build(
|
|
1850
|
+
sensor_id=SensorId.S0 if primary else SensorId.S1,
|
|
1851
|
+
node_id=sensor_node_for_mount(mount),
|
|
1852
|
+
)
|
|
1853
|
+
s_driver = SensorDriver()
|
|
1854
|
+
sensor_data = await s_driver.read(
|
|
1855
|
+
can_messenger=self._messenger,
|
|
1856
|
+
sensor=sensor,
|
|
1857
|
+
offset=False,
|
|
1858
|
+
)
|
|
1859
|
+
assert sensor_data is None or isinstance(sensor_data, EnvironmentSensorDataType)
|
|
1860
|
+
return sensor_data
|
|
1861
|
+
|
|
1862
|
+
async def read_env_temp_sensor(
|
|
1863
|
+
self, mount: OT3Mount, primary: bool
|
|
1864
|
+
) -> Optional[float]:
|
|
1865
|
+
"""Read and return the current sensor information."""
|
|
1866
|
+
s_data = await self._read_env_sensor(mount, primary)
|
|
1867
|
+
if s_data is None or s_data.temperature is None:
|
|
1868
|
+
return None
|
|
1869
|
+
return s_data.temperature.to_float()
|
|
1870
|
+
|
|
1871
|
+
async def read_env_hum_sensor(
|
|
1872
|
+
self, mount: OT3Mount, primary: bool
|
|
1873
|
+
) -> Optional[float]:
|
|
1874
|
+
"""Read and return the current sensor information."""
|
|
1875
|
+
s_data = await self._read_env_sensor(mount, primary)
|
|
1876
|
+
if s_data is None or s_data.humidity is None:
|
|
1877
|
+
return None
|
|
1878
|
+
return s_data.humidity.to_float()
|
|
1879
|
+
|
|
1880
|
+
async def read_pressure_sensor(
|
|
1881
|
+
self, mount: OT3Mount, primary: bool
|
|
1882
|
+
) -> Optional[float]:
|
|
1883
|
+
"""Read and return the current sensor information."""
|
|
1884
|
+
sensor = PressureSensor.build(
|
|
1885
|
+
sensor_id=SensorId.S0 if primary else SensorId.S1,
|
|
1886
|
+
node_id=sensor_node_for_mount(mount),
|
|
1887
|
+
)
|
|
1888
|
+
s_driver = SensorDriver()
|
|
1889
|
+
sensor_data = await s_driver.read(
|
|
1890
|
+
can_messenger=self._messenger,
|
|
1891
|
+
sensor=sensor,
|
|
1892
|
+
offset=False,
|
|
1893
|
+
)
|
|
1894
|
+
assert sensor_data is None or isinstance(sensor_data, SensorDataType)
|
|
1895
|
+
return sensor_data.to_float() if sensor_data else None
|
|
1896
|
+
|
|
1897
|
+
async def read_capacitive_sensor(
|
|
1898
|
+
self, mount: OT3Mount, primary: bool
|
|
1899
|
+
) -> Optional[float]:
|
|
1900
|
+
"""Read and return the current sensor information."""
|
|
1901
|
+
sensor = CapacitiveSensor.build(
|
|
1902
|
+
sensor_id=SensorId.S0 if primary else SensorId.S1,
|
|
1903
|
+
node_id=sensor_node_for_mount(mount),
|
|
1904
|
+
)
|
|
1905
|
+
s_driver = SensorDriver()
|
|
1906
|
+
sensor_data = await s_driver.read(
|
|
1907
|
+
can_messenger=self._messenger,
|
|
1908
|
+
sensor=sensor,
|
|
1909
|
+
offset=False,
|
|
1910
|
+
)
|
|
1911
|
+
assert sensor_data is None or isinstance(sensor_data, SensorDataType)
|
|
1912
|
+
return sensor_data.to_float() if sensor_data else None
|
|
@@ -67,6 +67,7 @@ from .flex_protocol import (
|
|
|
67
67
|
FlexBackend,
|
|
68
68
|
)
|
|
69
69
|
|
|
70
|
+
|
|
70
71
|
log = logging.getLogger(__name__)
|
|
71
72
|
|
|
72
73
|
AXIS_TO_SUBSYSTEM = {
|
|
@@ -874,3 +875,29 @@ class OT3Simulator(FlexBackend):
|
|
|
874
875
|
|
|
875
876
|
async def increase_evo_disp_count(self, mount: OT3Mount) -> None:
|
|
876
877
|
pass
|
|
878
|
+
|
|
879
|
+
async def read_env_temp_sensor(
|
|
880
|
+
self, mount: OT3Mount, primary: bool
|
|
881
|
+
) -> Optional[float]:
|
|
882
|
+
"""Read and return the current sensor information."""
|
|
883
|
+
|
|
884
|
+
return 0.0
|
|
885
|
+
|
|
886
|
+
async def read_env_hum_sensor(
|
|
887
|
+
self, mount: OT3Mount, primary: bool
|
|
888
|
+
) -> Optional[float]:
|
|
889
|
+
"""Read and return the current sensor information."""
|
|
890
|
+
|
|
891
|
+
return 0.0
|
|
892
|
+
|
|
893
|
+
async def read_pressure_sensor(
|
|
894
|
+
self, mount: OT3Mount, primary: bool
|
|
895
|
+
) -> Optional[float]:
|
|
896
|
+
"""Read and return the current sensor information."""
|
|
897
|
+
return 0.0
|
|
898
|
+
|
|
899
|
+
async def read_capacitive_sensor(
|
|
900
|
+
self, mount: OT3Mount, primary: bool
|
|
901
|
+
) -> Optional[float]:
|
|
902
|
+
"""Read and return the current sensor information."""
|
|
903
|
+
return 0.0
|
|
@@ -3140,3 +3140,35 @@ class OT3API(
|
|
|
3140
3140
|
"""Tell a pipette to increase its evo-tip-dispense-count in eeprom."""
|
|
3141
3141
|
realmount = OT3Mount.from_mount(mount)
|
|
3142
3142
|
await self._backend.increase_evo_disp_count(realmount)
|
|
3143
|
+
|
|
3144
|
+
async def read_stem_temperature(
|
|
3145
|
+
self, mount: Union[top_types.Mount, OT3Mount], primary: bool = True
|
|
3146
|
+
) -> float:
|
|
3147
|
+
"""Read and return the current stem temperature."""
|
|
3148
|
+
realmount = OT3Mount.from_mount(mount)
|
|
3149
|
+
s_data = await self._backend.read_env_temp_sensor(realmount, primary)
|
|
3150
|
+
return s_data if s_data else 0.0
|
|
3151
|
+
|
|
3152
|
+
async def read_stem_humidity(
|
|
3153
|
+
self, mount: Union[top_types.Mount, OT3Mount], primary: bool = True
|
|
3154
|
+
) -> float:
|
|
3155
|
+
"""Read and return the current primary stem humidity."""
|
|
3156
|
+
realmount = OT3Mount.from_mount(mount)
|
|
3157
|
+
s_data = await self._backend.read_env_hum_sensor(realmount, primary)
|
|
3158
|
+
return s_data if s_data else 0.0
|
|
3159
|
+
|
|
3160
|
+
async def read_stem_pressure(
|
|
3161
|
+
self, mount: Union[top_types.Mount, OT3Mount], primary: bool = True
|
|
3162
|
+
) -> float:
|
|
3163
|
+
"""Read and return the current primary stem pressure."""
|
|
3164
|
+
realmount = OT3Mount.from_mount(mount)
|
|
3165
|
+
s_data = await self._backend.read_pressure_sensor(realmount, primary)
|
|
3166
|
+
return s_data if s_data else 0.0
|
|
3167
|
+
|
|
3168
|
+
async def read_stem_capacitance(
|
|
3169
|
+
self, mount: Union[top_types.Mount, OT3Mount], primary: bool = True
|
|
3170
|
+
) -> float:
|
|
3171
|
+
"""Read and return the current primary stem capacitance."""
|
|
3172
|
+
realmount = OT3Mount.from_mount(mount)
|
|
3173
|
+
s_data = await self._backend.read_capacitive_sensor(realmount, primary)
|
|
3174
|
+
return s_data if s_data else 0.0
|
|
@@ -328,12 +328,18 @@ def transfer_with_liquid_class(
|
|
|
328
328
|
liquid_class: LiquidClass,
|
|
329
329
|
volume: float,
|
|
330
330
|
source: Union[Well, Sequence[Well], Sequence[Sequence[Well]]],
|
|
331
|
-
destination: Union[
|
|
331
|
+
destination: Union[
|
|
332
|
+
Well, Sequence[Well], Sequence[Sequence[Well]], TrashBin, WasteChute
|
|
333
|
+
],
|
|
332
334
|
) -> command_types.TransferWithLiquidClassCommand:
|
|
335
|
+
if isinstance(destination, (TrashBin, WasteChute)):
|
|
336
|
+
destination_text = stringify_disposal_location(destination)
|
|
337
|
+
else:
|
|
338
|
+
destination_text = stringify_well_list(destination)
|
|
333
339
|
text = (
|
|
334
340
|
"Transferring "
|
|
335
341
|
+ f"{volume} uL of {liquid_class.display_name} liquid class from "
|
|
336
|
-
+ f"{stringify_well_list(source)} to {
|
|
342
|
+
+ f"{stringify_well_list(source)} to {destination_text}"
|
|
337
343
|
)
|
|
338
344
|
return {
|
|
339
345
|
"name": command_types.TRANSFER_WITH_LIQUID_CLASS,
|
|
@@ -378,12 +384,18 @@ def consolidate_with_liquid_class(
|
|
|
378
384
|
liquid_class: LiquidClass,
|
|
379
385
|
volume: float,
|
|
380
386
|
source: Union[Well, Sequence[Well], Sequence[Sequence[Well]]],
|
|
381
|
-
destination: Union[
|
|
387
|
+
destination: Union[
|
|
388
|
+
Well, Sequence[Well], Sequence[Sequence[Well]], TrashBin, WasteChute
|
|
389
|
+
],
|
|
382
390
|
) -> command_types.ConsolidateWithLiquidClassCommand:
|
|
391
|
+
if isinstance(destination, (TrashBin, WasteChute)):
|
|
392
|
+
destination_text = stringify_disposal_location(destination)
|
|
393
|
+
else:
|
|
394
|
+
destination_text = stringify_well_list(destination)
|
|
383
395
|
text = (
|
|
384
396
|
"Consolidating "
|
|
385
397
|
+ f"{volume} uL of {liquid_class.display_name} liquid class from "
|
|
386
|
-
+ f"{stringify_well_list(source)} to {
|
|
398
|
+
+ f"{stringify_well_list(source)} to {destination_text}"
|
|
387
399
|
)
|
|
388
400
|
return {
|
|
389
401
|
"name": command_types.CONSOLIDATE_WITH_LIQUID_CLASS,
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from opentrons.types import Location, Mount, AxisMapType
|
|
2
|
+
from .helpers import stringify_location
|
|
3
|
+
from . import types as command_types
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def move_to(
|
|
8
|
+
mount: Mount, location: Location, speed: Optional[float]
|
|
9
|
+
) -> command_types.RobotMoveToCommand:
|
|
10
|
+
location_text = stringify_location(location)
|
|
11
|
+
text = f"Moving to {location_text} at {speed}"
|
|
12
|
+
return {
|
|
13
|
+
"name": command_types.ROBOT_MOVE_TO,
|
|
14
|
+
"payload": {"mount": mount, "location": location, "text": text},
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def move_axis_to(
|
|
19
|
+
axis_map: AxisMapType, speed: Optional[float]
|
|
20
|
+
) -> command_types.RobotMoveAxisToCommand:
|
|
21
|
+
text = f"Moving to the provided absolute axis map {axis_map} at {speed}."
|
|
22
|
+
return {
|
|
23
|
+
"name": command_types.ROBOT_MOVE_AXES_TO,
|
|
24
|
+
"payload": {"absolute_axes": axis_map, "text": text},
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def move_axis_relative(
|
|
29
|
+
axis_map: AxisMapType, speed: Optional[float]
|
|
30
|
+
) -> command_types.RobotMoveAxisRelativeCommand:
|
|
31
|
+
text = f"Moving to the provided relative axis map {axis_map} as {speed}"
|
|
32
|
+
return {
|
|
33
|
+
"name": command_types.ROBOT_MOVE_RELATIVE_TO,
|
|
34
|
+
"payload": {"relative_axes": axis_map, "text": text},
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def open_gripper() -> command_types.RobotOpenGripperJawCommand:
|
|
39
|
+
text = "Opening the gripper jaw."
|
|
40
|
+
return {
|
|
41
|
+
"name": command_types.ROBOT_OPEN_GRIPPER_JAW,
|
|
42
|
+
"payload": {"text": text},
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def close_gripper(force: Optional[float]) -> command_types.RobotCloseGripperJawCommand:
|
|
47
|
+
text = f"Closing the gripper jaw with force {force}."
|
|
48
|
+
return {
|
|
49
|
+
"name": command_types.ROBOT_CLOSE_GRIPPER_JAW,
|
|
50
|
+
"payload": {"text": text},
|
|
51
|
+
}
|
|
@@ -10,7 +10,7 @@ if TYPE_CHECKING:
|
|
|
10
10
|
from opentrons.protocol_api.disposal_locations import TrashBin, WasteChute
|
|
11
11
|
from opentrons.protocol_api._liquid import LiquidClass
|
|
12
12
|
|
|
13
|
-
from opentrons.types import Location
|
|
13
|
+
from opentrons.types import Location, Mount, AxisMapType
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
# type for subscriptions
|
|
@@ -86,6 +86,13 @@ THERMOCYCLER_SET_LID_TEMP: Final = "command.THERMOCYCLER_SET_LID_TEMP"
|
|
|
86
86
|
THERMOCYCLER_DEACTIVATE_LID: Final = "command.THERMOCYCLER_DEACTIVATE_LID"
|
|
87
87
|
THERMOCYCLER_DEACTIVATE_BLOCK: Final = "command.THERMOCYCLER_DEACTIVATE_BLOCK"
|
|
88
88
|
|
|
89
|
+
# Robot #
|
|
90
|
+
ROBOT_MOVE_TO: Final = "command.ROBOT_MOVE_TO"
|
|
91
|
+
ROBOT_MOVE_AXES_TO: Final = "command.ROBOT_MOVE_AXES_TO"
|
|
92
|
+
ROBOT_MOVE_RELATIVE_TO: Final = "command.ROBOT_MOVE_RELATIVE_TO"
|
|
93
|
+
ROBOT_OPEN_GRIPPER_JAW: Final = "command.ROBOT_OPEN_GRIPPER_JAW"
|
|
94
|
+
ROBOT_CLOSE_GRIPPER_JAW: Final = "command.ROBOT_CLOSE_GRIPPER_JAW"
|
|
95
|
+
|
|
89
96
|
|
|
90
97
|
class TextOnlyPayload(TypedDict):
|
|
91
98
|
text: str
|
|
@@ -548,7 +555,9 @@ class LiquidClassCommandPayload(TextOnlyPayload, SingleInstrumentPayload):
|
|
|
548
555
|
liquid_class: LiquidClass
|
|
549
556
|
volume: float
|
|
550
557
|
source: Union[Well, Sequence[Well], Sequence[Sequence[Well]]]
|
|
551
|
-
destination: Union[
|
|
558
|
+
destination: Union[
|
|
559
|
+
Well, Sequence[Well], Sequence[Sequence[Well]], TrashBin, WasteChute
|
|
560
|
+
]
|
|
552
561
|
|
|
553
562
|
|
|
554
563
|
class TransferWithLiquidClassCommand(TypedDict):
|
|
@@ -600,6 +609,49 @@ class PressurizeCommand(TypedDict):
|
|
|
600
609
|
payload: PressurizeCommandPayload
|
|
601
610
|
|
|
602
611
|
|
|
612
|
+
# Robot Commands and Payloads
|
|
613
|
+
class GripperCommandPayload(TextOnlyPayload):
|
|
614
|
+
pass
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
class RobotMoveToCommandPayload(TextOnlyPayload):
|
|
618
|
+
location: Location
|
|
619
|
+
mount: Mount
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
class RobotMoveAxisToCommandPayload(TextOnlyPayload):
|
|
623
|
+
absolute_axes: AxisMapType
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
class RobotMoveAxisRelativeCommandPayload(TextOnlyPayload):
|
|
627
|
+
relative_axes: AxisMapType
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
class RobotMoveToCommand(TypedDict):
|
|
631
|
+
name: Literal["command.ROBOT_MOVE_TO"]
|
|
632
|
+
payload: RobotMoveToCommandPayload
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
class RobotMoveAxisToCommand(TypedDict):
|
|
636
|
+
name: Literal["command.ROBOT_MOVE_AXES_TO"]
|
|
637
|
+
payload: RobotMoveAxisToCommandPayload
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
class RobotMoveAxisRelativeCommand(TypedDict):
|
|
641
|
+
name: Literal["command.ROBOT_MOVE_RELATIVE_TO"]
|
|
642
|
+
payload: RobotMoveAxisRelativeCommandPayload
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
class RobotOpenGripperJawCommand(TypedDict):
|
|
646
|
+
name: Literal["command.ROBOT_OPEN_GRIPPER_JAW"]
|
|
647
|
+
payload: GripperCommandPayload
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
class RobotCloseGripperJawCommand(TypedDict):
|
|
651
|
+
name: Literal["command.ROBOT_CLOSE_GRIPPER_JAW"]
|
|
652
|
+
payload: GripperCommandPayload
|
|
653
|
+
|
|
654
|
+
|
|
603
655
|
Command = Union[
|
|
604
656
|
DropTipCommand,
|
|
605
657
|
DropTipInDisposalLocationCommand,
|
|
@@ -654,6 +706,12 @@ Command = Union[
|
|
|
654
706
|
SealCommand,
|
|
655
707
|
UnsealCommand,
|
|
656
708
|
PressurizeCommand,
|
|
709
|
+
# Robot commands
|
|
710
|
+
RobotMoveToCommand,
|
|
711
|
+
RobotMoveAxisToCommand,
|
|
712
|
+
RobotMoveAxisRelativeCommand,
|
|
713
|
+
RobotOpenGripperJawCommand,
|
|
714
|
+
RobotCloseGripperJawCommand,
|
|
657
715
|
]
|
|
658
716
|
|
|
659
717
|
|
|
@@ -707,6 +765,11 @@ CommandPayload = Union[
|
|
|
707
765
|
SealCommandPayload,
|
|
708
766
|
UnsealCommandPayload,
|
|
709
767
|
PressurizeCommandPayload,
|
|
768
|
+
# Robot payloads
|
|
769
|
+
RobotMoveToCommandPayload,
|
|
770
|
+
RobotMoveAxisRelativeCommandPayload,
|
|
771
|
+
RobotMoveAxisToCommandPayload,
|
|
772
|
+
GripperCommandPayload,
|
|
710
773
|
]
|
|
711
774
|
|
|
712
775
|
|
|
@@ -947,6 +1010,26 @@ class MoveLabwareMessage(CommandMessageFields, MoveLabwareCommand):
|
|
|
947
1010
|
pass
|
|
948
1011
|
|
|
949
1012
|
|
|
1013
|
+
class RobotMoveToMessage(CommandMessageFields, RobotMoveToCommand):
|
|
1014
|
+
pass
|
|
1015
|
+
|
|
1016
|
+
|
|
1017
|
+
class RobotMoveAxisToMessage(CommandMessageFields, RobotMoveAxisToCommand):
|
|
1018
|
+
pass
|
|
1019
|
+
|
|
1020
|
+
|
|
1021
|
+
class RobotMoveAxisRelativeMessage(CommandMessageFields, RobotMoveAxisRelativeCommand):
|
|
1022
|
+
pass
|
|
1023
|
+
|
|
1024
|
+
|
|
1025
|
+
class RobotOpenGripperJawMessage(CommandMessageFields, RobotOpenGripperJawCommand):
|
|
1026
|
+
pass
|
|
1027
|
+
|
|
1028
|
+
|
|
1029
|
+
class RobotCloseGripperJawMessage(CommandMessageFields, RobotCloseGripperJawCommand):
|
|
1030
|
+
pass
|
|
1031
|
+
|
|
1032
|
+
|
|
950
1033
|
CommandMessage = Union[
|
|
951
1034
|
DropTipMessage,
|
|
952
1035
|
DropTipInDisposalLocationMessage,
|
|
@@ -994,4 +1077,10 @@ CommandMessage = Union[
|
|
|
994
1077
|
MoveToMessage,
|
|
995
1078
|
MoveToDisposalLocationMessage,
|
|
996
1079
|
MoveLabwareMessage,
|
|
1080
|
+
# Robot Messages
|
|
1081
|
+
RobotMoveToMessage,
|
|
1082
|
+
RobotMoveAxisToMessage,
|
|
1083
|
+
RobotMoveAxisRelativeMessage,
|
|
1084
|
+
RobotOpenGripperJawMessage,
|
|
1085
|
+
RobotCloseGripperJawMessage,
|
|
997
1086
|
]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Optional, Dict, Union, TYPE_CHECKING
|
|
4
|
+
from typing import Optional, Dict, Union, TYPE_CHECKING, Tuple
|
|
5
5
|
|
|
6
6
|
from opentrons_shared_data.liquid_classes.liquid_class_definition import (
|
|
7
7
|
LiquidClassSchemaV1,
|
|
@@ -63,6 +63,20 @@ class LiquidClass:
|
|
|
63
63
|
_by_pipette_setting=by_pipette_settings,
|
|
64
64
|
)
|
|
65
65
|
|
|
66
|
+
@classmethod
|
|
67
|
+
def create_from(
|
|
68
|
+
cls,
|
|
69
|
+
name: str,
|
|
70
|
+
display_name: str,
|
|
71
|
+
by_pipette_setting: Dict[str, Dict[str, TransferProperties]],
|
|
72
|
+
) -> "LiquidClass":
|
|
73
|
+
"""Create a liquid class from the passed in args."""
|
|
74
|
+
return cls(
|
|
75
|
+
_name=name,
|
|
76
|
+
_display_name=display_name,
|
|
77
|
+
_by_pipette_setting=by_pipette_setting,
|
|
78
|
+
)
|
|
79
|
+
|
|
66
80
|
@property
|
|
67
81
|
def name(self) -> str:
|
|
68
82
|
return self._name
|
|
@@ -71,10 +85,54 @@ class LiquidClass:
|
|
|
71
85
|
def display_name(self) -> str:
|
|
72
86
|
return self._display_name
|
|
73
87
|
|
|
88
|
+
def update_for(
|
|
89
|
+
self,
|
|
90
|
+
pipette: Union[str, InstrumentContext],
|
|
91
|
+
tip_rack: Union[str, Labware],
|
|
92
|
+
transfer_properties: TransferProperties,
|
|
93
|
+
) -> None:
|
|
94
|
+
"""Update the transfer properties for the given pipette and tip combo.
|
|
95
|
+
|
|
96
|
+
If an entry does not exist, it will be created.
|
|
97
|
+
"""
|
|
98
|
+
pipette_name, tiprack_uri = self._get_pipette_and_tiprack_names(
|
|
99
|
+
pipette, tip_rack
|
|
100
|
+
)
|
|
101
|
+
try:
|
|
102
|
+
self._by_pipette_setting[pipette_name].update(
|
|
103
|
+
{tiprack_uri: transfer_properties}
|
|
104
|
+
)
|
|
105
|
+
except KeyError:
|
|
106
|
+
self._by_pipette_setting[pipette_name] = {tiprack_uri: transfer_properties}
|
|
107
|
+
|
|
74
108
|
def get_for(
|
|
75
109
|
self, pipette: Union[str, InstrumentContext], tip_rack: Union[str, Labware]
|
|
76
110
|
) -> TransferProperties:
|
|
77
111
|
"""Get liquid class transfer properties for the specified pipette and tip."""
|
|
112
|
+
pipette_name, tiprack_uri = self._get_pipette_and_tiprack_names(
|
|
113
|
+
pipette, tip_rack
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
settings_for_pipette = self._by_pipette_setting[pipette_name]
|
|
118
|
+
except KeyError:
|
|
119
|
+
raise NoLiquidClassPropertyError(
|
|
120
|
+
f"No properties found for {pipette_name} in {self._name} liquid class"
|
|
121
|
+
)
|
|
122
|
+
try:
|
|
123
|
+
transfer_properties = settings_for_pipette[tiprack_uri]
|
|
124
|
+
except KeyError:
|
|
125
|
+
raise NoLiquidClassPropertyError(
|
|
126
|
+
f"No properties found for {tiprack_uri} for {pipette_name} in {self._name} liquid class"
|
|
127
|
+
)
|
|
128
|
+
return transfer_properties
|
|
129
|
+
|
|
130
|
+
@staticmethod
|
|
131
|
+
def _get_pipette_and_tiprack_names(
|
|
132
|
+
pipette: Union[str, InstrumentContext],
|
|
133
|
+
tip_rack: Union[str, Labware],
|
|
134
|
+
) -> Tuple[str, str]:
|
|
135
|
+
"""Return the pipette and tip rack name strings from the given pipette and tip rack."""
|
|
78
136
|
from . import InstrumentContext, Labware
|
|
79
137
|
|
|
80
138
|
if isinstance(pipette, InstrumentContext):
|
|
@@ -96,17 +154,4 @@ class LiquidClass:
|
|
|
96
154
|
f"{tip_rack} should either be a tiprack Labware object"
|
|
97
155
|
f" or a tiprack URI string."
|
|
98
156
|
)
|
|
99
|
-
|
|
100
|
-
try:
|
|
101
|
-
settings_for_pipette = self._by_pipette_setting[pipette_name]
|
|
102
|
-
except KeyError:
|
|
103
|
-
raise NoLiquidClassPropertyError(
|
|
104
|
-
f"No properties found for {pipette_name} in {self._name} liquid class"
|
|
105
|
-
)
|
|
106
|
-
try:
|
|
107
|
-
transfer_properties = settings_for_pipette[tiprack_uri]
|
|
108
|
-
except KeyError:
|
|
109
|
-
raise NoLiquidClassPropertyError(
|
|
110
|
-
f"No properties found for {tiprack_uri} for {pipette_name} in {self._name} liquid class"
|
|
111
|
-
)
|
|
112
|
-
return transfer_properties
|
|
157
|
+
return pipette_name, tiprack_uri
|