opentrons 8.3.0a0__py2.py3-none-any.whl → 8.3.0a2__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/calibration_storage/deck_configuration.py +3 -3
- opentrons/calibration_storage/file_operators.py +3 -3
- opentrons/calibration_storage/helpers.py +3 -1
- opentrons/calibration_storage/ot2/models/v1.py +16 -29
- opentrons/calibration_storage/ot2/tip_length.py +7 -4
- opentrons/calibration_storage/ot3/models/v1.py +14 -23
- opentrons/cli/analyze.py +18 -6
- opentrons/drivers/asyncio/communication/__init__.py +2 -0
- opentrons/drivers/asyncio/communication/errors.py +16 -3
- opentrons/drivers/asyncio/communication/serial_connection.py +24 -9
- opentrons/drivers/command_builder.py +2 -2
- opentrons/drivers/flex_stacker/__init__.py +9 -0
- opentrons/drivers/flex_stacker/abstract.py +89 -0
- opentrons/drivers/flex_stacker/driver.py +260 -0
- opentrons/drivers/flex_stacker/simulator.py +109 -0
- opentrons/drivers/flex_stacker/types.py +138 -0
- opentrons/drivers/heater_shaker/driver.py +18 -3
- opentrons/drivers/temp_deck/driver.py +13 -3
- opentrons/drivers/thermocycler/driver.py +17 -3
- opentrons/execute.py +3 -1
- opentrons/hardware_control/__init__.py +1 -2
- opentrons/hardware_control/api.py +28 -20
- opentrons/hardware_control/backends/flex_protocol.py +4 -6
- opentrons/hardware_control/backends/ot3controller.py +177 -59
- opentrons/hardware_control/backends/ot3simulator.py +10 -8
- opentrons/hardware_control/backends/ot3utils.py +3 -13
- opentrons/hardware_control/dev_types.py +2 -0
- opentrons/hardware_control/emulation/heater_shaker.py +4 -0
- opentrons/hardware_control/emulation/module_server/client.py +1 -1
- opentrons/hardware_control/emulation/module_server/server.py +5 -3
- opentrons/hardware_control/emulation/settings.py +3 -4
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +2 -1
- opentrons/hardware_control/instruments/ot2/pipette.py +9 -21
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +8 -1
- opentrons/hardware_control/instruments/ot3/gripper.py +2 -2
- opentrons/hardware_control/instruments/ot3/pipette.py +13 -22
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -1
- opentrons/hardware_control/modules/mod_abc.py +2 -2
- opentrons/hardware_control/motion_utilities.py +68 -0
- opentrons/hardware_control/nozzle_manager.py +39 -41
- opentrons/hardware_control/ot3_calibration.py +1 -1
- opentrons/hardware_control/ot3api.py +34 -22
- opentrons/hardware_control/protocols/gripper_controller.py +3 -0
- opentrons/hardware_control/protocols/hardware_manager.py +5 -1
- opentrons/hardware_control/protocols/liquid_handler.py +18 -0
- opentrons/hardware_control/protocols/motion_controller.py +6 -0
- opentrons/hardware_control/robot_calibration.py +1 -1
- opentrons/hardware_control/types.py +61 -0
- opentrons/protocol_api/__init__.py +20 -1
- opentrons/protocol_api/_liquid.py +24 -49
- opentrons/protocol_api/_liquid_properties.py +754 -0
- opentrons/protocol_api/_types.py +24 -0
- opentrons/protocol_api/core/common.py +2 -0
- opentrons/protocol_api/core/engine/instrument.py +67 -10
- opentrons/protocol_api/core/engine/labware.py +29 -7
- opentrons/protocol_api/core/engine/protocol.py +130 -5
- opentrons/protocol_api/core/engine/robot.py +139 -0
- opentrons/protocol_api/core/engine/well.py +4 -1
- opentrons/protocol_api/core/instrument.py +42 -4
- opentrons/protocol_api/core/labware.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +34 -3
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +32 -1
- opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +34 -3
- opentrons/protocol_api/core/protocol.py +34 -1
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/instrument_context.py +145 -43
- opentrons/protocol_api/labware.py +231 -7
- opentrons/protocol_api/module_contexts.py +21 -17
- opentrons/protocol_api/protocol_context.py +125 -4
- opentrons/protocol_api/robot_context.py +204 -32
- opentrons/protocol_api/validation.py +261 -3
- opentrons/protocol_engine/__init__.py +4 -0
- opentrons/protocol_engine/actions/actions.py +2 -3
- opentrons/protocol_engine/clients/sync_client.py +18 -0
- opentrons/protocol_engine/commands/__init__.py +81 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +0 -2
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +19 -5
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +0 -1
- opentrons/protocol_engine/commands/absorbance_reader/read.py +32 -9
- opentrons/protocol_engine/commands/air_gap_in_place.py +160 -0
- opentrons/protocol_engine/commands/aspirate.py +103 -53
- opentrons/protocol_engine/commands/aspirate_in_place.py +55 -51
- opentrons/protocol_engine/commands/blow_out.py +44 -39
- opentrons/protocol_engine/commands/blow_out_in_place.py +21 -32
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +13 -6
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +1 -1
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +3 -3
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +1 -1
- opentrons/protocol_engine/commands/command.py +73 -66
- opentrons/protocol_engine/commands/command_unions.py +101 -1
- opentrons/protocol_engine/commands/comment.py +1 -1
- opentrons/protocol_engine/commands/configure_for_volume.py +10 -3
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +6 -4
- opentrons/protocol_engine/commands/custom.py +6 -12
- opentrons/protocol_engine/commands/dispense.py +82 -48
- opentrons/protocol_engine/commands/dispense_in_place.py +71 -51
- opentrons/protocol_engine/commands/drop_tip.py +52 -31
- opentrons/protocol_engine/commands/drop_tip_in_place.py +13 -3
- opentrons/protocol_engine/commands/generate_command_schema.py +4 -11
- opentrons/protocol_engine/commands/get_next_tip.py +134 -0
- opentrons/protocol_engine/commands/get_tip_presence.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/home.py +13 -4
- opentrons/protocol_engine/commands/liquid_probe.py +60 -25
- opentrons/protocol_engine/commands/load_labware.py +29 -7
- opentrons/protocol_engine/commands/load_lid.py +146 -0
- opentrons/protocol_engine/commands/load_lid_stack.py +189 -0
- opentrons/protocol_engine/commands/load_liquid.py +12 -4
- opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
- opentrons/protocol_engine/commands/load_module.py +31 -10
- opentrons/protocol_engine/commands/load_pipette.py +19 -8
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +1 -1
- opentrons/protocol_engine/commands/magnetic_module/engage.py +1 -1
- opentrons/protocol_engine/commands/move_labware.py +19 -6
- opentrons/protocol_engine/commands/move_relative.py +35 -25
- opentrons/protocol_engine/commands/move_to_addressable_area.py +40 -27
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +53 -32
- opentrons/protocol_engine/commands/move_to_coordinates.py +36 -22
- opentrons/protocol_engine/commands/move_to_well.py +40 -24
- opentrons/protocol_engine/commands/movement_common.py +338 -0
- opentrons/protocol_engine/commands/pick_up_tip.py +49 -27
- opentrons/protocol_engine/commands/pipetting_common.py +169 -87
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +24 -33
- opentrons/protocol_engine/commands/reload_labware.py +1 -1
- opentrons/protocol_engine/commands/retract_axis.py +1 -1
- opentrons/protocol_engine/commands/robot/__init__.py +69 -0
- opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +86 -0
- opentrons/protocol_engine/commands/robot/common.py +18 -0
- opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
- opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
- opentrons/protocol_engine/commands/robot/move_to.py +94 -0
- opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +77 -0
- opentrons/protocol_engine/commands/save_position.py +14 -5
- opentrons/protocol_engine/commands/set_rail_lights.py +1 -1
- opentrons/protocol_engine/commands/set_status_bar.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +8 -2
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +9 -3
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +11 -4
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/touch_tip.py +65 -16
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +4 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -3
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +1 -4
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +1 -4
- opentrons/protocol_engine/commands/verify_tip_presence.py +11 -4
- opentrons/protocol_engine/commands/wait_for_duration.py +10 -3
- opentrons/protocol_engine/commands/wait_for_resume.py +10 -3
- opentrons/protocol_engine/errors/__init__.py +8 -0
- opentrons/protocol_engine/errors/error_occurrence.py +19 -20
- opentrons/protocol_engine/errors/exceptions.py +50 -0
- opentrons/protocol_engine/execution/command_executor.py +1 -1
- opentrons/protocol_engine/execution/equipment.py +73 -5
- opentrons/protocol_engine/execution/gantry_mover.py +364 -8
- opentrons/protocol_engine/execution/movement.py +27 -0
- opentrons/protocol_engine/execution/pipetting.py +5 -1
- opentrons/protocol_engine/execution/tip_handler.py +4 -6
- opentrons/protocol_engine/notes/notes.py +1 -1
- opentrons/protocol_engine/protocol_engine.py +7 -6
- opentrons/protocol_engine/resources/labware_data_provider.py +1 -1
- opentrons/protocol_engine/resources/labware_validation.py +5 -0
- opentrons/protocol_engine/resources/module_data_provider.py +1 -1
- opentrons/protocol_engine/resources/pipette_data_provider.py +12 -0
- opentrons/protocol_engine/slot_standardization.py +9 -9
- opentrons/protocol_engine/state/_move_types.py +9 -5
- opentrons/protocol_engine/state/_well_math.py +193 -0
- opentrons/protocol_engine/state/addressable_areas.py +25 -61
- opentrons/protocol_engine/state/command_history.py +12 -0
- opentrons/protocol_engine/state/commands.py +17 -13
- opentrons/protocol_engine/state/files.py +10 -12
- opentrons/protocol_engine/state/fluid_stack.py +138 -0
- opentrons/protocol_engine/state/frustum_helpers.py +57 -32
- opentrons/protocol_engine/state/geometry.py +47 -1
- opentrons/protocol_engine/state/labware.py +79 -25
- opentrons/protocol_engine/state/liquid_classes.py +82 -0
- opentrons/protocol_engine/state/liquids.py +16 -4
- opentrons/protocol_engine/state/modules.py +52 -70
- opentrons/protocol_engine/state/motion.py +6 -1
- opentrons/protocol_engine/state/pipettes.py +135 -58
- opentrons/protocol_engine/state/state.py +21 -2
- opentrons/protocol_engine/state/state_summary.py +4 -2
- opentrons/protocol_engine/state/tips.py +11 -44
- opentrons/protocol_engine/state/update_types.py +343 -48
- opentrons/protocol_engine/state/wells.py +19 -11
- opentrons/protocol_engine/types.py +176 -28
- opentrons/protocol_reader/extract_labware_definitions.py +5 -2
- opentrons/protocol_reader/file_format_validator.py +5 -5
- opentrons/protocol_runner/json_file_reader.py +9 -3
- opentrons/protocol_runner/json_translator.py +51 -25
- opentrons/protocol_runner/legacy_command_mapper.py +66 -64
- opentrons/protocol_runner/protocol_runner.py +35 -4
- opentrons/protocol_runner/python_protocol_wrappers.py +1 -1
- opentrons/protocol_runner/run_orchestrator.py +13 -3
- opentrons/protocols/advanced_control/common.py +38 -0
- opentrons/protocols/advanced_control/mix.py +1 -1
- opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
- opentrons/protocols/advanced_control/transfers/common.py +56 -0
- opentrons/protocols/advanced_control/{transfers.py → transfers/transfer.py} +10 -85
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/instrument.py +1 -1
- opentrons/protocols/api_support/util.py +10 -0
- opentrons/protocols/labware.py +70 -8
- opentrons/protocols/models/json_protocol.py +5 -9
- opentrons/simulate.py +3 -1
- opentrons/types.py +162 -2
- opentrons/util/entrypoint_util.py +2 -5
- opentrons/util/logging_config.py +1 -1
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/METADATA +16 -15
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/RECORD +229 -202
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/WHEEL +1 -1
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/LICENSE +0 -0
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/entry_points.txt +0 -0
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/top_level.txt +0 -0
|
@@ -53,7 +53,9 @@ class ModuleStatusServer(ProxyListener):
|
|
|
53
53
|
self._connections[identifier] = connection
|
|
54
54
|
for c in self._clients:
|
|
55
55
|
c.write(
|
|
56
|
-
Message(status="connected", connections=[connection])
|
|
56
|
+
Message(status="connected", connections=[connection])
|
|
57
|
+
.model_dump_json()
|
|
58
|
+
.encode()
|
|
57
59
|
)
|
|
58
60
|
c.write(b"\n")
|
|
59
61
|
|
|
@@ -72,7 +74,7 @@ class ModuleStatusServer(ProxyListener):
|
|
|
72
74
|
for c in self._clients:
|
|
73
75
|
c.write(
|
|
74
76
|
Message(status="disconnected", connections=[connection])
|
|
75
|
-
.
|
|
77
|
+
.model_dump_json()
|
|
76
78
|
.encode()
|
|
77
79
|
)
|
|
78
80
|
c.write(MessageDelimiter)
|
|
@@ -95,7 +97,7 @@ class ModuleStatusServer(ProxyListener):
|
|
|
95
97
|
# A client connected. Send a dump of all connected modules.
|
|
96
98
|
m = Message(status="dump", connections=list(self._connections.values()))
|
|
97
99
|
|
|
98
|
-
writer.write(m.
|
|
100
|
+
writer.write(m.model_dump_json().encode())
|
|
99
101
|
writer.write(MessageDelimiter)
|
|
100
102
|
|
|
101
103
|
self._clients.add(writer)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from typing import List
|
|
2
2
|
from opentrons.hardware_control.emulation.types import ModuleType
|
|
3
3
|
from opentrons.hardware_control.emulation.util import TEMPERATURE_ROOM
|
|
4
|
-
from pydantic import
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class PipetteSettings(BaseModel):
|
|
@@ -113,8 +114,6 @@ class Settings(BaseSettings):
|
|
|
113
114
|
emulator_port=9003, driver_port=9998
|
|
114
115
|
)
|
|
115
116
|
magdeck_proxy: ProxySettings = ProxySettings(emulator_port=9004, driver_port=9999)
|
|
116
|
-
|
|
117
|
-
class Config:
|
|
118
|
-
env_prefix = "OT_EMULATOR_"
|
|
117
|
+
model_config = SettingsConfigDict(env_prefix="OT_EMULATOR_")
|
|
119
118
|
|
|
120
119
|
module_server: ModuleServerSettings = ModuleServerSettings()
|
|
@@ -123,7 +123,8 @@ def load_tip_length_for_pipette(
|
|
|
123
123
|
) -> TipLengthCalibration:
|
|
124
124
|
if isinstance(tiprack, LabwareDefinition):
|
|
125
125
|
tiprack = typing.cast(
|
|
126
|
-
"TypeDictLabwareDef",
|
|
126
|
+
"TypeDictLabwareDef",
|
|
127
|
+
tiprack.model_dump(exclude_none=True, exclude_unset=True),
|
|
127
128
|
)
|
|
128
129
|
|
|
129
130
|
tip_length_data = calibration_storage.load_tip_length_calibration(
|
|
@@ -28,7 +28,7 @@ from opentrons_shared_data.errors.exceptions import (
|
|
|
28
28
|
CommandPreconditionViolated,
|
|
29
29
|
)
|
|
30
30
|
from opentrons_shared_data.pipette.ul_per_mm import (
|
|
31
|
-
|
|
31
|
+
calculate_ul_per_mm,
|
|
32
32
|
PIPETTING_FUNCTION_FALLBACK_VERSION,
|
|
33
33
|
PIPETTING_FUNCTION_LATEST_VERSION,
|
|
34
34
|
)
|
|
@@ -97,7 +97,7 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
97
97
|
use_old_aspiration_functions: bool = False,
|
|
98
98
|
) -> None:
|
|
99
99
|
self._config = config
|
|
100
|
-
self._config_as_dict = config.
|
|
100
|
+
self._config_as_dict = config.model_dump()
|
|
101
101
|
self._pipette_offset = pipette_offset_cal
|
|
102
102
|
self._pipette_type = self._config.pipette_type
|
|
103
103
|
self._pipette_version = self._config.version
|
|
@@ -277,7 +277,7 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
277
277
|
self._config, elements, liquid_class
|
|
278
278
|
)
|
|
279
279
|
# Update the cached dict representation
|
|
280
|
-
self._config_as_dict = self._config.
|
|
280
|
+
self._config_as_dict = self._config.model_dump()
|
|
281
281
|
|
|
282
282
|
def reload_configurations(self) -> None:
|
|
283
283
|
self._config = load_pipette_data.load_definition(
|
|
@@ -286,7 +286,7 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
286
286
|
self._pipette_model.pipette_version,
|
|
287
287
|
self._pipette_model.oem_type,
|
|
288
288
|
)
|
|
289
|
-
self._config_as_dict = self._config.
|
|
289
|
+
self._config_as_dict = self._config.model_dump()
|
|
290
290
|
|
|
291
291
|
def reset_state(self) -> None:
|
|
292
292
|
self._current_volume = 0.0
|
|
@@ -589,21 +589,9 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
589
589
|
# want this to unbounded.
|
|
590
590
|
@functools.lru_cache(maxsize=100)
|
|
591
591
|
def ul_per_mm(self, ul: float, action: UlPerMmAction) -> float:
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
]
|
|
596
|
-
sequence = self._active_tip_settings.aspirate.default.get(
|
|
597
|
-
self._pipetting_function_version, fallback
|
|
598
|
-
)
|
|
599
|
-
else:
|
|
600
|
-
fallback = self._active_tip_settings.dispense.default[
|
|
601
|
-
PIPETTING_FUNCTION_FALLBACK_VERSION
|
|
602
|
-
]
|
|
603
|
-
sequence = self._active_tip_settings.dispense.default.get(
|
|
604
|
-
self._pipetting_function_version, fallback
|
|
605
|
-
)
|
|
606
|
-
return piecewise_volume_conversion(ul, sequence)
|
|
592
|
+
return calculate_ul_per_mm(
|
|
593
|
+
ul, action, self._active_tip_settings, self._pipetting_function_version
|
|
594
|
+
)
|
|
607
595
|
|
|
608
596
|
def __str__(self) -> str:
|
|
609
597
|
return "{} current volume {}ul critical point: {} at {}".format(
|
|
@@ -673,8 +661,8 @@ def _reload_and_check_skip(
|
|
|
673
661
|
# Same config, good enough
|
|
674
662
|
return attached_instr, True
|
|
675
663
|
else:
|
|
676
|
-
newdict = new_config.
|
|
677
|
-
olddict = attached_instr.config.
|
|
664
|
+
newdict = new_config.model_dump()
|
|
665
|
+
olddict = attached_instr.config.model_dump()
|
|
678
666
|
changed: Set[str] = set()
|
|
679
667
|
for k in newdict.keys():
|
|
680
668
|
if newdict[k] != olddict[k]:
|
|
@@ -230,7 +230,7 @@ class PipetteHandlerProvider(Generic[MountType]):
|
|
|
230
230
|
result["current_nozzle_map"] = instr.nozzle_manager.current_configuration
|
|
231
231
|
result["min_volume"] = instr.liquid_class.min_volume
|
|
232
232
|
result["max_volume"] = instr.liquid_class.max_volume
|
|
233
|
-
result["channels"] = instr.
|
|
233
|
+
result["channels"] = instr._max_channels.value
|
|
234
234
|
result["has_tip"] = instr.has_tip
|
|
235
235
|
result["tip_length"] = instr.current_tip_length
|
|
236
236
|
result["aspirate_speed"] = self.plunger_speed(
|
|
@@ -260,6 +260,13 @@ class PipetteHandlerProvider(Generic[MountType]):
|
|
|
260
260
|
"pipette_bounding_box_offsets"
|
|
261
261
|
] = instr.config.pipette_bounding_box_offsets
|
|
262
262
|
result["lld_settings"] = instr.config.lld_settings
|
|
263
|
+
result["plunger_positions"] = {
|
|
264
|
+
"top": instr.plunger_positions.top,
|
|
265
|
+
"bottom": instr.plunger_positions.bottom,
|
|
266
|
+
"blow_out": instr.plunger_positions.blow_out,
|
|
267
|
+
"drop_tip": instr.plunger_positions.drop_tip,
|
|
268
|
+
}
|
|
269
|
+
result["shaft_ul_per_mm"] = instr.config.shaft_ul_per_mm
|
|
263
270
|
return cast(PipetteDict, result)
|
|
264
271
|
|
|
265
272
|
@property
|
|
@@ -318,8 +318,8 @@ def _reload_gripper(
|
|
|
318
318
|
# Same config, good enough
|
|
319
319
|
return attached_instr, True
|
|
320
320
|
else:
|
|
321
|
-
newdict = new_config.
|
|
322
|
-
olddict = attached_instr.config.
|
|
321
|
+
newdict = new_config.model_dump()
|
|
322
|
+
olddict = attached_instr.config.model_dump()
|
|
323
323
|
changed: Set[str] = set()
|
|
324
324
|
for k in newdict.keys():
|
|
325
325
|
if newdict[k] != olddict[k]:
|
|
@@ -27,7 +27,7 @@ from opentrons_shared_data.errors.exceptions import (
|
|
|
27
27
|
InvalidInstrumentData,
|
|
28
28
|
)
|
|
29
29
|
from opentrons_shared_data.pipette.ul_per_mm import (
|
|
30
|
-
|
|
30
|
+
calculate_ul_per_mm,
|
|
31
31
|
PIPETTING_FUNCTION_FALLBACK_VERSION,
|
|
32
32
|
PIPETTING_FUNCTION_LATEST_VERSION,
|
|
33
33
|
)
|
|
@@ -80,7 +80,7 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
80
80
|
use_old_aspiration_functions: bool = False,
|
|
81
81
|
) -> None:
|
|
82
82
|
self._config = config
|
|
83
|
-
self._config_as_dict = config.
|
|
83
|
+
self._config_as_dict = config.model_dump()
|
|
84
84
|
self._plunger_motor_current = config.plunger_motor_configurations
|
|
85
85
|
self._pick_up_configurations = config.pick_up_tip_configurations
|
|
86
86
|
self._plunger_homing_configurations = config.plunger_homing_configurations
|
|
@@ -257,7 +257,7 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
257
257
|
self._pipette_model.pipette_version,
|
|
258
258
|
self._pipette_model.oem_type,
|
|
259
259
|
)
|
|
260
|
-
self._config_as_dict = self._config.
|
|
260
|
+
self._config_as_dict = self._config.model_dump()
|
|
261
261
|
|
|
262
262
|
def reset_state(self) -> None:
|
|
263
263
|
self._current_volume = 0.0
|
|
@@ -539,23 +539,13 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
539
539
|
# want this to unbounded.
|
|
540
540
|
@functools.lru_cache(maxsize=100)
|
|
541
541
|
def ul_per_mm(self, ul: float, action: UlPerMmAction) -> float:
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
elif action == "blowout":
|
|
550
|
-
return self._config.shaft_ul_per_mm
|
|
551
|
-
else:
|
|
552
|
-
fallback = self._active_tip_settings.dispense.default[
|
|
553
|
-
PIPETTING_FUNCTION_FALLBACK_VERSION
|
|
554
|
-
]
|
|
555
|
-
sequence = self._active_tip_settings.dispense.default.get(
|
|
556
|
-
self._pipetting_function_version, fallback
|
|
557
|
-
)
|
|
558
|
-
return piecewise_volume_conversion(ul, sequence)
|
|
542
|
+
return calculate_ul_per_mm(
|
|
543
|
+
ul,
|
|
544
|
+
action,
|
|
545
|
+
self._active_tip_settings,
|
|
546
|
+
self._pipetting_function_version,
|
|
547
|
+
self._config.shaft_ul_per_mm,
|
|
548
|
+
)
|
|
559
549
|
|
|
560
550
|
def __str__(self) -> str:
|
|
561
551
|
return "{} current volume {}ul critical point: {} at {}".format(
|
|
@@ -595,6 +585,7 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
595
585
|
"versioned_tip_overlap": self.tip_overlap,
|
|
596
586
|
"back_compat_names": self._config.pipette_backcompat_names,
|
|
597
587
|
"supported_tips": self.liquid_class.supported_tips,
|
|
588
|
+
"shaft_ul_per_mm": self._config.shaft_ul_per_mm,
|
|
598
589
|
}
|
|
599
590
|
)
|
|
600
591
|
return self._config_as_dict
|
|
@@ -785,8 +776,8 @@ def _reload_and_check_skip(
|
|
|
785
776
|
# Same config, good enough
|
|
786
777
|
return attached_instr, True
|
|
787
778
|
else:
|
|
788
|
-
newdict = new_config.
|
|
789
|
-
olddict = attached_instr.config.
|
|
779
|
+
newdict = new_config.model_dump()
|
|
780
|
+
olddict = attached_instr.config.model_dump()
|
|
790
781
|
changed: Set[str] = set()
|
|
791
782
|
for k in newdict.keys():
|
|
792
783
|
if newdict[k] != olddict[k]:
|
|
@@ -237,6 +237,7 @@ class OT3PipetteHandler:
|
|
|
237
237
|
"back_compat_names",
|
|
238
238
|
"supported_tips",
|
|
239
239
|
"lld_settings",
|
|
240
|
+
"available_sensors",
|
|
240
241
|
]
|
|
241
242
|
|
|
242
243
|
instr_dict = instr.as_dict()
|
|
@@ -248,7 +249,7 @@ class OT3PipetteHandler:
|
|
|
248
249
|
result["current_nozzle_map"] = instr.nozzle_manager.current_configuration
|
|
249
250
|
result["min_volume"] = instr.liquid_class.min_volume
|
|
250
251
|
result["max_volume"] = instr.liquid_class.max_volume
|
|
251
|
-
result["channels"] = instr._max_channels
|
|
252
|
+
result["channels"] = instr._max_channels.value
|
|
252
253
|
result["has_tip"] = instr.has_tip
|
|
253
254
|
result["tip_length"] = instr.current_tip_length
|
|
254
255
|
result["aspirate_speed"] = self.plunger_speed(
|
|
@@ -282,6 +283,14 @@ class OT3PipetteHandler:
|
|
|
282
283
|
"pipette_bounding_box_offsets"
|
|
283
284
|
] = instr.config.pipette_bounding_box_offsets
|
|
284
285
|
result["lld_settings"] = instr.config.lld_settings
|
|
286
|
+
result["plunger_positions"] = {
|
|
287
|
+
"top": instr.plunger_positions.top,
|
|
288
|
+
"bottom": instr.plunger_positions.bottom,
|
|
289
|
+
"blow_out": instr.plunger_positions.blow_out,
|
|
290
|
+
"drop_tip": instr.plunger_positions.drop_tip,
|
|
291
|
+
}
|
|
292
|
+
result["shaft_ul_per_mm"] = instr.config.shaft_ul_per_mm
|
|
293
|
+
result["available_sensors"] = instr.config.available_sensors
|
|
285
294
|
return cast(PipetteDict, result)
|
|
286
295
|
|
|
287
296
|
@property
|
|
@@ -2,7 +2,7 @@ import abc
|
|
|
2
2
|
import asyncio
|
|
3
3
|
import logging
|
|
4
4
|
import re
|
|
5
|
-
from typing import ClassVar, Mapping, Optional, TypeVar
|
|
5
|
+
from typing import ClassVar, Mapping, Optional, TypeVar
|
|
6
6
|
from packaging.version import InvalidVersion, parse, Version
|
|
7
7
|
from opentrons.config import IS_ROBOT, ROBOT_FIRMWARE_DIR
|
|
8
8
|
from opentrons.drivers.rpi_drivers.types import USBPort
|
|
@@ -31,7 +31,7 @@ def parse_fw_version(version: str) -> Version:
|
|
|
31
31
|
raise InvalidVersion()
|
|
32
32
|
except InvalidVersion:
|
|
33
33
|
device_version = parse("v0.0.0")
|
|
34
|
-
return
|
|
34
|
+
return device_version
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
class AbstractModule(abc.ABC):
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
"""Utilities for calculating motion correctly."""
|
|
2
|
+
from logging import getLogger
|
|
3
|
+
|
|
2
4
|
from functools import lru_cache
|
|
3
5
|
from typing import Callable, Dict, Union, Optional, cast
|
|
4
6
|
from collections import OrderedDict
|
|
@@ -11,6 +13,7 @@ from opentrons.util import linal
|
|
|
11
13
|
|
|
12
14
|
from .types import Axis, OT3Mount
|
|
13
15
|
|
|
16
|
+
log = getLogger(__name__)
|
|
14
17
|
|
|
15
18
|
# TODO: The offset_for_mount function should be defined with an overload
|
|
16
19
|
# set, as with other functions in this module. Unfortunately, mypy < 0.920
|
|
@@ -36,6 +39,19 @@ from .types import Axis, OT3Mount
|
|
|
36
39
|
# ) -> Point:
|
|
37
40
|
# ...
|
|
38
41
|
|
|
42
|
+
EMPTY_ORDERED_DICT = OrderedDict(
|
|
43
|
+
(
|
|
44
|
+
(Axis.X, 0.0),
|
|
45
|
+
(Axis.Y, 0.0),
|
|
46
|
+
(Axis.Z_L, 0.0),
|
|
47
|
+
(Axis.Z_R, 0.0),
|
|
48
|
+
(Axis.Z_G, 0.0),
|
|
49
|
+
(Axis.P_L, 0.0),
|
|
50
|
+
(Axis.P_R, 0.0),
|
|
51
|
+
(Axis.Q, 0.0),
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
|
|
39
55
|
|
|
40
56
|
@lru_cache(4)
|
|
41
57
|
def offset_for_mount(
|
|
@@ -68,6 +84,7 @@ def target_position_from_absolute(
|
|
|
68
84
|
)
|
|
69
85
|
primary_cp = get_critical_point(mount)
|
|
70
86
|
primary_z = Axis.by_mount(mount)
|
|
87
|
+
|
|
71
88
|
target_position = OrderedDict(
|
|
72
89
|
(
|
|
73
90
|
(Axis.X, abs_position.x - offset.x - primary_cp.x),
|
|
@@ -97,6 +114,57 @@ def target_position_from_relative(
|
|
|
97
114
|
return target_position
|
|
98
115
|
|
|
99
116
|
|
|
117
|
+
def target_axis_map_from_absolute(
|
|
118
|
+
primary_mount: Union[OT3Mount, Mount],
|
|
119
|
+
axis_map: Dict[Axis, float],
|
|
120
|
+
get_critical_point: Callable[[Union[Mount, OT3Mount]], Point],
|
|
121
|
+
left_mount_offset: Point,
|
|
122
|
+
right_mount_offset: Point,
|
|
123
|
+
gripper_mount_offset: Optional[Point] = None,
|
|
124
|
+
) -> "OrderedDict[Axis, float]":
|
|
125
|
+
"""Create an absolute target position for all specified machine axes."""
|
|
126
|
+
keys_for_target_position = list(axis_map.keys())
|
|
127
|
+
|
|
128
|
+
offset = offset_for_mount(
|
|
129
|
+
primary_mount, left_mount_offset, right_mount_offset, gripper_mount_offset
|
|
130
|
+
)
|
|
131
|
+
primary_cp = get_critical_point(primary_mount)
|
|
132
|
+
primary_z = Axis.by_mount(primary_mount)
|
|
133
|
+
target_position = OrderedDict()
|
|
134
|
+
|
|
135
|
+
if Axis.X in keys_for_target_position:
|
|
136
|
+
target_position[Axis.X] = axis_map[Axis.X] - offset.x - primary_cp.x
|
|
137
|
+
if Axis.Y in keys_for_target_position:
|
|
138
|
+
target_position[Axis.Y] = axis_map[Axis.Y] - offset.y - primary_cp.y
|
|
139
|
+
if primary_z in keys_for_target_position:
|
|
140
|
+
# Since this function is intended to be used in conjunction with `API.move_axes`
|
|
141
|
+
# we must leave out the carriage offset subtraction from the target position as
|
|
142
|
+
# `move_axes` already does this calculation.
|
|
143
|
+
target_position[primary_z] = axis_map[primary_z] - primary_cp.z
|
|
144
|
+
|
|
145
|
+
target_position.update(
|
|
146
|
+
{ax: val for ax, val in axis_map.items() if ax not in Axis.gantry_axes()}
|
|
147
|
+
)
|
|
148
|
+
return target_position
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def target_axis_map_from_relative(
|
|
152
|
+
axis_map: Dict[Axis, float],
|
|
153
|
+
current_position: Dict[Axis, float],
|
|
154
|
+
) -> "OrderedDict[Axis, float]":
|
|
155
|
+
"""Create a target position for all specified machine axes."""
|
|
156
|
+
target_position = OrderedDict(
|
|
157
|
+
(
|
|
158
|
+
(ax, current_position[ax] + axis_map[ax])
|
|
159
|
+
for ax in EMPTY_ORDERED_DICT.keys()
|
|
160
|
+
if ax in axis_map.keys()
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
log.info(f"Current position {current_position} and axis map delta {axis_map}")
|
|
164
|
+
log.info(f"Relative move target {target_position}")
|
|
165
|
+
return target_position
|
|
166
|
+
|
|
167
|
+
|
|
100
168
|
def target_position_from_plunger(
|
|
101
169
|
mount: Union[Mount, OT3Mount],
|
|
102
170
|
delta: float,
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
from typing import Dict, List, Optional, Any, Sequence, Iterator, Tuple, cast
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
from collections import OrderedDict
|
|
4
|
-
from enum import Enum
|
|
5
4
|
from itertools import chain
|
|
6
5
|
|
|
7
6
|
from opentrons.hardware_control.types import CriticalPoint
|
|
8
|
-
from opentrons.types import
|
|
7
|
+
from opentrons.types import (
|
|
8
|
+
Point,
|
|
9
|
+
NozzleConfigurationType,
|
|
10
|
+
)
|
|
9
11
|
from opentrons_shared_data.pipette.pipette_definition import (
|
|
10
12
|
PipetteGeometryDefinition,
|
|
11
13
|
PipetteRowDefinition,
|
|
@@ -41,43 +43,6 @@ def _row_col_indices_for_nozzle(
|
|
|
41
43
|
)
|
|
42
44
|
|
|
43
45
|
|
|
44
|
-
class NozzleConfigurationType(Enum):
|
|
45
|
-
"""
|
|
46
|
-
Nozzle Configuration Type.
|
|
47
|
-
|
|
48
|
-
Represents the current nozzle
|
|
49
|
-
configuration stored in NozzleMap
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
COLUMN = "COLUMN"
|
|
53
|
-
ROW = "ROW"
|
|
54
|
-
SINGLE = "SINGLE"
|
|
55
|
-
FULL = "FULL"
|
|
56
|
-
SUBRECT = "SUBRECT"
|
|
57
|
-
|
|
58
|
-
@classmethod
|
|
59
|
-
def determine_nozzle_configuration(
|
|
60
|
-
cls,
|
|
61
|
-
physical_rows: "OrderedDict[str, List[str]]",
|
|
62
|
-
current_rows: "OrderedDict[str, List[str]]",
|
|
63
|
-
physical_cols: "OrderedDict[str, List[str]]",
|
|
64
|
-
current_cols: "OrderedDict[str, List[str]]",
|
|
65
|
-
) -> "NozzleConfigurationType":
|
|
66
|
-
"""
|
|
67
|
-
Determine the nozzle configuration based on the starting and
|
|
68
|
-
ending nozzle.
|
|
69
|
-
"""
|
|
70
|
-
if physical_rows == current_rows and physical_cols == current_cols:
|
|
71
|
-
return NozzleConfigurationType.FULL
|
|
72
|
-
if len(current_rows) == 1 and len(current_cols) == 1:
|
|
73
|
-
return NozzleConfigurationType.SINGLE
|
|
74
|
-
if len(current_rows) == 1:
|
|
75
|
-
return NozzleConfigurationType.ROW
|
|
76
|
-
if len(current_cols) == 1:
|
|
77
|
-
return NozzleConfigurationType.COLUMN
|
|
78
|
-
return NozzleConfigurationType.SUBRECT
|
|
79
|
-
|
|
80
|
-
|
|
81
46
|
@dataclass
|
|
82
47
|
class NozzleMap:
|
|
83
48
|
"""
|
|
@@ -113,6 +78,28 @@ class NozzleMap:
|
|
|
113
78
|
full_instrument_rows: Dict[str, List[str]]
|
|
114
79
|
#: A map of all the rows of an instrument
|
|
115
80
|
|
|
81
|
+
@classmethod
|
|
82
|
+
def determine_nozzle_configuration(
|
|
83
|
+
cls,
|
|
84
|
+
physical_rows: "OrderedDict[str, List[str]]",
|
|
85
|
+
current_rows: "OrderedDict[str, List[str]]",
|
|
86
|
+
physical_cols: "OrderedDict[str, List[str]]",
|
|
87
|
+
current_cols: "OrderedDict[str, List[str]]",
|
|
88
|
+
) -> "NozzleConfigurationType":
|
|
89
|
+
"""
|
|
90
|
+
Determine the nozzle configuration based on the starting and
|
|
91
|
+
ending nozzle.
|
|
92
|
+
"""
|
|
93
|
+
if physical_rows == current_rows and physical_cols == current_cols:
|
|
94
|
+
return NozzleConfigurationType.FULL
|
|
95
|
+
if len(current_rows) == 1 and len(current_cols) == 1:
|
|
96
|
+
return NozzleConfigurationType.SINGLE
|
|
97
|
+
if len(current_rows) == 1:
|
|
98
|
+
return NozzleConfigurationType.ROW
|
|
99
|
+
if len(current_cols) == 1:
|
|
100
|
+
return NozzleConfigurationType.COLUMN
|
|
101
|
+
return NozzleConfigurationType.SUBRECT
|
|
102
|
+
|
|
116
103
|
def __str__(self) -> str:
|
|
117
104
|
return f"back_left_nozzle: {self.back_left} front_right_nozzle: {self.front_right} configuration: {self.configuration}"
|
|
118
105
|
|
|
@@ -216,6 +203,16 @@ class NozzleMap:
|
|
|
216
203
|
"""The total number of active nozzles in the configuration, and thus the number of tips that will be picked up."""
|
|
217
204
|
return len(self.map_store)
|
|
218
205
|
|
|
206
|
+
@property
|
|
207
|
+
def physical_nozzle_count(self) -> int:
|
|
208
|
+
"""The number of physical nozzles, regardless of configuration."""
|
|
209
|
+
return len(self.full_instrument_map_store)
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def active_nozzles(self) -> list[str]:
|
|
213
|
+
"""An unstructured list of all nozzles active in the configuration."""
|
|
214
|
+
return list(self.map_store.keys())
|
|
215
|
+
|
|
219
216
|
@classmethod
|
|
220
217
|
def build( # noqa: C901
|
|
221
218
|
cls,
|
|
@@ -274,7 +271,7 @@ class NozzleMap:
|
|
|
274
271
|
)
|
|
275
272
|
|
|
276
273
|
if (
|
|
277
|
-
|
|
274
|
+
cls.determine_nozzle_configuration(
|
|
278
275
|
physical_rows, rows, physical_columns, columns
|
|
279
276
|
)
|
|
280
277
|
!= NozzleConfigurationType.FULL
|
|
@@ -289,6 +286,7 @@ class NozzleMap:
|
|
|
289
286
|
if valid_nozzle_maps.maps[map_key] == list(map_store.keys()):
|
|
290
287
|
validated_map_key = map_key
|
|
291
288
|
break
|
|
289
|
+
|
|
292
290
|
if validated_map_key is None:
|
|
293
291
|
raise IncompatibleNozzleConfiguration(
|
|
294
292
|
"Attempted Nozzle Configuration does not match any approved map layout for the current pipette."
|
|
@@ -302,7 +300,7 @@ class NozzleMap:
|
|
|
302
300
|
full_instrument_map_store=physical_nozzles,
|
|
303
301
|
full_instrument_rows=physical_rows,
|
|
304
302
|
columns=columns,
|
|
305
|
-
configuration=
|
|
303
|
+
configuration=cls.determine_nozzle_configuration(
|
|
306
304
|
physical_rows, rows, physical_columns, columns
|
|
307
305
|
),
|
|
308
306
|
)
|
|
@@ -968,7 +968,7 @@ def load_attitude_matrix(to_default: bool = True) -> DeckCalibration:
|
|
|
968
968
|
return DeckCalibration(
|
|
969
969
|
attitude=apply_machine_transform(calibration_data.attitude),
|
|
970
970
|
source=calibration_data.source,
|
|
971
|
-
status=types.CalibrationStatus(**calibration_data.status.
|
|
971
|
+
status=types.CalibrationStatus(**calibration_data.status.model_dump()),
|
|
972
972
|
belt_attitude=calibration_data.attitude,
|
|
973
973
|
last_modified=calibration_data.lastModified,
|
|
974
974
|
pipette_calibrated_with=calibration_data.pipetteCalibratedWith,
|