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,547 @@
|
|
|
1
|
+
""" opentrons.protocol_api.module_geometry: classes and functions for modules
|
|
2
|
+
as deck objects
|
|
3
|
+
|
|
4
|
+
This module provides things like :py:class:`ModuleGeometry` and
|
|
5
|
+
:py:func:`load_module` to create and manipulate module objects as geometric
|
|
6
|
+
objects on the deck (as opposed to calling commands on them, which is handled
|
|
7
|
+
by :py:mod:`.module_contexts`)
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
from enum import Enum
|
|
13
|
+
from typing import TYPE_CHECKING, Optional
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
from numpy.typing import NDArray
|
|
17
|
+
|
|
18
|
+
from opentrons_shared_data import module
|
|
19
|
+
from opentrons_shared_data.module.types import ModuleDefinitionV3
|
|
20
|
+
from opentrons_shared_data.module import OLD_TC_GEN2_LABWARE_OFFSET
|
|
21
|
+
|
|
22
|
+
from opentrons.types import Location, Point, LocationLabware
|
|
23
|
+
from opentrons.motion_planning.adjacent_slots_getters import (
|
|
24
|
+
get_north_south_slots,
|
|
25
|
+
get_east_west_slots,
|
|
26
|
+
get_adjacent_slots,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
from opentrons.drivers.types import ThermocyclerLidStatus
|
|
30
|
+
from opentrons.hardware_control.modules.types import (
|
|
31
|
+
ModuleModel,
|
|
32
|
+
ModuleType,
|
|
33
|
+
module_model_from_string,
|
|
34
|
+
ThermocyclerModuleModel,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
if TYPE_CHECKING:
|
|
38
|
+
from opentrons.protocol_api.labware import Labware
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
_log = logging.getLogger(__name__)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ThermocyclerConfiguration(str, Enum):
|
|
45
|
+
FULL = "full"
|
|
46
|
+
SEMI = "semi"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class NoSuchModuleError(ValueError):
|
|
50
|
+
"""An error raised if a requested model does not match a known module."""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class PipetteMovementRestrictedByHeaterShakerError(Exception):
|
|
54
|
+
"""Error raised when trying to move to labware restricted by Heater-Shaker."""
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# TODO (spp, 2022-05-09): add tests
|
|
58
|
+
class ModuleGeometry:
|
|
59
|
+
"""
|
|
60
|
+
This class represents an active peripheral, such as an Opentrons Magnetic
|
|
61
|
+
Module, Temperature Module or Thermocycler Module. It defines the physical
|
|
62
|
+
geometry of the device (primarily the offset that modifies the position of
|
|
63
|
+
the labware mounted on top of it).
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def separate_calibration(self) -> bool:
|
|
68
|
+
_log.warning(
|
|
69
|
+
"ModuleGeometry.separate_calibrations is a deprecated internal property."
|
|
70
|
+
" It has no longer has meaning, but will always return `True`"
|
|
71
|
+
)
|
|
72
|
+
return True
|
|
73
|
+
|
|
74
|
+
def __init__(
|
|
75
|
+
self,
|
|
76
|
+
display_name: str,
|
|
77
|
+
model: ModuleModel,
|
|
78
|
+
module_type: ModuleType,
|
|
79
|
+
offset: Point,
|
|
80
|
+
overall_height: float,
|
|
81
|
+
height_over_labware: float,
|
|
82
|
+
parent: Location,
|
|
83
|
+
) -> None:
|
|
84
|
+
"""
|
|
85
|
+
Create a Module for tracking the position of a module.
|
|
86
|
+
|
|
87
|
+
Note that modules do not currently have a concept of calibration apart
|
|
88
|
+
from calibration of labware on top of the module. The practical result
|
|
89
|
+
of this is that if the module parent :py:class:`.Location` is
|
|
90
|
+
incorrect, then a correct calibration of one labware on the deck would
|
|
91
|
+
be incorrect on the module, and vice-versa. Currently, the way around
|
|
92
|
+
this would be to correct the :py:class:`.Location` so that the
|
|
93
|
+
calibrated labware is targeted accurately in both positions.
|
|
94
|
+
|
|
95
|
+
:param display_name: A human-readable display name of only the module
|
|
96
|
+
(for instance, "Thermocycler Module" - not
|
|
97
|
+
including parents or location)
|
|
98
|
+
:param model: The model of module this represents
|
|
99
|
+
:param offset: The offset from the slot origin at which labware loaded
|
|
100
|
+
on this module should be placed
|
|
101
|
+
:param overall_height: The height of the module without labware
|
|
102
|
+
:param height_over_labware: The height of this module over the top of
|
|
103
|
+
the labware
|
|
104
|
+
:param parent: A location representing location of the front left of
|
|
105
|
+
the outside of the module (usually the front-left corner
|
|
106
|
+
of a slot on the deck).
|
|
107
|
+
:type parent: :py:class:`.Location`
|
|
108
|
+
"""
|
|
109
|
+
self._parent = parent
|
|
110
|
+
self._module_type = module_type
|
|
111
|
+
|
|
112
|
+
self._display_name = display_name
|
|
113
|
+
self._model = model
|
|
114
|
+
self._offset = offset
|
|
115
|
+
self._height = overall_height + self._parent.point.z
|
|
116
|
+
self._over_labware = height_over_labware
|
|
117
|
+
self._labware: Optional[Labware] = None
|
|
118
|
+
self._location = Location(point=self._offset + self._parent.point, labware=self)
|
|
119
|
+
|
|
120
|
+
def add_labware(self, labware: Labware) -> Labware:
|
|
121
|
+
if self._labware is not None:
|
|
122
|
+
raise RuntimeError(f"{self._labware} is already on this module")
|
|
123
|
+
self._labware = labware
|
|
124
|
+
return self._labware
|
|
125
|
+
|
|
126
|
+
def reset_labware(self) -> None:
|
|
127
|
+
self._labware = None
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def display_name(self) -> str:
|
|
131
|
+
return self._display_name
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def model(self) -> ModuleModel:
|
|
135
|
+
return self._model
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def load_name(self) -> str:
|
|
139
|
+
# Mypy (at the time of writing, v0.910) incorrectly types self.model.value as
|
|
140
|
+
# Any. It seems to have trouble with it being a union of enums.
|
|
141
|
+
assert isinstance(self.model.value, str)
|
|
142
|
+
return self.model.value
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def module_type(self) -> ModuleType:
|
|
146
|
+
"""The Moduletype"""
|
|
147
|
+
return self._module_type
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def parent(self) -> LocationLabware:
|
|
151
|
+
return self._parent.labware.object
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def labware(self) -> Optional[Labware]:
|
|
155
|
+
return self._labware
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def location(self) -> Location:
|
|
159
|
+
"""
|
|
160
|
+
:return: a :py:class:`.Location` representing the top of the module
|
|
161
|
+
"""
|
|
162
|
+
return self._location
|
|
163
|
+
|
|
164
|
+
@property
|
|
165
|
+
def labware_offset(self) -> Point:
|
|
166
|
+
"""
|
|
167
|
+
:return: a :py:class:`.Point` representing the transformation
|
|
168
|
+
between the critical point of the module and the critical
|
|
169
|
+
point of its contained labware
|
|
170
|
+
"""
|
|
171
|
+
return self._offset
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def highest_z(self) -> float:
|
|
175
|
+
if self.labware:
|
|
176
|
+
return self.labware.highest_z + self._over_labware
|
|
177
|
+
else:
|
|
178
|
+
return self._height
|
|
179
|
+
|
|
180
|
+
def __repr__(self) -> str:
|
|
181
|
+
location = f" on {self.parent}" if isinstance(self.parent, str) else ""
|
|
182
|
+
return f"{self._display_name}{location}"
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class ThermocyclerGeometry(ModuleGeometry):
|
|
186
|
+
def __init__(
|
|
187
|
+
self,
|
|
188
|
+
display_name: str,
|
|
189
|
+
model: ModuleModel,
|
|
190
|
+
module_type: ModuleType,
|
|
191
|
+
offset: Point,
|
|
192
|
+
overall_height: float,
|
|
193
|
+
height_over_labware: float,
|
|
194
|
+
lid_height: float,
|
|
195
|
+
parent: Location,
|
|
196
|
+
configuration: ThermocyclerConfiguration = ThermocyclerConfiguration.FULL,
|
|
197
|
+
) -> None:
|
|
198
|
+
"""
|
|
199
|
+
Create a Module for tracking the position of a module.
|
|
200
|
+
|
|
201
|
+
Note that modules do not currently have a concept of calibration apart
|
|
202
|
+
from calibration of labware on top of the module. The practical result
|
|
203
|
+
of this is that if the module parent :py:class:`.Location` is
|
|
204
|
+
incorrect, then a correct calibration of one labware on the deck would
|
|
205
|
+
be incorrect on the module, and vice-versa. Currently, the way around
|
|
206
|
+
this would be to correct the :py:class:`.Location` so that the
|
|
207
|
+
calibrated labware is targeted accurately in both positions.
|
|
208
|
+
|
|
209
|
+
:param display_name: A human-readable display name of only the module
|
|
210
|
+
(for instance, "Thermocycler Module" - not
|
|
211
|
+
including parents or location)
|
|
212
|
+
:param model: The model of module this represents
|
|
213
|
+
:param offset: The offset from the slot origin at which labware loaded
|
|
214
|
+
on this module should be placed
|
|
215
|
+
:param overall_height: The height of the module without labware
|
|
216
|
+
:param height_over_labware: The height of this module over the top of
|
|
217
|
+
the labware
|
|
218
|
+
:param parent: A location representing location of the front left of
|
|
219
|
+
the outside of the module (usually the front-left corner
|
|
220
|
+
of a slot on the deck).
|
|
221
|
+
:type parent: :py:class:`.Location`
|
|
222
|
+
:param configuration: Used to specify the slot configuration of
|
|
223
|
+
the Thermocycler. It should by of type
|
|
224
|
+
:py:class:`.ThermocyclerConfiguration` and can
|
|
225
|
+
either be FULL or SEMI.
|
|
226
|
+
"""
|
|
227
|
+
super().__init__(
|
|
228
|
+
display_name,
|
|
229
|
+
model,
|
|
230
|
+
module_type,
|
|
231
|
+
offset,
|
|
232
|
+
overall_height,
|
|
233
|
+
height_over_labware,
|
|
234
|
+
parent,
|
|
235
|
+
)
|
|
236
|
+
self._lid_height = lid_height
|
|
237
|
+
self._lid_status = ThermocyclerLidStatus.OPEN # Needs to reflect true status
|
|
238
|
+
self._configuration = configuration
|
|
239
|
+
if self.is_semi_configuration:
|
|
240
|
+
self._offset = self._offset + Point(-23.28, 0, 0)
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
def highest_z(self) -> float:
|
|
244
|
+
# TODO: BC 2019-08-27 this highest_z value represents the distance
|
|
245
|
+
# from the top of the open TC chassis to the base. Once we have a
|
|
246
|
+
# more robust collision detection system in place, the collision
|
|
247
|
+
# model for the TC should change based on it's lid_status
|
|
248
|
+
# (open or closed). A prerequisite for that check will be
|
|
249
|
+
# path-specific highest z calculations, as opposed to the current
|
|
250
|
+
# global check on instrument.move_to. For example: a move from slot 1
|
|
251
|
+
# to slot 3 should only check the highest z of all deck items between
|
|
252
|
+
# the source and destination in the x,y plane.
|
|
253
|
+
return super().highest_z
|
|
254
|
+
|
|
255
|
+
@property
|
|
256
|
+
def lid_status(self) -> ThermocyclerLidStatus:
|
|
257
|
+
return self._lid_status
|
|
258
|
+
|
|
259
|
+
@lid_status.setter
|
|
260
|
+
def lid_status(self, status: ThermocyclerLidStatus) -> None:
|
|
261
|
+
self._lid_status = status
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def is_semi_configuration(self) -> bool:
|
|
265
|
+
return bool(self._configuration == ThermocyclerConfiguration.SEMI)
|
|
266
|
+
|
|
267
|
+
# TODO(mc, 2022-11-16): this method causes bugs and should not be used;
|
|
268
|
+
# Thermocycler `configuration="semi"` does not work properly and should be removed
|
|
269
|
+
# https://opentrons.atlassian.net/browse/RSS-106
|
|
270
|
+
def labware_accessor(self, labware: Labware) -> Labware:
|
|
271
|
+
from opentrons.protocol_api.labware import Labware
|
|
272
|
+
from opentrons.protocol_api.core.legacy.legacy_labware_core import (
|
|
273
|
+
LegacyLabwareCore,
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
definition = labware._core.get_definition()
|
|
277
|
+
|
|
278
|
+
# For type checking. This should always pass because
|
|
279
|
+
# opentrons.protocol_api.core.legacy should only load labware with schema 2.
|
|
280
|
+
assert definition["schemaVersion"] == 2
|
|
281
|
+
|
|
282
|
+
# Block first three columns from being accessed
|
|
283
|
+
definition["ordering"] = definition["ordering"][2::]
|
|
284
|
+
return Labware(
|
|
285
|
+
core=LegacyLabwareCore(definition, super().location),
|
|
286
|
+
api_version=labware.api_version,
|
|
287
|
+
protocol_core=None, # type: ignore[arg-type]
|
|
288
|
+
core_map=None, # type: ignore[arg-type]
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
def add_labware(self, labware: Labware) -> Labware:
|
|
292
|
+
if self._labware is not None:
|
|
293
|
+
raise RuntimeError(f"{self._labware} is already on this module")
|
|
294
|
+
if self.lid_status == "closed":
|
|
295
|
+
raise RuntimeError("Cannot place labware in closed module")
|
|
296
|
+
if self.is_semi_configuration:
|
|
297
|
+
self._labware = self.labware_accessor(labware)
|
|
298
|
+
else:
|
|
299
|
+
self._labware = labware
|
|
300
|
+
return self._labware
|
|
301
|
+
|
|
302
|
+
def flag_unsafe_move(
|
|
303
|
+
self,
|
|
304
|
+
to_loc: Location,
|
|
305
|
+
from_loc: Location,
|
|
306
|
+
lid_position: Optional[str],
|
|
307
|
+
) -> None:
|
|
308
|
+
to_lw, to_well = to_loc.labware.get_parent_labware_and_well()
|
|
309
|
+
from_lw, from_well = from_loc.labware.get_parent_labware_and_well()
|
|
310
|
+
|
|
311
|
+
if (
|
|
312
|
+
self.labware is not None
|
|
313
|
+
and (self.labware == to_lw or self.labware == from_lw)
|
|
314
|
+
and lid_position != "open"
|
|
315
|
+
):
|
|
316
|
+
raise RuntimeError(
|
|
317
|
+
"Cannot move to labware loaded in Thermocycler"
|
|
318
|
+
" when lid is not fully open."
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
class HeaterShakerGeometry(ModuleGeometry):
|
|
323
|
+
"""Class holding the state of a Heater-Shaker's physical geometry."""
|
|
324
|
+
|
|
325
|
+
def flag_unsafe_move(
|
|
326
|
+
self,
|
|
327
|
+
to_slot: int,
|
|
328
|
+
is_tiprack: bool,
|
|
329
|
+
is_using_multichannel: bool,
|
|
330
|
+
is_labware_latch_closed: bool,
|
|
331
|
+
is_plate_shaking: bool,
|
|
332
|
+
) -> None:
|
|
333
|
+
"""Raise error if unsafe to move pipette due to Heater-Shaker placement."""
|
|
334
|
+
assert isinstance(self.parent, str), "Could not determine module slot location"
|
|
335
|
+
|
|
336
|
+
heater_shaker_slot = int(self.parent)
|
|
337
|
+
dest_east_west = to_slot in get_east_west_slots(heater_shaker_slot)
|
|
338
|
+
dest_north_south = to_slot in get_north_south_slots(heater_shaker_slot)
|
|
339
|
+
dest_heater_shaker = to_slot == heater_shaker_slot
|
|
340
|
+
|
|
341
|
+
# If Heater-Shaker is running, can't move to or around it
|
|
342
|
+
if (
|
|
343
|
+
any([dest_east_west, dest_north_south, dest_heater_shaker])
|
|
344
|
+
and is_plate_shaking
|
|
345
|
+
):
|
|
346
|
+
raise PipetteMovementRestrictedByHeaterShakerError(
|
|
347
|
+
"Cannot move pipette to Heater-Shaker or adjacent slot while module is shaking"
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
# If Heater-Shaker's latch is open, can't move to it or east and west of it
|
|
351
|
+
elif (dest_east_west or dest_heater_shaker) and not is_labware_latch_closed:
|
|
352
|
+
raise PipetteMovementRestrictedByHeaterShakerError(
|
|
353
|
+
"Cannot move pipette to Heater-Shaker or adjacent slot to the left or right while labware latch is open"
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
elif is_using_multichannel:
|
|
357
|
+
# Can't go to east/west slot under any circumstances if pipette is multi-channel
|
|
358
|
+
if dest_east_west:
|
|
359
|
+
raise PipetteMovementRestrictedByHeaterShakerError(
|
|
360
|
+
"Cannot move 8-Channel pipette to slot adjacent to the left or right of Heater-Shaker"
|
|
361
|
+
)
|
|
362
|
+
# Can only go north/south if the labware is a tip rack
|
|
363
|
+
elif dest_north_south and not is_tiprack:
|
|
364
|
+
raise PipetteMovementRestrictedByHeaterShakerError(
|
|
365
|
+
"Cannot move 8-Channel pipette to non-tip-rack labware directly in front of or behind a Heater-Shaker"
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
def is_pipette_blocking_shake_movement(
|
|
369
|
+
self, pipette_location: Optional[Location]
|
|
370
|
+
) -> bool:
|
|
371
|
+
"""Check whether pipette is parked adjacent to Heater-Shaker.
|
|
372
|
+
|
|
373
|
+
Returns True if pipette's last known location was in a slot adjacent to or
|
|
374
|
+
on the Heater-Shaker. Also returns True if last location is not known or is
|
|
375
|
+
not associated with a slot.
|
|
376
|
+
"""
|
|
377
|
+
if pipette_location is None:
|
|
378
|
+
# If we don't know the pipette's latest location then let's be extra
|
|
379
|
+
# cautious and call it blocking
|
|
380
|
+
return True
|
|
381
|
+
|
|
382
|
+
pipette_location_slot = pipette_location.labware.first_parent()
|
|
383
|
+
if pipette_location_slot is None:
|
|
384
|
+
# If a location is not associated w/ a slot (e.g., if it has labware=None)
|
|
385
|
+
# then we don't know if it's close to the h/s, so, we will be cautious
|
|
386
|
+
# and call it blocking
|
|
387
|
+
return True
|
|
388
|
+
|
|
389
|
+
heater_shaker_slot = self.parent
|
|
390
|
+
|
|
391
|
+
assert isinstance(
|
|
392
|
+
heater_shaker_slot, str
|
|
393
|
+
), "Could not determine module slot location"
|
|
394
|
+
|
|
395
|
+
return heater_shaker_slot == pipette_location_slot or int(
|
|
396
|
+
pipette_location_slot
|
|
397
|
+
) in get_adjacent_slots(int(heater_shaker_slot))
|
|
398
|
+
|
|
399
|
+
def is_pipette_blocking_latch_movement(
|
|
400
|
+
self, pipette_location: Optional[Location]
|
|
401
|
+
) -> bool:
|
|
402
|
+
"""Check whether pipette is parked left or right of Heater-Shaker.
|
|
403
|
+
|
|
404
|
+
Returns True is pipette's last known location was on the Heater-Shaker
|
|
405
|
+
or in a slot adjacent to its left or right. Also returns True if last
|
|
406
|
+
location is not known or is not associated with a slot.
|
|
407
|
+
"""
|
|
408
|
+
if pipette_location is None:
|
|
409
|
+
# If we don't know the pipette's latest location then let's be extra
|
|
410
|
+
# cautious and call it blocking
|
|
411
|
+
return True
|
|
412
|
+
|
|
413
|
+
pipette_location_slot = pipette_location.labware.first_parent()
|
|
414
|
+
if pipette_location_slot is None:
|
|
415
|
+
# If a location is not associated w/ a slot (e.g., if it has labware=None)
|
|
416
|
+
# then we don't know if it's close to the h/s, so, we will be cautious
|
|
417
|
+
# and call it blocking
|
|
418
|
+
return True
|
|
419
|
+
|
|
420
|
+
heater_shaker_slot = self.parent
|
|
421
|
+
|
|
422
|
+
assert isinstance(
|
|
423
|
+
heater_shaker_slot, str
|
|
424
|
+
), "Could not determine module slot location"
|
|
425
|
+
|
|
426
|
+
return heater_shaker_slot == pipette_location_slot or int(
|
|
427
|
+
pipette_location_slot
|
|
428
|
+
) in get_east_west_slots(int(heater_shaker_slot))
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def create_geometry(
|
|
432
|
+
definition: ModuleDefinitionV3,
|
|
433
|
+
parent: Location,
|
|
434
|
+
configuration: Optional[str],
|
|
435
|
+
) -> ModuleGeometry:
|
|
436
|
+
"""Create a module geometry object from the module's definition and location.
|
|
437
|
+
|
|
438
|
+
The definition should be schema checked before being passed to this
|
|
439
|
+
function; all definitions passed here are assumed to be valid.
|
|
440
|
+
"""
|
|
441
|
+
module_type = ModuleType(definition["moduleType"])
|
|
442
|
+
module_model = module_model_from_string(definition["model"])
|
|
443
|
+
overall_height = definition["dimensions"]["bareOverallHeight"]
|
|
444
|
+
height_over_labware = definition["dimensions"]["overLabwareHeight"]
|
|
445
|
+
display_name = definition["displayName"]
|
|
446
|
+
|
|
447
|
+
if module_model == ThermocyclerModuleModel.THERMOCYCLER_V2:
|
|
448
|
+
pre_transform: NDArray[np.double] = np.array(
|
|
449
|
+
(
|
|
450
|
+
OLD_TC_GEN2_LABWARE_OFFSET["x"],
|
|
451
|
+
OLD_TC_GEN2_LABWARE_OFFSET["y"],
|
|
452
|
+
OLD_TC_GEN2_LABWARE_OFFSET["z"],
|
|
453
|
+
1,
|
|
454
|
+
)
|
|
455
|
+
)
|
|
456
|
+
else:
|
|
457
|
+
pre_transform = np.array(
|
|
458
|
+
(
|
|
459
|
+
definition["labwareOffset"]["x"],
|
|
460
|
+
definition["labwareOffset"]["y"],
|
|
461
|
+
definition["labwareOffset"]["z"],
|
|
462
|
+
1,
|
|
463
|
+
)
|
|
464
|
+
)
|
|
465
|
+
if not parent.labware.is_slot:
|
|
466
|
+
par = ""
|
|
467
|
+
_log.warning(
|
|
468
|
+
f"module location parent labware was {parent.labware} which is"
|
|
469
|
+
"not a slot name; slot transforms will not be loaded"
|
|
470
|
+
)
|
|
471
|
+
else:
|
|
472
|
+
par = str(parent.labware.object)
|
|
473
|
+
|
|
474
|
+
# This ModuleGeometry class is only used in Python Protocol API versions <=2.13,
|
|
475
|
+
# which only support the OT-2, so we can ignore OT-3s and hard-code "ot2_standard."
|
|
476
|
+
# We also assume that "ot2_short_trash" has the same transforms as "ot2_standard."
|
|
477
|
+
xforms_ser = (
|
|
478
|
+
definition["slotTransforms"]
|
|
479
|
+
.get("ot2_standard", {})
|
|
480
|
+
.get(
|
|
481
|
+
par,
|
|
482
|
+
{"labwareOffset": [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]},
|
|
483
|
+
)
|
|
484
|
+
)
|
|
485
|
+
xform_ser = xforms_ser["labwareOffset"]
|
|
486
|
+
|
|
487
|
+
# apply the slot transform if any
|
|
488
|
+
xform: NDArray[np.double] = np.array(xform_ser)
|
|
489
|
+
xformed = np.dot(xform, pre_transform)
|
|
490
|
+
labware_offset = Point(xformed[0], xformed[1], xformed[2])
|
|
491
|
+
|
|
492
|
+
if module_type == ModuleType.MAGNETIC or module_type == ModuleType.TEMPERATURE:
|
|
493
|
+
return ModuleGeometry(
|
|
494
|
+
parent=parent,
|
|
495
|
+
offset=labware_offset,
|
|
496
|
+
overall_height=overall_height,
|
|
497
|
+
height_over_labware=height_over_labware,
|
|
498
|
+
model=module_model,
|
|
499
|
+
module_type=module_type,
|
|
500
|
+
display_name=display_name,
|
|
501
|
+
)
|
|
502
|
+
elif module_type == ModuleType.THERMOCYCLER:
|
|
503
|
+
return ThermocyclerGeometry(
|
|
504
|
+
parent=parent,
|
|
505
|
+
offset=labware_offset,
|
|
506
|
+
overall_height=overall_height,
|
|
507
|
+
height_over_labware=height_over_labware,
|
|
508
|
+
model=module_model,
|
|
509
|
+
module_type=module_type,
|
|
510
|
+
display_name=display_name,
|
|
511
|
+
lid_height=definition["dimensions"]["lidHeight"],
|
|
512
|
+
configuration=(
|
|
513
|
+
ThermocyclerConfiguration(configuration)
|
|
514
|
+
if configuration is not None
|
|
515
|
+
else ThermocyclerConfiguration.FULL
|
|
516
|
+
),
|
|
517
|
+
)
|
|
518
|
+
elif module_type == ModuleType.HEATER_SHAKER:
|
|
519
|
+
return HeaterShakerGeometry(
|
|
520
|
+
parent=parent,
|
|
521
|
+
offset=labware_offset,
|
|
522
|
+
overall_height=overall_height,
|
|
523
|
+
height_over_labware=height_over_labware,
|
|
524
|
+
model=module_model,
|
|
525
|
+
module_type=module_type,
|
|
526
|
+
display_name=display_name,
|
|
527
|
+
)
|
|
528
|
+
else:
|
|
529
|
+
raise AssertionError(f"Module type {module_type} is invalid")
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def load_definition(model: str) -> ModuleDefinitionV3:
|
|
533
|
+
"""Load the geometry definition of a given module by model."""
|
|
534
|
+
try:
|
|
535
|
+
return module.load_definition("3", model)
|
|
536
|
+
except module.ModuleNotFoundError:
|
|
537
|
+
raise NoSuchModuleError(f'Could not find a module with model "{model}"')
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
def models_compatible(
|
|
541
|
+
requested_model: ModuleModel, candidate_definition: ModuleDefinitionV3
|
|
542
|
+
) -> bool:
|
|
543
|
+
"""Check if a requested model is compatible with a given definition."""
|
|
544
|
+
return (
|
|
545
|
+
requested_model.value == candidate_definition["model"]
|
|
546
|
+
or requested_model.value in candidate_definition["compatibleWith"]
|
|
547
|
+
)
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Optional, cast, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from opentrons.types import Point
|
|
6
|
+
from opentrons_shared_data.labware.types import (
|
|
7
|
+
WellDefinition2 as WellDefinition,
|
|
8
|
+
CircularWellDefinition2 as CircularWellDefinition,
|
|
9
|
+
RectangularWellDefinition2 as RectangularWellDefinition,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from .legacy_labware_core import LegacyLabwareCore
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class WellGeometry:
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
well_props: WellDefinition,
|
|
20
|
+
parent_point: Point,
|
|
21
|
+
parent_object: LegacyLabwareCore,
|
|
22
|
+
):
|
|
23
|
+
"""
|
|
24
|
+
Construct a well geometry object.
|
|
25
|
+
|
|
26
|
+
:param well_props: Properties from the labware definition
|
|
27
|
+
:param parent_point: The coordinate of parent labware
|
|
28
|
+
:param parent_object: The parent labware
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
self._position = (
|
|
32
|
+
Point(
|
|
33
|
+
well_props["x"], well_props["y"], well_props["z"] + well_props["depth"]
|
|
34
|
+
)
|
|
35
|
+
+ parent_point
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
if not parent_object:
|
|
39
|
+
raise ValueError("Wells must have a parent")
|
|
40
|
+
|
|
41
|
+
self._parent = parent_object
|
|
42
|
+
|
|
43
|
+
self._length: Optional[float] = None
|
|
44
|
+
self._width: Optional[float] = None
|
|
45
|
+
self._diameter: Optional[float] = None
|
|
46
|
+
|
|
47
|
+
shape = well_props["shape"]
|
|
48
|
+
if shape == "rectangular":
|
|
49
|
+
rect_props = cast(RectangularWellDefinition, well_props)
|
|
50
|
+
self._length = rect_props["xDimension"]
|
|
51
|
+
self._width = rect_props["yDimension"]
|
|
52
|
+
self._x_size = self._length
|
|
53
|
+
self._y_size = self._width
|
|
54
|
+
elif shape == "circular":
|
|
55
|
+
circular_props = cast(CircularWellDefinition, well_props)
|
|
56
|
+
self._diameter = circular_props["diameter"]
|
|
57
|
+
self._x_size = self._y_size = self._diameter
|
|
58
|
+
else:
|
|
59
|
+
raise ValueError(f'Shape "{shape}" is not a supported well shape')
|
|
60
|
+
|
|
61
|
+
self._max_volume = well_props["totalLiquidVolume"]
|
|
62
|
+
self._depth = well_props["depth"]
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def parent(self) -> LegacyLabwareCore:
|
|
66
|
+
return self._parent
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def position(self) -> Point:
|
|
70
|
+
return self._position
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def diameter(self) -> Optional[float]:
|
|
74
|
+
return self._diameter
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def length(self) -> Optional[float]:
|
|
78
|
+
return self._length
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def width(self) -> Optional[float]:
|
|
82
|
+
return self._width
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def depth(self) -> float:
|
|
86
|
+
return self._depth
|
|
87
|
+
|
|
88
|
+
def top(self, z: float = 0.0) -> Point:
|
|
89
|
+
return self._position + Point(0, 0, z)
|
|
90
|
+
|
|
91
|
+
def bottom(self, z: float = 0.0) -> Point:
|
|
92
|
+
top = self.top()
|
|
93
|
+
bottom_z = top.z - self._depth + z
|
|
94
|
+
return Point(x=top.x, y=top.y, z=bottom_z)
|
|
95
|
+
|
|
96
|
+
def center(self) -> Point:
|
|
97
|
+
top = self.top()
|
|
98
|
+
center_z = top.z - (self._depth / 2.0)
|
|
99
|
+
return Point(x=top.x, y=top.y, z=center_z)
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def max_volume(self) -> float:
|
|
103
|
+
return self._max_volume
|
|
104
|
+
|
|
105
|
+
def from_center_cartesian(self, x: float, y: float, z: float) -> Point:
|
|
106
|
+
"""
|
|
107
|
+
Specifies an arbitrary point in deck coordinates based
|
|
108
|
+
on percentages of the radius in each axis. For example, to specify the
|
|
109
|
+
back-right corner of a well at 1/4 of the well depth from the bottom,
|
|
110
|
+
the call would be `from_center_cartesian(1, 1, -0.5)`.
|
|
111
|
+
|
|
112
|
+
No checks are performed to ensure that the resulting position will be
|
|
113
|
+
inside of the well.
|
|
114
|
+
|
|
115
|
+
To use this point in a liquid handling command, you must create a
|
|
116
|
+
location object using the well such as,
|
|
117
|
+
|
|
118
|
+
.. code-block:: python
|
|
119
|
+
|
|
120
|
+
from opentrons import types
|
|
121
|
+
|
|
122
|
+
# Cannot be passed into a liquid handling function
|
|
123
|
+
point = well.from_center_cartesian(1, 1, -0.5)
|
|
124
|
+
|
|
125
|
+
# Can be passed into a liquid handling function
|
|
126
|
+
location = types.Location(
|
|
127
|
+
well.from_center_cartesian(1, 1, -0.5), well)
|
|
128
|
+
|
|
129
|
+
:param x: a float in the range [-1.0, 1.0] for a percentage of half of
|
|
130
|
+
the radius/length in the X axis
|
|
131
|
+
:param y: a float in the range [-1.0, 1.0] for a percentage of half of
|
|
132
|
+
the radius/width in the Y axis
|
|
133
|
+
:param z: a float in the range [-1.0, 1.0] for a percentage of half of
|
|
134
|
+
the height above/below the center
|
|
135
|
+
|
|
136
|
+
:return: a Point representing the specified location in absolute deck
|
|
137
|
+
coordinates
|
|
138
|
+
"""
|
|
139
|
+
center = self.center()
|
|
140
|
+
x_size = self._x_size
|
|
141
|
+
y_size = self._y_size
|
|
142
|
+
z_size = self._depth
|
|
143
|
+
|
|
144
|
+
return Point(
|
|
145
|
+
x=center.x + (x * (x_size / 2.0)),
|
|
146
|
+
y=center.y + (y * (y_size / 2.0)),
|
|
147
|
+
z=center.z + (z * (z_size / 2.0)),
|
|
148
|
+
)
|