opentrons 8.2.0a4__py2.py3-none-any.whl → 8.3.0a1__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/config/defaults_ot3.py +1 -0
- 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 +17 -7
- opentrons/hardware_control/backends/ot3controller.py +213 -63
- opentrons/hardware_control/backends/ot3simulator.py +18 -9
- opentrons/hardware_control/backends/ot3utils.py +43 -15
- opentrons/hardware_control/dev_types.py +4 -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 +15 -22
- 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 +23 -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 +60 -23
- 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 +82 -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 +46 -4
- opentrons/protocol_api/core/labware.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +37 -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 +37 -3
- opentrons/protocol_api/core/protocol.py +34 -1
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/instrument_context.py +158 -44
- 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 +262 -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 +67 -24
- 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 +26 -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 +144 -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 +39 -6
- opentrons/protocols/models/json_protocol.py +5 -9
- opentrons/simulate.py +3 -1
- opentrons/types.py +162 -2
- opentrons/util/logging_config.py +1 -1
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/METADATA +16 -15
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/RECORD +229 -202
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/WHEEL +1 -1
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/LICENSE +0 -0
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/entry_points.txt +0 -0
- {opentrons-8.2.0a4.dist-info → opentrons-8.3.0a1.dist-info}/top_level.txt +0 -0
|
@@ -45,6 +45,7 @@ from opentrons.hardware_control.types import (
|
|
|
45
45
|
EstopPhysicalStatus,
|
|
46
46
|
HardwareEventHandler,
|
|
47
47
|
HardwareEventUnsubscriber,
|
|
48
|
+
PipetteSensorResponseQueue,
|
|
48
49
|
)
|
|
49
50
|
|
|
50
51
|
from opentrons_shared_data.pipette.types import PipetteName, PipetteModel
|
|
@@ -62,9 +63,9 @@ from opentrons.hardware_control.dev_types import (
|
|
|
62
63
|
)
|
|
63
64
|
from opentrons.util.async_helpers import ensure_yield
|
|
64
65
|
from .types import HWStopCondition
|
|
65
|
-
from .flex_protocol import
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
from .flex_protocol import (
|
|
67
|
+
FlexBackend,
|
|
68
|
+
)
|
|
68
69
|
|
|
69
70
|
log = logging.getLogger(__name__)
|
|
70
71
|
|
|
@@ -235,7 +236,11 @@ class OT3Simulator(FlexBackend):
|
|
|
235
236
|
self._sim_gantry_load = gantry_load
|
|
236
237
|
|
|
237
238
|
def update_constraints_for_plunger_acceleration(
|
|
238
|
-
self,
|
|
239
|
+
self,
|
|
240
|
+
mount: OT3Mount,
|
|
241
|
+
acceleration: float,
|
|
242
|
+
gantry_load: GantryLoad,
|
|
243
|
+
high_speed_pipette: bool = False,
|
|
239
244
|
) -> None:
|
|
240
245
|
self._sim_gantry_load = gantry_load
|
|
241
246
|
|
|
@@ -348,11 +353,10 @@ class OT3Simulator(FlexBackend):
|
|
|
348
353
|
threshold_pascals: float,
|
|
349
354
|
plunger_impulse_time: float,
|
|
350
355
|
num_baseline_reads: int,
|
|
356
|
+
z_offset_for_plunger_prep: float,
|
|
351
357
|
probe: InstrumentProbeType = InstrumentProbeType.PRIMARY,
|
|
352
358
|
force_both_sensors: bool = False,
|
|
353
|
-
response_queue: Optional[
|
|
354
|
-
asyncio.Queue[Dict[SensorId, List[SensorDataType]]]
|
|
355
|
-
] = None,
|
|
359
|
+
response_queue: Optional[PipetteSensorResponseQueue] = None,
|
|
356
360
|
) -> float:
|
|
357
361
|
z_axis = Axis.by_mount(mount)
|
|
358
362
|
pos = self._position
|
|
@@ -439,10 +443,12 @@ class OT3Simulator(FlexBackend):
|
|
|
439
443
|
return self._sim_jaw_state
|
|
440
444
|
|
|
441
445
|
async def tip_action(
|
|
442
|
-
self, origin:
|
|
446
|
+
self, origin: float, targets: List[Tuple[float, float]]
|
|
443
447
|
) -> None:
|
|
444
448
|
self._gear_motor_position.update(
|
|
445
|
-
coalesce_move_segments(
|
|
449
|
+
coalesce_move_segments(
|
|
450
|
+
{Axis.Q: origin}, [{Axis.Q: target[0]} for target in targets]
|
|
451
|
+
)
|
|
446
452
|
)
|
|
447
453
|
await asyncio.sleep(0)
|
|
448
454
|
|
|
@@ -505,6 +511,7 @@ class OT3Simulator(FlexBackend):
|
|
|
505
511
|
converted_name.pipette_type,
|
|
506
512
|
converted_name.pipette_channels,
|
|
507
513
|
converted_name.pipette_version,
|
|
514
|
+
converted_name.oem_type,
|
|
508
515
|
),
|
|
509
516
|
"id": None,
|
|
510
517
|
}
|
|
@@ -527,6 +534,7 @@ class OT3Simulator(FlexBackend):
|
|
|
527
534
|
converted_name.pipette_type,
|
|
528
535
|
converted_name.pipette_channels,
|
|
529
536
|
converted_name.pipette_version,
|
|
537
|
+
converted_name.oem_type,
|
|
530
538
|
),
|
|
531
539
|
"id": init_instr["id"],
|
|
532
540
|
}
|
|
@@ -538,6 +546,7 @@ class OT3Simulator(FlexBackend):
|
|
|
538
546
|
converted_name.pipette_type,
|
|
539
547
|
converted_name.pipette_channels,
|
|
540
548
|
converted_name.pipette_version,
|
|
549
|
+
converted_name.oem_type,
|
|
541
550
|
),
|
|
542
551
|
"id": None,
|
|
543
552
|
}
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
from typing import Dict, Iterable, List, Set, Tuple, TypeVar, cast, Sequence, Optional
|
|
3
3
|
from typing_extensions import Literal
|
|
4
4
|
from logging import getLogger
|
|
5
|
-
from opentrons.config.defaults_ot3 import
|
|
5
|
+
from opentrons.config.defaults_ot3 import (
|
|
6
|
+
DEFAULT_CALIBRATION_AXIS_MAX_SPEED,
|
|
7
|
+
DEFAULT_EMULSIFYING_PIPETTE_AXIS_MAX_SPEED,
|
|
8
|
+
)
|
|
6
9
|
from opentrons.config.types import OT3MotionSettings, OT3CurrentSettings, GantryLoad
|
|
7
10
|
from opentrons.hardware_control.types import (
|
|
8
11
|
Axis,
|
|
@@ -281,12 +284,22 @@ def get_system_constraints_for_plunger_acceleration(
|
|
|
281
284
|
gantry_load: GantryLoad,
|
|
282
285
|
mount: OT3Mount,
|
|
283
286
|
acceleration: float,
|
|
287
|
+
high_speed_pipette: bool = False,
|
|
284
288
|
) -> "SystemConstraints[Axis]":
|
|
285
289
|
old_constraints = config.by_gantry_load(gantry_load)
|
|
286
290
|
new_constraints = {}
|
|
287
291
|
axis_kinds = set([k for _, v in old_constraints.items() for k in v.keys()])
|
|
292
|
+
|
|
293
|
+
def _get_axis_max_speed(ax: Axis) -> float:
|
|
294
|
+
if ax == Axis.of_main_tool_actuator(mount) and high_speed_pipette:
|
|
295
|
+
_max_speed = float(DEFAULT_EMULSIFYING_PIPETTE_AXIS_MAX_SPEED)
|
|
296
|
+
else:
|
|
297
|
+
_max_speed = old_constraints["default_max_speed"][axis_kind]
|
|
298
|
+
return _max_speed
|
|
299
|
+
|
|
288
300
|
for axis_kind in axis_kinds:
|
|
289
301
|
for axis in Axis.of_kind(axis_kind):
|
|
302
|
+
_default_max_speed = _get_axis_max_speed(axis)
|
|
290
303
|
if axis == Axis.of_main_tool_actuator(mount):
|
|
291
304
|
_accel = acceleration
|
|
292
305
|
else:
|
|
@@ -295,7 +308,32 @@ def get_system_constraints_for_plunger_acceleration(
|
|
|
295
308
|
_accel,
|
|
296
309
|
old_constraints["max_speed_discontinuity"][axis_kind],
|
|
297
310
|
old_constraints["direction_change_speed_discontinuity"][axis_kind],
|
|
298
|
-
|
|
311
|
+
_default_max_speed,
|
|
312
|
+
)
|
|
313
|
+
return new_constraints
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def get_system_constraints_for_emulsifying_pipette(
|
|
317
|
+
config: OT3MotionSettings,
|
|
318
|
+
gantry_load: GantryLoad,
|
|
319
|
+
mount: OT3Mount,
|
|
320
|
+
) -> "SystemConstraints[Axis]":
|
|
321
|
+
old_constraints = config.by_gantry_load(gantry_load)
|
|
322
|
+
new_constraints = {}
|
|
323
|
+
axis_kinds = set([k for _, v in old_constraints.items() for k in v.keys()])
|
|
324
|
+
for axis_kind in axis_kinds:
|
|
325
|
+
for axis in Axis.of_kind(axis_kind):
|
|
326
|
+
if axis == Axis.of_main_tool_actuator(mount):
|
|
327
|
+
_max_speed = float(DEFAULT_EMULSIFYING_PIPETTE_AXIS_MAX_SPEED)
|
|
328
|
+
else:
|
|
329
|
+
_max_speed = old_constraints["default_max_speed"][axis_kind]
|
|
330
|
+
new_constraints[axis] = AxisConstraints.build(
|
|
331
|
+
max_acceleration=old_constraints["acceleration"][axis_kind],
|
|
332
|
+
max_speed_discont=old_constraints["max_speed_discontinuity"][axis_kind],
|
|
333
|
+
max_direction_change_speed_discont=old_constraints[
|
|
334
|
+
"direction_change_speed_discontinuity"
|
|
335
|
+
][axis_kind],
|
|
336
|
+
max_speed=_max_speed,
|
|
299
337
|
)
|
|
300
338
|
return new_constraints
|
|
301
339
|
|
|
@@ -498,10 +536,10 @@ def create_gripper_jaw_hold_group(encoder_position_um: int) -> MoveGroup:
|
|
|
498
536
|
return move_group
|
|
499
537
|
|
|
500
538
|
|
|
501
|
-
def moving_pipettes_in_move_group(
|
|
539
|
+
def moving_pipettes_in_move_group(
|
|
540
|
+
all_nodes: Set[NodeId], moving_nodes: Set[NodeId]
|
|
541
|
+
) -> List[NodeId]:
|
|
502
542
|
"""Utility function to get which pipette nodes are moving either in z or their plunger."""
|
|
503
|
-
all_nodes = [node for step in group for node, _ in step.items()]
|
|
504
|
-
moving_nodes = moving_axes_in_move_group(group)
|
|
505
543
|
pipettes_moving: List[NodeId] = [
|
|
506
544
|
k for k in moving_nodes if k in [NodeId.pipette_left, NodeId.pipette_right]
|
|
507
545
|
]
|
|
@@ -512,16 +550,6 @@ def moving_pipettes_in_move_group(group: MoveGroup) -> List[NodeId]:
|
|
|
512
550
|
return pipettes_moving
|
|
513
551
|
|
|
514
552
|
|
|
515
|
-
def moving_axes_in_move_group(group: MoveGroup) -> Set[NodeId]:
|
|
516
|
-
"""Utility function to get only the moving nodes in a move group."""
|
|
517
|
-
ret: Set[NodeId] = set()
|
|
518
|
-
for step in group:
|
|
519
|
-
for node, node_step in step.items():
|
|
520
|
-
if node_step.is_moving_step():
|
|
521
|
-
ret.add(node)
|
|
522
|
-
return ret
|
|
523
|
-
|
|
524
|
-
|
|
525
553
|
AxisMapPayload = TypeVar("AxisMapPayload")
|
|
526
554
|
|
|
527
555
|
|
|
@@ -20,6 +20,7 @@ from opentrons_shared_data.pipette.pipette_definition import (
|
|
|
20
20
|
PipetteConfigurations,
|
|
21
21
|
SupportedTipsDefinition,
|
|
22
22
|
PipetteBoundingBoxOffsetDefinition,
|
|
23
|
+
AvailableSensorDefinition,
|
|
23
24
|
)
|
|
24
25
|
from opentrons_shared_data.gripper import (
|
|
25
26
|
GripperModel,
|
|
@@ -100,6 +101,9 @@ class PipetteDict(InstrumentDict):
|
|
|
100
101
|
pipette_bounding_box_offsets: PipetteBoundingBoxOffsetDefinition
|
|
101
102
|
current_nozzle_map: NozzleMap
|
|
102
103
|
lld_settings: Optional[Dict[str, Dict[str, float]]]
|
|
104
|
+
plunger_positions: Dict[str, float]
|
|
105
|
+
shaft_ul_per_mm: float
|
|
106
|
+
available_sensors: AvailableSensorDefinition
|
|
103
107
|
|
|
104
108
|
|
|
105
109
|
class PipetteStateDict(TypedDict):
|
|
@@ -45,6 +45,7 @@ class HeaterShakerEmulator(AbstractEmulator):
|
|
|
45
45
|
GCODE.HOME.value: self._home,
|
|
46
46
|
GCODE.ENTER_BOOTLOADER.value: self._enter_bootloader,
|
|
47
47
|
GCODE.GET_VERSION.value: self._get_version,
|
|
48
|
+
GCODE.GET_RESET_REASON.value: self._get_reset_reason,
|
|
48
49
|
GCODE.OPEN_LABWARE_LATCH.value: self._open_labware_latch,
|
|
49
50
|
GCODE.CLOSE_LABWARE_LATCH.value: self._close_labware_latch,
|
|
50
51
|
GCODE.GET_LABWARE_LATCH_STATE.value: self._get_labware_latch_state,
|
|
@@ -126,6 +127,9 @@ class HeaterShakerEmulator(AbstractEmulator):
|
|
|
126
127
|
f"SerialNo:{self._settings.serial_number}"
|
|
127
128
|
)
|
|
128
129
|
|
|
130
|
+
def _get_reset_reason(self, command: Command) -> str:
|
|
131
|
+
return "M114 Last Reset Reason: 01"
|
|
132
|
+
|
|
129
133
|
def _open_labware_latch(self, command: Command) -> str:
|
|
130
134
|
self._latch_status = HeaterShakerLabwareLatchStatus.IDLE_OPEN
|
|
131
135
|
return "M242"
|
|
@@ -66,7 +66,7 @@ class ModuleStatusClient:
|
|
|
66
66
|
"""Read a message from the module server."""
|
|
67
67
|
try:
|
|
68
68
|
b = await self._reader.readuntil(MessageDelimiter)
|
|
69
|
-
m: Message = Message.
|
|
69
|
+
m: Message = Message.model_validate_json(b)
|
|
70
70
|
return m
|
|
71
71
|
except LimitOverrunError as e:
|
|
72
72
|
raise ModuleServerClientError(str(e))
|
|
@@ -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
|
)
|
|
@@ -56,6 +56,7 @@ from opentrons_shared_data.pipette.types import (
|
|
|
56
56
|
UlPerMmAction,
|
|
57
57
|
PipetteName,
|
|
58
58
|
PipetteModel,
|
|
59
|
+
PipetteOEMType,
|
|
59
60
|
)
|
|
60
61
|
from opentrons.hardware_control.dev_types import InstrumentHardwareConfigs
|
|
61
62
|
|
|
@@ -96,7 +97,7 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
96
97
|
use_old_aspiration_functions: bool = False,
|
|
97
98
|
) -> None:
|
|
98
99
|
self._config = config
|
|
99
|
-
self._config_as_dict = config.
|
|
100
|
+
self._config_as_dict = config.model_dump()
|
|
100
101
|
self._pipette_offset = pipette_offset_cal
|
|
101
102
|
self._pipette_type = self._config.pipette_type
|
|
102
103
|
self._pipette_version = self._config.version
|
|
@@ -112,17 +113,20 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
112
113
|
pipette_type=config.pipette_type,
|
|
113
114
|
pipette_channels=config.channels,
|
|
114
115
|
pipette_generation=config.display_category,
|
|
116
|
+
oem_type=PipetteOEMType.OT,
|
|
115
117
|
)
|
|
116
118
|
self._acting_as = self._pipette_name
|
|
117
119
|
self._pipette_model = PipetteModelVersionType(
|
|
118
120
|
pipette_type=config.pipette_type,
|
|
119
121
|
pipette_channels=config.channels,
|
|
120
122
|
pipette_version=config.version,
|
|
123
|
+
oem_type=PipetteOEMType.OT,
|
|
121
124
|
)
|
|
122
125
|
self._valid_nozzle_maps = load_pipette_data.load_valid_nozzle_maps(
|
|
123
126
|
self._pipette_model.pipette_type,
|
|
124
127
|
self._pipette_model.pipette_channels,
|
|
125
128
|
self._pipette_model.pipette_version,
|
|
129
|
+
PipetteOEMType.OT,
|
|
126
130
|
)
|
|
127
131
|
self._nozzle_offset = self._config.nozzle_offset
|
|
128
132
|
self._nozzle_manager = (
|
|
@@ -189,7 +193,7 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
189
193
|
], f"{self.name} is not back-compatible with {name}"
|
|
190
194
|
|
|
191
195
|
liquid_model = load_pipette_data.load_liquid_model(
|
|
192
|
-
name.pipette_type, name.pipette_channels, name.get_version()
|
|
196
|
+
name.pipette_type, name.pipette_channels, name.get_version(), name.oem_type
|
|
193
197
|
)
|
|
194
198
|
# TODO need to grab name config here to deal with act as test
|
|
195
199
|
self._liquid_class.max_volume = liquid_model["default"].max_volume
|
|
@@ -273,15 +277,16 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
273
277
|
self._config, elements, liquid_class
|
|
274
278
|
)
|
|
275
279
|
# Update the cached dict representation
|
|
276
|
-
self._config_as_dict = self._config.
|
|
280
|
+
self._config_as_dict = self._config.model_dump()
|
|
277
281
|
|
|
278
282
|
def reload_configurations(self) -> None:
|
|
279
283
|
self._config = load_pipette_data.load_definition(
|
|
280
284
|
self._pipette_model.pipette_type,
|
|
281
285
|
self._pipette_model.pipette_channels,
|
|
282
286
|
self._pipette_model.pipette_version,
|
|
287
|
+
self._pipette_model.oem_type,
|
|
283
288
|
)
|
|
284
|
-
self._config_as_dict = self._config.
|
|
289
|
+
self._config_as_dict = self._config.model_dump()
|
|
285
290
|
|
|
286
291
|
def reset_state(self) -> None:
|
|
287
292
|
self._current_volume = 0.0
|
|
@@ -584,21 +589,9 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
584
589
|
# want this to unbounded.
|
|
585
590
|
@functools.lru_cache(maxsize=100)
|
|
586
591
|
def ul_per_mm(self, ul: float, action: UlPerMmAction) -> float:
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
]
|
|
591
|
-
sequence = self._active_tip_settings.aspirate.default.get(
|
|
592
|
-
self._pipetting_function_version, fallback
|
|
593
|
-
)
|
|
594
|
-
else:
|
|
595
|
-
fallback = self._active_tip_settings.dispense.default[
|
|
596
|
-
PIPETTING_FUNCTION_FALLBACK_VERSION
|
|
597
|
-
]
|
|
598
|
-
sequence = self._active_tip_settings.dispense.default.get(
|
|
599
|
-
self._pipetting_function_version, fallback
|
|
600
|
-
)
|
|
601
|
-
return piecewise_volume_conversion(ul, sequence)
|
|
592
|
+
return calculate_ul_per_mm(
|
|
593
|
+
ul, action, self._active_tip_settings, self._pipetting_function_version
|
|
594
|
+
)
|
|
602
595
|
|
|
603
596
|
def __str__(self) -> str:
|
|
604
597
|
return "{} current volume {}ul critical point: {} at {}".format(
|
|
@@ -668,8 +661,8 @@ def _reload_and_check_skip(
|
|
|
668
661
|
# Same config, good enough
|
|
669
662
|
return attached_instr, True
|
|
670
663
|
else:
|
|
671
|
-
newdict = new_config.
|
|
672
|
-
olddict = attached_instr.config.
|
|
664
|
+
newdict = new_config.model_dump()
|
|
665
|
+
olddict = attached_instr.config.model_dump()
|
|
673
666
|
changed: Set[str] = set()
|
|
674
667
|
for k in newdict.keys():
|
|
675
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
|
)
|
|
@@ -41,6 +41,8 @@ from opentrons_shared_data.pipette.types import (
|
|
|
41
41
|
UlPerMmAction,
|
|
42
42
|
PipetteName,
|
|
43
43
|
PipetteModel,
|
|
44
|
+
Quirks,
|
|
45
|
+
PipetteOEMType,
|
|
44
46
|
)
|
|
45
47
|
from opentrons_shared_data.pipette import (
|
|
46
48
|
load_data as load_pipette_data,
|
|
@@ -78,7 +80,7 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
78
80
|
use_old_aspiration_functions: bool = False,
|
|
79
81
|
) -> None:
|
|
80
82
|
self._config = config
|
|
81
|
-
self._config_as_dict = config.
|
|
83
|
+
self._config_as_dict = config.model_dump()
|
|
82
84
|
self._plunger_motor_current = config.plunger_motor_configurations
|
|
83
85
|
self._pick_up_configurations = config.pick_up_tip_configurations
|
|
84
86
|
self._plunger_homing_configurations = config.plunger_homing_configurations
|
|
@@ -92,22 +94,26 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
92
94
|
self._liquid_class_name = pip_types.LiquidClasses.default
|
|
93
95
|
self._liquid_class = self._config.liquid_properties[self._liquid_class_name]
|
|
94
96
|
|
|
97
|
+
oem = PipetteOEMType.get_oem_from_quirks(config.quirks)
|
|
95
98
|
# TODO (lc 12-05-2022) figure out how we can safely deprecate "name" and "model"
|
|
96
99
|
self._pipette_name = PipetteNameType(
|
|
97
100
|
pipette_type=config.pipette_type,
|
|
98
101
|
pipette_channels=config.channels,
|
|
99
102
|
pipette_generation=config.display_category,
|
|
103
|
+
oem_type=oem,
|
|
100
104
|
)
|
|
101
105
|
self._acting_as = self._pipette_name
|
|
102
106
|
self._pipette_model = PipetteModelVersionType(
|
|
103
107
|
pipette_type=config.pipette_type,
|
|
104
108
|
pipette_channels=config.channels,
|
|
105
109
|
pipette_version=config.version,
|
|
110
|
+
oem_type=oem,
|
|
106
111
|
)
|
|
107
112
|
self._valid_nozzle_maps = load_pipette_data.load_valid_nozzle_maps(
|
|
108
113
|
self._pipette_model.pipette_type,
|
|
109
114
|
self._pipette_model.pipette_channels,
|
|
110
115
|
self._pipette_model.pipette_version,
|
|
116
|
+
self._pipette_model.oem_type,
|
|
111
117
|
)
|
|
112
118
|
self._nozzle_offset = self._config.nozzle_offset
|
|
113
119
|
self._nozzle_manager = (
|
|
@@ -225,6 +231,9 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
225
231
|
def push_out_volume(self) -> float:
|
|
226
232
|
return self._active_tip_settings.default_push_out_volume
|
|
227
233
|
|
|
234
|
+
def is_high_speed_pipette(self) -> bool:
|
|
235
|
+
return Quirks.highSpeed in self._config.quirks
|
|
236
|
+
|
|
228
237
|
def act_as(self, name: PipetteName) -> None:
|
|
229
238
|
"""Reconfigure to act as ``name``. ``name`` must be either the
|
|
230
239
|
actual name of the pipette, or a name in its back-compatibility
|
|
@@ -246,8 +255,9 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
246
255
|
self._pipette_model.pipette_type,
|
|
247
256
|
self._pipette_model.pipette_channels,
|
|
248
257
|
self._pipette_model.pipette_version,
|
|
258
|
+
self._pipette_model.oem_type,
|
|
249
259
|
)
|
|
250
|
-
self._config_as_dict = self._config.
|
|
260
|
+
self._config_as_dict = self._config.model_dump()
|
|
251
261
|
|
|
252
262
|
def reset_state(self) -> None:
|
|
253
263
|
self._current_volume = 0.0
|
|
@@ -529,23 +539,13 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
529
539
|
# want this to unbounded.
|
|
530
540
|
@functools.lru_cache(maxsize=100)
|
|
531
541
|
def ul_per_mm(self, ul: float, action: UlPerMmAction) -> float:
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
elif action == "blowout":
|
|
540
|
-
return self._config.shaft_ul_per_mm
|
|
541
|
-
else:
|
|
542
|
-
fallback = self._active_tip_settings.dispense.default[
|
|
543
|
-
PIPETTING_FUNCTION_FALLBACK_VERSION
|
|
544
|
-
]
|
|
545
|
-
sequence = self._active_tip_settings.dispense.default.get(
|
|
546
|
-
self._pipetting_function_version, fallback
|
|
547
|
-
)
|
|
548
|
-
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
|
+
)
|
|
549
549
|
|
|
550
550
|
def __str__(self) -> str:
|
|
551
551
|
return "{} current volume {}ul critical point: {} at {}".format(
|
|
@@ -585,6 +585,7 @@ class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
|
585
585
|
"versioned_tip_overlap": self.tip_overlap,
|
|
586
586
|
"back_compat_names": self._config.pipette_backcompat_names,
|
|
587
587
|
"supported_tips": self.liquid_class.supported_tips,
|
|
588
|
+
"shaft_ul_per_mm": self._config.shaft_ul_per_mm,
|
|
588
589
|
}
|
|
589
590
|
)
|
|
590
591
|
return self._config_as_dict
|
|
@@ -775,8 +776,8 @@ def _reload_and_check_skip(
|
|
|
775
776
|
# Same config, good enough
|
|
776
777
|
return attached_instr, True
|
|
777
778
|
else:
|
|
778
|
-
newdict = new_config.
|
|
779
|
-
olddict = attached_instr.config.
|
|
779
|
+
newdict = new_config.model_dump()
|
|
780
|
+
olddict = attached_instr.config.model_dump()
|
|
780
781
|
changed: Set[str] = set()
|
|
781
782
|
for k in newdict.keys():
|
|
782
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):
|