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,400 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import asyncio
|
|
3
|
+
from contextlib import contextmanager, AsyncExitStack
|
|
4
|
+
import logging
|
|
5
|
+
from typing import (
|
|
6
|
+
Callable,
|
|
7
|
+
Iterator,
|
|
8
|
+
Any,
|
|
9
|
+
Dict,
|
|
10
|
+
List,
|
|
11
|
+
Optional,
|
|
12
|
+
Tuple,
|
|
13
|
+
TYPE_CHECKING,
|
|
14
|
+
Union,
|
|
15
|
+
Sequence,
|
|
16
|
+
cast,
|
|
17
|
+
)
|
|
18
|
+
from typing_extensions import Final
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
import aionotify # type: ignore[import-untyped]
|
|
23
|
+
except (OSError, ModuleNotFoundError):
|
|
24
|
+
aionotify = None
|
|
25
|
+
|
|
26
|
+
from opentrons_shared_data.pipette import (
|
|
27
|
+
pipette_load_name_conversions as pipette_load_name,
|
|
28
|
+
mutable_configurations,
|
|
29
|
+
)
|
|
30
|
+
from opentrons_shared_data.pipette.types import PipetteName
|
|
31
|
+
|
|
32
|
+
from opentrons.drivers.smoothie_drivers import SmoothieDriver
|
|
33
|
+
from opentrons.drivers.rpi_drivers import build_gpio_chardev
|
|
34
|
+
import opentrons.config
|
|
35
|
+
from opentrons.config.types import RobotConfig
|
|
36
|
+
from opentrons.types import Mount
|
|
37
|
+
|
|
38
|
+
from ..module_control import AttachedModulesControl
|
|
39
|
+
from ..types import AionotifyEvent, BoardRevision, Axis, DoorState
|
|
40
|
+
from ..util import ot2_axis_to_string
|
|
41
|
+
|
|
42
|
+
if TYPE_CHECKING:
|
|
43
|
+
from opentrons_shared_data.pipette.types import PipetteModel
|
|
44
|
+
from ..dev_types import (
|
|
45
|
+
AttachedPipette,
|
|
46
|
+
AttachedInstruments,
|
|
47
|
+
InstrumentHardwareConfigs,
|
|
48
|
+
)
|
|
49
|
+
from opentrons.drivers.rpi_drivers.dev_types import GPIODriverLike
|
|
50
|
+
|
|
51
|
+
MODULE_LOG = logging.getLogger(__name__)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class Controller:
|
|
55
|
+
"""The concrete instance of the controller for actually controlling
|
|
56
|
+
hardware.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
async def build(cls, config: Optional[RobotConfig]) -> Controller:
|
|
61
|
+
"""Build a Controller instance.
|
|
62
|
+
|
|
63
|
+
Use this factory method rather than the initializer to handle proper
|
|
64
|
+
GPIO initialization.
|
|
65
|
+
|
|
66
|
+
:param config: A loaded robot config.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
gpio = build_gpio_chardev("gpiochip0")
|
|
70
|
+
gpio.config_by_board_rev()
|
|
71
|
+
await gpio.setup()
|
|
72
|
+
return cls(config, gpio)
|
|
73
|
+
|
|
74
|
+
def __init__(self, config: Optional[RobotConfig], gpio: GPIODriverLike):
|
|
75
|
+
"""Build a Controller instance.
|
|
76
|
+
|
|
77
|
+
Always prefer using :py:meth:`.build` to create an instance of this class. For
|
|
78
|
+
more information on arguments, see that method. If you want to use this
|
|
79
|
+
directly, you must pass in an initialized _and set up_ GPIO driver instance.
|
|
80
|
+
"""
|
|
81
|
+
if not opentrons.config.IS_ROBOT:
|
|
82
|
+
MODULE_LOG.warning(
|
|
83
|
+
"This is intended to run on a robot, and while it can connect "
|
|
84
|
+
"to a smoothie via a usb/serial adapter unexpected things "
|
|
85
|
+
"using gpios (such as smoothie reset or light management) "
|
|
86
|
+
"will fail. If you are seeing this message and you are "
|
|
87
|
+
"running on a robot, you need to set the RUNNING_ON_PI "
|
|
88
|
+
"environmental variable to 1."
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
self.config = config or opentrons.config.robot_configs.load_ot2()
|
|
92
|
+
|
|
93
|
+
self._gpio_chardev: Final = gpio
|
|
94
|
+
self._board_revision: Final = self.gpio_chardev.board_rev
|
|
95
|
+
# We handle our own locks in the hardware controller thank you
|
|
96
|
+
self._smoothie_driver = SmoothieDriver(
|
|
97
|
+
config=self.config, gpio_chardev=self._gpio_chardev
|
|
98
|
+
)
|
|
99
|
+
self._cached_fw_version: Optional[str] = None
|
|
100
|
+
self._module_controls: Optional[AttachedModulesControl] = None
|
|
101
|
+
try:
|
|
102
|
+
self._event_watcher = self._build_event_watcher()
|
|
103
|
+
except AttributeError:
|
|
104
|
+
MODULE_LOG.warning(
|
|
105
|
+
"Failed to initiate aionotify, cannot watch modules "
|
|
106
|
+
"or door, likely because not running on linux"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
@staticmethod
|
|
110
|
+
def _build_event_watcher() -> aionotify.Watcher:
|
|
111
|
+
watcher = aionotify.Watcher()
|
|
112
|
+
watcher.watch(
|
|
113
|
+
alias="modules",
|
|
114
|
+
path="/dev",
|
|
115
|
+
flags=(
|
|
116
|
+
aionotify.Flags.CREATE
|
|
117
|
+
| aionotify.Flags.DELETE
|
|
118
|
+
| aionotify.Flags.MOVED_FROM
|
|
119
|
+
| aionotify.Flags.MOVED_TO
|
|
120
|
+
),
|
|
121
|
+
)
|
|
122
|
+
return watcher
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def gpio_chardev(self) -> GPIODriverLike:
|
|
126
|
+
return self._gpio_chardev
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def board_revision(self) -> BoardRevision:
|
|
130
|
+
return self._board_revision
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def module_controls(self) -> AttachedModulesControl:
|
|
134
|
+
if not self._module_controls:
|
|
135
|
+
raise AttributeError("Module controls not found.")
|
|
136
|
+
return self._module_controls
|
|
137
|
+
|
|
138
|
+
@module_controls.setter
|
|
139
|
+
def module_controls(self, module_controls: AttachedModulesControl) -> None:
|
|
140
|
+
self._module_controls = module_controls
|
|
141
|
+
|
|
142
|
+
async def get_serial_number(self) -> Optional[str]:
|
|
143
|
+
try:
|
|
144
|
+
return Path("/var/serial").read_text().strip()
|
|
145
|
+
except OSError:
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
def start_gpio_door_watcher(
|
|
149
|
+
self,
|
|
150
|
+
loop: asyncio.AbstractEventLoop,
|
|
151
|
+
update_door_state: Callable[[DoorState], None],
|
|
152
|
+
) -> None:
|
|
153
|
+
self.gpio_chardev.start_door_switch_watcher(
|
|
154
|
+
loop=loop, update_door_state=update_door_state
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
async def update_position(self) -> Dict[str, float]:
|
|
158
|
+
await self._smoothie_driver.update_position()
|
|
159
|
+
return self._smoothie_driver.position
|
|
160
|
+
|
|
161
|
+
def _unhomed_axes(self, axes: Sequence[str]) -> List[str]:
|
|
162
|
+
return list(
|
|
163
|
+
axis
|
|
164
|
+
for axis in axes
|
|
165
|
+
if not self._smoothie_driver.homed_flags.get(axis, False)
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
def is_homed(self, axes: Sequence[str]) -> bool:
|
|
169
|
+
return not any(self._unhomed_axes(axes))
|
|
170
|
+
|
|
171
|
+
async def move(
|
|
172
|
+
self,
|
|
173
|
+
target_position: Dict[str, float],
|
|
174
|
+
home_flagged_axes: bool = True,
|
|
175
|
+
speed: Optional[float] = None,
|
|
176
|
+
axis_max_speeds: Optional[Dict[str, float]] = None,
|
|
177
|
+
) -> None:
|
|
178
|
+
async with AsyncExitStack() as cmstack:
|
|
179
|
+
if axis_max_speeds:
|
|
180
|
+
await cmstack.enter_async_context(
|
|
181
|
+
self._smoothie_driver.restore_axis_max_speed(axis_max_speeds)
|
|
182
|
+
)
|
|
183
|
+
await self._smoothie_driver.move(
|
|
184
|
+
target_position, home_flagged_axes=home_flagged_axes, speed=speed
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
async def home(self, axes: Optional[List[str]] = None) -> Dict[str, float]:
|
|
188
|
+
if axes:
|
|
189
|
+
args: Tuple[Any, ...] = ("".join(axes),)
|
|
190
|
+
else:
|
|
191
|
+
args = tuple()
|
|
192
|
+
return await self._smoothie_driver.home(*args)
|
|
193
|
+
|
|
194
|
+
async def fast_home(self, axes: Sequence[str], margin: float) -> Dict[str, float]:
|
|
195
|
+
converted_axes = "".join(axes)
|
|
196
|
+
return await self._smoothie_driver.fast_home(converted_axes, margin)
|
|
197
|
+
|
|
198
|
+
async def _query_mount(
|
|
199
|
+
self, mount: Mount, expected: Union[PipetteModel, PipetteName, None]
|
|
200
|
+
) -> AttachedPipette:
|
|
201
|
+
found_model: Optional[
|
|
202
|
+
PipetteModel
|
|
203
|
+
] = await self._smoothie_driver.read_pipette_model( # type: ignore
|
|
204
|
+
mount.name.lower()
|
|
205
|
+
)
|
|
206
|
+
if found_model and not pipette_load_name.supported_pipette(found_model):
|
|
207
|
+
# TODO: Consider how to handle this error - it bubbles up now
|
|
208
|
+
# and will cause problems at higher levels
|
|
209
|
+
MODULE_LOG.error(f"Bad model on {mount.name}: {found_model}")
|
|
210
|
+
found_model = None
|
|
211
|
+
found_id = await self._smoothie_driver.read_pipette_id(mount.name.lower())
|
|
212
|
+
|
|
213
|
+
if found_model:
|
|
214
|
+
path_to_overrides = opentrons.config.get_opentrons_path(
|
|
215
|
+
"pipette_config_overrides_dir"
|
|
216
|
+
)
|
|
217
|
+
converted_found_model = pipette_load_name.convert_pipette_model(found_model)
|
|
218
|
+
converted_found_name = pipette_load_name.convert_to_pipette_name_type(
|
|
219
|
+
found_model
|
|
220
|
+
)
|
|
221
|
+
config = mutable_configurations.load_with_mutable_configurations(
|
|
222
|
+
converted_found_model, path_to_overrides, found_id
|
|
223
|
+
)
|
|
224
|
+
if expected:
|
|
225
|
+
acceptable = [
|
|
226
|
+
cast(PipetteName, str(converted_found_name))
|
|
227
|
+
] + config.pipette_backcompat_names
|
|
228
|
+
if expected not in acceptable:
|
|
229
|
+
raise RuntimeError(
|
|
230
|
+
f"mount {mount}: instrument"
|
|
231
|
+
f" {expected} was requested"
|
|
232
|
+
f" but {converted_found_model} is present"
|
|
233
|
+
)
|
|
234
|
+
return {"config": config, "id": found_id}
|
|
235
|
+
else:
|
|
236
|
+
if expected:
|
|
237
|
+
raise RuntimeError(
|
|
238
|
+
f"mount {mount}: instrument {expected} was"
|
|
239
|
+
f" requested, but no instrument is present"
|
|
240
|
+
)
|
|
241
|
+
return {"config": None, "id": None}
|
|
242
|
+
|
|
243
|
+
async def get_attached_instruments(
|
|
244
|
+
self, expected: Dict[Mount, PipetteName]
|
|
245
|
+
) -> AttachedInstruments:
|
|
246
|
+
"""Find the instruments attached to our mounts.
|
|
247
|
+
:param expected: is ignored, it is just meant to enforce
|
|
248
|
+
the same interface as the simulator, where
|
|
249
|
+
required instruments can be manipulated.
|
|
250
|
+
|
|
251
|
+
:returns: A dict with mounts as the top-level keys. Each mount value is
|
|
252
|
+
a dict with keys 'model' (containing an instrument model name or
|
|
253
|
+
`None`) and 'id' (containing the serial number of the pipette
|
|
254
|
+
attached to that mount, or `None`). Both mounts will always be
|
|
255
|
+
specified.
|
|
256
|
+
"""
|
|
257
|
+
return {
|
|
258
|
+
mount: await self._query_mount(mount, expected.get(mount))
|
|
259
|
+
for mount in Mount.ot2_mounts()
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
def set_active_current(self, axis_currents: Dict[Axis, float]) -> None:
|
|
263
|
+
"""
|
|
264
|
+
This method sets only the 'active' current, i.e., the current for an
|
|
265
|
+
axis' movement. Smoothie driver automatically resets the current for
|
|
266
|
+
pipette axis to a low current (dwelling current) after each move
|
|
267
|
+
"""
|
|
268
|
+
self._smoothie_driver.set_active_current(
|
|
269
|
+
{ot2_axis_to_string(axis): amp for axis, amp in axis_currents.items()}
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
@contextmanager
|
|
273
|
+
def save_current(self) -> Iterator[None]:
|
|
274
|
+
self._smoothie_driver.push_active_current()
|
|
275
|
+
try:
|
|
276
|
+
yield
|
|
277
|
+
finally:
|
|
278
|
+
self._smoothie_driver.pop_active_current()
|
|
279
|
+
|
|
280
|
+
async def _handle_watch_event(self) -> None:
|
|
281
|
+
try:
|
|
282
|
+
event = await self._event_watcher.get_event()
|
|
283
|
+
except asyncio.IncompleteReadError:
|
|
284
|
+
MODULE_LOG.debug("incomplete read error when quitting watcher")
|
|
285
|
+
return
|
|
286
|
+
if event is not None:
|
|
287
|
+
if "ot_module" in event.name:
|
|
288
|
+
event_name = event.name
|
|
289
|
+
flags = aionotify.Flags.parse(event.flags)
|
|
290
|
+
event_description = AionotifyEvent.build(event_name, flags)
|
|
291
|
+
await self.module_controls.handle_module_appearance(event_description)
|
|
292
|
+
|
|
293
|
+
async def watch(self, loop: asyncio.AbstractEventLoop) -> None:
|
|
294
|
+
can_watch = aionotify is not None
|
|
295
|
+
if can_watch:
|
|
296
|
+
await self._event_watcher.setup(loop)
|
|
297
|
+
|
|
298
|
+
while can_watch and (not self._event_watcher.closed):
|
|
299
|
+
await self._handle_watch_event()
|
|
300
|
+
|
|
301
|
+
async def connect(self, port: Optional[str] = None) -> None:
|
|
302
|
+
"""Build driver and connect to it."""
|
|
303
|
+
await self._smoothie_driver.connect(port)
|
|
304
|
+
await self.update_fw_version()
|
|
305
|
+
|
|
306
|
+
@property
|
|
307
|
+
def axis_bounds(self) -> Dict[Axis, Tuple[float, float]]:
|
|
308
|
+
"""The (minimum, maximum) bounds for each axis."""
|
|
309
|
+
return {
|
|
310
|
+
Axis[ax]: (0, pos)
|
|
311
|
+
for ax, pos in self._smoothie_driver.axis_bounds.items()
|
|
312
|
+
if ax not in "BC"
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
@property
|
|
316
|
+
def fw_version(self) -> Optional[str]:
|
|
317
|
+
return self._cached_fw_version
|
|
318
|
+
|
|
319
|
+
async def update_fw_version(self) -> None:
|
|
320
|
+
self._cached_fw_version = await self._smoothie_driver.get_fw_version()
|
|
321
|
+
|
|
322
|
+
async def update_firmware(
|
|
323
|
+
self, filename: str, loop: asyncio.AbstractEventLoop, modeset: bool
|
|
324
|
+
) -> str:
|
|
325
|
+
msg = await self._smoothie_driver.update_firmware(filename, loop, modeset)
|
|
326
|
+
await self.update_fw_version()
|
|
327
|
+
return msg
|
|
328
|
+
|
|
329
|
+
def engaged_axes(self) -> Dict[str, bool]:
|
|
330
|
+
return self._smoothie_driver.engaged_axes
|
|
331
|
+
|
|
332
|
+
async def disengage_axes(self, axes: List[str]) -> None:
|
|
333
|
+
await self._smoothie_driver.disengage_axis("".join(axes))
|
|
334
|
+
|
|
335
|
+
def set_lights(self, button: Optional[bool], rails: Optional[bool]) -> None:
|
|
336
|
+
if button is not None:
|
|
337
|
+
self.gpio_chardev.set_button_light(blue=button)
|
|
338
|
+
if rails is not None:
|
|
339
|
+
self.gpio_chardev.set_rail_lights(rails)
|
|
340
|
+
|
|
341
|
+
def get_lights(self) -> Dict[str, bool]:
|
|
342
|
+
return {
|
|
343
|
+
"button": self.gpio_chardev.get_button_light()[2],
|
|
344
|
+
"rails": self.gpio_chardev.get_rail_lights(),
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
def pause(self) -> None:
|
|
348
|
+
self._smoothie_driver.pause()
|
|
349
|
+
|
|
350
|
+
def resume(self) -> None:
|
|
351
|
+
self._smoothie_driver.resume()
|
|
352
|
+
|
|
353
|
+
async def halt(self) -> None:
|
|
354
|
+
await self._smoothie_driver.kill()
|
|
355
|
+
|
|
356
|
+
async def hard_halt(self) -> None:
|
|
357
|
+
await self._smoothie_driver.hard_halt()
|
|
358
|
+
|
|
359
|
+
async def probe(self, axis: str, distance: float) -> Dict[str, float]:
|
|
360
|
+
"""Run a probe and return the new position dict"""
|
|
361
|
+
return await self._smoothie_driver.probe_axis(axis, distance)
|
|
362
|
+
|
|
363
|
+
async def clean_up(self) -> None:
|
|
364
|
+
try:
|
|
365
|
+
loop = asyncio.get_event_loop()
|
|
366
|
+
except RuntimeError:
|
|
367
|
+
return
|
|
368
|
+
if hasattr(self, "_event_watcher"):
|
|
369
|
+
if loop.is_running() and self._event_watcher:
|
|
370
|
+
self._event_watcher.close()
|
|
371
|
+
if hasattr(self, "gpio_chardev"):
|
|
372
|
+
try:
|
|
373
|
+
if not loop.is_closed():
|
|
374
|
+
self.gpio_chardev.stop_door_switch_watcher(loop)
|
|
375
|
+
except RuntimeError:
|
|
376
|
+
pass
|
|
377
|
+
|
|
378
|
+
async def configure_mount(
|
|
379
|
+
self, mount: Mount, config: InstrumentHardwareConfigs
|
|
380
|
+
) -> None:
|
|
381
|
+
mount_axis = Axis.by_mount(mount)
|
|
382
|
+
plunger_axis = Axis.of_plunger(mount)
|
|
383
|
+
|
|
384
|
+
await self._smoothie_driver.update_steps_per_mm(
|
|
385
|
+
{ot2_axis_to_string(plunger_axis): config["steps_per_mm"]}
|
|
386
|
+
)
|
|
387
|
+
await self._smoothie_driver.update_pipette_config(
|
|
388
|
+
ot2_axis_to_string(mount_axis), {"home": config["home_pos"]}
|
|
389
|
+
)
|
|
390
|
+
await self._smoothie_driver.update_pipette_config(
|
|
391
|
+
ot2_axis_to_string(plunger_axis), {"max_travel": config["max_travel"]}
|
|
392
|
+
)
|
|
393
|
+
self._smoothie_driver.set_dwelling_current(
|
|
394
|
+
{ot2_axis_to_string(plunger_axis): config["idle_current"]}
|
|
395
|
+
)
|
|
396
|
+
ms = config["splits"]
|
|
397
|
+
if ms:
|
|
398
|
+
self._smoothie_driver.configure_splits_for(
|
|
399
|
+
{ot2_axis_to_string(plunger_axis): ms}
|
|
400
|
+
)
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""opentrons.hardware_control.estop_state: module to manage estop state machine on OT-3."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
|
|
5
|
+
from opentrons_hardware.hardware_control.estop.detector import (
|
|
6
|
+
EstopSummary,
|
|
7
|
+
EstopDetector,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from opentrons.hardware_control.types import (
|
|
11
|
+
EstopState,
|
|
12
|
+
EstopPhysicalStatus,
|
|
13
|
+
EstopAttachLocation,
|
|
14
|
+
EstopStateNotification,
|
|
15
|
+
HardwareEventHandler,
|
|
16
|
+
HardwareEventUnsubscriber,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class EstopStateMachine:
|
|
21
|
+
"""Class to manage global Estop state."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, detector: Optional[EstopDetector]) -> None:
|
|
24
|
+
"""Create a new EstopStateMachine.
|
|
25
|
+
|
|
26
|
+
If detector is None, the state machine will be initialized in
|
|
27
|
+
a happy state (Disengaged, both estops detected) until it is
|
|
28
|
+
hooked up to a valid detector.
|
|
29
|
+
"""
|
|
30
|
+
self._detector: Optional[EstopDetector] = None
|
|
31
|
+
self._state: EstopState = EstopState.DISENGAGED
|
|
32
|
+
# Start off in a happy state until a detector is added
|
|
33
|
+
self._summary = EstopSummary(
|
|
34
|
+
left_detected=True, right_detected=True, engaged=False
|
|
35
|
+
)
|
|
36
|
+
if detector is not None:
|
|
37
|
+
self.subscribe_to_detector(detector=detector)
|
|
38
|
+
self._listeners: List[HardwareEventHandler] = []
|
|
39
|
+
|
|
40
|
+
def subscribe_to_detector(self, detector: EstopDetector) -> None:
|
|
41
|
+
"""Configure the estop state machine to listen to a detector.
|
|
42
|
+
|
|
43
|
+
This function will also transition the state based on the current
|
|
44
|
+
status of the detector."""
|
|
45
|
+
if self._detector is not None:
|
|
46
|
+
self._detector.remove_listener(self.detector_listener)
|
|
47
|
+
self._detector = detector
|
|
48
|
+
detector.add_listener(listener=self.detector_listener)
|
|
49
|
+
self._handle_state_transition(new_summary=detector.status)
|
|
50
|
+
|
|
51
|
+
def __del__(self) -> None:
|
|
52
|
+
if self._detector is not None:
|
|
53
|
+
self._detector.remove_listener(self.detector_listener)
|
|
54
|
+
|
|
55
|
+
def add_listener(self, listener: HardwareEventHandler) -> HardwareEventUnsubscriber:
|
|
56
|
+
"""Add a hardware event listener for estop event changes."""
|
|
57
|
+
if listener not in self._listeners:
|
|
58
|
+
self._listeners.append(listener)
|
|
59
|
+
return lambda: self.remove_listener(listener)
|
|
60
|
+
return lambda: None
|
|
61
|
+
|
|
62
|
+
def remove_listener(self, listener: HardwareEventHandler) -> None:
|
|
63
|
+
"""Remove an existing hardware event listener for estop detector changes."""
|
|
64
|
+
if listener in self._listeners:
|
|
65
|
+
self._listeners.remove(listener)
|
|
66
|
+
|
|
67
|
+
def detector_listener(self, summary: EstopSummary) -> None:
|
|
68
|
+
"""Callback from the detector."""
|
|
69
|
+
self._handle_state_transition(new_summary=summary)
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def _transition_from_physically_engaged(summary: EstopSummary) -> EstopState:
|
|
73
|
+
if not summary.engaged:
|
|
74
|
+
# Estop disengaged, move to Logically Engaged
|
|
75
|
+
return EstopState.LOGICALLY_ENGAGED
|
|
76
|
+
return EstopState.PHYSICALLY_ENGAGED
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def _transition_from_disengaged(summary: EstopSummary) -> EstopState:
|
|
80
|
+
if summary.engaged:
|
|
81
|
+
# Estop engaged, move to physically engaged
|
|
82
|
+
return EstopState.PHYSICALLY_ENGAGED
|
|
83
|
+
if summary.left_detected or summary.right_detected:
|
|
84
|
+
# An estop is still plugged in, stay disengaged
|
|
85
|
+
return EstopState.DISENGAGED
|
|
86
|
+
# Everything unplugged, block all action
|
|
87
|
+
return EstopState.NOT_PRESENT
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def _transition_from_not_present(summary: EstopSummary) -> EstopState:
|
|
91
|
+
if summary.engaged:
|
|
92
|
+
# Estop plugged in and is ON, go to physically engaged
|
|
93
|
+
return EstopState.PHYSICALLY_ENGAGED
|
|
94
|
+
if summary.left_detected or summary.right_detected:
|
|
95
|
+
# Plugged in and NOT on, go to Disengaged
|
|
96
|
+
return EstopState.DISENGAGED
|
|
97
|
+
return EstopState.NOT_PRESENT
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def _transition_from_logically_engaged(summary: EstopSummary) -> EstopState:
|
|
101
|
+
if summary.engaged:
|
|
102
|
+
# Estop was turned on, go back to physically engaged
|
|
103
|
+
return EstopState.PHYSICALLY_ENGAGED
|
|
104
|
+
return EstopState.LOGICALLY_ENGAGED
|
|
105
|
+
|
|
106
|
+
def _emit_event(self, prev_state: EstopState) -> None:
|
|
107
|
+
"""Broadcast a state change to all listeners."""
|
|
108
|
+
event = EstopStateNotification(old_state=prev_state, new_state=self._state)
|
|
109
|
+
for listener in self._listeners:
|
|
110
|
+
listener(event)
|
|
111
|
+
|
|
112
|
+
def _handle_state_transition(self, new_summary: EstopSummary) -> None:
|
|
113
|
+
"""Caches the new state summary and changes the _state variable."""
|
|
114
|
+
self._summary = new_summary
|
|
115
|
+
|
|
116
|
+
prev_state = self._state
|
|
117
|
+
|
|
118
|
+
self._state = {
|
|
119
|
+
EstopState.PHYSICALLY_ENGAGED: self._transition_from_physically_engaged,
|
|
120
|
+
EstopState.DISENGAGED: self._transition_from_disengaged,
|
|
121
|
+
EstopState.NOT_PRESENT: self._transition_from_not_present,
|
|
122
|
+
EstopState.LOGICALLY_ENGAGED: self._transition_from_logically_engaged,
|
|
123
|
+
}[prev_state](new_summary)
|
|
124
|
+
|
|
125
|
+
if self._state != prev_state:
|
|
126
|
+
self._emit_event(prev_state=prev_state)
|
|
127
|
+
|
|
128
|
+
def get_physical_status(self, location: EstopAttachLocation) -> EstopPhysicalStatus:
|
|
129
|
+
"""Get the physical status of an attach location"""
|
|
130
|
+
detected = (
|
|
131
|
+
self._summary.left_detected
|
|
132
|
+
if location == EstopAttachLocation.LEFT
|
|
133
|
+
else self._summary.right_detected
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
if not detected:
|
|
137
|
+
return EstopPhysicalStatus.NOT_PRESENT
|
|
138
|
+
# Note that we actually *don't* have a way to check if an individual
|
|
139
|
+
# estop is activated or not. But we can return Engaged or Disengaged
|
|
140
|
+
# based on the global state.
|
|
141
|
+
return (
|
|
142
|
+
EstopPhysicalStatus.ENGAGED
|
|
143
|
+
if self._summary.engaged
|
|
144
|
+
else EstopPhysicalStatus.DISENGAGED
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def state(self) -> EstopState:
|
|
149
|
+
return self._state
|
|
150
|
+
|
|
151
|
+
def acknowledge_and_clear(self) -> EstopState:
|
|
152
|
+
"""Acknowledge a `logically_engaged` status if relevant.
|
|
153
|
+
|
|
154
|
+
If the current state is not LOGICALLY_ENGAGED, this does nothing.
|
|
155
|
+
|
|
156
|
+
If the current state *is* LOGICALLY_ENGAGED, this will move to the
|
|
157
|
+
correct return state (NOT_PRESENT or ENGAGED)"""
|
|
158
|
+
if self._state == EstopState.LOGICALLY_ENGAGED:
|
|
159
|
+
if self._summary.left_detected or self._summary.right_detected:
|
|
160
|
+
self._state = EstopState.DISENGAGED
|
|
161
|
+
else:
|
|
162
|
+
self._state = EstopState.NOT_PRESENT
|
|
163
|
+
self._emit_event(EstopState.LOGICALLY_ENGAGED)
|
|
164
|
+
return self._state
|