opentrons 8.6.0a1__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.
Potentially problematic release.
This version of opentrons might be problematic. Click here for more details.
- opentrons/__init__.py +150 -0
- opentrons/_version.py +34 -0
- opentrons/calibration_storage/__init__.py +54 -0
- opentrons/calibration_storage/deck_configuration.py +62 -0
- opentrons/calibration_storage/encoder_decoder.py +31 -0
- opentrons/calibration_storage/file_operators.py +142 -0
- opentrons/calibration_storage/helpers.py +103 -0
- opentrons/calibration_storage/ot2/__init__.py +34 -0
- opentrons/calibration_storage/ot2/deck_attitude.py +85 -0
- opentrons/calibration_storage/ot2/mark_bad_calibration.py +27 -0
- opentrons/calibration_storage/ot2/models/__init__.py +0 -0
- opentrons/calibration_storage/ot2/models/v1.py +149 -0
- opentrons/calibration_storage/ot2/pipette_offset.py +129 -0
- opentrons/calibration_storage/ot2/tip_length.py +281 -0
- opentrons/calibration_storage/ot3/__init__.py +31 -0
- opentrons/calibration_storage/ot3/deck_attitude.py +83 -0
- opentrons/calibration_storage/ot3/gripper_offset.py +156 -0
- opentrons/calibration_storage/ot3/models/__init__.py +0 -0
- opentrons/calibration_storage/ot3/models/v1.py +122 -0
- opentrons/calibration_storage/ot3/module_offset.py +138 -0
- opentrons/calibration_storage/ot3/pipette_offset.py +95 -0
- opentrons/calibration_storage/types.py +45 -0
- opentrons/cli/__init__.py +21 -0
- opentrons/cli/__main__.py +5 -0
- opentrons/cli/analyze.py +501 -0
- opentrons/config/__init__.py +631 -0
- opentrons/config/advanced_settings.py +871 -0
- opentrons/config/defaults_ot2.py +214 -0
- opentrons/config/defaults_ot3.py +499 -0
- opentrons/config/feature_flags.py +86 -0
- opentrons/config/gripper_config.py +55 -0
- opentrons/config/reset.py +203 -0
- opentrons/config/robot_configs.py +187 -0
- opentrons/config/types.py +183 -0
- opentrons/drivers/__init__.py +0 -0
- opentrons/drivers/absorbance_reader/__init__.py +11 -0
- opentrons/drivers/absorbance_reader/abstract.py +72 -0
- opentrons/drivers/absorbance_reader/async_byonoy.py +352 -0
- opentrons/drivers/absorbance_reader/driver.py +81 -0
- opentrons/drivers/absorbance_reader/hid_protocol.py +161 -0
- opentrons/drivers/absorbance_reader/simulator.py +84 -0
- opentrons/drivers/asyncio/__init__.py +0 -0
- opentrons/drivers/asyncio/communication/__init__.py +22 -0
- opentrons/drivers/asyncio/communication/async_serial.py +183 -0
- opentrons/drivers/asyncio/communication/errors.py +88 -0
- opentrons/drivers/asyncio/communication/serial_connection.py +552 -0
- opentrons/drivers/command_builder.py +102 -0
- opentrons/drivers/flex_stacker/__init__.py +13 -0
- opentrons/drivers/flex_stacker/abstract.py +214 -0
- opentrons/drivers/flex_stacker/driver.py +768 -0
- opentrons/drivers/flex_stacker/errors.py +68 -0
- opentrons/drivers/flex_stacker/simulator.py +309 -0
- opentrons/drivers/flex_stacker/types.py +367 -0
- opentrons/drivers/flex_stacker/utils.py +19 -0
- opentrons/drivers/heater_shaker/__init__.py +5 -0
- opentrons/drivers/heater_shaker/abstract.py +76 -0
- opentrons/drivers/heater_shaker/driver.py +204 -0
- opentrons/drivers/heater_shaker/simulator.py +94 -0
- opentrons/drivers/mag_deck/__init__.py +6 -0
- opentrons/drivers/mag_deck/abstract.py +44 -0
- opentrons/drivers/mag_deck/driver.py +208 -0
- opentrons/drivers/mag_deck/simulator.py +63 -0
- opentrons/drivers/rpi_drivers/__init__.py +33 -0
- opentrons/drivers/rpi_drivers/dev_types.py +94 -0
- opentrons/drivers/rpi_drivers/gpio.py +282 -0
- opentrons/drivers/rpi_drivers/gpio_simulator.py +127 -0
- opentrons/drivers/rpi_drivers/interfaces.py +15 -0
- opentrons/drivers/rpi_drivers/types.py +364 -0
- opentrons/drivers/rpi_drivers/usb.py +102 -0
- opentrons/drivers/rpi_drivers/usb_simulator.py +22 -0
- opentrons/drivers/serial_communication.py +151 -0
- opentrons/drivers/smoothie_drivers/__init__.py +4 -0
- opentrons/drivers/smoothie_drivers/connection.py +51 -0
- opentrons/drivers/smoothie_drivers/constants.py +121 -0
- opentrons/drivers/smoothie_drivers/driver_3_0.py +1933 -0
- opentrons/drivers/smoothie_drivers/errors.py +49 -0
- opentrons/drivers/smoothie_drivers/parse_utils.py +143 -0
- opentrons/drivers/smoothie_drivers/simulator.py +99 -0
- opentrons/drivers/smoothie_drivers/types.py +16 -0
- opentrons/drivers/temp_deck/__init__.py +10 -0
- opentrons/drivers/temp_deck/abstract.py +54 -0
- opentrons/drivers/temp_deck/driver.py +197 -0
- opentrons/drivers/temp_deck/simulator.py +57 -0
- opentrons/drivers/thermocycler/__init__.py +12 -0
- opentrons/drivers/thermocycler/abstract.py +99 -0
- opentrons/drivers/thermocycler/driver.py +395 -0
- opentrons/drivers/thermocycler/simulator.py +126 -0
- opentrons/drivers/types.py +107 -0
- opentrons/drivers/utils.py +222 -0
- opentrons/execute.py +742 -0
- opentrons/hardware_control/__init__.py +65 -0
- opentrons/hardware_control/__main__.py +77 -0
- opentrons/hardware_control/adapters.py +98 -0
- opentrons/hardware_control/api.py +1347 -0
- opentrons/hardware_control/backends/__init__.py +7 -0
- opentrons/hardware_control/backends/controller.py +400 -0
- opentrons/hardware_control/backends/errors.py +9 -0
- opentrons/hardware_control/backends/estop_state.py +164 -0
- opentrons/hardware_control/backends/flex_protocol.py +497 -0
- opentrons/hardware_control/backends/ot3controller.py +1930 -0
- opentrons/hardware_control/backends/ot3simulator.py +900 -0
- opentrons/hardware_control/backends/ot3utils.py +664 -0
- opentrons/hardware_control/backends/simulator.py +442 -0
- opentrons/hardware_control/backends/status_bar_state.py +240 -0
- opentrons/hardware_control/backends/subsystem_manager.py +431 -0
- opentrons/hardware_control/backends/tip_presence_manager.py +173 -0
- opentrons/hardware_control/backends/types.py +14 -0
- opentrons/hardware_control/constants.py +6 -0
- opentrons/hardware_control/dev_types.py +125 -0
- opentrons/hardware_control/emulation/__init__.py +0 -0
- opentrons/hardware_control/emulation/abstract_emulator.py +21 -0
- opentrons/hardware_control/emulation/app.py +56 -0
- opentrons/hardware_control/emulation/connection_handler.py +38 -0
- opentrons/hardware_control/emulation/heater_shaker.py +150 -0
- opentrons/hardware_control/emulation/magdeck.py +60 -0
- opentrons/hardware_control/emulation/module_server/__init__.py +8 -0
- opentrons/hardware_control/emulation/module_server/client.py +78 -0
- opentrons/hardware_control/emulation/module_server/helpers.py +130 -0
- opentrons/hardware_control/emulation/module_server/models.py +31 -0
- opentrons/hardware_control/emulation/module_server/server.py +110 -0
- opentrons/hardware_control/emulation/parser.py +74 -0
- opentrons/hardware_control/emulation/proxy.py +241 -0
- opentrons/hardware_control/emulation/run_emulator.py +68 -0
- opentrons/hardware_control/emulation/scripts/__init__.py +0 -0
- opentrons/hardware_control/emulation/scripts/run_app.py +54 -0
- opentrons/hardware_control/emulation/scripts/run_module_emulator.py +72 -0
- opentrons/hardware_control/emulation/scripts/run_smoothie.py +37 -0
- opentrons/hardware_control/emulation/settings.py +119 -0
- opentrons/hardware_control/emulation/simulations.py +133 -0
- opentrons/hardware_control/emulation/smoothie.py +192 -0
- opentrons/hardware_control/emulation/tempdeck.py +69 -0
- opentrons/hardware_control/emulation/thermocycler.py +128 -0
- opentrons/hardware_control/emulation/types.py +10 -0
- opentrons/hardware_control/emulation/util.py +38 -0
- opentrons/hardware_control/errors.py +43 -0
- opentrons/hardware_control/execution_manager.py +164 -0
- opentrons/hardware_control/instruments/__init__.py +5 -0
- opentrons/hardware_control/instruments/instrument_abc.py +39 -0
- opentrons/hardware_control/instruments/ot2/__init__.py +0 -0
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +152 -0
- opentrons/hardware_control/instruments/ot2/pipette.py +777 -0
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +995 -0
- opentrons/hardware_control/instruments/ot3/__init__.py +0 -0
- opentrons/hardware_control/instruments/ot3/gripper.py +420 -0
- opentrons/hardware_control/instruments/ot3/gripper_handler.py +173 -0
- opentrons/hardware_control/instruments/ot3/instrument_calibration.py +214 -0
- opentrons/hardware_control/instruments/ot3/pipette.py +858 -0
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +1030 -0
- opentrons/hardware_control/module_control.py +332 -0
- opentrons/hardware_control/modules/__init__.py +69 -0
- opentrons/hardware_control/modules/absorbance_reader.py +373 -0
- opentrons/hardware_control/modules/errors.py +7 -0
- opentrons/hardware_control/modules/flex_stacker.py +948 -0
- opentrons/hardware_control/modules/heater_shaker.py +426 -0
- opentrons/hardware_control/modules/lid_temp_status.py +35 -0
- opentrons/hardware_control/modules/magdeck.py +233 -0
- opentrons/hardware_control/modules/mod_abc.py +245 -0
- opentrons/hardware_control/modules/module_calibration.py +93 -0
- opentrons/hardware_control/modules/plate_temp_status.py +61 -0
- opentrons/hardware_control/modules/tempdeck.py +299 -0
- opentrons/hardware_control/modules/thermocycler.py +731 -0
- opentrons/hardware_control/modules/types.py +417 -0
- opentrons/hardware_control/modules/update.py +255 -0
- opentrons/hardware_control/modules/utils.py +73 -0
- opentrons/hardware_control/motion_utilities.py +318 -0
- opentrons/hardware_control/nozzle_manager.py +422 -0
- opentrons/hardware_control/ot3_calibration.py +1171 -0
- opentrons/hardware_control/ot3api.py +3227 -0
- opentrons/hardware_control/pause_manager.py +31 -0
- opentrons/hardware_control/poller.py +112 -0
- opentrons/hardware_control/protocols/__init__.py +106 -0
- opentrons/hardware_control/protocols/asyncio_configurable.py +11 -0
- opentrons/hardware_control/protocols/calibratable.py +45 -0
- opentrons/hardware_control/protocols/chassis_accessory_manager.py +90 -0
- opentrons/hardware_control/protocols/configurable.py +48 -0
- opentrons/hardware_control/protocols/event_sourcer.py +18 -0
- opentrons/hardware_control/protocols/execution_controllable.py +33 -0
- opentrons/hardware_control/protocols/flex_calibratable.py +96 -0
- opentrons/hardware_control/protocols/flex_instrument_configurer.py +52 -0
- opentrons/hardware_control/protocols/gripper_controller.py +55 -0
- opentrons/hardware_control/protocols/hardware_manager.py +51 -0
- opentrons/hardware_control/protocols/identifiable.py +16 -0
- opentrons/hardware_control/protocols/instrument_configurer.py +206 -0
- opentrons/hardware_control/protocols/liquid_handler.py +266 -0
- opentrons/hardware_control/protocols/module_provider.py +16 -0
- opentrons/hardware_control/protocols/motion_controller.py +243 -0
- opentrons/hardware_control/protocols/position_estimator.py +45 -0
- opentrons/hardware_control/protocols/simulatable.py +10 -0
- opentrons/hardware_control/protocols/stoppable.py +9 -0
- opentrons/hardware_control/protocols/types.py +27 -0
- opentrons/hardware_control/robot_calibration.py +224 -0
- opentrons/hardware_control/scripts/README.md +28 -0
- opentrons/hardware_control/scripts/__init__.py +1 -0
- opentrons/hardware_control/scripts/gripper_control.py +208 -0
- opentrons/hardware_control/scripts/ot3gripper +7 -0
- opentrons/hardware_control/scripts/ot3repl +7 -0
- opentrons/hardware_control/scripts/repl.py +187 -0
- opentrons/hardware_control/scripts/tc_control.py +97 -0
- opentrons/hardware_control/simulator_setup.py +260 -0
- opentrons/hardware_control/thread_manager.py +431 -0
- opentrons/hardware_control/threaded_async_lock.py +97 -0
- opentrons/hardware_control/types.py +792 -0
- opentrons/hardware_control/util.py +234 -0
- opentrons/legacy_broker.py +53 -0
- opentrons/legacy_commands/__init__.py +1 -0
- opentrons/legacy_commands/commands.py +483 -0
- opentrons/legacy_commands/helpers.py +153 -0
- opentrons/legacy_commands/module_commands.py +215 -0
- opentrons/legacy_commands/protocol_commands.py +54 -0
- opentrons/legacy_commands/publisher.py +155 -0
- opentrons/legacy_commands/robot_commands.py +51 -0
- opentrons/legacy_commands/types.py +1115 -0
- opentrons/motion_planning/__init__.py +32 -0
- opentrons/motion_planning/adjacent_slots_getters.py +168 -0
- opentrons/motion_planning/deck_conflict.py +396 -0
- opentrons/motion_planning/errors.py +35 -0
- opentrons/motion_planning/types.py +42 -0
- opentrons/motion_planning/waypoints.py +218 -0
- opentrons/ordered_set.py +138 -0
- opentrons/protocol_api/__init__.py +105 -0
- opentrons/protocol_api/_liquid.py +157 -0
- opentrons/protocol_api/_liquid_properties.py +814 -0
- opentrons/protocol_api/_nozzle_layout.py +31 -0
- opentrons/protocol_api/_parameter_context.py +300 -0
- opentrons/protocol_api/_parameters.py +31 -0
- opentrons/protocol_api/_transfer_liquid_validation.py +108 -0
- opentrons/protocol_api/_types.py +43 -0
- opentrons/protocol_api/config.py +23 -0
- opentrons/protocol_api/core/__init__.py +23 -0
- opentrons/protocol_api/core/common.py +33 -0
- opentrons/protocol_api/core/core_map.py +74 -0
- opentrons/protocol_api/core/engine/__init__.py +22 -0
- opentrons/protocol_api/core/engine/_default_labware_versions.py +179 -0
- opentrons/protocol_api/core/engine/deck_conflict.py +348 -0
- opentrons/protocol_api/core/engine/exceptions.py +19 -0
- opentrons/protocol_api/core/engine/instrument.py +2391 -0
- opentrons/protocol_api/core/engine/labware.py +238 -0
- opentrons/protocol_api/core/engine/load_labware_params.py +73 -0
- opentrons/protocol_api/core/engine/module_core.py +1025 -0
- opentrons/protocol_api/core/engine/overlap_versions.py +20 -0
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +358 -0
- opentrons/protocol_api/core/engine/point_calculations.py +64 -0
- opentrons/protocol_api/core/engine/protocol.py +1153 -0
- opentrons/protocol_api/core/engine/robot.py +139 -0
- opentrons/protocol_api/core/engine/stringify.py +74 -0
- opentrons/protocol_api/core/engine/transfer_components_executor.py +990 -0
- opentrons/protocol_api/core/engine/well.py +241 -0
- opentrons/protocol_api/core/instrument.py +459 -0
- opentrons/protocol_api/core/labware.py +151 -0
- opentrons/protocol_api/core/legacy/__init__.py +11 -0
- opentrons/protocol_api/core/legacy/_labware_geometry.py +37 -0
- opentrons/protocol_api/core/legacy/deck.py +369 -0
- opentrons/protocol_api/core/legacy/labware_offset_provider.py +108 -0
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +709 -0
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +235 -0
- opentrons/protocol_api/core/legacy/legacy_module_core.py +592 -0
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +612 -0
- opentrons/protocol_api/core/legacy/legacy_well_core.py +162 -0
- opentrons/protocol_api/core/legacy/load_info.py +67 -0
- opentrons/protocol_api/core/legacy/module_geometry.py +547 -0
- opentrons/protocol_api/core/legacy/well_geometry.py +148 -0
- opentrons/protocol_api/core/legacy_simulator/__init__.py +16 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +624 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +85 -0
- opentrons/protocol_api/core/module.py +484 -0
- opentrons/protocol_api/core/protocol.py +311 -0
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/core/well.py +116 -0
- opentrons/protocol_api/core/well_grid.py +45 -0
- opentrons/protocol_api/create_protocol_context.py +177 -0
- opentrons/protocol_api/deck.py +223 -0
- opentrons/protocol_api/disposal_locations.py +244 -0
- opentrons/protocol_api/instrument_context.py +3212 -0
- opentrons/protocol_api/labware.py +1579 -0
- opentrons/protocol_api/module_contexts.py +1425 -0
- opentrons/protocol_api/module_validation_and_errors.py +61 -0
- opentrons/protocol_api/protocol_context.py +1688 -0
- opentrons/protocol_api/robot_context.py +303 -0
- opentrons/protocol_api/validation.py +761 -0
- opentrons/protocol_engine/__init__.py +155 -0
- opentrons/protocol_engine/actions/__init__.py +65 -0
- opentrons/protocol_engine/actions/action_dispatcher.py +30 -0
- opentrons/protocol_engine/actions/action_handler.py +13 -0
- opentrons/protocol_engine/actions/actions.py +302 -0
- opentrons/protocol_engine/actions/get_state_update.py +38 -0
- opentrons/protocol_engine/clients/__init__.py +5 -0
- opentrons/protocol_engine/clients/sync_client.py +174 -0
- opentrons/protocol_engine/clients/transports.py +197 -0
- opentrons/protocol_engine/commands/__init__.py +757 -0
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +61 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +154 -0
- opentrons/protocol_engine/commands/absorbance_reader/common.py +6 -0
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +151 -0
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +154 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +226 -0
- opentrons/protocol_engine/commands/air_gap_in_place.py +162 -0
- opentrons/protocol_engine/commands/aspirate.py +244 -0
- opentrons/protocol_engine/commands/aspirate_in_place.py +184 -0
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +211 -0
- opentrons/protocol_engine/commands/blow_out.py +146 -0
- opentrons/protocol_engine/commands/blow_out_in_place.py +119 -0
- opentrons/protocol_engine/commands/calibration/__init__.py +60 -0
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +166 -0
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +117 -0
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +96 -0
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +156 -0
- opentrons/protocol_engine/commands/command.py +308 -0
- opentrons/protocol_engine/commands/command_unions.py +974 -0
- opentrons/protocol_engine/commands/comment.py +57 -0
- opentrons/protocol_engine/commands/configure_for_volume.py +108 -0
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +115 -0
- opentrons/protocol_engine/commands/custom.py +67 -0
- opentrons/protocol_engine/commands/dispense.py +194 -0
- opentrons/protocol_engine/commands/dispense_in_place.py +179 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
- opentrons/protocol_engine/commands/drop_tip.py +232 -0
- opentrons/protocol_engine/commands/drop_tip_in_place.py +205 -0
- opentrons/protocol_engine/commands/flex_stacker/__init__.py +64 -0
- opentrons/protocol_engine/commands/flex_stacker/common.py +900 -0
- opentrons/protocol_engine/commands/flex_stacker/empty.py +293 -0
- opentrons/protocol_engine/commands/flex_stacker/fill.py +281 -0
- opentrons/protocol_engine/commands/flex_stacker/retrieve.py +339 -0
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +328 -0
- opentrons/protocol_engine/commands/flex_stacker/store.py +326 -0
- opentrons/protocol_engine/commands/generate_command_schema.py +61 -0
- opentrons/protocol_engine/commands/get_next_tip.py +134 -0
- opentrons/protocol_engine/commands/get_tip_presence.py +87 -0
- opentrons/protocol_engine/commands/hash_command_params.py +38 -0
- opentrons/protocol_engine/commands/heater_shaker/__init__.py +102 -0
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +83 -0
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +82 -0
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +84 -0
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +110 -0
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +125 -0
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +90 -0
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +102 -0
- opentrons/protocol_engine/commands/home.py +100 -0
- opentrons/protocol_engine/commands/identify_module.py +86 -0
- opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
- opentrons/protocol_engine/commands/liquid_probe.py +464 -0
- opentrons/protocol_engine/commands/load_labware.py +210 -0
- opentrons/protocol_engine/commands/load_lid.py +154 -0
- opentrons/protocol_engine/commands/load_lid_stack.py +272 -0
- opentrons/protocol_engine/commands/load_liquid.py +95 -0
- opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
- opentrons/protocol_engine/commands/load_module.py +223 -0
- opentrons/protocol_engine/commands/load_pipette.py +167 -0
- opentrons/protocol_engine/commands/magnetic_module/__init__.py +32 -0
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +97 -0
- opentrons/protocol_engine/commands/magnetic_module/engage.py +119 -0
- opentrons/protocol_engine/commands/move_labware.py +546 -0
- opentrons/protocol_engine/commands/move_relative.py +102 -0
- opentrons/protocol_engine/commands/move_to_addressable_area.py +176 -0
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +198 -0
- opentrons/protocol_engine/commands/move_to_coordinates.py +107 -0
- opentrons/protocol_engine/commands/move_to_well.py +119 -0
- opentrons/protocol_engine/commands/movement_common.py +338 -0
- opentrons/protocol_engine/commands/pick_up_tip.py +241 -0
- opentrons/protocol_engine/commands/pipetting_common.py +443 -0
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +121 -0
- opentrons/protocol_engine/commands/pressure_dispense.py +155 -0
- opentrons/protocol_engine/commands/reload_labware.py +90 -0
- opentrons/protocol_engine/commands/retract_axis.py +75 -0
- opentrons/protocol_engine/commands/robot/__init__.py +70 -0
- opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +96 -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 +86 -0
- opentrons/protocol_engine/commands/save_position.py +109 -0
- opentrons/protocol_engine/commands/seal_pipette_to_tip.py +353 -0
- opentrons/protocol_engine/commands/set_rail_lights.py +67 -0
- opentrons/protocol_engine/commands/set_status_bar.py +89 -0
- opentrons/protocol_engine/commands/temperature_module/__init__.py +46 -0
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +86 -0
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +97 -0
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +104 -0
- opentrons/protocol_engine/commands/thermocycler/__init__.py +152 -0
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +87 -0
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +80 -0
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +80 -0
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +87 -0
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +171 -0
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +124 -0
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +140 -0
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +100 -0
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +93 -0
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +89 -0
- opentrons/protocol_engine/commands/touch_tip.py +189 -0
- opentrons/protocol_engine/commands/unsafe/__init__.py +161 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +100 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +121 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +82 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_close_latch.py +94 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_manual_retrieve.py +295 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_open_latch.py +91 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_prepare_shuttle.py +136 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +90 -0
- opentrons/protocol_engine/commands/unseal_pipette_from_tip.py +153 -0
- opentrons/protocol_engine/commands/verify_tip_presence.py +100 -0
- opentrons/protocol_engine/commands/wait_for_duration.py +76 -0
- opentrons/protocol_engine/commands/wait_for_resume.py +75 -0
- opentrons/protocol_engine/create_protocol_engine.py +193 -0
- opentrons/protocol_engine/engine_support.py +28 -0
- opentrons/protocol_engine/error_recovery_policy.py +81 -0
- opentrons/protocol_engine/errors/__init__.py +191 -0
- opentrons/protocol_engine/errors/error_occurrence.py +182 -0
- opentrons/protocol_engine/errors/exceptions.py +1308 -0
- opentrons/protocol_engine/execution/__init__.py +50 -0
- opentrons/protocol_engine/execution/command_executor.py +216 -0
- opentrons/protocol_engine/execution/create_queue_worker.py +102 -0
- opentrons/protocol_engine/execution/door_watcher.py +119 -0
- opentrons/protocol_engine/execution/equipment.py +819 -0
- opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
- opentrons/protocol_engine/execution/gantry_mover.py +686 -0
- opentrons/protocol_engine/execution/hardware_stopper.py +147 -0
- opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +207 -0
- opentrons/protocol_engine/execution/labware_movement.py +297 -0
- opentrons/protocol_engine/execution/movement.py +349 -0
- opentrons/protocol_engine/execution/pipetting.py +607 -0
- opentrons/protocol_engine/execution/queue_worker.py +86 -0
- opentrons/protocol_engine/execution/rail_lights.py +25 -0
- opentrons/protocol_engine/execution/run_control.py +33 -0
- opentrons/protocol_engine/execution/status_bar.py +34 -0
- opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +188 -0
- opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +81 -0
- opentrons/protocol_engine/execution/tip_handler.py +550 -0
- opentrons/protocol_engine/labware_offset_standardization.py +194 -0
- opentrons/protocol_engine/notes/__init__.py +17 -0
- opentrons/protocol_engine/notes/notes.py +59 -0
- opentrons/protocol_engine/plugins.py +104 -0
- opentrons/protocol_engine/protocol_engine.py +683 -0
- opentrons/protocol_engine/resources/__init__.py +26 -0
- opentrons/protocol_engine/resources/deck_configuration_provider.py +232 -0
- opentrons/protocol_engine/resources/deck_data_provider.py +94 -0
- opentrons/protocol_engine/resources/file_provider.py +161 -0
- opentrons/protocol_engine/resources/fixture_validation.py +58 -0
- opentrons/protocol_engine/resources/labware_data_provider.py +106 -0
- opentrons/protocol_engine/resources/labware_validation.py +73 -0
- opentrons/protocol_engine/resources/model_utils.py +32 -0
- opentrons/protocol_engine/resources/module_data_provider.py +44 -0
- opentrons/protocol_engine/resources/ot3_validation.py +21 -0
- opentrons/protocol_engine/resources/pipette_data_provider.py +379 -0
- opentrons/protocol_engine/slot_standardization.py +128 -0
- opentrons/protocol_engine/state/__init__.py +1 -0
- opentrons/protocol_engine/state/_abstract_store.py +27 -0
- opentrons/protocol_engine/state/_axis_aligned_bounding_box.py +50 -0
- opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
- opentrons/protocol_engine/state/_move_types.py +83 -0
- opentrons/protocol_engine/state/_well_math.py +193 -0
- opentrons/protocol_engine/state/addressable_areas.py +699 -0
- opentrons/protocol_engine/state/command_history.py +309 -0
- opentrons/protocol_engine/state/commands.py +1158 -0
- opentrons/protocol_engine/state/config.py +39 -0
- opentrons/protocol_engine/state/files.py +57 -0
- opentrons/protocol_engine/state/fluid_stack.py +138 -0
- opentrons/protocol_engine/state/geometry.py +2359 -0
- opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
- opentrons/protocol_engine/state/labware.py +1459 -0
- opentrons/protocol_engine/state/liquid_classes.py +82 -0
- opentrons/protocol_engine/state/liquids.py +73 -0
- opentrons/protocol_engine/state/module_substates/__init__.py +45 -0
- opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +35 -0
- opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +112 -0
- opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +115 -0
- opentrons/protocol_engine/state/module_substates/magnetic_block_substate.py +17 -0
- opentrons/protocol_engine/state/module_substates/magnetic_module_substate.py +65 -0
- opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +67 -0
- opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +163 -0
- opentrons/protocol_engine/state/modules.py +1500 -0
- opentrons/protocol_engine/state/motion.py +373 -0
- opentrons/protocol_engine/state/pipettes.py +905 -0
- opentrons/protocol_engine/state/state.py +421 -0
- opentrons/protocol_engine/state/state_summary.py +36 -0
- opentrons/protocol_engine/state/tips.py +420 -0
- opentrons/protocol_engine/state/update_types.py +904 -0
- opentrons/protocol_engine/state/wells.py +290 -0
- opentrons/protocol_engine/types/__init__.py +308 -0
- opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
- opentrons/protocol_engine/types/command_annotations.py +53 -0
- opentrons/protocol_engine/types/deck_configuration.py +81 -0
- opentrons/protocol_engine/types/execution.py +96 -0
- opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
- opentrons/protocol_engine/types/instrument.py +47 -0
- opentrons/protocol_engine/types/instrument_sensors.py +47 -0
- opentrons/protocol_engine/types/labware.py +131 -0
- opentrons/protocol_engine/types/labware_movement.py +22 -0
- opentrons/protocol_engine/types/labware_offset_location.py +111 -0
- opentrons/protocol_engine/types/labware_offset_vector.py +16 -0
- opentrons/protocol_engine/types/liquid.py +40 -0
- opentrons/protocol_engine/types/liquid_class.py +59 -0
- opentrons/protocol_engine/types/liquid_handling.py +13 -0
- opentrons/protocol_engine/types/liquid_level_detection.py +191 -0
- opentrons/protocol_engine/types/location.py +194 -0
- opentrons/protocol_engine/types/module.py +303 -0
- opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
- opentrons/protocol_engine/types/run_time_parameters.py +133 -0
- opentrons/protocol_engine/types/tip.py +18 -0
- opentrons/protocol_engine/types/util.py +21 -0
- opentrons/protocol_engine/types/well_position.py +124 -0
- opentrons/protocol_reader/__init__.py +37 -0
- opentrons/protocol_reader/extract_labware_definitions.py +66 -0
- opentrons/protocol_reader/file_format_validator.py +152 -0
- opentrons/protocol_reader/file_hasher.py +27 -0
- opentrons/protocol_reader/file_identifier.py +284 -0
- opentrons/protocol_reader/file_reader_writer.py +90 -0
- opentrons/protocol_reader/input_file.py +16 -0
- opentrons/protocol_reader/protocol_files_invalid_error.py +6 -0
- opentrons/protocol_reader/protocol_reader.py +188 -0
- opentrons/protocol_reader/protocol_source.py +124 -0
- opentrons/protocol_reader/role_analyzer.py +86 -0
- opentrons/protocol_runner/__init__.py +26 -0
- opentrons/protocol_runner/create_simulating_orchestrator.py +118 -0
- opentrons/protocol_runner/json_file_reader.py +55 -0
- opentrons/protocol_runner/json_translator.py +314 -0
- opentrons/protocol_runner/legacy_command_mapper.py +848 -0
- opentrons/protocol_runner/legacy_context_plugin.py +116 -0
- opentrons/protocol_runner/protocol_runner.py +530 -0
- opentrons/protocol_runner/python_protocol_wrappers.py +179 -0
- opentrons/protocol_runner/run_orchestrator.py +496 -0
- opentrons/protocol_runner/task_queue.py +95 -0
- opentrons/protocols/__init__.py +6 -0
- opentrons/protocols/advanced_control/__init__.py +0 -0
- opentrons/protocols/advanced_control/common.py +38 -0
- opentrons/protocols/advanced_control/mix.py +60 -0
- opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
- opentrons/protocols/advanced_control/transfers/common.py +180 -0
- opentrons/protocols/advanced_control/transfers/transfer.py +972 -0
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +231 -0
- opentrons/protocols/api_support/__init__.py +0 -0
- opentrons/protocols/api_support/constants.py +8 -0
- opentrons/protocols/api_support/deck_type.py +110 -0
- opentrons/protocols/api_support/definitions.py +18 -0
- opentrons/protocols/api_support/instrument.py +151 -0
- opentrons/protocols/api_support/labware_like.py +233 -0
- opentrons/protocols/api_support/tip_tracker.py +175 -0
- opentrons/protocols/api_support/types.py +32 -0
- opentrons/protocols/api_support/util.py +403 -0
- opentrons/protocols/bundle.py +89 -0
- opentrons/protocols/duration/__init__.py +4 -0
- opentrons/protocols/duration/errors.py +5 -0
- opentrons/protocols/duration/estimator.py +628 -0
- opentrons/protocols/execution/__init__.py +0 -0
- opentrons/protocols/execution/dev_types.py +181 -0
- opentrons/protocols/execution/errors.py +40 -0
- opentrons/protocols/execution/execute.py +84 -0
- opentrons/protocols/execution/execute_json_v3.py +275 -0
- opentrons/protocols/execution/execute_json_v4.py +359 -0
- opentrons/protocols/execution/execute_json_v5.py +28 -0
- opentrons/protocols/execution/execute_python.py +169 -0
- opentrons/protocols/execution/json_dispatchers.py +87 -0
- opentrons/protocols/execution/types.py +7 -0
- opentrons/protocols/geometry/__init__.py +0 -0
- opentrons/protocols/geometry/planning.py +297 -0
- opentrons/protocols/labware.py +312 -0
- opentrons/protocols/models/__init__.py +0 -0
- opentrons/protocols/models/json_protocol.py +679 -0
- opentrons/protocols/parameters/__init__.py +0 -0
- opentrons/protocols/parameters/csv_parameter_definition.py +77 -0
- opentrons/protocols/parameters/csv_parameter_interface.py +96 -0
- opentrons/protocols/parameters/exceptions.py +34 -0
- opentrons/protocols/parameters/parameter_definition.py +272 -0
- opentrons/protocols/parameters/types.py +17 -0
- opentrons/protocols/parameters/validation.py +267 -0
- opentrons/protocols/parse.py +671 -0
- opentrons/protocols/types.py +159 -0
- opentrons/py.typed +0 -0
- opentrons/resources/scripts/lpc21isp +0 -0
- opentrons/resources/smoothie-edge-8414642.hex +23010 -0
- opentrons/simulate.py +1065 -0
- opentrons/system/__init__.py +6 -0
- opentrons/system/camera.py +51 -0
- opentrons/system/log_control.py +59 -0
- opentrons/system/nmcli.py +856 -0
- opentrons/system/resin.py +24 -0
- opentrons/system/smoothie_update.py +15 -0
- opentrons/system/wifi.py +204 -0
- opentrons/tools/__init__.py +0 -0
- opentrons/tools/args_handler.py +22 -0
- opentrons/tools/write_pipette_memory.py +157 -0
- opentrons/types.py +618 -0
- opentrons/util/__init__.py +1 -0
- opentrons/util/async_helpers.py +166 -0
- opentrons/util/broker.py +84 -0
- opentrons/util/change_notifier.py +47 -0
- opentrons/util/entrypoint_util.py +278 -0
- opentrons/util/get_union_elements.py +26 -0
- opentrons/util/helpers.py +6 -0
- opentrons/util/linal.py +178 -0
- opentrons/util/logging_config.py +265 -0
- opentrons/util/logging_queue_handler.py +61 -0
- opentrons/util/performance_helpers.py +157 -0
- opentrons-8.6.0a1.dist-info/METADATA +37 -0
- opentrons-8.6.0a1.dist-info/RECORD +600 -0
- opentrons-8.6.0a1.dist-info/WHEEL +4 -0
- opentrons-8.6.0a1.dist-info/entry_points.txt +3 -0
- opentrons-8.6.0a1.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,777 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
|
|
5
|
+
""" Classes and functions for pipette state tracking
|
|
6
|
+
"""
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Any, Dict, Optional, Set, Tuple, Union, cast
|
|
9
|
+
|
|
10
|
+
from opentrons_shared_data.pipette.pipette_definition import (
|
|
11
|
+
PipetteConfigurations,
|
|
12
|
+
PlungerPositions,
|
|
13
|
+
MotorConfigurations,
|
|
14
|
+
SupportedTipsDefinition,
|
|
15
|
+
PickUpTipConfigurations,
|
|
16
|
+
DropTipConfigurations,
|
|
17
|
+
PipetteModelVersionType,
|
|
18
|
+
PipetteNameType,
|
|
19
|
+
PipetteLiquidPropertiesDefinition,
|
|
20
|
+
PressFitPickUpTipConfiguration,
|
|
21
|
+
)
|
|
22
|
+
from opentrons_shared_data.pipette import (
|
|
23
|
+
load_data as load_pipette_data,
|
|
24
|
+
types as pip_types,
|
|
25
|
+
)
|
|
26
|
+
from opentrons_shared_data.errors.exceptions import (
|
|
27
|
+
InvalidLiquidClassName,
|
|
28
|
+
CommandPreconditionViolated,
|
|
29
|
+
)
|
|
30
|
+
from opentrons_shared_data.pipette.ul_per_mm import (
|
|
31
|
+
calculate_ul_per_mm,
|
|
32
|
+
PIPETTING_FUNCTION_FALLBACK_VERSION,
|
|
33
|
+
PIPETTING_FUNCTION_LATEST_VERSION,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
from opentrons.types import Point, Mount
|
|
38
|
+
from opentrons.config import robot_configs
|
|
39
|
+
from opentrons.config.types import RobotConfig
|
|
40
|
+
from opentrons.drivers.types import MoveSplit
|
|
41
|
+
from ..instrument_abc import AbstractInstrument
|
|
42
|
+
|
|
43
|
+
from .instrument_calibration import (
|
|
44
|
+
PipetteOffsetByPipetteMount,
|
|
45
|
+
load_pipette_offset,
|
|
46
|
+
)
|
|
47
|
+
from opentrons.hardware_control.types import (
|
|
48
|
+
CriticalPoint,
|
|
49
|
+
BoardRevision,
|
|
50
|
+
)
|
|
51
|
+
from opentrons.hardware_control.errors import InvalidCriticalPoint
|
|
52
|
+
from opentrons.hardware_control import nozzle_manager
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
from opentrons_shared_data.pipette.types import (
|
|
56
|
+
UlPerMmAction,
|
|
57
|
+
PipetteName,
|
|
58
|
+
PipetteModel,
|
|
59
|
+
PipetteOEMType,
|
|
60
|
+
)
|
|
61
|
+
from opentrons.hardware_control.dev_types import InstrumentHardwareConfigs
|
|
62
|
+
|
|
63
|
+
from opentrons.hardware_control.util import (
|
|
64
|
+
pick_up_speed_by_configuration,
|
|
65
|
+
pick_up_distance_by_configuration,
|
|
66
|
+
pick_up_current_by_configuration,
|
|
67
|
+
nominal_tip_overlap_dictionary_by_configuration,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
RECONFIG_KEYS = {"quirks"}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
mod_log = logging.getLogger(__name__)
|
|
74
|
+
|
|
75
|
+
# TODO (lc 11-1-2022) Once we unify calibration loading
|
|
76
|
+
# for the hardware controller, we will be able to
|
|
77
|
+
# unify the pipette classes again.
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Pipette(AbstractInstrument[PipetteConfigurations]):
|
|
81
|
+
"""A class to gather and track pipette state and configs.
|
|
82
|
+
|
|
83
|
+
This class should not touch hardware or call back out to the hardware
|
|
84
|
+
control API. Its only purpose is to gather state.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
DictType = Dict[
|
|
88
|
+
str, Union[str, float, bool]
|
|
89
|
+
] # spp: as_dict() has value items that aren't Union[str, float, bool]..
|
|
90
|
+
#: The type of this data class as a dict
|
|
91
|
+
|
|
92
|
+
def __init__(
|
|
93
|
+
self,
|
|
94
|
+
config: PipetteConfigurations,
|
|
95
|
+
pipette_offset_cal: PipetteOffsetByPipetteMount,
|
|
96
|
+
pipette_id: Optional[str] = None,
|
|
97
|
+
use_old_aspiration_functions: bool = False,
|
|
98
|
+
) -> None:
|
|
99
|
+
self._config = config
|
|
100
|
+
self._config_as_dict = config.model_dump()
|
|
101
|
+
self._pipette_offset = pipette_offset_cal
|
|
102
|
+
self._pipette_type = self._config.pipette_type
|
|
103
|
+
self._pipette_version = self._config.version
|
|
104
|
+
self._max_channels = self._config.channels
|
|
105
|
+
self._backlash_distance = config.backlash_distance
|
|
106
|
+
self._pick_up_configurations = config.pick_up_tip_configurations
|
|
107
|
+
|
|
108
|
+
self._liquid_class_name = pip_types.LiquidClasses.default
|
|
109
|
+
self._liquid_class = self._config.liquid_properties[self._liquid_class_name]
|
|
110
|
+
|
|
111
|
+
# TODO (lc 12-05-2022) figure out how we can safely deprecate "name" and "model"
|
|
112
|
+
self._pipette_name = PipetteNameType(
|
|
113
|
+
pipette_type=config.pipette_type,
|
|
114
|
+
pipette_channels=config.channels,
|
|
115
|
+
pipette_generation=config.display_category,
|
|
116
|
+
oem_type=PipetteOEMType.OT,
|
|
117
|
+
)
|
|
118
|
+
self._acting_as = self._pipette_name
|
|
119
|
+
self._pipette_model = PipetteModelVersionType(
|
|
120
|
+
pipette_type=config.pipette_type,
|
|
121
|
+
pipette_channels=config.channels,
|
|
122
|
+
pipette_version=config.version,
|
|
123
|
+
oem_type=PipetteOEMType.OT,
|
|
124
|
+
)
|
|
125
|
+
self._valid_nozzle_maps = load_pipette_data.load_valid_nozzle_maps(
|
|
126
|
+
self._pipette_model.pipette_type,
|
|
127
|
+
self._pipette_model.pipette_channels,
|
|
128
|
+
self._pipette_model.pipette_version,
|
|
129
|
+
PipetteOEMType.OT,
|
|
130
|
+
)
|
|
131
|
+
self._nozzle_offset = self._config.nozzle_offset
|
|
132
|
+
self._nozzle_manager = (
|
|
133
|
+
nozzle_manager.NozzleConfigurationManager.build_from_config(
|
|
134
|
+
self._config, self._valid_nozzle_maps
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
self._current_volume = 0.0
|
|
138
|
+
self._working_volume = float(self._liquid_class.max_volume)
|
|
139
|
+
self._current_tip_length = 0.0
|
|
140
|
+
self._current_tiprack_diameter = 0.0
|
|
141
|
+
self._has_tip = False
|
|
142
|
+
self._pipette_id = pipette_id
|
|
143
|
+
self._log = mod_log.getChild(
|
|
144
|
+
self._pipette_id if self._pipette_id else "<unknown>"
|
|
145
|
+
)
|
|
146
|
+
self._log.info(
|
|
147
|
+
"loaded: {}, pipette offset: {}".format(
|
|
148
|
+
self._pipette_model, self._pipette_offset.offset
|
|
149
|
+
)
|
|
150
|
+
)
|
|
151
|
+
self.ready_to_aspirate = False
|
|
152
|
+
#: True if ready to aspirate
|
|
153
|
+
|
|
154
|
+
self._active_tip_settings = self._liquid_class.supported_tips[
|
|
155
|
+
pip_types.PipetteTipType(self._liquid_class.max_volume)
|
|
156
|
+
]
|
|
157
|
+
self._fallback_tip_length = self._active_tip_settings.default_tip_length
|
|
158
|
+
|
|
159
|
+
self._aspirate_flow_rate = (
|
|
160
|
+
self._active_tip_settings.default_aspirate_flowrate.default
|
|
161
|
+
)
|
|
162
|
+
self._dispense_flow_rate = (
|
|
163
|
+
self._active_tip_settings.default_dispense_flowrate.default
|
|
164
|
+
)
|
|
165
|
+
self._blow_out_flow_rate = (
|
|
166
|
+
self._active_tip_settings.default_blowout_flowrate.default
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
self._versioned_tip_overlap_dictionary = (
|
|
170
|
+
self.get_nominal_tip_overlap_dictionary_by_configuration()
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
if use_old_aspiration_functions:
|
|
174
|
+
self._pipetting_function_version = PIPETTING_FUNCTION_FALLBACK_VERSION
|
|
175
|
+
else:
|
|
176
|
+
self._pipetting_function_version = PIPETTING_FUNCTION_LATEST_VERSION
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def push_out_volume(self) -> float:
|
|
180
|
+
return self._active_tip_settings.default_push_out_volume
|
|
181
|
+
|
|
182
|
+
def act_as(self, name: PipetteNameType) -> None:
|
|
183
|
+
"""Reconfigure to act as ``name``. ``name`` must be either the
|
|
184
|
+
actual name of the pipette, or a name in its back-compatibility
|
|
185
|
+
config.
|
|
186
|
+
"""
|
|
187
|
+
if name == self._acting_as:
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
str_name = f"{name.pipette_type.name}_{str(name.pipette_channels)}"
|
|
191
|
+
assert str_name in self._config.pipette_backcompat_names + [
|
|
192
|
+
self.name
|
|
193
|
+
], f"{self.name} is not back-compatible with {name}"
|
|
194
|
+
|
|
195
|
+
liquid_model = load_pipette_data.load_liquid_model(
|
|
196
|
+
name.pipette_type, name.pipette_channels, name.get_version(), name.oem_type
|
|
197
|
+
)
|
|
198
|
+
# TODO need to grab name config here to deal with act as test
|
|
199
|
+
self._liquid_class.max_volume = liquid_model["default"].max_volume
|
|
200
|
+
self._liquid_class.min_volume = liquid_model["default"].min_volume
|
|
201
|
+
self.working_volume = liquid_model["default"].max_volume
|
|
202
|
+
self.update_config_item(
|
|
203
|
+
{
|
|
204
|
+
"min_volume": liquid_model["default"].min_volume,
|
|
205
|
+
"max_volume": liquid_model["default"].max_volume,
|
|
206
|
+
},
|
|
207
|
+
pip_types.LiquidClasses.default,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
@property
|
|
211
|
+
def acting_as(self) -> PipetteNameType:
|
|
212
|
+
return self._acting_as
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def config(self) -> PipetteConfigurations:
|
|
216
|
+
return self._config
|
|
217
|
+
|
|
218
|
+
@property
|
|
219
|
+
def liquid_class(self) -> PipetteLiquidPropertiesDefinition:
|
|
220
|
+
return self._liquid_class
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def liquid_class_name(self) -> pip_types.LiquidClasses:
|
|
224
|
+
return self._liquid_class_name
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def nozzle_offset(self) -> Point:
|
|
228
|
+
return self._nozzle_manager.starting_nozzle_offset
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def nozzle_manager(self) -> nozzle_manager.NozzleConfigurationManager:
|
|
232
|
+
return self._nozzle_manager
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def pipette_offset(self) -> PipetteOffsetByPipetteMount:
|
|
236
|
+
return self._pipette_offset
|
|
237
|
+
|
|
238
|
+
@property
|
|
239
|
+
def tip_overlap(self) -> Dict[str, Dict[str, float]]:
|
|
240
|
+
return self._versioned_tip_overlap_dictionary
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
def channels(self) -> pip_types.PipetteChannelType:
|
|
244
|
+
return self._max_channels
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def plunger_positions(self) -> PlungerPositions:
|
|
248
|
+
return self._config.plunger_positions_configurations[self._liquid_class_name]
|
|
249
|
+
|
|
250
|
+
@property
|
|
251
|
+
def plunger_motor_current(self) -> MotorConfigurations:
|
|
252
|
+
return self._config.plunger_motor_configurations
|
|
253
|
+
|
|
254
|
+
@property
|
|
255
|
+
def pick_up_configurations(self) -> PickUpTipConfigurations:
|
|
256
|
+
return self._config.pick_up_tip_configurations
|
|
257
|
+
|
|
258
|
+
@pick_up_configurations.setter
|
|
259
|
+
def pick_up_configurations(self, pick_up_configs: PickUpTipConfigurations) -> None:
|
|
260
|
+
self._pick_up_configurations = pick_up_configs
|
|
261
|
+
|
|
262
|
+
@property
|
|
263
|
+
def drop_configurations(self) -> DropTipConfigurations:
|
|
264
|
+
return self._config.drop_tip_configurations
|
|
265
|
+
|
|
266
|
+
@property
|
|
267
|
+
def active_tip_settings(self) -> SupportedTipsDefinition:
|
|
268
|
+
return self._active_tip_settings
|
|
269
|
+
|
|
270
|
+
def update_config_item(
|
|
271
|
+
self,
|
|
272
|
+
elements: Dict[str, Any],
|
|
273
|
+
liquid_class: Optional[pip_types.LiquidClasses] = None,
|
|
274
|
+
) -> None:
|
|
275
|
+
self._log.info(f"updated config: {elements}")
|
|
276
|
+
self._config = load_pipette_data.update_pipette_configuration(
|
|
277
|
+
self._config, elements, liquid_class
|
|
278
|
+
)
|
|
279
|
+
# Update the cached dict representation
|
|
280
|
+
self._config_as_dict = self._config.model_dump()
|
|
281
|
+
|
|
282
|
+
def reload_configurations(self) -> None:
|
|
283
|
+
self._config = load_pipette_data.load_definition(
|
|
284
|
+
self._pipette_model.pipette_type,
|
|
285
|
+
self._pipette_model.pipette_channels,
|
|
286
|
+
self._pipette_model.pipette_version,
|
|
287
|
+
self._pipette_model.oem_type,
|
|
288
|
+
)
|
|
289
|
+
self._config_as_dict = self._config.model_dump()
|
|
290
|
+
|
|
291
|
+
def reset_state(self) -> None:
|
|
292
|
+
self._current_volume = 0.0
|
|
293
|
+
self._working_volume = float(self.liquid_class.max_volume)
|
|
294
|
+
self._current_tip_length = 0.0
|
|
295
|
+
self._current_tiprack_diameter = 0.0
|
|
296
|
+
self._has_tip = False
|
|
297
|
+
self.ready_to_aspirate = False
|
|
298
|
+
#: True if ready to aspirate
|
|
299
|
+
self._active_tip_settings = self.liquid_class.supported_tips[
|
|
300
|
+
pip_types.PipetteTipType(self._working_volume)
|
|
301
|
+
]
|
|
302
|
+
self._fallback_tip_length = self.active_tip_settings.default_tip_length
|
|
303
|
+
|
|
304
|
+
self._aspirate_flow_rate = (
|
|
305
|
+
self.active_tip_settings.default_aspirate_flowrate.default
|
|
306
|
+
)
|
|
307
|
+
self._dispense_flow_rate = (
|
|
308
|
+
self.active_tip_settings.default_dispense_flowrate.default
|
|
309
|
+
)
|
|
310
|
+
self._blow_out_flow_rate = (
|
|
311
|
+
self.active_tip_settings.default_blowout_flowrate.default
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
self._versioned_tip_overlap_dictionary = (
|
|
315
|
+
self.get_nominal_tip_overlap_dictionary_by_configuration()
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
self._nozzle_manager = (
|
|
319
|
+
nozzle_manager.NozzleConfigurationManager.build_from_config(
|
|
320
|
+
self._config, self._valid_nozzle_maps
|
|
321
|
+
)
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
def reset_pipette_offset(self, mount: Mount, to_default: bool) -> None:
|
|
325
|
+
"""Reset the pipette offset to system defaults."""
|
|
326
|
+
if to_default:
|
|
327
|
+
self._pipette_offset = load_pipette_offset(pip_id=None, mount=mount)
|
|
328
|
+
else:
|
|
329
|
+
self._pipette_offset = load_pipette_offset(self._pipette_id, mount)
|
|
330
|
+
|
|
331
|
+
def save_pipette_offset(self, mount: Mount, offset: Point) -> None:
|
|
332
|
+
"""Update the pipette offset to a new value."""
|
|
333
|
+
# TODO (lc 10-31-2022) We should have this command be supported properly by
|
|
334
|
+
# ot-3 and ot-2 when we split out the pipette class
|
|
335
|
+
self._pipette_offset = load_pipette_offset(self._pipette_id, mount)
|
|
336
|
+
|
|
337
|
+
@property
|
|
338
|
+
def name(self) -> PipetteName:
|
|
339
|
+
return cast(PipetteName, f"{self._pipette_name}")
|
|
340
|
+
|
|
341
|
+
@property
|
|
342
|
+
def model(self) -> PipetteModel:
|
|
343
|
+
return cast(PipetteModel, f"{self._pipette_model}")
|
|
344
|
+
|
|
345
|
+
@property
|
|
346
|
+
def pipette_type(self) -> pip_types.PipetteModelType:
|
|
347
|
+
return self._pipette_type
|
|
348
|
+
|
|
349
|
+
@property
|
|
350
|
+
def pipette_id(self) -> Optional[str]:
|
|
351
|
+
return self._pipette_id
|
|
352
|
+
|
|
353
|
+
def critical_point(self, cp_override: Optional[CriticalPoint] = None) -> Point:
|
|
354
|
+
"""
|
|
355
|
+
The vector from the pipette's origin to its critical point. The
|
|
356
|
+
critical point for a pipette is the end of the nozzle if no tip is
|
|
357
|
+
attached, or the end of the tip if a tip is attached.
|
|
358
|
+
|
|
359
|
+
If `cp_override` is specified and valid - so is either
|
|
360
|
+
:py:attr:`CriticalPoint.NOZZLE` or :py:attr:`CriticalPoint.TIP` when
|
|
361
|
+
we have a tip, or :py:attr:`CriticalPoint.XY_CENTER` - the specified
|
|
362
|
+
critical point will be used.
|
|
363
|
+
"""
|
|
364
|
+
|
|
365
|
+
if cp_override in [
|
|
366
|
+
CriticalPoint.GRIPPER_JAW_CENTER,
|
|
367
|
+
CriticalPoint.GRIPPER_FRONT_CALIBRATION_PIN,
|
|
368
|
+
CriticalPoint.GRIPPER_REAR_CALIBRATION_PIN,
|
|
369
|
+
]:
|
|
370
|
+
raise InvalidCriticalPoint(cp_override.name, "pipette")
|
|
371
|
+
|
|
372
|
+
instr = Point(*self._pipette_offset.offset)
|
|
373
|
+
cp_with_tip_length = self._nozzle_manager.critical_point_with_tip_length(
|
|
374
|
+
cp_override,
|
|
375
|
+
self.current_tip_length if cp_override != CriticalPoint.NOZZLE else 0.0,
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
cp = cp_with_tip_length + instr
|
|
379
|
+
|
|
380
|
+
if self._log.isEnabledFor(logging.DEBUG):
|
|
381
|
+
info_str = "cp: {}{}: {} (from: ".format(
|
|
382
|
+
cp_override, " (from override)" if cp_override else "", cp
|
|
383
|
+
)
|
|
384
|
+
info_str += "model offset: {} + instrument offset: {}".format(
|
|
385
|
+
cp_with_tip_length, instr
|
|
386
|
+
)
|
|
387
|
+
info_str += " - tip_length: {}".format(self.current_tip_length)
|
|
388
|
+
info_str += ")"
|
|
389
|
+
self._log.debug(info_str)
|
|
390
|
+
|
|
391
|
+
return cp
|
|
392
|
+
|
|
393
|
+
@property
|
|
394
|
+
def current_volume(self) -> float:
|
|
395
|
+
"""The amount of liquid currently aspirated"""
|
|
396
|
+
return self._current_volume
|
|
397
|
+
|
|
398
|
+
@property
|
|
399
|
+
def current_tip_length(self) -> float:
|
|
400
|
+
"""The length of the current tip attached (0.0 if no tip)"""
|
|
401
|
+
return self._current_tip_length
|
|
402
|
+
|
|
403
|
+
@current_tip_length.setter
|
|
404
|
+
def current_tip_length(self, tip_length: float) -> None:
|
|
405
|
+
self._current_tip_length = tip_length
|
|
406
|
+
|
|
407
|
+
@property
|
|
408
|
+
def current_tiprack_diameter(self) -> float:
|
|
409
|
+
"""The diameter of the current tip rack (0.0 if no tip)"""
|
|
410
|
+
return self._current_tiprack_diameter
|
|
411
|
+
|
|
412
|
+
@current_tiprack_diameter.setter
|
|
413
|
+
def current_tiprack_diameter(self, diameter: float) -> None:
|
|
414
|
+
self._current_tiprack_diameter = diameter
|
|
415
|
+
|
|
416
|
+
@property
|
|
417
|
+
def aspirate_flow_rate(self) -> float:
|
|
418
|
+
"""Current active flow rate (not config value)"""
|
|
419
|
+
return self._aspirate_flow_rate
|
|
420
|
+
|
|
421
|
+
@aspirate_flow_rate.setter
|
|
422
|
+
def aspirate_flow_rate(self, new_flow_rate: float) -> None:
|
|
423
|
+
assert new_flow_rate > 0
|
|
424
|
+
self._aspirate_flow_rate = new_flow_rate
|
|
425
|
+
|
|
426
|
+
@property
|
|
427
|
+
def dispense_flow_rate(self) -> float:
|
|
428
|
+
"""Current active flow rate (not config value)"""
|
|
429
|
+
return self._dispense_flow_rate
|
|
430
|
+
|
|
431
|
+
@dispense_flow_rate.setter
|
|
432
|
+
def dispense_flow_rate(self, new_flow_rate: float) -> None:
|
|
433
|
+
assert new_flow_rate > 0
|
|
434
|
+
self._dispense_flow_rate = new_flow_rate
|
|
435
|
+
|
|
436
|
+
@property
|
|
437
|
+
def blow_out_flow_rate(self) -> float:
|
|
438
|
+
"""Current active flow rate (not config value)"""
|
|
439
|
+
return self._blow_out_flow_rate
|
|
440
|
+
|
|
441
|
+
@blow_out_flow_rate.setter
|
|
442
|
+
def blow_out_flow_rate(self, new_flow_rate: float) -> None:
|
|
443
|
+
assert new_flow_rate > 0
|
|
444
|
+
self._blow_out_flow_rate = new_flow_rate
|
|
445
|
+
|
|
446
|
+
@property
|
|
447
|
+
def aspirate_flow_rates_lookup(self) -> Dict[str, float]:
|
|
448
|
+
return self._active_tip_settings.default_aspirate_flowrate.values_by_api_level
|
|
449
|
+
|
|
450
|
+
@property
|
|
451
|
+
def dispense_flow_rates_lookup(self) -> Dict[str, float]:
|
|
452
|
+
return self._active_tip_settings.default_dispense_flowrate.values_by_api_level
|
|
453
|
+
|
|
454
|
+
@property
|
|
455
|
+
def blow_out_flow_rates_lookup(self) -> Dict[str, float]:
|
|
456
|
+
return self.active_tip_settings.default_blowout_flowrate.values_by_api_level
|
|
457
|
+
|
|
458
|
+
@property
|
|
459
|
+
def working_volume(self) -> float:
|
|
460
|
+
"""The working volume of the pipette"""
|
|
461
|
+
return self._working_volume
|
|
462
|
+
|
|
463
|
+
@working_volume.setter
|
|
464
|
+
def working_volume(self, tip_volume: float) -> None:
|
|
465
|
+
"""The working volume is the current tip max volume"""
|
|
466
|
+
self._working_volume = min(self.liquid_class.max_volume, tip_volume)
|
|
467
|
+
tip_size_type = pip_types.PipetteTipType.check_and_return_type(
|
|
468
|
+
int(self._working_volume), self.liquid_class.max_volume
|
|
469
|
+
)
|
|
470
|
+
self._active_tip_settings = self.liquid_class.supported_tips[tip_size_type]
|
|
471
|
+
self._fallback_tip_length = self._active_tip_settings.default_tip_length
|
|
472
|
+
|
|
473
|
+
@property
|
|
474
|
+
def minimum_volume(self) -> float:
|
|
475
|
+
"""The smallest controllable volume the pipette can handle with the current liquid class.."""
|
|
476
|
+
return self.liquid_class.min_volume
|
|
477
|
+
|
|
478
|
+
@property
|
|
479
|
+
def available_volume(self) -> float:
|
|
480
|
+
"""The amount of liquid possible to aspirate"""
|
|
481
|
+
return self.working_volume - self.current_volume
|
|
482
|
+
|
|
483
|
+
def set_current_volume(self, new_volume: float) -> None:
|
|
484
|
+
assert new_volume >= 0
|
|
485
|
+
assert new_volume <= self.working_volume
|
|
486
|
+
self._current_volume = new_volume
|
|
487
|
+
|
|
488
|
+
def add_current_volume(self, volume_incr: float) -> None:
|
|
489
|
+
assert self.ok_to_add_volume(volume_incr)
|
|
490
|
+
self._current_volume += volume_incr
|
|
491
|
+
|
|
492
|
+
def remove_current_volume(self, volume_incr: float) -> None:
|
|
493
|
+
assert self._current_volume >= volume_incr
|
|
494
|
+
self._current_volume -= volume_incr
|
|
495
|
+
|
|
496
|
+
def ok_to_add_volume(self, volume_incr: float) -> bool:
|
|
497
|
+
return self.current_volume + volume_incr <= self.working_volume
|
|
498
|
+
|
|
499
|
+
def ok_to_push_out(self, push_out_dist_mm: float) -> bool:
|
|
500
|
+
return push_out_dist_mm <= (
|
|
501
|
+
self.plunger_positions.bottom - self.plunger_positions.blow_out
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
def update_nozzle_configuration(
|
|
505
|
+
self,
|
|
506
|
+
back_left_nozzle: str,
|
|
507
|
+
front_right_nozzle: str,
|
|
508
|
+
starting_nozzle: Optional[str] = None,
|
|
509
|
+
) -> None:
|
|
510
|
+
"""
|
|
511
|
+
Update nozzle configuration manager.
|
|
512
|
+
"""
|
|
513
|
+
self._nozzle_manager.update_nozzle_configuration(
|
|
514
|
+
back_left_nozzle, front_right_nozzle, starting_nozzle
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
def reset_nozzle_configuration(self) -> None:
|
|
518
|
+
"""
|
|
519
|
+
Reset nozzle configuration manager.
|
|
520
|
+
"""
|
|
521
|
+
self._nozzle_manager.reset_to_default_configuration()
|
|
522
|
+
|
|
523
|
+
def add_tip(self, tip_length: float) -> None:
|
|
524
|
+
"""
|
|
525
|
+
Add a tip to the pipette for position tracking and validation
|
|
526
|
+
(effectively updates the pipette's critical point)
|
|
527
|
+
|
|
528
|
+
:param tip_length: a positive, non-zero float presenting the distance
|
|
529
|
+
in Z from the end of the pipette nozzle to the end of the tip
|
|
530
|
+
:return:
|
|
531
|
+
"""
|
|
532
|
+
assert tip_length > 0.0, "tip_length must be greater than 0"
|
|
533
|
+
assert not self.has_tip
|
|
534
|
+
self._has_tip = True
|
|
535
|
+
self._current_tip_length = tip_length
|
|
536
|
+
|
|
537
|
+
def remove_tip(self) -> None:
|
|
538
|
+
"""
|
|
539
|
+
Remove the tip from the pipette (effectively updates the pipette's
|
|
540
|
+
critical point)
|
|
541
|
+
"""
|
|
542
|
+
self._has_tip = False
|
|
543
|
+
self._current_tip_length = 0.0
|
|
544
|
+
|
|
545
|
+
@property
|
|
546
|
+
def has_tip(self) -> bool:
|
|
547
|
+
return self._has_tip
|
|
548
|
+
|
|
549
|
+
def get_pick_up_speed_by_configuration(
|
|
550
|
+
self,
|
|
551
|
+
config: PressFitPickUpTipConfiguration,
|
|
552
|
+
) -> float:
|
|
553
|
+
return pick_up_speed_by_configuration(
|
|
554
|
+
config,
|
|
555
|
+
self._nozzle_manager.current_configuration.valid_map_key,
|
|
556
|
+
pip_types.PipetteTipType(self._liquid_class.max_volume),
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
def get_pick_up_distance_by_configuration(
|
|
560
|
+
self,
|
|
561
|
+
config: PressFitPickUpTipConfiguration,
|
|
562
|
+
) -> float:
|
|
563
|
+
return pick_up_distance_by_configuration(
|
|
564
|
+
config,
|
|
565
|
+
self._nozzle_manager.current_configuration.valid_map_key,
|
|
566
|
+
pip_types.PipetteTipType(self._liquid_class.max_volume),
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
def get_pick_up_current_by_configuration(
|
|
570
|
+
self,
|
|
571
|
+
config: PressFitPickUpTipConfiguration,
|
|
572
|
+
) -> float:
|
|
573
|
+
return pick_up_current_by_configuration(
|
|
574
|
+
config,
|
|
575
|
+
self._nozzle_manager.current_configuration.valid_map_key,
|
|
576
|
+
pip_types.PipetteTipType(self._liquid_class.max_volume),
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
def get_nominal_tip_overlap_dictionary_by_configuration(
|
|
580
|
+
self,
|
|
581
|
+
) -> Dict[str, Dict[str, float]]:
|
|
582
|
+
return nominal_tip_overlap_dictionary_by_configuration(
|
|
583
|
+
self._config,
|
|
584
|
+
self._nozzle_manager.current_configuration.valid_map_key,
|
|
585
|
+
pip_types.PipetteTipType(self._liquid_class.max_volume),
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
# Cache max is chosen somewhat arbitrarily. With a float is input we don't
|
|
589
|
+
# want this to unbounded.
|
|
590
|
+
@functools.lru_cache(maxsize=100)
|
|
591
|
+
def ul_per_mm(self, ul: float, action: UlPerMmAction) -> float:
|
|
592
|
+
return calculate_ul_per_mm(
|
|
593
|
+
ul, action, self._active_tip_settings, self._pipetting_function_version
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
def __str__(self) -> str:
|
|
597
|
+
return "{} current volume {}ul critical point: {} at {}".format(
|
|
598
|
+
self._config.display_name,
|
|
599
|
+
self.current_volume,
|
|
600
|
+
"tip end" if self.has_tip else "nozzle end",
|
|
601
|
+
0,
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
def __repr__(self) -> str:
|
|
605
|
+
return "<{}: {} {}>".format(
|
|
606
|
+
self.__class__.__name__, self._config.display_name, id(self)
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
def as_dict(self) -> "Pipette.DictType":
|
|
610
|
+
self._config_as_dict.update(
|
|
611
|
+
{
|
|
612
|
+
"current_volume": self.current_volume,
|
|
613
|
+
"available_volume": self.available_volume,
|
|
614
|
+
"name": self.name,
|
|
615
|
+
"model": self.model,
|
|
616
|
+
"pipette_id": self.pipette_id,
|
|
617
|
+
"has_tip": self.has_tip,
|
|
618
|
+
"working_volume": self.working_volume,
|
|
619
|
+
"aspirate_flow_rate": self.aspirate_flow_rate,
|
|
620
|
+
"dispense_flow_rate": self.dispense_flow_rate,
|
|
621
|
+
"blow_out_flow_rate": self.blow_out_flow_rate,
|
|
622
|
+
"default_aspirate_flow_rates": self.aspirate_flow_rates_lookup,
|
|
623
|
+
"default_blow_out_flow_rates": self.blow_out_flow_rates_lookup,
|
|
624
|
+
"default_dispense_flow_rates": self.dispense_flow_rates_lookup,
|
|
625
|
+
"tip_length": self.current_tip_length,
|
|
626
|
+
"return_tip_height": self.active_tip_settings.default_return_tip_height,
|
|
627
|
+
"tip_overlap": self.tip_overlap["v0"],
|
|
628
|
+
"versioned_tip_overlap": self.tip_overlap,
|
|
629
|
+
"back_compat_names": self._config.pipette_backcompat_names,
|
|
630
|
+
"supported_tips": self.liquid_class.supported_tips,
|
|
631
|
+
}
|
|
632
|
+
)
|
|
633
|
+
return self._config_as_dict
|
|
634
|
+
|
|
635
|
+
def set_liquid_class_by_name(self, class_name: str) -> None:
|
|
636
|
+
"""Change the currently active liquid class."""
|
|
637
|
+
if self.current_volume > 0:
|
|
638
|
+
raise CommandPreconditionViolated(
|
|
639
|
+
"Cannot switch liquid classes when liquid is in the tip"
|
|
640
|
+
)
|
|
641
|
+
if class_name != "default":
|
|
642
|
+
raise InvalidLiquidClassName(
|
|
643
|
+
message=f"Liquid class {class_name} is not valid for {self._config.display_name}"
|
|
644
|
+
)
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
def _reload_and_check_skip(
|
|
648
|
+
new_config: PipetteConfigurations,
|
|
649
|
+
attached_instr: Pipette,
|
|
650
|
+
pipette_offset: PipetteOffsetByPipetteMount,
|
|
651
|
+
use_old_aspiration_functions: bool,
|
|
652
|
+
) -> Tuple[Pipette, bool]:
|
|
653
|
+
# Once we have determined that the new and attached pipettes
|
|
654
|
+
# are similar enough that we might skip, see if the configs
|
|
655
|
+
# match closely enough.
|
|
656
|
+
# Returns a pipette object and True if we may skip hw reconfig
|
|
657
|
+
if (
|
|
658
|
+
new_config == attached_instr.config
|
|
659
|
+
and pipette_offset == attached_instr._pipette_offset
|
|
660
|
+
):
|
|
661
|
+
# Same config, good enough
|
|
662
|
+
return attached_instr, True
|
|
663
|
+
else:
|
|
664
|
+
newdict = new_config.model_dump()
|
|
665
|
+
olddict = attached_instr.config.model_dump()
|
|
666
|
+
changed: Set[str] = set()
|
|
667
|
+
for k in newdict.keys():
|
|
668
|
+
if newdict[k] != olddict[k]:
|
|
669
|
+
changed.add(k)
|
|
670
|
+
if changed.intersection(RECONFIG_KEYS):
|
|
671
|
+
# Something has changed that requires reconfig
|
|
672
|
+
p = Pipette(
|
|
673
|
+
new_config,
|
|
674
|
+
pipette_offset,
|
|
675
|
+
attached_instr._pipette_id,
|
|
676
|
+
use_old_aspiration_functions,
|
|
677
|
+
)
|
|
678
|
+
p.act_as(attached_instr.acting_as)
|
|
679
|
+
return p, False
|
|
680
|
+
# Good to skip
|
|
681
|
+
return attached_instr, True
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
def load_from_config_and_check_skip(
|
|
685
|
+
config: Optional[PipetteConfigurations],
|
|
686
|
+
attached: Optional[Pipette],
|
|
687
|
+
requested: Optional[PipetteName],
|
|
688
|
+
serial: Optional[str],
|
|
689
|
+
pipette_offset: PipetteOffsetByPipetteMount,
|
|
690
|
+
use_old_aspiration_functions: bool,
|
|
691
|
+
) -> Tuple[Optional[Pipette], bool]:
|
|
692
|
+
"""
|
|
693
|
+
Given the pipette config for an attached pipette (if any) freshly read
|
|
694
|
+
from disk, and any attached instruments,
|
|
695
|
+
|
|
696
|
+
- Compare the new and configured pipette configs
|
|
697
|
+
- Load the new configs if they differ
|
|
698
|
+
- Return a bool indicating whether hardware reconfiguration may be
|
|
699
|
+
skipped
|
|
700
|
+
"""
|
|
701
|
+
|
|
702
|
+
if not config and not attached:
|
|
703
|
+
# nothing attached now, nothing used to be attached, nothing
|
|
704
|
+
# to reconfigure
|
|
705
|
+
return attached, True
|
|
706
|
+
|
|
707
|
+
if config and attached:
|
|
708
|
+
# something was attached and something is attached. are they
|
|
709
|
+
# the same? we can tell by comparing serials
|
|
710
|
+
if serial == attached.pipette_id:
|
|
711
|
+
if requested:
|
|
712
|
+
# if there is an explicit instrument request, in addition
|
|
713
|
+
# to checking if the old and new responses are the same
|
|
714
|
+
# we also have to make sure the old pipette is properly
|
|
715
|
+
# configured to the request
|
|
716
|
+
if requested == str(attached.acting_as):
|
|
717
|
+
# similar enough to check
|
|
718
|
+
return _reload_and_check_skip(
|
|
719
|
+
config, attached, pipette_offset, use_old_aspiration_functions
|
|
720
|
+
)
|
|
721
|
+
else:
|
|
722
|
+
# if there is no request, make sure that the old pipette
|
|
723
|
+
# did not have backcompat applied
|
|
724
|
+
if str(attached.acting_as) == attached.name:
|
|
725
|
+
# similar enough to check
|
|
726
|
+
return _reload_and_check_skip(
|
|
727
|
+
config, attached, pipette_offset, use_old_aspiration_functions
|
|
728
|
+
)
|
|
729
|
+
|
|
730
|
+
if config:
|
|
731
|
+
return (
|
|
732
|
+
Pipette(config, pipette_offset, serial, use_old_aspiration_functions),
|
|
733
|
+
False,
|
|
734
|
+
)
|
|
735
|
+
else:
|
|
736
|
+
return None, False
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
def _build_splits(pipette: Pipette) -> Optional[MoveSplit]:
|
|
740
|
+
if pip_types.Quirks.needsUnstick in pipette.config.quirks:
|
|
741
|
+
return MoveSplit(
|
|
742
|
+
split_distance=1,
|
|
743
|
+
split_current=1.75,
|
|
744
|
+
split_speed=1,
|
|
745
|
+
after_time=1800,
|
|
746
|
+
fullstep=True,
|
|
747
|
+
)
|
|
748
|
+
else:
|
|
749
|
+
return None
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
def generate_hardware_configs(
|
|
753
|
+
pipette: Optional[Pipette], robot_config: RobotConfig, revision: BoardRevision
|
|
754
|
+
) -> InstrumentHardwareConfigs:
|
|
755
|
+
"""
|
|
756
|
+
Fuse robot and pipette configuration to generate commands to send to
|
|
757
|
+
the motor driver if required
|
|
758
|
+
"""
|
|
759
|
+
if pipette:
|
|
760
|
+
return {
|
|
761
|
+
"steps_per_mm": pipette.config.mount_configurations.stepsPerMM,
|
|
762
|
+
"home_pos": pipette.config.mount_configurations.homePosition,
|
|
763
|
+
"max_travel": pipette.config.mount_configurations.travelDistance,
|
|
764
|
+
"idle_current": pipette.plunger_motor_current.idle,
|
|
765
|
+
"splits": _build_splits(pipette),
|
|
766
|
+
}
|
|
767
|
+
else:
|
|
768
|
+
dpcs = robot_config.default_pipette_configs
|
|
769
|
+
return {
|
|
770
|
+
"steps_per_mm": dpcs["stepsPerMM"],
|
|
771
|
+
"home_pos": dpcs["homePosition"],
|
|
772
|
+
"max_travel": dpcs["maxTravel"],
|
|
773
|
+
"idle_current": robot_configs.current_for_revision(
|
|
774
|
+
robot_config.low_current, revision
|
|
775
|
+
)["B"],
|
|
776
|
+
"splits": None,
|
|
777
|
+
}
|