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,900 @@
|
|
|
1
|
+
"""OT3 Hardware Controller Backend."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
import asyncio
|
|
5
|
+
from contextlib import asynccontextmanager
|
|
6
|
+
import logging
|
|
7
|
+
from typing import (
|
|
8
|
+
Dict,
|
|
9
|
+
List,
|
|
10
|
+
Optional,
|
|
11
|
+
Tuple,
|
|
12
|
+
Sequence,
|
|
13
|
+
AsyncIterator,
|
|
14
|
+
cast,
|
|
15
|
+
Set,
|
|
16
|
+
Union,
|
|
17
|
+
Mapping,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from opentrons.config.types import OT3Config, GantryLoad
|
|
21
|
+
from opentrons.config import gripper_config
|
|
22
|
+
|
|
23
|
+
from opentrons.hardware_control.module_control import AttachedModulesControl
|
|
24
|
+
from opentrons.hardware_control import modules
|
|
25
|
+
from opentrons.hardware_control.types import (
|
|
26
|
+
BoardRevision,
|
|
27
|
+
Axis,
|
|
28
|
+
HepaFanState,
|
|
29
|
+
HepaUVState,
|
|
30
|
+
OT3Mount,
|
|
31
|
+
OT3AxisMap,
|
|
32
|
+
CurrentConfig,
|
|
33
|
+
InstrumentProbeType,
|
|
34
|
+
MotorStatus,
|
|
35
|
+
UpdateStatus,
|
|
36
|
+
UpdateState,
|
|
37
|
+
SubSystem,
|
|
38
|
+
SubSystemState,
|
|
39
|
+
TipStateType,
|
|
40
|
+
GripperJawState,
|
|
41
|
+
HardwareFeatureFlags,
|
|
42
|
+
StatusBarState,
|
|
43
|
+
EstopOverallStatus,
|
|
44
|
+
EstopState,
|
|
45
|
+
EstopPhysicalStatus,
|
|
46
|
+
HardwareEventHandler,
|
|
47
|
+
HardwareEventUnsubscriber,
|
|
48
|
+
PipetteSensorResponseQueue,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
from opentrons_shared_data.pipette.types import PipetteName, PipetteModel
|
|
52
|
+
from opentrons_shared_data.pipette import (
|
|
53
|
+
pipette_load_name_conversions as pipette_load_name,
|
|
54
|
+
load_data as load_pipette_data,
|
|
55
|
+
)
|
|
56
|
+
from opentrons_shared_data.gripper.gripper_definition import GripperModel
|
|
57
|
+
from opentrons.hardware_control.dev_types import (
|
|
58
|
+
PipetteSpec,
|
|
59
|
+
GripperSpec,
|
|
60
|
+
AttachedPipette,
|
|
61
|
+
AttachedGripper,
|
|
62
|
+
OT3AttachedInstruments,
|
|
63
|
+
)
|
|
64
|
+
from opentrons.util.async_helpers import ensure_yield
|
|
65
|
+
from .types import HWStopCondition
|
|
66
|
+
from .flex_protocol import (
|
|
67
|
+
FlexBackend,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
log = logging.getLogger(__name__)
|
|
72
|
+
|
|
73
|
+
AXIS_TO_SUBSYSTEM = {
|
|
74
|
+
Axis.X: SubSystem.gantry_x,
|
|
75
|
+
Axis.Y: SubSystem.gantry_y,
|
|
76
|
+
Axis.Z_L: SubSystem.head,
|
|
77
|
+
Axis.Z_R: SubSystem.head,
|
|
78
|
+
Axis.Z_G: SubSystem.gripper,
|
|
79
|
+
Axis.G: SubSystem.gripper,
|
|
80
|
+
Axis.P_L: SubSystem.pipette_left,
|
|
81
|
+
Axis.P_R: SubSystem.pipette_right,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def coalesce_move_segments(
|
|
86
|
+
origin: Dict[Axis, float], targets: List[Dict[Axis, float]]
|
|
87
|
+
) -> Dict[Axis, float]:
|
|
88
|
+
for target in targets:
|
|
89
|
+
for axis, increment in target.items():
|
|
90
|
+
origin[axis] += increment
|
|
91
|
+
return origin
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def axis_pad(positions: Dict[Axis, float], default_value: float) -> Dict[Axis, float]:
|
|
95
|
+
return {ax: positions.get(ax, default_value) for ax in Axis.node_axes()}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class OT3Simulator(FlexBackend):
|
|
99
|
+
"""OT3 Hardware Controller Backend."""
|
|
100
|
+
|
|
101
|
+
_position: Dict[Axis, float]
|
|
102
|
+
_encoder_position: Dict[Axis, float]
|
|
103
|
+
_motor_status: Dict[Axis, MotorStatus]
|
|
104
|
+
_engaged_axes: Dict[Axis, bool]
|
|
105
|
+
|
|
106
|
+
@classmethod
|
|
107
|
+
async def build(
|
|
108
|
+
cls,
|
|
109
|
+
attached_instruments: Dict[OT3Mount, Dict[str, Optional[str]]],
|
|
110
|
+
attached_modules: Dict[str, List[modules.SimulatingModule]],
|
|
111
|
+
config: OT3Config,
|
|
112
|
+
loop: asyncio.AbstractEventLoop,
|
|
113
|
+
strict_attached_instruments: bool = True,
|
|
114
|
+
feature_flags: Optional[HardwareFeatureFlags] = None,
|
|
115
|
+
) -> OT3Simulator:
|
|
116
|
+
"""Create the OT3Simulator instance.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
config: Robot configuration
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Instance.
|
|
123
|
+
"""
|
|
124
|
+
return cls(
|
|
125
|
+
attached_instruments,
|
|
126
|
+
attached_modules,
|
|
127
|
+
config,
|
|
128
|
+
loop,
|
|
129
|
+
strict_attached_instruments,
|
|
130
|
+
feature_flags,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
def __init__(
|
|
134
|
+
self,
|
|
135
|
+
attached_instruments: Dict[OT3Mount, Dict[str, Optional[str]]],
|
|
136
|
+
attached_modules: Dict[str, List[modules.SimulatingModule]],
|
|
137
|
+
config: OT3Config,
|
|
138
|
+
loop: asyncio.AbstractEventLoop,
|
|
139
|
+
strict_attached_instruments: bool = True,
|
|
140
|
+
feature_flags: Optional[HardwareFeatureFlags] = None,
|
|
141
|
+
) -> None:
|
|
142
|
+
"""Construct.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
config: Robot configuration
|
|
146
|
+
driver: The Can Driver
|
|
147
|
+
"""
|
|
148
|
+
self._configuration = config
|
|
149
|
+
self._loop = loop
|
|
150
|
+
self._strict_attached = bool(strict_attached_instruments)
|
|
151
|
+
self._stubbed_attached_modules = attached_modules
|
|
152
|
+
self._update_required = False
|
|
153
|
+
self._initialized = False
|
|
154
|
+
self._lights = {"button": False, "rails": False}
|
|
155
|
+
self._gear_motor_position: Dict[Axis, float] = {}
|
|
156
|
+
self._engaged_axes: Dict[Axis, bool] = {}
|
|
157
|
+
self._feature_flags = feature_flags or HardwareFeatureFlags()
|
|
158
|
+
|
|
159
|
+
def _sanitize_attached_instrument(
|
|
160
|
+
mount: OT3Mount, passed_ai: Optional[Dict[str, Optional[str]]] = None
|
|
161
|
+
) -> Union[PipetteSpec, GripperSpec]:
|
|
162
|
+
if mount is OT3Mount.GRIPPER:
|
|
163
|
+
gripper_spec: GripperSpec = {"model": None, "id": None}
|
|
164
|
+
if passed_ai and passed_ai.get("model"):
|
|
165
|
+
gripper_spec["model"] = GripperModel.v1
|
|
166
|
+
gripper_spec["id"] = passed_ai.get("id")
|
|
167
|
+
return gripper_spec
|
|
168
|
+
|
|
169
|
+
# TODO (lc 12-5-2022) need to not always pass in defaults here
|
|
170
|
+
# but doing it to satisfy linter errors for now.
|
|
171
|
+
pipette_spec: PipetteSpec = {"model": None, "id": None}
|
|
172
|
+
if not passed_ai or not passed_ai.get("model"):
|
|
173
|
+
return pipette_spec
|
|
174
|
+
|
|
175
|
+
if pipette_load_name.supported_pipette(
|
|
176
|
+
cast(PipetteModel, passed_ai["model"])
|
|
177
|
+
):
|
|
178
|
+
pipette_spec["model"] = cast(PipetteModel, passed_ai.get("model"))
|
|
179
|
+
pipette_spec["id"] = passed_ai.get("id")
|
|
180
|
+
return pipette_spec
|
|
181
|
+
# TODO (lc 12-05-2022) When the time comes we should properly
|
|
182
|
+
# support backwards compatibility
|
|
183
|
+
raise KeyError(
|
|
184
|
+
"If you specify attached_instruments, the model "
|
|
185
|
+
"should be pipette names or pipette models, but "
|
|
186
|
+
f'{passed_ai["model"]} is not'
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
self._attached_instruments = {
|
|
190
|
+
m: _sanitize_attached_instrument(m, attached_instruments.get(m))
|
|
191
|
+
for m in OT3Mount
|
|
192
|
+
}
|
|
193
|
+
self._module_controls: Optional[AttachedModulesControl] = None
|
|
194
|
+
self._position = self._get_home_position()
|
|
195
|
+
self._encoder_position = self._get_home_position()
|
|
196
|
+
self._motor_status = {}
|
|
197
|
+
axes = set((Axis.Z_L, Axis.Z_R, Axis.X, Axis.Y))
|
|
198
|
+
if self._attached_instruments[OT3Mount.LEFT].get("model", None):
|
|
199
|
+
axes.add(Axis.P_L)
|
|
200
|
+
if self._attached_instruments[OT3Mount.RIGHT].get("model", None):
|
|
201
|
+
axes.add(Axis.P_L)
|
|
202
|
+
if self._attached_instruments.get(
|
|
203
|
+
OT3Mount.GRIPPER
|
|
204
|
+
) and self._attached_instruments[OT3Mount.GRIPPER].get("model", None):
|
|
205
|
+
axes.update((Axis.G, Axis.Z_G))
|
|
206
|
+
self._present_axes = axes
|
|
207
|
+
self._current_settings: Optional[OT3AxisMap[CurrentConfig]] = None
|
|
208
|
+
self._sim_jaw_state = GripperJawState.HOMED_READY
|
|
209
|
+
self._sim_tip_state: Dict[OT3Mount, Optional[bool]] = {
|
|
210
|
+
mount: False if self._attached_instruments[mount] else None
|
|
211
|
+
for mount in [OT3Mount.LEFT, OT3Mount.RIGHT]
|
|
212
|
+
}
|
|
213
|
+
self._sim_gantry_load = GantryLoad.LOW_THROUGHPUT
|
|
214
|
+
self._sim_status_bar_state = StatusBarState.IDLE
|
|
215
|
+
self._sim_estop_state = EstopState.DISENGAGED
|
|
216
|
+
self._sim_estop_left_state = EstopPhysicalStatus.DISENGAGED
|
|
217
|
+
self._sim_estop_right_state = EstopPhysicalStatus.DISENGAGED
|
|
218
|
+
|
|
219
|
+
async def get_serial_number(self) -> Optional[str]:
|
|
220
|
+
return "simulator"
|
|
221
|
+
|
|
222
|
+
@asynccontextmanager
|
|
223
|
+
async def restore_system_constraints(self) -> AsyncIterator[None]:
|
|
224
|
+
log.debug("Simulating saving system constraints")
|
|
225
|
+
try:
|
|
226
|
+
yield
|
|
227
|
+
finally:
|
|
228
|
+
log.debug("Simulating restoring system constraints")
|
|
229
|
+
|
|
230
|
+
def update_constraints_for_gantry_load(self, gantry_load: GantryLoad) -> None:
|
|
231
|
+
self._sim_gantry_load = gantry_load
|
|
232
|
+
|
|
233
|
+
def update_constraints_for_plunger_acceleration(
|
|
234
|
+
self,
|
|
235
|
+
mount: OT3Mount,
|
|
236
|
+
acceleration: float,
|
|
237
|
+
gantry_load: GantryLoad,
|
|
238
|
+
high_speed_pipette: bool = False,
|
|
239
|
+
) -> None:
|
|
240
|
+
self._sim_gantry_load = gantry_load
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
def initialized(self) -> bool:
|
|
244
|
+
"""True when the hardware controller has initialized and is ready."""
|
|
245
|
+
return self._initialized
|
|
246
|
+
|
|
247
|
+
@initialized.setter
|
|
248
|
+
def initialized(self, value: bool) -> None:
|
|
249
|
+
self._initialized = value
|
|
250
|
+
|
|
251
|
+
@property
|
|
252
|
+
def gear_motor_position(self) -> Optional[float]:
|
|
253
|
+
return self._gear_motor_position.get(Axis.Q, None)
|
|
254
|
+
|
|
255
|
+
@property
|
|
256
|
+
def board_revision(self) -> BoardRevision:
|
|
257
|
+
"""Get the board revision"""
|
|
258
|
+
return BoardRevision.UNKNOWN
|
|
259
|
+
|
|
260
|
+
@property
|
|
261
|
+
def module_controls(self) -> AttachedModulesControl:
|
|
262
|
+
"""Get the module controls."""
|
|
263
|
+
if self._module_controls is None:
|
|
264
|
+
raise AttributeError("Module controls not found.")
|
|
265
|
+
return self._module_controls
|
|
266
|
+
|
|
267
|
+
@module_controls.setter
|
|
268
|
+
def module_controls(self, module_controls: AttachedModulesControl) -> None:
|
|
269
|
+
"""Set the module controls"""
|
|
270
|
+
self._module_controls = module_controls
|
|
271
|
+
|
|
272
|
+
@ensure_yield
|
|
273
|
+
async def update_to_default_current_settings(self, gantry_load: GantryLoad) -> None:
|
|
274
|
+
self._gantry_load = gantry_load
|
|
275
|
+
|
|
276
|
+
def update_feature_flags(self, feature_flags: HardwareFeatureFlags) -> None:
|
|
277
|
+
"""Update the hardware feature flags used by the hardware controller."""
|
|
278
|
+
self._feature_flags = feature_flags
|
|
279
|
+
|
|
280
|
+
def _handle_motor_status_update(self, response: Dict[Axis, float]) -> None:
|
|
281
|
+
self._position.update(response)
|
|
282
|
+
self._encoder_position.update(response)
|
|
283
|
+
self._motor_status.update(
|
|
284
|
+
(node, MotorStatus(True, True)) for node in response.keys()
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
@ensure_yield
|
|
288
|
+
async def update_motor_status(self) -> None:
|
|
289
|
+
"""Retreieve motor and encoder status and position from all present devices"""
|
|
290
|
+
if not self._motor_status:
|
|
291
|
+
# Simulate condition at boot, status would not be ok
|
|
292
|
+
self._motor_status.update(
|
|
293
|
+
(axis, MotorStatus(False, False)) for axis in self._present_axes
|
|
294
|
+
)
|
|
295
|
+
else:
|
|
296
|
+
self._motor_status.update(
|
|
297
|
+
(axis, MotorStatus(True, True)) for axis in self._present_axes
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
@ensure_yield
|
|
301
|
+
async def update_motor_estimation(self, axes: Sequence[Axis]) -> None:
|
|
302
|
+
"""Update motor position estimation for commanded axes, and update cache of data."""
|
|
303
|
+
# Simulate conditions as if there are no stalls, aka do nothing
|
|
304
|
+
return None
|
|
305
|
+
|
|
306
|
+
def _get_motor_status(
|
|
307
|
+
self, axes: Sequence[Axis]
|
|
308
|
+
) -> Dict[Axis, Optional[MotorStatus]]:
|
|
309
|
+
return {ax: self._motor_status.get(ax) for ax in axes}
|
|
310
|
+
|
|
311
|
+
def get_invalid_motor_axes(self, axes: Sequence[Axis]) -> List[Axis]:
|
|
312
|
+
"""Get axes that currently do not have the motor-ok flag."""
|
|
313
|
+
return [
|
|
314
|
+
ax
|
|
315
|
+
for ax, status in self._get_motor_status(axes).items()
|
|
316
|
+
if not status or not status.motor_ok
|
|
317
|
+
]
|
|
318
|
+
|
|
319
|
+
def get_invalid_encoder_axes(self, axes: Sequence[Axis]) -> List[Axis]:
|
|
320
|
+
"""Get axes that currently do not have the encoder-ok flag."""
|
|
321
|
+
return [
|
|
322
|
+
ax
|
|
323
|
+
for ax, status in self._get_motor_status(axes).items()
|
|
324
|
+
if not status or not status.encoder_ok
|
|
325
|
+
]
|
|
326
|
+
|
|
327
|
+
def check_motor_status(self, axes: Sequence[Axis]) -> bool:
|
|
328
|
+
return len(self.get_invalid_motor_axes(axes)) == 0
|
|
329
|
+
|
|
330
|
+
def check_encoder_status(self, axes: Sequence[Axis]) -> bool:
|
|
331
|
+
return len(self.get_invalid_encoder_axes(axes)) == 0
|
|
332
|
+
|
|
333
|
+
async def update_position(self) -> OT3AxisMap[float]:
|
|
334
|
+
"""Get the current position."""
|
|
335
|
+
return axis_pad(self._position, 0.0)
|
|
336
|
+
|
|
337
|
+
async def update_encoder_position(self) -> OT3AxisMap[float]:
|
|
338
|
+
"""Get the encoder current position."""
|
|
339
|
+
return axis_pad(self._encoder_position, 0.0)
|
|
340
|
+
|
|
341
|
+
@ensure_yield
|
|
342
|
+
async def liquid_probe(
|
|
343
|
+
self,
|
|
344
|
+
mount: OT3Mount,
|
|
345
|
+
max_p_distance: float,
|
|
346
|
+
mount_speed: float,
|
|
347
|
+
plunger_speed: float,
|
|
348
|
+
threshold_pascals: float,
|
|
349
|
+
plunger_impulse_time: float,
|
|
350
|
+
num_baseline_reads: int,
|
|
351
|
+
z_offset_for_plunger_prep: float,
|
|
352
|
+
probe: InstrumentProbeType = InstrumentProbeType.PRIMARY,
|
|
353
|
+
force_both_sensors: bool = False,
|
|
354
|
+
response_queue: Optional[PipetteSensorResponseQueue] = None,
|
|
355
|
+
) -> float:
|
|
356
|
+
z_axis = Axis.by_mount(mount)
|
|
357
|
+
pos = self._position
|
|
358
|
+
self._position.update(pos)
|
|
359
|
+
self._encoder_position.update(pos)
|
|
360
|
+
return self._position[z_axis]
|
|
361
|
+
|
|
362
|
+
@ensure_yield
|
|
363
|
+
async def move(
|
|
364
|
+
self,
|
|
365
|
+
origin: Dict[Axis, float],
|
|
366
|
+
target: Dict[Axis, float],
|
|
367
|
+
speed: Optional[float] = None,
|
|
368
|
+
stop_condition: HWStopCondition = HWStopCondition.none,
|
|
369
|
+
nodes_in_moves_only: bool = True,
|
|
370
|
+
) -> None:
|
|
371
|
+
"""Move to a position.
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
target_position: Map of axis to position.
|
|
375
|
+
home_flagged_axes: Whether to home afterwords.
|
|
376
|
+
speed: Optional speed
|
|
377
|
+
axis_max_speeds: Optional map of axis to speed.
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
None
|
|
381
|
+
"""
|
|
382
|
+
for ax in origin:
|
|
383
|
+
self._engaged_axes[ax] = True
|
|
384
|
+
self._position.update(target)
|
|
385
|
+
self._encoder_position.update(target)
|
|
386
|
+
|
|
387
|
+
@ensure_yield
|
|
388
|
+
async def home(
|
|
389
|
+
self, axes: Sequence[Axis], gantry_load: GantryLoad
|
|
390
|
+
) -> OT3AxisMap[float]:
|
|
391
|
+
"""Home axes.
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
axes: Optional list of axes.
|
|
395
|
+
|
|
396
|
+
Returns:
|
|
397
|
+
Homed position.
|
|
398
|
+
"""
|
|
399
|
+
if axes:
|
|
400
|
+
homed = axes
|
|
401
|
+
else:
|
|
402
|
+
homed = list(iter(self._position.keys()))
|
|
403
|
+
for h in homed:
|
|
404
|
+
self._position[h] = self._get_home_position()[h]
|
|
405
|
+
self._motor_status[h] = MotorStatus(True, True)
|
|
406
|
+
self._engaged_axes[h] = True
|
|
407
|
+
return axis_pad(self._position, 0.0)
|
|
408
|
+
|
|
409
|
+
@ensure_yield
|
|
410
|
+
async def gripper_grip_jaw(
|
|
411
|
+
self,
|
|
412
|
+
duty_cycle: float,
|
|
413
|
+
expected_displacement: float,
|
|
414
|
+
stop_condition: HWStopCondition = HWStopCondition.none,
|
|
415
|
+
stay_engaged: bool = True,
|
|
416
|
+
) -> None:
|
|
417
|
+
"""Move gripper inward."""
|
|
418
|
+
self._sim_jaw_state = GripperJawState.GRIPPING
|
|
419
|
+
self._encoder_position[Axis.G] = expected_displacement
|
|
420
|
+
|
|
421
|
+
@ensure_yield
|
|
422
|
+
async def gripper_home_jaw(self, duty_cycle: float) -> None:
|
|
423
|
+
"""Move gripper outward."""
|
|
424
|
+
self._motor_status[Axis.G] = MotorStatus(True, True)
|
|
425
|
+
self._encoder_position[Axis.G] = self._get_home_position()[Axis.G]
|
|
426
|
+
self._sim_jaw_state = GripperJawState.HOMED_READY
|
|
427
|
+
|
|
428
|
+
@ensure_yield
|
|
429
|
+
async def gripper_hold_jaw(
|
|
430
|
+
self,
|
|
431
|
+
encoder_position_um: int,
|
|
432
|
+
) -> None:
|
|
433
|
+
self._encoder_position[Axis.G] = encoder_position_um / 1000.0
|
|
434
|
+
self._sim_jaw_state = GripperJawState.HOLDING
|
|
435
|
+
|
|
436
|
+
async def get_jaw_state(self) -> GripperJawState:
|
|
437
|
+
"""Get the state of the gripper jaw."""
|
|
438
|
+
return self._sim_jaw_state
|
|
439
|
+
|
|
440
|
+
async def tip_action(
|
|
441
|
+
self, origin: float, targets: List[Tuple[float, float]]
|
|
442
|
+
) -> None:
|
|
443
|
+
self._gear_motor_position.update(
|
|
444
|
+
coalesce_move_segments(
|
|
445
|
+
{Axis.Q: origin}, [{Axis.Q: target[0]} for target in targets]
|
|
446
|
+
)
|
|
447
|
+
)
|
|
448
|
+
await asyncio.sleep(0)
|
|
449
|
+
|
|
450
|
+
async def home_tip_motors(
|
|
451
|
+
self,
|
|
452
|
+
distance: float,
|
|
453
|
+
velocity: float,
|
|
454
|
+
back_off: bool = True,
|
|
455
|
+
) -> None:
|
|
456
|
+
pass
|
|
457
|
+
|
|
458
|
+
def _attached_to_mount(
|
|
459
|
+
self, mount: OT3Mount, expected_instr: Optional[PipetteName]
|
|
460
|
+
) -> OT3AttachedInstruments:
|
|
461
|
+
init_instr = self._attached_instruments.get(mount, {"model": None, "id": None})
|
|
462
|
+
if mount is OT3Mount.GRIPPER:
|
|
463
|
+
return self._attached_gripper_to_mount(cast(GripperSpec, init_instr))
|
|
464
|
+
return self._attached_pipette_to_mount(
|
|
465
|
+
mount, cast(PipetteSpec, init_instr), expected_instr
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
def _attached_gripper_to_mount(self, init_instr: GripperSpec) -> AttachedGripper:
|
|
469
|
+
found_model = init_instr["model"]
|
|
470
|
+
if found_model:
|
|
471
|
+
return {
|
|
472
|
+
"config": gripper_config.load(GripperModel.v1),
|
|
473
|
+
"id": init_instr["id"],
|
|
474
|
+
}
|
|
475
|
+
else:
|
|
476
|
+
return {"config": None, "id": None}
|
|
477
|
+
|
|
478
|
+
def _attached_pipette_to_mount(
|
|
479
|
+
self,
|
|
480
|
+
mount: OT3Mount,
|
|
481
|
+
init_instr: PipetteSpec,
|
|
482
|
+
expected_instr: Optional[PipetteName],
|
|
483
|
+
) -> AttachedPipette:
|
|
484
|
+
found_model = init_instr["model"]
|
|
485
|
+
|
|
486
|
+
# TODO (lc 12-05-2022) When the time comes, we should think about supporting
|
|
487
|
+
# backwards compatability -- hopefully not relying on config keys only,
|
|
488
|
+
# but TBD.
|
|
489
|
+
if expected_instr and not pipette_load_name.supported_pipette(
|
|
490
|
+
cast(PipetteModel, expected_instr)
|
|
491
|
+
):
|
|
492
|
+
raise RuntimeError(
|
|
493
|
+
f"mount {mount.name} requested a {expected_instr} which is not supported on the OT3"
|
|
494
|
+
)
|
|
495
|
+
if found_model and expected_instr and (expected_instr not in found_model):
|
|
496
|
+
if self._strict_attached:
|
|
497
|
+
raise RuntimeError(
|
|
498
|
+
"mount {}: expected instrument {} but got {}".format(
|
|
499
|
+
mount.name, expected_instr, found_model
|
|
500
|
+
)
|
|
501
|
+
)
|
|
502
|
+
else:
|
|
503
|
+
converted_name = pipette_load_name.convert_pipette_name(expected_instr)
|
|
504
|
+
return {
|
|
505
|
+
"config": load_pipette_data.load_definition(
|
|
506
|
+
converted_name.pipette_type,
|
|
507
|
+
converted_name.pipette_channels,
|
|
508
|
+
converted_name.pipette_version,
|
|
509
|
+
converted_name.oem_type,
|
|
510
|
+
),
|
|
511
|
+
"id": None,
|
|
512
|
+
}
|
|
513
|
+
if found_model and init_instr["id"] is not None:
|
|
514
|
+
# Instrument detected matches instrument expected (note:
|
|
515
|
+
# "instrument detected" means passed as an argument to the
|
|
516
|
+
# constructor of this class)
|
|
517
|
+
|
|
518
|
+
# OR Instrument detected and no expected instrument specified
|
|
519
|
+
|
|
520
|
+
found_model_version = ""
|
|
521
|
+
if found_model.find("flex") > -1:
|
|
522
|
+
found_model = found_model.replace("_flex", "") # type: ignore
|
|
523
|
+
found_model_version = f"{init_instr['id'][4]}.{init_instr['id'][5]}"
|
|
524
|
+
converted_name = pipette_load_name.convert_pipette_model(
|
|
525
|
+
found_model, found_model_version
|
|
526
|
+
)
|
|
527
|
+
return {
|
|
528
|
+
"config": load_pipette_data.load_definition(
|
|
529
|
+
converted_name.pipette_type,
|
|
530
|
+
converted_name.pipette_channels,
|
|
531
|
+
converted_name.pipette_version,
|
|
532
|
+
converted_name.oem_type,
|
|
533
|
+
),
|
|
534
|
+
"id": init_instr["id"],
|
|
535
|
+
}
|
|
536
|
+
elif expected_instr:
|
|
537
|
+
# Expected instrument specified and no instrument detected
|
|
538
|
+
converted_name = pipette_load_name.convert_pipette_name(expected_instr)
|
|
539
|
+
return {
|
|
540
|
+
"config": load_pipette_data.load_definition(
|
|
541
|
+
converted_name.pipette_type,
|
|
542
|
+
converted_name.pipette_channels,
|
|
543
|
+
converted_name.pipette_version,
|
|
544
|
+
converted_name.oem_type,
|
|
545
|
+
),
|
|
546
|
+
"id": None,
|
|
547
|
+
}
|
|
548
|
+
else:
|
|
549
|
+
# No instrument detected or expected
|
|
550
|
+
return {"config": None, "id": None}
|
|
551
|
+
|
|
552
|
+
@ensure_yield
|
|
553
|
+
async def get_attached_instruments(
|
|
554
|
+
self, expected: Mapping[OT3Mount, Optional[PipetteName]]
|
|
555
|
+
) -> Mapping[OT3Mount, OT3AttachedInstruments]:
|
|
556
|
+
"""Get attached instruments.
|
|
557
|
+
|
|
558
|
+
Args:
|
|
559
|
+
expected: Which mounts are expected.
|
|
560
|
+
|
|
561
|
+
Returns:
|
|
562
|
+
A map of mount to pipette name.
|
|
563
|
+
"""
|
|
564
|
+
return {
|
|
565
|
+
mount: self._attached_to_mount(mount, expected.get(mount))
|
|
566
|
+
for mount in OT3Mount
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
@ensure_yield
|
|
570
|
+
async def get_limit_switches(self) -> OT3AxisMap[bool]:
|
|
571
|
+
"""Get the state of the gantry's limit switches on each axis."""
|
|
572
|
+
return {}
|
|
573
|
+
|
|
574
|
+
@ensure_yield
|
|
575
|
+
async def set_active_current(self, axis_currents: OT3AxisMap[float]) -> None:
|
|
576
|
+
"""Set the active current.
|
|
577
|
+
|
|
578
|
+
Args:
|
|
579
|
+
axis_currents: Axes' currents
|
|
580
|
+
|
|
581
|
+
Returns:
|
|
582
|
+
None
|
|
583
|
+
"""
|
|
584
|
+
return None
|
|
585
|
+
|
|
586
|
+
@asynccontextmanager
|
|
587
|
+
async def motor_current(
|
|
588
|
+
self,
|
|
589
|
+
run_currents: Optional[OT3AxisMap[float]] = None,
|
|
590
|
+
hold_currents: Optional[OT3AxisMap[float]] = None,
|
|
591
|
+
) -> AsyncIterator[None]:
|
|
592
|
+
"""Save the current."""
|
|
593
|
+
yield
|
|
594
|
+
|
|
595
|
+
@asynccontextmanager
|
|
596
|
+
async def restore_z_r_run_current(self) -> AsyncIterator[None]:
|
|
597
|
+
"""
|
|
598
|
+
Temporarily restore the active current ONLY when homing or
|
|
599
|
+
retracting the Z_R axis while the 96-channel is attached.
|
|
600
|
+
"""
|
|
601
|
+
yield
|
|
602
|
+
|
|
603
|
+
@asynccontextmanager
|
|
604
|
+
async def increase_z_l_hold_current(self) -> AsyncIterator[None]:
|
|
605
|
+
"""
|
|
606
|
+
Temporarily increase the hold current when engaging the Z_L axis
|
|
607
|
+
while the 96-channel is attached
|
|
608
|
+
"""
|
|
609
|
+
yield
|
|
610
|
+
|
|
611
|
+
@ensure_yield
|
|
612
|
+
async def watch(self, loop: asyncio.AbstractEventLoop) -> None:
|
|
613
|
+
new_mods_at_ports = []
|
|
614
|
+
for mod_name, list_of_modules in self._stubbed_attached_modules.items():
|
|
615
|
+
for module_details in list_of_modules:
|
|
616
|
+
new_mods_at_ports.append(
|
|
617
|
+
modules.SimulatingModuleAtPort(
|
|
618
|
+
port=f"/dev/ot_module_sim_{mod_name}{str(module_details.serial_number)}",
|
|
619
|
+
name=mod_name,
|
|
620
|
+
serial_number=module_details.serial_number,
|
|
621
|
+
model=module_details.model,
|
|
622
|
+
)
|
|
623
|
+
)
|
|
624
|
+
await self.module_controls.register_modules(new_mods_at_ports=new_mods_at_ports)
|
|
625
|
+
|
|
626
|
+
@property
|
|
627
|
+
def axis_bounds(self) -> OT3AxisMap[Tuple[float, float]]:
|
|
628
|
+
"""Get the axis bounds."""
|
|
629
|
+
# TODO (AL, 2021-11-18): The bounds need to be defined
|
|
630
|
+
phony_bounds = (0, 10000)
|
|
631
|
+
return {
|
|
632
|
+
Axis.Z_R: phony_bounds,
|
|
633
|
+
Axis.Z_L: phony_bounds,
|
|
634
|
+
Axis.P_L: phony_bounds,
|
|
635
|
+
Axis.P_R: phony_bounds,
|
|
636
|
+
Axis.Y: phony_bounds,
|
|
637
|
+
Axis.X: phony_bounds,
|
|
638
|
+
Axis.Z_G: phony_bounds,
|
|
639
|
+
Axis.Q: phony_bounds,
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
@property
|
|
643
|
+
def fw_version(self) -> Dict[SubSystem, int]:
|
|
644
|
+
"""Get the firmware version."""
|
|
645
|
+
return {AXIS_TO_SUBSYSTEM[axis]: 0 for axis in self._present_axes}
|
|
646
|
+
|
|
647
|
+
def axis_is_present(self, axis: Axis) -> bool:
|
|
648
|
+
return axis in self._present_axes
|
|
649
|
+
|
|
650
|
+
@property
|
|
651
|
+
def update_required(self) -> bool:
|
|
652
|
+
return self._update_required
|
|
653
|
+
|
|
654
|
+
@update_required.setter
|
|
655
|
+
def update_required(self, value: bool) -> None:
|
|
656
|
+
if value != self._update_required:
|
|
657
|
+
log.info(f"Firmware Update Flag set {self._update_required} -> {value}")
|
|
658
|
+
self._update_required = value
|
|
659
|
+
|
|
660
|
+
async def update_firmware(
|
|
661
|
+
self,
|
|
662
|
+
subsystems: Set[SubSystem],
|
|
663
|
+
force: bool = False,
|
|
664
|
+
) -> AsyncIterator[UpdateStatus]:
|
|
665
|
+
"""Updates the firmware on the OT3."""
|
|
666
|
+
for subsystem in subsystems:
|
|
667
|
+
yield UpdateStatus(
|
|
668
|
+
subsystem=subsystem, state=UpdateState.done, progress=100
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
def engaged_axes(self) -> OT3AxisMap[bool]:
|
|
672
|
+
"""Get engaged axes."""
|
|
673
|
+
return self._engaged_axes
|
|
674
|
+
|
|
675
|
+
async def update_engaged_axes(self) -> None:
|
|
676
|
+
"""Update engaged axes."""
|
|
677
|
+
return None
|
|
678
|
+
|
|
679
|
+
async def is_motor_engaged(self, axis: Axis) -> bool:
|
|
680
|
+
if axis not in self._engaged_axes.keys():
|
|
681
|
+
return False
|
|
682
|
+
return self._engaged_axes[axis]
|
|
683
|
+
|
|
684
|
+
@ensure_yield
|
|
685
|
+
async def disengage_axes(self, axes: List[Axis]) -> None:
|
|
686
|
+
"""Disengage axes."""
|
|
687
|
+
for ax in axes:
|
|
688
|
+
self._engaged_axes.update({ax: False})
|
|
689
|
+
return None
|
|
690
|
+
|
|
691
|
+
@ensure_yield
|
|
692
|
+
async def engage_axes(self, axes: List[Axis]) -> None:
|
|
693
|
+
"""Engage axes."""
|
|
694
|
+
for ax in axes:
|
|
695
|
+
self._engaged_axes.update({ax: True})
|
|
696
|
+
return None
|
|
697
|
+
|
|
698
|
+
@ensure_yield
|
|
699
|
+
async def set_lights(self, button: Optional[bool], rails: Optional[bool]) -> None:
|
|
700
|
+
"""Set the light states."""
|
|
701
|
+
# Simulate how the real driver does this - there's no button so it's always false
|
|
702
|
+
if rails is not None:
|
|
703
|
+
self._lights["rails"] = rails
|
|
704
|
+
|
|
705
|
+
@ensure_yield
|
|
706
|
+
async def get_lights(self) -> Dict[str, bool]:
|
|
707
|
+
"""Get the light state."""
|
|
708
|
+
return self._lights
|
|
709
|
+
|
|
710
|
+
def pause(self) -> None:
|
|
711
|
+
"""Pause the controller activity."""
|
|
712
|
+
return None
|
|
713
|
+
|
|
714
|
+
def resume(self) -> None:
|
|
715
|
+
"""Resume the controller activity."""
|
|
716
|
+
return None
|
|
717
|
+
|
|
718
|
+
@ensure_yield
|
|
719
|
+
async def halt(self) -> None:
|
|
720
|
+
"""Halt the motors."""
|
|
721
|
+
return None
|
|
722
|
+
|
|
723
|
+
@ensure_yield
|
|
724
|
+
async def probe(self, axis: Axis, distance: float) -> OT3AxisMap[float]:
|
|
725
|
+
"""Probe."""
|
|
726
|
+
return {}
|
|
727
|
+
|
|
728
|
+
@ensure_yield
|
|
729
|
+
async def clean_up(self) -> None:
|
|
730
|
+
"""Clean up."""
|
|
731
|
+
pass
|
|
732
|
+
|
|
733
|
+
@staticmethod
|
|
734
|
+
def _get_home_position() -> Dict[Axis, float]:
|
|
735
|
+
return {
|
|
736
|
+
Axis.Z_L: 0,
|
|
737
|
+
Axis.Z_R: 0,
|
|
738
|
+
Axis.X: 0,
|
|
739
|
+
Axis.Y: 0,
|
|
740
|
+
Axis.P_L: 0,
|
|
741
|
+
Axis.P_R: 0,
|
|
742
|
+
Axis.Z_G: 0,
|
|
743
|
+
Axis.G: 0,
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
@staticmethod
|
|
747
|
+
def home_position() -> OT3AxisMap[float]:
|
|
748
|
+
return OT3Simulator._get_home_position()
|
|
749
|
+
|
|
750
|
+
@ensure_yield
|
|
751
|
+
async def capacitive_probe(
|
|
752
|
+
self,
|
|
753
|
+
mount: OT3Mount,
|
|
754
|
+
moving: Axis,
|
|
755
|
+
distance_mm: float,
|
|
756
|
+
speed_mm_per_s: float,
|
|
757
|
+
sensor_threshold_pf: float,
|
|
758
|
+
probe: InstrumentProbeType = InstrumentProbeType.PRIMARY,
|
|
759
|
+
) -> bool:
|
|
760
|
+
self._position[moving] += distance_mm
|
|
761
|
+
return True
|
|
762
|
+
|
|
763
|
+
@ensure_yield
|
|
764
|
+
async def capacitive_pass(
|
|
765
|
+
self,
|
|
766
|
+
mount: OT3Mount,
|
|
767
|
+
moving: Axis,
|
|
768
|
+
distance_mm: float,
|
|
769
|
+
speed_mm_per_s: float,
|
|
770
|
+
probe: InstrumentProbeType,
|
|
771
|
+
) -> List[float]:
|
|
772
|
+
self._position[moving] += distance_mm
|
|
773
|
+
return []
|
|
774
|
+
|
|
775
|
+
@property
|
|
776
|
+
def subsystems(self) -> Dict[SubSystem, SubSystemState]:
|
|
777
|
+
return {
|
|
778
|
+
AXIS_TO_SUBSYSTEM[axis]: SubSystemState(
|
|
779
|
+
ok=True,
|
|
780
|
+
current_fw_version=1,
|
|
781
|
+
next_fw_version=1,
|
|
782
|
+
fw_update_needed=False,
|
|
783
|
+
current_fw_sha="simulated",
|
|
784
|
+
pcba_revision="A1",
|
|
785
|
+
update_state=None,
|
|
786
|
+
)
|
|
787
|
+
for axis in self._present_axes
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
async def get_tip_status(
|
|
791
|
+
self,
|
|
792
|
+
mount: OT3Mount,
|
|
793
|
+
follow_singular_sensor: Optional[InstrumentProbeType] = None,
|
|
794
|
+
) -> TipStateType:
|
|
795
|
+
return TipStateType(self._sim_tip_state[mount])
|
|
796
|
+
|
|
797
|
+
def current_tip_state(self, mount: OT3Mount) -> Optional[bool]:
|
|
798
|
+
return self._sim_tip_state[mount]
|
|
799
|
+
|
|
800
|
+
async def update_tip_detector(self, mount: OT3Mount, sensor_count: int) -> None:
|
|
801
|
+
pass
|
|
802
|
+
|
|
803
|
+
async def teardown_tip_detector(self, mount: OT3Mount) -> None:
|
|
804
|
+
pass
|
|
805
|
+
|
|
806
|
+
async def set_status_bar_state(self, state: StatusBarState) -> None:
|
|
807
|
+
self._sim_status_bar_state = state
|
|
808
|
+
await asyncio.sleep(0)
|
|
809
|
+
|
|
810
|
+
async def set_status_bar_enabled(self, enabled: bool) -> None:
|
|
811
|
+
await asyncio.sleep(0)
|
|
812
|
+
|
|
813
|
+
def get_status_bar_enabled(self) -> bool:
|
|
814
|
+
return True
|
|
815
|
+
|
|
816
|
+
def get_status_bar_state(self) -> StatusBarState:
|
|
817
|
+
return self._sim_status_bar_state
|
|
818
|
+
|
|
819
|
+
@property
|
|
820
|
+
def estop_status(self) -> EstopOverallStatus:
|
|
821
|
+
return EstopOverallStatus(
|
|
822
|
+
state=self._sim_estop_state,
|
|
823
|
+
left_physical_state=self._sim_estop_left_state,
|
|
824
|
+
right_physical_state=self._sim_estop_right_state,
|
|
825
|
+
)
|
|
826
|
+
|
|
827
|
+
def estop_acknowledge_and_clear(self) -> EstopOverallStatus:
|
|
828
|
+
"""Attempt to acknowledge an Estop event and clear the status.
|
|
829
|
+
|
|
830
|
+
Returns the estop status after clearing the status."""
|
|
831
|
+
self._sim_estop_state = EstopState.DISENGAGED
|
|
832
|
+
self._sim_estop_left_state = EstopPhysicalStatus.DISENGAGED
|
|
833
|
+
self._sim_estop_right_state = EstopPhysicalStatus.DISENGAGED
|
|
834
|
+
return self.estop_status
|
|
835
|
+
|
|
836
|
+
def get_estop_state(self) -> EstopState:
|
|
837
|
+
return self._sim_estop_state
|
|
838
|
+
|
|
839
|
+
def add_estop_callback(self, cb: HardwareEventHandler) -> HardwareEventUnsubscriber:
|
|
840
|
+
return lambda: None
|
|
841
|
+
|
|
842
|
+
def check_gripper_position_within_bounds(
|
|
843
|
+
self,
|
|
844
|
+
expected_grip_width: float,
|
|
845
|
+
grip_width_uncertainty_wider: float,
|
|
846
|
+
grip_width_uncertainty_narrower: float,
|
|
847
|
+
jaw_width: float,
|
|
848
|
+
max_allowed_grip_error: float,
|
|
849
|
+
hard_limit_lower: float,
|
|
850
|
+
hard_limit_upper: float,
|
|
851
|
+
) -> None:
|
|
852
|
+
# This is a (pretty bad) simulation of the gripper actually gripping something,
|
|
853
|
+
# but it should work.
|
|
854
|
+
self._encoder_position[Axis.G] = (hard_limit_upper - jaw_width) / 2
|
|
855
|
+
|
|
856
|
+
async def set_hepa_fan_state(self, fan_on: bool, duty_cycle: int) -> bool:
|
|
857
|
+
return False
|
|
858
|
+
|
|
859
|
+
async def get_hepa_fan_state(self) -> Optional[HepaFanState]:
|
|
860
|
+
return None
|
|
861
|
+
|
|
862
|
+
async def set_hepa_uv_state(self, light_on: bool, timeout_s: int) -> bool:
|
|
863
|
+
return False
|
|
864
|
+
|
|
865
|
+
async def get_hepa_uv_state(self) -> Optional[HepaUVState]:
|
|
866
|
+
return None
|
|
867
|
+
|
|
868
|
+
def _update_tip_state(self, mount: OT3Mount, status: bool) -> None:
|
|
869
|
+
"""This is something we only use in the simulator.
|
|
870
|
+
It is required so that PE simulations using ot3api don't break."""
|
|
871
|
+
self._sim_tip_state[mount] = status
|
|
872
|
+
|
|
873
|
+
async def increase_evo_disp_count(self, mount: OT3Mount) -> None:
|
|
874
|
+
pass
|
|
875
|
+
|
|
876
|
+
async def read_env_temp_sensor(
|
|
877
|
+
self, mount: OT3Mount, primary: bool
|
|
878
|
+
) -> Optional[float]:
|
|
879
|
+
"""Read and return the current sensor information."""
|
|
880
|
+
|
|
881
|
+
return 0.0
|
|
882
|
+
|
|
883
|
+
async def read_env_hum_sensor(
|
|
884
|
+
self, mount: OT3Mount, primary: bool
|
|
885
|
+
) -> Optional[float]:
|
|
886
|
+
"""Read and return the current sensor information."""
|
|
887
|
+
|
|
888
|
+
return 0.0
|
|
889
|
+
|
|
890
|
+
async def read_pressure_sensor(
|
|
891
|
+
self, mount: OT3Mount, primary: bool
|
|
892
|
+
) -> Optional[float]:
|
|
893
|
+
"""Read and return the current sensor information."""
|
|
894
|
+
return 0.0
|
|
895
|
+
|
|
896
|
+
async def read_capacitive_sensor(
|
|
897
|
+
self, mount: OT3Mount, primary: bool
|
|
898
|
+
) -> Optional[float]:
|
|
899
|
+
"""Read and return the current sensor information."""
|
|
900
|
+
return 0.0
|