opentrons 8.6.0__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 +557 -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 +187 -0
- opentrons/drivers/asyncio/communication/errors.py +88 -0
- opentrons/drivers/asyncio/communication/serial_connection.py +557 -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/scripts/update_module_fw.py +274 -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 +276 -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 +1186 -0
- opentrons/motion_planning/__init__.py +32 -0
- opentrons/motion_planning/adjacent_slots_getters.py +168 -0
- opentrons/motion_planning/deck_conflict.py +501 -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 +400 -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 +1027 -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 +1006 -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 +3272 -0
- opentrons/protocol_api/labware.py +1579 -0
- opentrons/protocol_api/module_contexts.py +1447 -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 +339 -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 +350 -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 +68 -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 +1164 -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 +2408 -0
- opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
- opentrons/protocol_engine/state/labware.py +1432 -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 +1515 -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 +310 -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 +310 -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 +852 -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.0.dist-info/METADATA +37 -0
- opentrons-8.6.0.dist-info/RECORD +601 -0
- opentrons-8.6.0.dist-info/WHEEL +4 -0
- opentrons-8.6.0.dist-info/entry_points.txt +3 -0
- opentrons-8.6.0.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""Post-protocol hardware stopper."""
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from opentrons.hardware_control import HardwareControlAPI
|
|
6
|
+
from opentrons.types import PipetteNotAttachedError as HwPipetteNotAttachedError
|
|
7
|
+
|
|
8
|
+
from ..resources.ot3_validation import ensure_ot3_hardware
|
|
9
|
+
from ..state.state import StateStore
|
|
10
|
+
from ..types import MotorAxis, PostRunHardwareState
|
|
11
|
+
from ..errors import HardwareNotSupportedError
|
|
12
|
+
|
|
13
|
+
from .movement import MovementHandler
|
|
14
|
+
from .gantry_mover import HardwareGantryMover
|
|
15
|
+
from .tip_handler import TipHandler, HardwareTipHandler
|
|
16
|
+
from ...hardware_control.types import OT3Mount
|
|
17
|
+
|
|
18
|
+
from opentrons.protocol_engine.types import AddressableOffsetVector
|
|
19
|
+
|
|
20
|
+
log = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
# TODO(mc, 2022-03-07): this constant dup'd from opentrons.protocols.geometry.deck
|
|
23
|
+
# to avoid a circular dependency that needs to be figured out.
|
|
24
|
+
FIXED_TRASH_ID = "fixedTrash"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class HardwareStopper:
|
|
28
|
+
"""Class to implement hardware stopping."""
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
hardware_api: HardwareControlAPI,
|
|
33
|
+
state_store: StateStore,
|
|
34
|
+
movement: Optional[MovementHandler] = None,
|
|
35
|
+
tip_handler: Optional[TipHandler] = None,
|
|
36
|
+
) -> None:
|
|
37
|
+
"""Hardware stopper initializer."""
|
|
38
|
+
self._hardware_api = hardware_api
|
|
39
|
+
self._state_store = state_store
|
|
40
|
+
self._movement_handler = movement or MovementHandler(
|
|
41
|
+
hardware_api=hardware_api,
|
|
42
|
+
state_store=state_store,
|
|
43
|
+
gantry_mover=HardwareGantryMover(
|
|
44
|
+
hardware_api=hardware_api,
|
|
45
|
+
state_view=state_store,
|
|
46
|
+
),
|
|
47
|
+
)
|
|
48
|
+
self._tip_handler = tip_handler or HardwareTipHandler(
|
|
49
|
+
hardware_api=hardware_api,
|
|
50
|
+
state_view=state_store,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
async def _home_everything_except_plungers(self) -> None:
|
|
54
|
+
# TODO: Update this once gripper MotorAxis is available in engine.
|
|
55
|
+
try:
|
|
56
|
+
ot3api = ensure_ot3_hardware(hardware_api=self._hardware_api)
|
|
57
|
+
if (
|
|
58
|
+
not self._state_store.config.use_virtual_gripper
|
|
59
|
+
and ot3api.has_gripper()
|
|
60
|
+
):
|
|
61
|
+
await ot3api.home_z(mount=OT3Mount.GRIPPER)
|
|
62
|
+
except HardwareNotSupportedError:
|
|
63
|
+
pass
|
|
64
|
+
await self._movement_handler.home(
|
|
65
|
+
axes=[MotorAxis.X, MotorAxis.Y, MotorAxis.LEFT_Z, MotorAxis.RIGHT_Z]
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
async def _try_to_drop_tips(self) -> None:
|
|
69
|
+
"""Drop currently attached tip, if any, into trash after a run cancel."""
|
|
70
|
+
attached_tips = self._state_store.pipettes.get_all_attached_tips()
|
|
71
|
+
|
|
72
|
+
if attached_tips:
|
|
73
|
+
await self._hardware_api.stop(home_after=False)
|
|
74
|
+
|
|
75
|
+
await self._home_everything_except_plungers()
|
|
76
|
+
|
|
77
|
+
for pipette_id, tip in attached_tips:
|
|
78
|
+
try:
|
|
79
|
+
if self._state_store.labware.get_fixed_trash_id() == FIXED_TRASH_ID:
|
|
80
|
+
# OT-2 and Flex 2.15 protocols will default to the Fixed Trash Labware
|
|
81
|
+
self._tip_handler.cache_tip(pipette_id=pipette_id, tip=tip)
|
|
82
|
+
await self._movement_handler.move_to_well(
|
|
83
|
+
pipette_id=pipette_id,
|
|
84
|
+
labware_id=FIXED_TRASH_ID,
|
|
85
|
+
well_name="A1",
|
|
86
|
+
)
|
|
87
|
+
await self._tip_handler.drop_tip(
|
|
88
|
+
pipette_id=pipette_id,
|
|
89
|
+
home_after=False,
|
|
90
|
+
)
|
|
91
|
+
elif self._state_store.config.robot_type == "OT-2 Standard":
|
|
92
|
+
# API 2.16 and above OT2 protocols use addressable areas
|
|
93
|
+
self._tip_handler.cache_tip(pipette_id=pipette_id, tip=tip)
|
|
94
|
+
await self._movement_handler.move_to_addressable_area(
|
|
95
|
+
pipette_id=pipette_id,
|
|
96
|
+
addressable_area_name="fixedTrash",
|
|
97
|
+
offset=AddressableOffsetVector(x=0, y=0, z=0),
|
|
98
|
+
force_direct=False,
|
|
99
|
+
speed=None,
|
|
100
|
+
minimum_z_height=None,
|
|
101
|
+
)
|
|
102
|
+
await self._tip_handler.drop_tip(
|
|
103
|
+
pipette_id=pipette_id,
|
|
104
|
+
home_after=False,
|
|
105
|
+
)
|
|
106
|
+
else:
|
|
107
|
+
log.debug(
|
|
108
|
+
"Flex Protocols API Version 2.16 and beyond do not support automatic tip dropping at this time."
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
except HwPipetteNotAttachedError:
|
|
112
|
+
# this will happen normally during protocol analysis, but
|
|
113
|
+
# should not happen during an actual run
|
|
114
|
+
log.debug(f"Pipette ID {pipette_id} no longer attached.")
|
|
115
|
+
|
|
116
|
+
async def do_halt(self, disengage_before_stopping: bool = False) -> None:
|
|
117
|
+
"""Issue a halt signal to the hardware API.
|
|
118
|
+
|
|
119
|
+
After issuing a halt, you must call do_stop_and_recover after
|
|
120
|
+
anything using the HardwareAPI has settled.
|
|
121
|
+
"""
|
|
122
|
+
await self._hardware_api.halt(
|
|
123
|
+
disengage_before_stopping=disengage_before_stopping
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
async def do_stop_and_recover(
|
|
127
|
+
self,
|
|
128
|
+
post_run_hardware_state: PostRunHardwareState,
|
|
129
|
+
drop_tips_after_run: bool = False,
|
|
130
|
+
) -> None:
|
|
131
|
+
"""Stop and reset the HardwareAPI, homing and dropping tips independently if specified. If modules are attached that require recovery handle them."""
|
|
132
|
+
home_after_stop = post_run_hardware_state in (
|
|
133
|
+
PostRunHardwareState.HOME_AND_STAY_ENGAGED,
|
|
134
|
+
PostRunHardwareState.HOME_THEN_DISENGAGE,
|
|
135
|
+
)
|
|
136
|
+
try:
|
|
137
|
+
if drop_tips_after_run:
|
|
138
|
+
await self._try_to_drop_tips()
|
|
139
|
+
|
|
140
|
+
await self._hardware_api.stop(home_after=False)
|
|
141
|
+
|
|
142
|
+
if home_after_stop:
|
|
143
|
+
await self._home_everything_except_plungers()
|
|
144
|
+
finally:
|
|
145
|
+
# Ensure module state recovery is handled
|
|
146
|
+
for module in self._hardware_api.attached_modules:
|
|
147
|
+
module.cleanup_persistent()
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""Helpers for flagging unsafe movements around a Heater-Shaker Module."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
|
|
5
|
+
from opentrons.motion_planning.adjacent_slots_getters import (
|
|
6
|
+
get_east_west_slots,
|
|
7
|
+
get_north_south_slots,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from ..errors import (
|
|
11
|
+
PipetteMovementRestrictedByHeaterShakerError,
|
|
12
|
+
HeaterShakerLabwareLatchNotOpenError,
|
|
13
|
+
HeaterShakerLabwareLatchStatusUnknown,
|
|
14
|
+
WrongModuleTypeError,
|
|
15
|
+
)
|
|
16
|
+
from ..state.state import StateStore
|
|
17
|
+
from ..state.module_substates import HeaterShakerModuleSubState
|
|
18
|
+
from ..types import (
|
|
19
|
+
HeaterShakerMovementRestrictors,
|
|
20
|
+
HeaterShakerLatchStatus,
|
|
21
|
+
LabwareLocation,
|
|
22
|
+
ModuleLocation,
|
|
23
|
+
)
|
|
24
|
+
from ...hardware_control import HardwareControlAPI
|
|
25
|
+
from ...hardware_control.modules import HeaterShaker as HardwareHeaterShaker
|
|
26
|
+
from ...drivers.types import (
|
|
27
|
+
HeaterShakerLabwareLatchStatus as HeaterShakerHardwareLatchStatus,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class HeaterShakerMovementFlagger:
|
|
32
|
+
"""A helper for flagging unsafe movements to a Heater-Shaker."""
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self, state_store: StateStore, hardware_api: HardwareControlAPI
|
|
36
|
+
) -> None:
|
|
37
|
+
self._state_store = state_store
|
|
38
|
+
self._hardware_api = hardware_api
|
|
39
|
+
|
|
40
|
+
async def raise_if_labware_latched_on_heater_shaker(
|
|
41
|
+
self, labware_parent: LabwareLocation
|
|
42
|
+
) -> None:
|
|
43
|
+
"""Flag unsafe movements to a heater-shaker.
|
|
44
|
+
|
|
45
|
+
If the given labware is on a heater-shaker, and that heater-shaker's labware
|
|
46
|
+
latch is not open according to the engine's h/s state as well as the
|
|
47
|
+
hardware API (for non-virtual modules), raises HeaterShakerLabwareLatchNotOpenError.
|
|
48
|
+
If it is a virtual module, checks only for heater-shaker latch state in engine.
|
|
49
|
+
|
|
50
|
+
Otherwise, no-ops.
|
|
51
|
+
"""
|
|
52
|
+
if isinstance(labware_parent, ModuleLocation):
|
|
53
|
+
module_id = labware_parent.moduleId
|
|
54
|
+
else:
|
|
55
|
+
return # Labware not on a module.
|
|
56
|
+
try:
|
|
57
|
+
hs_substate = self._state_store.modules.get_heater_shaker_module_substate(
|
|
58
|
+
module_id=module_id
|
|
59
|
+
)
|
|
60
|
+
except WrongModuleTypeError:
|
|
61
|
+
return # Labware on a module, but not a Heater-Shaker.
|
|
62
|
+
|
|
63
|
+
if hs_substate.labware_latch_status == HeaterShakerLatchStatus.CLOSED:
|
|
64
|
+
raise HeaterShakerLabwareLatchNotOpenError(
|
|
65
|
+
"Heater-Shaker labware latch must be open when moving labware to/from it."
|
|
66
|
+
)
|
|
67
|
+
elif hs_substate.labware_latch_status == HeaterShakerLatchStatus.UNKNOWN:
|
|
68
|
+
raise HeaterShakerLabwareLatchStatusUnknown(
|
|
69
|
+
"Heater-Shaker labware latch must be opened before moving labware to/from it."
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# There is a chance that the engine might not have the latest latch status;
|
|
73
|
+
# do a hardware state check to be sure that the latch is truly open
|
|
74
|
+
if not self._state_store.config.use_virtual_modules:
|
|
75
|
+
await self._check_hardware_module_latch_status(hs_substate)
|
|
76
|
+
|
|
77
|
+
async def _check_hardware_module_latch_status(
|
|
78
|
+
self, hs_substate: HeaterShakerModuleSubState
|
|
79
|
+
) -> None:
|
|
80
|
+
try:
|
|
81
|
+
hs_latch_status = await self._get_hardware_heater_shaker_latch_status(
|
|
82
|
+
module_id=hs_substate.module_id
|
|
83
|
+
)
|
|
84
|
+
except self._HardwareHeaterShakerMissingError as e:
|
|
85
|
+
raise HeaterShakerLabwareLatchNotOpenError(
|
|
86
|
+
"Heater-Shaker labware latch must be open when moving labware to/from it,"
|
|
87
|
+
" but the latch status is unknown."
|
|
88
|
+
) from e
|
|
89
|
+
|
|
90
|
+
if hs_latch_status != HeaterShakerHardwareLatchStatus.IDLE_OPEN:
|
|
91
|
+
raise HeaterShakerLabwareLatchNotOpenError(
|
|
92
|
+
f"Heater-Shaker labware latch must be open when moving labware to/from it,"
|
|
93
|
+
f" but the latch is currently {hs_latch_status}"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
async def _get_hardware_heater_shaker_latch_status(
|
|
97
|
+
self,
|
|
98
|
+
module_id: str,
|
|
99
|
+
) -> HeaterShakerHardwareLatchStatus:
|
|
100
|
+
"""Get latch status of the hardware H/S corresponding with the module ID.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Latch status of the requested attached heater-shaker.
|
|
104
|
+
|
|
105
|
+
Raises:
|
|
106
|
+
_HardwareHeaterShakerMissingError: If we can't find that H/S in
|
|
107
|
+
the hardware API, so we can't fetch its current latch status.
|
|
108
|
+
It's unclear if this can happen in practice...
|
|
109
|
+
maybe if the module disconnects between when it was loaded into
|
|
110
|
+
Protocol Engine and when this function is called?
|
|
111
|
+
"""
|
|
112
|
+
hs_serial = self._state_store.modules.get_serial_number(module_id=module_id)
|
|
113
|
+
heater_shaker = await self._find_heater_shaker_by_serial(
|
|
114
|
+
serial_number=hs_serial
|
|
115
|
+
)
|
|
116
|
+
if heater_shaker is None:
|
|
117
|
+
raise self._HardwareHeaterShakerMissingError(
|
|
118
|
+
f"No Heater-Shaker found with serial number {hs_serial}"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
latch_status = heater_shaker.labware_latch_status
|
|
122
|
+
# An attached H/S should always have latch status unless it's in error or
|
|
123
|
+
# it was just connected and hasn't been polled for status yet.
|
|
124
|
+
assert latch_status is not None, (
|
|
125
|
+
"Did not receive a valid latch status from heater-shaker. "
|
|
126
|
+
"Cannot verify safe labware movement."
|
|
127
|
+
)
|
|
128
|
+
return latch_status
|
|
129
|
+
|
|
130
|
+
async def _find_heater_shaker_by_serial(
|
|
131
|
+
self, serial_number: str
|
|
132
|
+
) -> Optional[HardwareHeaterShaker]:
|
|
133
|
+
"""Find the hardware H/S with the given serial number.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
The matching hardware H/S, or None if none was found.
|
|
137
|
+
"""
|
|
138
|
+
for module in self._hardware_api.attached_modules:
|
|
139
|
+
# Different module types have different keys under .device_info.
|
|
140
|
+
# Heater-Shaker should always have .device_info["serial"].
|
|
141
|
+
if (
|
|
142
|
+
isinstance(module, HardwareHeaterShaker)
|
|
143
|
+
and module.device_info["serial"] == serial_number
|
|
144
|
+
):
|
|
145
|
+
return module
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
def raise_if_movement_restricted(
|
|
149
|
+
self,
|
|
150
|
+
hs_movement_restrictors: List[HeaterShakerMovementRestrictors],
|
|
151
|
+
destination_slot: int,
|
|
152
|
+
is_multi_channel: bool,
|
|
153
|
+
destination_is_tip_rack: bool,
|
|
154
|
+
) -> None:
|
|
155
|
+
"""Flag restricted movement around/to a Heater-Shaker."""
|
|
156
|
+
for hs_movement_restrictor in hs_movement_restrictors:
|
|
157
|
+
dest_east_west = destination_slot in get_east_west_slots(
|
|
158
|
+
hs_movement_restrictor.deck_slot
|
|
159
|
+
)
|
|
160
|
+
dest_north_south = destination_slot in get_north_south_slots(
|
|
161
|
+
hs_movement_restrictor.deck_slot
|
|
162
|
+
)
|
|
163
|
+
dest_heater_shaker = destination_slot == hs_movement_restrictor.deck_slot
|
|
164
|
+
|
|
165
|
+
# If Heater-Shaker is running, can't move to or around it
|
|
166
|
+
if (
|
|
167
|
+
any([dest_east_west, dest_north_south, dest_heater_shaker])
|
|
168
|
+
and hs_movement_restrictor.plate_shaking
|
|
169
|
+
):
|
|
170
|
+
raise PipetteMovementRestrictedByHeaterShakerError(
|
|
171
|
+
"Cannot move pipette to Heater-Shaker or adjacent slot while module is shaking"
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# If Heater-Shaker's latch is open, can't move to it or east and west of it
|
|
175
|
+
elif hs_movement_restrictor.latch_status != HeaterShakerLatchStatus.CLOSED:
|
|
176
|
+
if dest_heater_shaker:
|
|
177
|
+
raise PipetteMovementRestrictedByHeaterShakerError(
|
|
178
|
+
f"Cannot move pipette to Heater-Shaker while labware latch"
|
|
179
|
+
f" {'has not been closed' if hs_movement_restrictor.latch_status == HeaterShakerLatchStatus.UNKNOWN else 'is open'}."
|
|
180
|
+
)
|
|
181
|
+
if (
|
|
182
|
+
dest_east_west
|
|
183
|
+
and self._state_store.config.robot_type == "OT-2 Standard"
|
|
184
|
+
):
|
|
185
|
+
raise PipetteMovementRestrictedByHeaterShakerError(
|
|
186
|
+
"Cannot move pipette to left or right of Heater-Shaker while labware latch "
|
|
187
|
+
f" {'has not been closed' if hs_movement_restrictor.latch_status == HeaterShakerLatchStatus.UNKNOWN else 'is open'}."
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
elif (
|
|
191
|
+
is_multi_channel
|
|
192
|
+
and self._state_store.config.robot_type == "OT-2 Standard"
|
|
193
|
+
):
|
|
194
|
+
# Can't go to east/west slot under any circumstances on OT-2
|
|
195
|
+
# if pipette is multi-channel
|
|
196
|
+
if dest_east_west:
|
|
197
|
+
raise PipetteMovementRestrictedByHeaterShakerError(
|
|
198
|
+
"Cannot move 8-Channel pipette to slot adjacent to the left or right of Heater-Shaker"
|
|
199
|
+
)
|
|
200
|
+
# Can only go north/south if the labware is a tip rack
|
|
201
|
+
elif dest_north_south and not destination_is_tip_rack:
|
|
202
|
+
raise PipetteMovementRestrictedByHeaterShakerError(
|
|
203
|
+
"Cannot move 8-Channel pipette to non-tip-rack labware directly in front of or behind a Heater-Shaker"
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
class _HardwareHeaterShakerMissingError(Exception):
|
|
207
|
+
pass
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"""Labware movement command handling."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Optional, TYPE_CHECKING, overload
|
|
6
|
+
|
|
7
|
+
from opentrons_shared_data.labware.labware_definition import LabwareDefinition
|
|
8
|
+
|
|
9
|
+
from opentrons.types import Point
|
|
10
|
+
|
|
11
|
+
from opentrons.hardware_control import HardwareControlAPI
|
|
12
|
+
from opentrons.hardware_control.types import OT3Mount, Axis
|
|
13
|
+
from opentrons.motion_planning import get_gripper_labware_movement_waypoints
|
|
14
|
+
|
|
15
|
+
from opentrons.protocol_engine.state.state import StateStore
|
|
16
|
+
from opentrons.protocol_engine.resources.ot3_validation import ensure_ot3_hardware
|
|
17
|
+
|
|
18
|
+
from .thermocycler_movement_flagger import ThermocyclerMovementFlagger
|
|
19
|
+
from .heater_shaker_movement_flagger import HeaterShakerMovementFlagger
|
|
20
|
+
from .thermocycler_plate_lifter import ThermocyclerPlateLifter
|
|
21
|
+
|
|
22
|
+
from ..errors import (
|
|
23
|
+
GripperNotAttachedError,
|
|
24
|
+
LabwareMovementNotAllowedError,
|
|
25
|
+
ThermocyclerNotOpenError,
|
|
26
|
+
HeaterShakerLabwareLatchNotOpenError,
|
|
27
|
+
CannotPerformGripperAction,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
from ..types import (
|
|
31
|
+
OnLabwareLocation,
|
|
32
|
+
LabwareLocation,
|
|
33
|
+
OnDeckLabwareLocation,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from opentrons.protocol_engine.execution import EquipmentHandler, MovementHandler
|
|
38
|
+
|
|
39
|
+
_GRIPPER_HOMED_POSITION_Z = 166.125 # Height of the center of the gripper critical point from the deck when homed
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class LabwareMovementHandler:
|
|
43
|
+
"""Implementation logic for labware movement."""
|
|
44
|
+
|
|
45
|
+
_hardware_api: HardwareControlAPI
|
|
46
|
+
_state_store: StateStore
|
|
47
|
+
_movement: MovementHandler
|
|
48
|
+
_equipment: EquipmentHandler
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
hardware_api: HardwareControlAPI,
|
|
53
|
+
state_store: StateStore,
|
|
54
|
+
equipment: EquipmentHandler,
|
|
55
|
+
movement: MovementHandler,
|
|
56
|
+
thermocycler_plate_lifter: Optional[ThermocyclerPlateLifter] = None,
|
|
57
|
+
thermocycler_movement_flagger: Optional[ThermocyclerMovementFlagger] = None,
|
|
58
|
+
heater_shaker_movement_flagger: Optional[HeaterShakerMovementFlagger] = None,
|
|
59
|
+
) -> None:
|
|
60
|
+
"""Initialize a LabwareMovementHandler instance."""
|
|
61
|
+
self._hardware_api = hardware_api
|
|
62
|
+
self._state_store = state_store
|
|
63
|
+
self._equipment = equipment
|
|
64
|
+
self._thermocycler_plate_lifter = (
|
|
65
|
+
thermocycler_plate_lifter
|
|
66
|
+
or ThermocyclerPlateLifter(
|
|
67
|
+
state_store=self._state_store,
|
|
68
|
+
equipment=equipment,
|
|
69
|
+
movement=movement,
|
|
70
|
+
)
|
|
71
|
+
)
|
|
72
|
+
self._tc_movement_flagger = (
|
|
73
|
+
thermocycler_movement_flagger
|
|
74
|
+
or ThermocyclerMovementFlagger(
|
|
75
|
+
state_store=self._state_store,
|
|
76
|
+
hardware_api=self._hardware_api,
|
|
77
|
+
equipment=self._equipment
|
|
78
|
+
or EquipmentHandler(
|
|
79
|
+
hardware_api=self._hardware_api,
|
|
80
|
+
state_store=self._state_store,
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
self._hs_movement_flagger = (
|
|
85
|
+
heater_shaker_movement_flagger
|
|
86
|
+
or HeaterShakerMovementFlagger(
|
|
87
|
+
state_store=self._state_store, hardware_api=self._hardware_api
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
@overload
|
|
92
|
+
async def move_labware_with_gripper(
|
|
93
|
+
self,
|
|
94
|
+
*,
|
|
95
|
+
labware_id: str,
|
|
96
|
+
current_location: OnDeckLabwareLocation,
|
|
97
|
+
new_location: OnDeckLabwareLocation,
|
|
98
|
+
user_pick_up_offset: Point,
|
|
99
|
+
user_drop_offset: Point,
|
|
100
|
+
post_drop_slide_offset: Optional[Point],
|
|
101
|
+
) -> None:
|
|
102
|
+
...
|
|
103
|
+
|
|
104
|
+
@overload
|
|
105
|
+
async def move_labware_with_gripper(
|
|
106
|
+
self,
|
|
107
|
+
*,
|
|
108
|
+
labware_definition: LabwareDefinition,
|
|
109
|
+
current_location: OnDeckLabwareLocation,
|
|
110
|
+
new_location: OnDeckLabwareLocation,
|
|
111
|
+
user_pick_up_offset: Point,
|
|
112
|
+
user_drop_offset: Point,
|
|
113
|
+
post_drop_slide_offset: Optional[Point],
|
|
114
|
+
gripper_z_offset: Optional[float],
|
|
115
|
+
) -> None:
|
|
116
|
+
...
|
|
117
|
+
|
|
118
|
+
async def move_labware_with_gripper( # noqa: C901
|
|
119
|
+
self,
|
|
120
|
+
*,
|
|
121
|
+
labware_id: str | None = None,
|
|
122
|
+
labware_definition: LabwareDefinition | None = None,
|
|
123
|
+
current_location: OnDeckLabwareLocation,
|
|
124
|
+
new_location: OnDeckLabwareLocation,
|
|
125
|
+
user_pick_up_offset: Point,
|
|
126
|
+
user_drop_offset: Point,
|
|
127
|
+
post_drop_slide_offset: Optional[Point],
|
|
128
|
+
gripper_z_offset: Optional[float] = None,
|
|
129
|
+
) -> None:
|
|
130
|
+
"""Physically move a labware from one location to another using the gripper.
|
|
131
|
+
|
|
132
|
+
Generally, provide the `labware_id` of a loaded labware, and this method will
|
|
133
|
+
automatically look up its labware definition. If you're physically moving
|
|
134
|
+
something that has not been loaded as a labware (this is not common),
|
|
135
|
+
provide the `labware_definition` yourself instead.
|
|
136
|
+
"""
|
|
137
|
+
use_virtual_gripper = self._state_store.config.use_virtual_gripper
|
|
138
|
+
|
|
139
|
+
if labware_definition is None:
|
|
140
|
+
assert labware_id is not None # From this method's @typing.overloads.
|
|
141
|
+
labware_definition = self._state_store.labware.get_definition(labware_id)
|
|
142
|
+
|
|
143
|
+
from_labware_center = self._state_store.geometry.get_labware_grip_point(
|
|
144
|
+
labware_definition=labware_definition, location=current_location
|
|
145
|
+
)
|
|
146
|
+
to_labware_center = self._state_store.geometry.get_labware_grip_point(
|
|
147
|
+
labware_definition=labware_definition, location=new_location
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if use_virtual_gripper:
|
|
151
|
+
# todo(mm, 2024-11-07): We should do this collision checking even when we
|
|
152
|
+
# only have a `labware_definition`, not a `labware_id`. Resolve when
|
|
153
|
+
# `check_gripper_labware_tip_collision()` can be made independent of `labware_id`.
|
|
154
|
+
if labware_id is not None:
|
|
155
|
+
self._state_store.geometry.check_gripper_labware_tip_collision(
|
|
156
|
+
# During Analysis we will pass in hard coded estimates for certain positions only accessible during execution
|
|
157
|
+
gripper_homed_position_z=_GRIPPER_HOMED_POSITION_Z,
|
|
158
|
+
labware_id=labware_id,
|
|
159
|
+
current_location=current_location,
|
|
160
|
+
)
|
|
161
|
+
return
|
|
162
|
+
|
|
163
|
+
ot3api = ensure_ot3_hardware(
|
|
164
|
+
hardware_api=self._hardware_api,
|
|
165
|
+
error_msg="Gripper is only available on Opentrons Flex",
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
if not ot3api.has_gripper():
|
|
169
|
+
raise GripperNotAttachedError(
|
|
170
|
+
"No gripper found for performing labware movements."
|
|
171
|
+
)
|
|
172
|
+
if not ot3api.gripper_jaw_can_home():
|
|
173
|
+
raise CannotPerformGripperAction(
|
|
174
|
+
"Cannot pick up labware when gripper is already gripping."
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
gripper_mount = OT3Mount.GRIPPER
|
|
178
|
+
|
|
179
|
+
# Retract all mounts
|
|
180
|
+
await ot3api.home(axes=[Axis.Z_L, Axis.Z_R, Axis.Z_G])
|
|
181
|
+
gripper_homed_position = await ot3api.gantry_position(mount=gripper_mount)
|
|
182
|
+
|
|
183
|
+
# todo(mm, 2024-11-07): We should do this collision checking even when we
|
|
184
|
+
# only have a `labware_definition`, not a `labware_id`. Resolve when
|
|
185
|
+
# `check_gripper_labware_tip_collision()` can be made independent of `labware_id`.
|
|
186
|
+
if labware_id is not None:
|
|
187
|
+
self._state_store.geometry.check_gripper_labware_tip_collision(
|
|
188
|
+
gripper_homed_position_z=gripper_homed_position.z,
|
|
189
|
+
labware_id=labware_id,
|
|
190
|
+
current_location=current_location,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
async with self._thermocycler_plate_lifter.lift_plate_for_labware_movement(
|
|
194
|
+
labware_location=current_location
|
|
195
|
+
):
|
|
196
|
+
final_offsets = (
|
|
197
|
+
self._state_store.geometry.get_final_labware_movement_offset_vectors(
|
|
198
|
+
from_location=current_location,
|
|
199
|
+
to_location=new_location,
|
|
200
|
+
additional_pick_up_offset=user_pick_up_offset,
|
|
201
|
+
additional_drop_offset=user_drop_offset,
|
|
202
|
+
current_labware=labware_definition,
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
movement_waypoints = get_gripper_labware_movement_waypoints(
|
|
206
|
+
from_labware_center=from_labware_center,
|
|
207
|
+
to_labware_center=to_labware_center,
|
|
208
|
+
gripper_home_z=gripper_homed_position.z,
|
|
209
|
+
offset_data=final_offsets,
|
|
210
|
+
post_drop_slide_offset=post_drop_slide_offset,
|
|
211
|
+
gripper_home_z_offset=gripper_z_offset,
|
|
212
|
+
)
|
|
213
|
+
labware_grip_force = self._state_store.labware.get_grip_force(
|
|
214
|
+
labware_definition
|
|
215
|
+
)
|
|
216
|
+
holding_labware = False
|
|
217
|
+
for waypoint_data in movement_waypoints:
|
|
218
|
+
if waypoint_data.jaw_open:
|
|
219
|
+
if waypoint_data.dropping:
|
|
220
|
+
# This `disengage_axes` step is important in order to engage
|
|
221
|
+
# the electronic brake on the Z axis of the gripper. The brake
|
|
222
|
+
# has a stronger holding force on the axis than the hold current,
|
|
223
|
+
# and prevents the axis from spuriously dropping when e.g. the notch
|
|
224
|
+
# on the side of a falling tiprack catches the jaw.
|
|
225
|
+
await ot3api.disengage_axes([Axis.Z_G])
|
|
226
|
+
await ot3api.ungrip()
|
|
227
|
+
holding_labware = True
|
|
228
|
+
if waypoint_data.dropping:
|
|
229
|
+
# We lost the position estimation after disengaging the axis, so
|
|
230
|
+
# it is necessary to home it next
|
|
231
|
+
await ot3api.home_z(OT3Mount.GRIPPER)
|
|
232
|
+
else:
|
|
233
|
+
await ot3api.grip(force_newtons=labware_grip_force)
|
|
234
|
+
# we only want to check position after the gripper has opened and
|
|
235
|
+
# should be holding labware
|
|
236
|
+
if holding_labware:
|
|
237
|
+
labware_bbox = self._state_store.labware.get_dimensions(
|
|
238
|
+
labware_definition=labware_definition
|
|
239
|
+
)
|
|
240
|
+
well_bbox = self._state_store.labware.get_well_bbox(
|
|
241
|
+
labware_definition=labware_definition
|
|
242
|
+
)
|
|
243
|
+
# todo(mm, 2024-09-26): This currently raises a lower-level 2015 FailedGripperPickupError.
|
|
244
|
+
# Convert this to a higher-level 3001 LabwareDroppedError or 3002 LabwareNotPickedUpError,
|
|
245
|
+
# depending on what waypoint we're at, to propagate a more specific error code to users.
|
|
246
|
+
ot3api.raise_error_if_gripper_pickup_failed(
|
|
247
|
+
expected_grip_width=labware_bbox.y,
|
|
248
|
+
grip_width_uncertainty_wider=abs(
|
|
249
|
+
max(well_bbox.y - labware_bbox.y, 0)
|
|
250
|
+
),
|
|
251
|
+
grip_width_uncertainty_narrower=abs(
|
|
252
|
+
min(well_bbox.y - labware_bbox.y, 0)
|
|
253
|
+
),
|
|
254
|
+
)
|
|
255
|
+
await ot3api.move_to(
|
|
256
|
+
mount=gripper_mount, abs_position=waypoint_data.position
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
# this makes sure gripper jaw is closed between two move labware calls
|
|
260
|
+
await ot3api.idle_gripper()
|
|
261
|
+
|
|
262
|
+
async def ensure_movement_not_obstructed_by_module(
|
|
263
|
+
self, labware_id: str, new_location: LabwareLocation
|
|
264
|
+
) -> None:
|
|
265
|
+
"""Ensure that the labware movement is not obstructed by a parent module.
|
|
266
|
+
|
|
267
|
+
Raises: LabwareMovementNotAllowedError if either current location or
|
|
268
|
+
new location is a module that is in a state that prevents the labware from
|
|
269
|
+
being moved (either manually or using gripper).
|
|
270
|
+
"""
|
|
271
|
+
current_parent = self._state_store.labware.get_parent_location(
|
|
272
|
+
labware_id=labware_id
|
|
273
|
+
)
|
|
274
|
+
if isinstance(new_location, OnLabwareLocation):
|
|
275
|
+
new_location = self._state_store.labware.get_parent_location(
|
|
276
|
+
labware_id=new_location.labwareId
|
|
277
|
+
)
|
|
278
|
+
for parent in (current_parent, new_location):
|
|
279
|
+
try:
|
|
280
|
+
await self._tc_movement_flagger.ensure_labware_in_open_thermocycler(
|
|
281
|
+
labware_parent=parent
|
|
282
|
+
)
|
|
283
|
+
if not self._state_store.labware.is_lid(labware_id):
|
|
284
|
+
# Lid placement is actually improved by holding the labware latched on the H/S
|
|
285
|
+
# So, we skip this check for lids.
|
|
286
|
+
await self._hs_movement_flagger.raise_if_labware_latched_on_heater_shaker(
|
|
287
|
+
labware_parent=parent
|
|
288
|
+
)
|
|
289
|
+
except ThermocyclerNotOpenError:
|
|
290
|
+
raise LabwareMovementNotAllowedError(
|
|
291
|
+
"Cannot move labware to or from a Thermocycler with its lid closed."
|
|
292
|
+
)
|
|
293
|
+
except HeaterShakerLabwareLatchNotOpenError:
|
|
294
|
+
raise LabwareMovementNotAllowedError(
|
|
295
|
+
"Cannot move labware to or from a Heater-Shaker"
|
|
296
|
+
" with its labware latch closed."
|
|
297
|
+
)
|