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,768 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import re
|
|
3
|
+
import base64
|
|
4
|
+
from typing import List, Optional
|
|
5
|
+
|
|
6
|
+
from opentrons.drivers.asyncio.communication.errors import (
|
|
7
|
+
NoResponse,
|
|
8
|
+
TaskNotReady,
|
|
9
|
+
)
|
|
10
|
+
from opentrons.drivers.command_builder import CommandBuilder
|
|
11
|
+
from opentrons.drivers.asyncio.communication import AsyncResponseSerialConnection
|
|
12
|
+
|
|
13
|
+
from .abstract import AbstractFlexStackerDriver
|
|
14
|
+
from .errors import StackerErrorCodes, MotorStallDetected
|
|
15
|
+
from .types import (
|
|
16
|
+
GCODE,
|
|
17
|
+
ActiveRange,
|
|
18
|
+
LEDPattern,
|
|
19
|
+
MeasurementKind,
|
|
20
|
+
MoveResult,
|
|
21
|
+
SpadMapID,
|
|
22
|
+
StackerAxis,
|
|
23
|
+
PlatformStatus,
|
|
24
|
+
Direction,
|
|
25
|
+
StackerInfo,
|
|
26
|
+
HardwareRevision,
|
|
27
|
+
MoveParams,
|
|
28
|
+
LimitSwitchStatus,
|
|
29
|
+
LEDColor,
|
|
30
|
+
StallGuardParams,
|
|
31
|
+
TOFConfiguration,
|
|
32
|
+
TOFMeasurement,
|
|
33
|
+
TOFMeasurementFrame,
|
|
34
|
+
TOFMeasurementResult,
|
|
35
|
+
TOFSensor,
|
|
36
|
+
TOFSensorMode,
|
|
37
|
+
TOFSensorState,
|
|
38
|
+
TOFSensorStatus,
|
|
39
|
+
)
|
|
40
|
+
from .utils import (
|
|
41
|
+
NUMBER_OF_BINS,
|
|
42
|
+
validate_histogram_frame,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
FS_BAUDRATE = 115200
|
|
47
|
+
DEFAULT_FS_TIMEOUT = 5
|
|
48
|
+
FS_MOVE_TIMEOUT = 20
|
|
49
|
+
FS_TOF_TIMEOUT = 20
|
|
50
|
+
FS_TOF_FRAME_RETRIES = 1
|
|
51
|
+
FS_TOF_INIT_TIMEOUT = 5
|
|
52
|
+
FS_ACK = "OK\n"
|
|
53
|
+
FS_ERROR_KEYWORD = "err"
|
|
54
|
+
FS_ASYNC_ERROR_ACK = "async"
|
|
55
|
+
DEFAULT_COMMAND_RETRIES = 2
|
|
56
|
+
GCODE_ROUNDING_PRECISION = 2
|
|
57
|
+
|
|
58
|
+
# LED animation range values
|
|
59
|
+
MIN_DURATION_MS = 25 # 25ms
|
|
60
|
+
MAX_DURATION_MS = 10000 # 10s
|
|
61
|
+
MAX_REPS = 10
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class FlexStackerDriver(AbstractFlexStackerDriver):
|
|
65
|
+
"""FLEX Stacker driver."""
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def parse_device_info(cls, response: str) -> StackerInfo:
|
|
69
|
+
"""Parse stacker info."""
|
|
70
|
+
_RE = re.compile(
|
|
71
|
+
f"^{GCODE.DEVICE_INFO} FW:(?P<fw>\\S+) HW:Opentrons-flex-stacker-(?P<hw>\\S+) SerialNo:(?P<sn>\\S+)$"
|
|
72
|
+
)
|
|
73
|
+
m = _RE.match(response)
|
|
74
|
+
if not m:
|
|
75
|
+
raise ValueError(f"Incorrect Response for device info: {response}")
|
|
76
|
+
return StackerInfo(
|
|
77
|
+
m.group("fw"), HardwareRevision(m.group("hw")), m.group("sn")
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def parse_reset_reason(cls, response: str) -> int:
|
|
82
|
+
"""Parse the reset reason"""
|
|
83
|
+
_RE = re.compile(rf"^{GCODE.GET_RESET_REASON} R:(?P<R>\d)$")
|
|
84
|
+
match = _RE.match(response)
|
|
85
|
+
if not match:
|
|
86
|
+
raise ValueError(f"Incorrect Response for reset reason: {response}")
|
|
87
|
+
return int(match.group("R"))
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
def parse_limit_switch_status(cls, response: str) -> LimitSwitchStatus:
|
|
91
|
+
"""Parse limit switch statuses."""
|
|
92
|
+
field_names = LimitSwitchStatus.get_fields()
|
|
93
|
+
pattern = r"\s".join([rf"{name}:(?P<{name}>\d)" for name in field_names])
|
|
94
|
+
_RE = re.compile(f"^{GCODE.GET_LIMIT_SWITCH} {pattern}$")
|
|
95
|
+
m = _RE.match(response)
|
|
96
|
+
if not m:
|
|
97
|
+
raise ValueError(f"Incorrect Response for limit switch status: {response}")
|
|
98
|
+
return LimitSwitchStatus(*(bool(int(m.group(name))) for name in field_names))
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def parse_platform_sensor_status(cls, response: str) -> PlatformStatus:
|
|
102
|
+
"""Parse platform statuses."""
|
|
103
|
+
field_names = PlatformStatus.get_fields()
|
|
104
|
+
pattern = r"\s".join([rf"{name}:(?P<{name}>\d)" for name in field_names])
|
|
105
|
+
_RE = re.compile(f"^{GCODE.GET_PLATFORM_SENSOR} {pattern}$")
|
|
106
|
+
m = _RE.match(response)
|
|
107
|
+
if not m:
|
|
108
|
+
raise ValueError(f"Incorrect Response for platform status: {response}")
|
|
109
|
+
return PlatformStatus(*(bool(int(m.group(name))) for name in field_names))
|
|
110
|
+
|
|
111
|
+
@classmethod
|
|
112
|
+
def parse_door_closed(cls, response: str) -> bool:
|
|
113
|
+
"""Parse door closed."""
|
|
114
|
+
_RE = re.compile(rf"^{GCODE.GET_DOOR_SWITCH} D:(\d)$")
|
|
115
|
+
match = _RE.match(response)
|
|
116
|
+
if not match:
|
|
117
|
+
raise ValueError(f"Incorrect Response for door closed: {response}")
|
|
118
|
+
return bool(int(match.group(1)))
|
|
119
|
+
|
|
120
|
+
@classmethod
|
|
121
|
+
def parse_installation_detected(cls, response: str) -> bool:
|
|
122
|
+
"""Parse install detection."""
|
|
123
|
+
_RE = re.compile(rf"^{GCODE.GET_INSTALL_DETECTED} I:(\d)$")
|
|
124
|
+
match = _RE.match(response)
|
|
125
|
+
if not match:
|
|
126
|
+
raise ValueError(
|
|
127
|
+
f"Incorrect Response for installation detected: {response}"
|
|
128
|
+
)
|
|
129
|
+
return bool(int(match.group(1)))
|
|
130
|
+
|
|
131
|
+
@classmethod
|
|
132
|
+
def parse_estop_engaged(cls, response: str) -> bool:
|
|
133
|
+
"""Parse estop enagaged."""
|
|
134
|
+
_RE = re.compile(rf"^{GCODE.GET_ESTOP_ENGAGED} E:(\d)$")
|
|
135
|
+
match = _RE.match(response)
|
|
136
|
+
if not match:
|
|
137
|
+
raise ValueError(f"Incorrect Response for Estop engaged: {response}")
|
|
138
|
+
return bool(int(match.group(1)))
|
|
139
|
+
|
|
140
|
+
@classmethod
|
|
141
|
+
def parse_move_params(cls, response: str) -> MoveParams:
|
|
142
|
+
"""Parse move params."""
|
|
143
|
+
field_names = MoveParams.get_fields()
|
|
144
|
+
pattern = r"\s".join(rf"{f}:(?P<{f}>(\d*\.)?\d+)" for f in field_names)
|
|
145
|
+
_RE = re.compile(rf"^{GCODE.GET_MOVE_PARAMS} M:([XZL]) {pattern}$")
|
|
146
|
+
m = _RE.match(response)
|
|
147
|
+
if not m:
|
|
148
|
+
raise ValueError(f"Incorrect Response for move params: {response}")
|
|
149
|
+
return MoveParams(
|
|
150
|
+
max_speed=float(m.group("V")),
|
|
151
|
+
acceleration=float(m.group("A")),
|
|
152
|
+
max_speed_discont=float(m.group("D")),
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
@classmethod
|
|
156
|
+
def parse_stallguard_params(cls, response: str) -> StallGuardParams:
|
|
157
|
+
"""Parse stallguard params."""
|
|
158
|
+
pattern = r"(?P<M>[XZL]):(?P<E>\d) T:(?P<T>\d+)"
|
|
159
|
+
_RE = re.compile(f"^{GCODE.GET_STALLGUARD_THRESHOLD} {pattern}$")
|
|
160
|
+
m = _RE.match(response)
|
|
161
|
+
if not m:
|
|
162
|
+
raise ValueError(f"Incorrect Response for stallfguard params: {response}")
|
|
163
|
+
return StallGuardParams(
|
|
164
|
+
axis=StackerAxis(m.group("M")),
|
|
165
|
+
enabled=bool(int(m.group("E"))),
|
|
166
|
+
threshold=int(m.group("T")),
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
@classmethod
|
|
170
|
+
def parse_get_motor_register(cls, response: str) -> int:
|
|
171
|
+
"""Parse get motor register value."""
|
|
172
|
+
pattern = r"(?P<M>[XZL]):(?P<R>\d+) V:(?P<V>\d+)"
|
|
173
|
+
_RE = re.compile(f"^{GCODE.GET_MOTOR_DRIVER_REGISTER} {pattern}$")
|
|
174
|
+
m = _RE.match(response)
|
|
175
|
+
if not m:
|
|
176
|
+
raise ValueError(
|
|
177
|
+
f"Incorrect Response for get motor driver register: {response}"
|
|
178
|
+
)
|
|
179
|
+
return int(m.group("V"))
|
|
180
|
+
|
|
181
|
+
@classmethod
|
|
182
|
+
def parse_get_tof_sensor_register(cls, response: str) -> int:
|
|
183
|
+
"""Parse get tof sensor register value."""
|
|
184
|
+
pattern = r"(?P<S>[XZ]):(?P<R>\d+) V:(?P<V>\d+)"
|
|
185
|
+
_RE = re.compile(f"^{GCODE.GET_TOF_DRIVER_REGISTER} {pattern}$")
|
|
186
|
+
m = _RE.match(response)
|
|
187
|
+
if not m:
|
|
188
|
+
raise ValueError(
|
|
189
|
+
f"Incorrect Response for get tof sensor driver register: {response}"
|
|
190
|
+
)
|
|
191
|
+
return int(m.group("V"))
|
|
192
|
+
|
|
193
|
+
@classmethod
|
|
194
|
+
def parse_tof_sensor_status(cls, response: str) -> TOFSensorStatus:
|
|
195
|
+
"""Parse get tof sensor status response."""
|
|
196
|
+
pattern = r"(?P<S>[XZ]):(?P<O>\d) T:(?P<T>\d) M:(?P<M>\d)"
|
|
197
|
+
_RE = re.compile(f"^{GCODE.GET_TOF_SENSOR_STATUS} {pattern}$")
|
|
198
|
+
m = _RE.match(response)
|
|
199
|
+
if not m:
|
|
200
|
+
raise ValueError(
|
|
201
|
+
f"Incorrect Response for get tof sensor status: {response}"
|
|
202
|
+
)
|
|
203
|
+
return TOFSensorStatus(
|
|
204
|
+
sensor=TOFSensor(m.group("S")),
|
|
205
|
+
state=TOFSensorState(int(m.group("T"))),
|
|
206
|
+
mode=TOFSensorMode(int(m.group("M"))),
|
|
207
|
+
ok=bool(int(m.group("O"))),
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
@classmethod
|
|
211
|
+
def parse_manage_tof_measurement(cls, response: str) -> TOFMeasurement:
|
|
212
|
+
"""Parse manage tof measurement response."""
|
|
213
|
+
pattern = r"(?P<S>[XZ]) K:(?P<K>\d+) C:(?P<C>\d) L:(?P<L>\d+)"
|
|
214
|
+
_RE = re.compile(f"^{GCODE.MANAGE_TOF_MEASUREMENT} {pattern}$")
|
|
215
|
+
m = _RE.match(response)
|
|
216
|
+
if not m:
|
|
217
|
+
raise ValueError(
|
|
218
|
+
f"Incorrect Response for manage tof measurements: {response}"
|
|
219
|
+
)
|
|
220
|
+
return TOFMeasurement(
|
|
221
|
+
sensor=TOFSensor(m.group("S")),
|
|
222
|
+
kind=MeasurementKind(int(m.group("K"))),
|
|
223
|
+
cancelled=bool(int(m.group("C"))),
|
|
224
|
+
total_bytes=int(m.group("L")),
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
@classmethod
|
|
228
|
+
def parse_get_tof_measurement(cls, response: str) -> TOFMeasurementFrame:
|
|
229
|
+
"""Parse get tof measurement response frame."""
|
|
230
|
+
pattern = r"(?P<S>[XZ]) I:(?P<I>\d+) D:(?P<D>.+)"
|
|
231
|
+
_RE = re.compile(f"^{GCODE.GET_TOF_MEASUREMENT} {pattern}$")
|
|
232
|
+
m = _RE.match(response)
|
|
233
|
+
if not m:
|
|
234
|
+
raise ValueError(
|
|
235
|
+
f"Incorrect Response for get tof measurement frame: {response}"
|
|
236
|
+
)
|
|
237
|
+
return TOFMeasurementFrame(
|
|
238
|
+
sensor=TOFSensor(m.group("S")),
|
|
239
|
+
frame_id=int(m.group("I")),
|
|
240
|
+
data=base64.b64decode(m.group("D")),
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
@classmethod
|
|
244
|
+
def parse_get_tof_configuration(cls, response: str) -> TOFConfiguration:
|
|
245
|
+
"""Parse get tof sensor configuration response."""
|
|
246
|
+
pattern = r"(?P<S>[XZ]) I:(?P<I>\d+) A:(?P<A>\d+) K:(?P<K>\d+) P:(?P<P>\d+) H:(?P<H>\d)"
|
|
247
|
+
_RE = re.compile(f"^{GCODE.GET_TOF_CONFIGURATION} {pattern}$")
|
|
248
|
+
m = _RE.match(response)
|
|
249
|
+
if not m:
|
|
250
|
+
raise ValueError(
|
|
251
|
+
f"Incorrect Response for get tof sensor configuration: {response}"
|
|
252
|
+
)
|
|
253
|
+
return TOFConfiguration(
|
|
254
|
+
sensor=TOFSensor(m.group("S")),
|
|
255
|
+
spad_map_id=SpadMapID(int(m.group("I"))),
|
|
256
|
+
active_range=ActiveRange(int(m.group("A"))),
|
|
257
|
+
kilo_iterations=int(m.group("K")),
|
|
258
|
+
report_period_ms=int(m.group("P")),
|
|
259
|
+
histogram_dump=bool(m.group("H")),
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
@classmethod
|
|
263
|
+
def append_move_params(
|
|
264
|
+
cls, command: CommandBuilder, params: MoveParams | None
|
|
265
|
+
) -> CommandBuilder:
|
|
266
|
+
"""Append move params."""
|
|
267
|
+
if params is not None:
|
|
268
|
+
command.add_float("V", params.max_speed, GCODE_ROUNDING_PRECISION)
|
|
269
|
+
command.add_float("A", params.acceleration, GCODE_ROUNDING_PRECISION)
|
|
270
|
+
command.add_float("D", params.max_speed_discont, GCODE_ROUNDING_PRECISION)
|
|
271
|
+
return command
|
|
272
|
+
|
|
273
|
+
@classmethod
|
|
274
|
+
async def create(
|
|
275
|
+
cls, port: str, loop: Optional[asyncio.AbstractEventLoop]
|
|
276
|
+
) -> "FlexStackerDriver":
|
|
277
|
+
"""Create a FLEX Stacker driver."""
|
|
278
|
+
connection = await AsyncResponseSerialConnection.create(
|
|
279
|
+
port=port,
|
|
280
|
+
baud_rate=FS_BAUDRATE,
|
|
281
|
+
timeout=DEFAULT_FS_TIMEOUT,
|
|
282
|
+
number_of_retries=DEFAULT_COMMAND_RETRIES,
|
|
283
|
+
ack=FS_ACK,
|
|
284
|
+
loop=loop,
|
|
285
|
+
error_keyword=FS_ERROR_KEYWORD,
|
|
286
|
+
async_error_ack=FS_ASYNC_ERROR_ACK,
|
|
287
|
+
reset_buffer_before_write=True,
|
|
288
|
+
error_codes=StackerErrorCodes,
|
|
289
|
+
)
|
|
290
|
+
return cls(connection)
|
|
291
|
+
|
|
292
|
+
def __init__(self, connection: AsyncResponseSerialConnection) -> None:
|
|
293
|
+
"""
|
|
294
|
+
Constructor
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
connection: Connection to the FLEX Stacker
|
|
298
|
+
"""
|
|
299
|
+
self._connection = connection
|
|
300
|
+
|
|
301
|
+
async def connect(self) -> None:
|
|
302
|
+
"""Connect to stacker."""
|
|
303
|
+
await self._connection.open()
|
|
304
|
+
|
|
305
|
+
async def disconnect(self) -> None:
|
|
306
|
+
"""Disconnect from stacker."""
|
|
307
|
+
await self._connection.close()
|
|
308
|
+
|
|
309
|
+
async def is_connected(self) -> bool:
|
|
310
|
+
"""Check connection to stacker."""
|
|
311
|
+
return await self._connection.is_open()
|
|
312
|
+
|
|
313
|
+
async def get_device_info(self) -> StackerInfo:
|
|
314
|
+
"""Get Device Info."""
|
|
315
|
+
response = await self._connection.send_command(
|
|
316
|
+
GCODE.DEVICE_INFO.build_command()
|
|
317
|
+
)
|
|
318
|
+
device_info = self.parse_device_info(response)
|
|
319
|
+
reason_resp = await self._connection.send_command(
|
|
320
|
+
GCODE.GET_RESET_REASON.build_command()
|
|
321
|
+
)
|
|
322
|
+
reason = self.parse_reset_reason(reason_resp)
|
|
323
|
+
device_info.rr = reason
|
|
324
|
+
return device_info
|
|
325
|
+
|
|
326
|
+
async def set_serial_number(self, sn: str) -> None:
|
|
327
|
+
"""Set Serial Number."""
|
|
328
|
+
if not re.match(r"^FST[\w]{1}[\d]{2}[\d]{8}[\d]+$", sn):
|
|
329
|
+
raise ValueError(
|
|
330
|
+
f"Invalid serial number: ({sn}) expected format: FSTA1020250119001"
|
|
331
|
+
)
|
|
332
|
+
resp = await self._connection.send_command(
|
|
333
|
+
GCODE.SET_SERIAL_NUMBER.build_command().add_element(sn)
|
|
334
|
+
)
|
|
335
|
+
if not re.match(rf"^{GCODE.SET_SERIAL_NUMBER}$", resp):
|
|
336
|
+
raise ValueError(f"Incorrect Response for set serial number: {resp}")
|
|
337
|
+
|
|
338
|
+
async def enable_motors(self, axis: List[StackerAxis]) -> None:
|
|
339
|
+
"""Enables the axis motor if present, disables it otherwise."""
|
|
340
|
+
command = GCODE.ENABLE_MOTORS.build_command()
|
|
341
|
+
for a in axis:
|
|
342
|
+
command.add_element(a.name)
|
|
343
|
+
resp = await self._connection.send_command(command)
|
|
344
|
+
if not re.match(rf"^{GCODE.ENABLE_MOTORS}$", resp):
|
|
345
|
+
raise ValueError(f"Incorrect Response for enable motors: {resp}")
|
|
346
|
+
|
|
347
|
+
async def stop_motors(self) -> None:
|
|
348
|
+
"""Stop all motor movement."""
|
|
349
|
+
resp = await self._connection.send_command(GCODE.STOP_MOTORS.build_command())
|
|
350
|
+
if not re.match(rf"^{GCODE.STOP_MOTORS}$", resp):
|
|
351
|
+
raise ValueError(f"Incorrect Response for stop motors: {resp}")
|
|
352
|
+
|
|
353
|
+
async def set_run_current(self, axis: StackerAxis, current: float) -> None:
|
|
354
|
+
"""Set axis peak run current in amps."""
|
|
355
|
+
resp = await self._connection.send_command(
|
|
356
|
+
GCODE.SET_RUN_CURRENT.build_command().add_float(axis.name, current)
|
|
357
|
+
)
|
|
358
|
+
if not re.match(rf"^{GCODE.SET_RUN_CURRENT}$", resp):
|
|
359
|
+
raise ValueError(f"Incorrect Response for set run current: {resp}")
|
|
360
|
+
|
|
361
|
+
async def set_ihold_current(self, axis: StackerAxis, current: float) -> None:
|
|
362
|
+
"""Set axis hold current in amps."""
|
|
363
|
+
resp = await self._connection.send_command(
|
|
364
|
+
GCODE.SET_IHOLD_CURRENT.build_command().add_float(axis.name, current)
|
|
365
|
+
)
|
|
366
|
+
if not re.match(rf"^{GCODE.SET_IHOLD_CURRENT}$", resp):
|
|
367
|
+
raise ValueError(f"Incorrect Response for set ihold current: {resp}")
|
|
368
|
+
|
|
369
|
+
async def set_stallguard_threshold(
|
|
370
|
+
self, axis: StackerAxis, enable: bool, threshold: int
|
|
371
|
+
) -> None:
|
|
372
|
+
"""Enables and sets the stallguard threshold for the given axis motor."""
|
|
373
|
+
assert axis != StackerAxis.L, "Stallguard not supported for L axis"
|
|
374
|
+
if not -64 < threshold < 63:
|
|
375
|
+
raise ValueError(
|
|
376
|
+
f"Threshold value ({threshold}) should be between -64 and 63."
|
|
377
|
+
)
|
|
378
|
+
resp = await self._connection.send_command(
|
|
379
|
+
GCODE.SET_STALLGUARD.build_command()
|
|
380
|
+
.add_int(axis.name, int(enable))
|
|
381
|
+
.add_int("T", threshold)
|
|
382
|
+
)
|
|
383
|
+
if not re.match(rf"^{GCODE.SET_STALLGUARD}$", resp):
|
|
384
|
+
raise ValueError(f"Incorrect Response for set stallguard threshold: {resp}")
|
|
385
|
+
|
|
386
|
+
async def enable_tof_sensor(self, sensor: TOFSensor, enable: bool) -> None:
|
|
387
|
+
"""Enable or disable the TOF sensor."""
|
|
388
|
+
# Enabling the TOF sensor takes a while, so give extra timeout.
|
|
389
|
+
timeout = FS_TOF_TIMEOUT if enable else DEFAULT_FS_TIMEOUT
|
|
390
|
+
resp = await self._connection.send_command(
|
|
391
|
+
GCODE.ENABLE_TOF_SENSOR.build_command().add_int(sensor.name, int(enable)),
|
|
392
|
+
timeout=timeout,
|
|
393
|
+
)
|
|
394
|
+
if not re.match(rf"^{GCODE.ENABLE_TOF_SENSOR}$", resp):
|
|
395
|
+
raise ValueError(f"Incorrect Response for enable TOF sensor: {resp}")
|
|
396
|
+
|
|
397
|
+
async def set_tof_configuration(
|
|
398
|
+
self,
|
|
399
|
+
sensor: TOFSensor,
|
|
400
|
+
spad_map_id: SpadMapID,
|
|
401
|
+
active_range: Optional[ActiveRange] = None,
|
|
402
|
+
kilo_iterations: Optional[int] = None,
|
|
403
|
+
report_period_ms: Optional[int] = None,
|
|
404
|
+
histogram_dump: Optional[bool] = None,
|
|
405
|
+
) -> None:
|
|
406
|
+
"""Set the configuration of the TOF sensor.
|
|
407
|
+
|
|
408
|
+
:param sensor: The TOF sensor to configure.
|
|
409
|
+
:param spad_map_id: The pre-defined SPAD map which sets the fov and focus area (14 default).
|
|
410
|
+
:active_range: The operating mode Short-range high-accuracy (default) or long range.
|
|
411
|
+
:kilo_iterations: The Measurement iterations times 1024 (4000 default).
|
|
412
|
+
:report_period_ms: The reporting period before each measurement (500 default).
|
|
413
|
+
:histogram_dump: Enables/Disables histogram measurements (True default).
|
|
414
|
+
:return: None
|
|
415
|
+
"""
|
|
416
|
+
command = (
|
|
417
|
+
GCODE.SET_TOF_CONFIGURATION.build_command()
|
|
418
|
+
.add_element(sensor.name)
|
|
419
|
+
.add_int("I", spad_map_id.value)
|
|
420
|
+
)
|
|
421
|
+
if active_range:
|
|
422
|
+
command.add_int("A", active_range.value)
|
|
423
|
+
if kilo_iterations:
|
|
424
|
+
command.add_int("K", kilo_iterations)
|
|
425
|
+
if report_period_ms:
|
|
426
|
+
command.add_int("P", report_period_ms)
|
|
427
|
+
if histogram_dump:
|
|
428
|
+
command.add_int("H", int(histogram_dump))
|
|
429
|
+
resp = await self._connection.send_command(command)
|
|
430
|
+
if not re.match(rf"^{GCODE.SET_TOF_CONFIGURATION}$", resp):
|
|
431
|
+
raise ValueError(f"Incorrect Response for set TOF configuration: {resp}")
|
|
432
|
+
|
|
433
|
+
async def get_tof_configuration(self, sensor: TOFSensor) -> TOFConfiguration:
|
|
434
|
+
"""Get the configuration of the TOF sensor."""
|
|
435
|
+
resp = await self._connection.send_command(
|
|
436
|
+
GCODE.GET_TOF_CONFIGURATION.build_command().add_element(sensor.value)
|
|
437
|
+
)
|
|
438
|
+
return self.parse_get_tof_configuration(resp)
|
|
439
|
+
|
|
440
|
+
async def manage_tof_measurement(
|
|
441
|
+
self,
|
|
442
|
+
sensor: TOFSensor,
|
|
443
|
+
kind: MeasurementKind = MeasurementKind.HISTOGRAM,
|
|
444
|
+
start: bool = True,
|
|
445
|
+
) -> TOFMeasurement:
|
|
446
|
+
"""Start or stop Measurements from the TOF sensor."""
|
|
447
|
+
command = (
|
|
448
|
+
GCODE.MANAGE_TOF_MEASUREMENT.build_command()
|
|
449
|
+
.add_element(sensor.name)
|
|
450
|
+
.add_int("K", kind.value)
|
|
451
|
+
)
|
|
452
|
+
if not start:
|
|
453
|
+
command.add_element("C")
|
|
454
|
+
resp = await self._connection.send_command(command)
|
|
455
|
+
return self.parse_manage_tof_measurement(resp)
|
|
456
|
+
|
|
457
|
+
async def _get_tof_histogram_frame(
|
|
458
|
+
self, sensor: TOFSensor, resend: bool = False
|
|
459
|
+
) -> TOFMeasurementFrame:
|
|
460
|
+
"""Get the next measurement frame from TOF sensor or resend previous."""
|
|
461
|
+
command = GCODE.GET_TOF_MEASUREMENT.build_command().add_element(sensor.name)
|
|
462
|
+
if resend:
|
|
463
|
+
command.add_element("R")
|
|
464
|
+
resp = await self._connection.send_command(command)
|
|
465
|
+
return self.parse_get_tof_measurement(resp)
|
|
466
|
+
|
|
467
|
+
async def get_tof_histogram(self, sensor: TOFSensor) -> TOFMeasurementResult:
|
|
468
|
+
"""Get the full histogram measurement from the TOF sensor."""
|
|
469
|
+
data = []
|
|
470
|
+
data_len = 0
|
|
471
|
+
next_frame_id = 0
|
|
472
|
+
resend = False
|
|
473
|
+
retries = FS_TOF_FRAME_RETRIES
|
|
474
|
+
|
|
475
|
+
# Cancel any ongoing measurements
|
|
476
|
+
status = await self.get_tof_sensor_status(sensor)
|
|
477
|
+
if status.state == TOFSensorState.MEASURING:
|
|
478
|
+
await self.manage_tof_measurement(sensor, start=False)
|
|
479
|
+
|
|
480
|
+
# Put the TOF sensor into histogram measurement mode
|
|
481
|
+
start = await self.manage_tof_measurement(
|
|
482
|
+
sensor, MeasurementKind.HISTOGRAM, start=True
|
|
483
|
+
)
|
|
484
|
+
# Request frames until the full histogram is transfered
|
|
485
|
+
while data_len < start.total_bytes:
|
|
486
|
+
try:
|
|
487
|
+
# Request next histogram frame
|
|
488
|
+
frame = await self._get_tof_histogram_frame(sensor, resend=resend)
|
|
489
|
+
# Validate histogram frame
|
|
490
|
+
validate_histogram_frame(frame.data, next_frame_id)
|
|
491
|
+
# append frame data
|
|
492
|
+
channel = frame.data[7:]
|
|
493
|
+
data.append(channel)
|
|
494
|
+
data_len += len(channel)
|
|
495
|
+
assert (
|
|
496
|
+
not data_len > start.total_bytes
|
|
497
|
+
), f"Invalid number of bytes, expected {start.total_bytes} got {data_len}."
|
|
498
|
+
retries = FS_TOF_FRAME_RETRIES
|
|
499
|
+
next_frame_id += 1
|
|
500
|
+
resend = False
|
|
501
|
+
except (ValueError, NoResponse):
|
|
502
|
+
# There was a timeout or timing error, request previous frame.
|
|
503
|
+
if retries <= 0:
|
|
504
|
+
# Cancel the measurement
|
|
505
|
+
await self.manage_tof_measurement(sensor, start.kind, start=False)
|
|
506
|
+
raise RuntimeError(f"Exceded frame {next_frame_id} retries")
|
|
507
|
+
retries -= 1
|
|
508
|
+
resend = True
|
|
509
|
+
continue
|
|
510
|
+
except Exception as e:
|
|
511
|
+
# Cancel the histogram request
|
|
512
|
+
await self.manage_tof_measurement(sensor, start.kind, start=False)
|
|
513
|
+
raise RuntimeError(f"Could not get {sensor} Histogram", e)
|
|
514
|
+
|
|
515
|
+
# Parse channel bin measurements from data
|
|
516
|
+
#
|
|
517
|
+
# There are 10 channels (0 - 9), each channel is comprised of 3 * 128 bytes.
|
|
518
|
+
# The data starts with all the 128 LSB bytes, then all the 128 MID bytes, and
|
|
519
|
+
# finally all the 128 MSB bytes for all the channels as seen below.
|
|
520
|
+
#
|
|
521
|
+
# ch0 lsb = data[0], mid = data[10], msb = data[20]
|
|
522
|
+
# ch1 lsb = data[1], mid = data[11], msb = data[21]
|
|
523
|
+
# ch2 lsb = data[2], mid = data[12], msb = data[22]
|
|
524
|
+
# ...
|
|
525
|
+
# ch9 lsb = data[9], mid = data[19], msb = data[29]
|
|
526
|
+
#
|
|
527
|
+
# Each channel has 128 bins comprised of the lsb, mid, and msb payload from above.
|
|
528
|
+
# We can get the bins for each channel by combining the lsb, mid, and msb payload
|
|
529
|
+
# for that specific channel.
|
|
530
|
+
bins = {}
|
|
531
|
+
for ch in range(10): # 0-9 channels
|
|
532
|
+
# Get the lsb, mid, and msb payload for the ch
|
|
533
|
+
lsb = data[ch]
|
|
534
|
+
mid = data[ch + 10]
|
|
535
|
+
msb = data[ch + 20]
|
|
536
|
+
# combine lsb, mid, and msb bytes to generate bin count for the ch
|
|
537
|
+
bins[ch] = [
|
|
538
|
+
float((msb[b] << 16) | (mid[b] << 8) | lsb[b])
|
|
539
|
+
for b in range(NUMBER_OF_BINS)
|
|
540
|
+
]
|
|
541
|
+
return TOFMeasurementResult(start.sensor, start.kind, bins)
|
|
542
|
+
|
|
543
|
+
async def set_motor_driver_register(
|
|
544
|
+
self, axis: StackerAxis, reg: int, value: int
|
|
545
|
+
) -> None:
|
|
546
|
+
"""Set the register of the given motor axis driver to the given value."""
|
|
547
|
+
resp = await self._connection.send_command(
|
|
548
|
+
GCODE.SET_MOTOR_DRIVER_REGISTER.build_command()
|
|
549
|
+
.add_int(axis.name, reg)
|
|
550
|
+
.add_element(str(value))
|
|
551
|
+
)
|
|
552
|
+
if not re.match(rf"^{GCODE.SET_MOTOR_DRIVER_REGISTER}$", resp):
|
|
553
|
+
raise ValueError(
|
|
554
|
+
f"Incorrect Response for set motor driver register: {resp}"
|
|
555
|
+
)
|
|
556
|
+
|
|
557
|
+
async def get_motor_driver_register(self, axis: StackerAxis, reg: int) -> int:
|
|
558
|
+
"""Gets the register value of the given motor axis driver."""
|
|
559
|
+
response = await self._connection.send_command(
|
|
560
|
+
GCODE.GET_MOTOR_DRIVER_REGISTER.build_command().add_int(axis.name, reg)
|
|
561
|
+
)
|
|
562
|
+
return self.parse_get_motor_register(response)
|
|
563
|
+
|
|
564
|
+
async def set_tof_driver_register(
|
|
565
|
+
self, sensor: TOFSensor, reg: int, value: int
|
|
566
|
+
) -> None:
|
|
567
|
+
"""Set the register of the given tof sensor driver to the given value."""
|
|
568
|
+
resp = await self._connection.send_command(
|
|
569
|
+
GCODE.SET_TOF_DRIVER_REGISTER.build_command()
|
|
570
|
+
.add_int(sensor.name, reg)
|
|
571
|
+
.add_element(str(value))
|
|
572
|
+
)
|
|
573
|
+
if not re.match(rf"^{GCODE.SET_TOF_DRIVER_REGISTER}$", resp):
|
|
574
|
+
raise ValueError(
|
|
575
|
+
f"Incorrect Response for set tof sensor driver register: {resp}"
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
async def get_tof_driver_register(self, sensor: TOFSensor, reg: int) -> int:
|
|
579
|
+
"""Gets the register value of the given tof sensor driver."""
|
|
580
|
+
response = await self._connection.send_command(
|
|
581
|
+
GCODE.GET_TOF_DRIVER_REGISTER.build_command().add_int(sensor.name, reg)
|
|
582
|
+
)
|
|
583
|
+
return self.parse_get_tof_sensor_register(response)
|
|
584
|
+
|
|
585
|
+
async def get_tof_sensor_status(self, sensor: TOFSensor) -> TOFSensorStatus:
|
|
586
|
+
"""Get the status of the tof sensor."""
|
|
587
|
+
# This can fail early because the TOF sensor task cannot respond to messages
|
|
588
|
+
# while the TOF sensors are initializing.
|
|
589
|
+
try:
|
|
590
|
+
response = await self._connection.send_command(
|
|
591
|
+
GCODE.GET_TOF_SENSOR_STATUS.build_command().add_element(sensor.name),
|
|
592
|
+
timeout=FS_TOF_INIT_TIMEOUT,
|
|
593
|
+
)
|
|
594
|
+
return self.parse_tof_sensor_status(response)
|
|
595
|
+
except (TaskNotReady):
|
|
596
|
+
return TOFSensorStatus(
|
|
597
|
+
sensor, TOFSensorState.INITIALIZING, TOFSensorMode.UNKNOWN, False
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
async def get_motion_params(self, axis: StackerAxis) -> MoveParams:
|
|
601
|
+
"""Get the motion parameters used by the given axis motor."""
|
|
602
|
+
response = await self._connection.send_command(
|
|
603
|
+
GCODE.GET_MOVE_PARAMS.build_command().add_element(axis.name)
|
|
604
|
+
)
|
|
605
|
+
return self.parse_move_params(response)
|
|
606
|
+
|
|
607
|
+
async def get_stallguard_threshold(self, axis: StackerAxis) -> StallGuardParams:
|
|
608
|
+
"""Get the stallguard parameters by the given axis motor."""
|
|
609
|
+
response = await self._connection.send_command(
|
|
610
|
+
GCODE.GET_STALLGUARD_THRESHOLD.build_command().add_element(axis.name)
|
|
611
|
+
)
|
|
612
|
+
return self.parse_stallguard_params(response)
|
|
613
|
+
|
|
614
|
+
async def get_limit_switch(self, axis: StackerAxis, direction: Direction) -> bool:
|
|
615
|
+
"""Get limit switch status.
|
|
616
|
+
|
|
617
|
+
:return: True if limit switch is triggered, False otherwise
|
|
618
|
+
"""
|
|
619
|
+
response = await self.get_limit_switches_status()
|
|
620
|
+
return response.get(axis, direction)
|
|
621
|
+
|
|
622
|
+
async def get_limit_switches_status(self) -> LimitSwitchStatus:
|
|
623
|
+
"""Get limit switch statuses for all axes."""
|
|
624
|
+
response = await self._connection.send_command(
|
|
625
|
+
GCODE.GET_LIMIT_SWITCH.build_command()
|
|
626
|
+
)
|
|
627
|
+
return self.parse_limit_switch_status(response)
|
|
628
|
+
|
|
629
|
+
async def get_platform_sensor(self, direction: Direction) -> bool:
|
|
630
|
+
"""Get platform sensor at one direction."""
|
|
631
|
+
response = await self.get_platform_status()
|
|
632
|
+
return response.get(direction)
|
|
633
|
+
|
|
634
|
+
async def get_platform_status(self) -> PlatformStatus:
|
|
635
|
+
"""Get platform sensor status.
|
|
636
|
+
|
|
637
|
+
:return: True if platform is detected, False otherwise
|
|
638
|
+
"""
|
|
639
|
+
response = await self._connection.send_command(
|
|
640
|
+
GCODE.GET_PLATFORM_SENSOR.build_command()
|
|
641
|
+
)
|
|
642
|
+
return self.parse_platform_sensor_status(response)
|
|
643
|
+
|
|
644
|
+
async def get_hopper_door_closed(self) -> bool:
|
|
645
|
+
"""Get whether or not door is closed.
|
|
646
|
+
|
|
647
|
+
:return: True if door is closed, False otherwise
|
|
648
|
+
"""
|
|
649
|
+
response = await self._connection.send_command(
|
|
650
|
+
GCODE.GET_DOOR_SWITCH.build_command()
|
|
651
|
+
)
|
|
652
|
+
return self.parse_door_closed(response)
|
|
653
|
+
|
|
654
|
+
async def get_installation_detected(self) -> bool:
|
|
655
|
+
"""Get whether or not installation is detected.
|
|
656
|
+
|
|
657
|
+
:return: True if installation is detected, False otherwise
|
|
658
|
+
"""
|
|
659
|
+
response = await self._connection.send_command(
|
|
660
|
+
GCODE.GET_INSTALL_DETECTED.build_command()
|
|
661
|
+
)
|
|
662
|
+
return self.parse_installation_detected(response)
|
|
663
|
+
|
|
664
|
+
async def get_estop_engaged(self) -> bool:
|
|
665
|
+
"""Get whether or not the estop was detected by this stacker.
|
|
666
|
+
|
|
667
|
+
:return: True if the estop is trigguered, False otherwise
|
|
668
|
+
"""
|
|
669
|
+
response = await self._connection.send_command(
|
|
670
|
+
GCODE.GET_ESTOP_ENGAGED.build_command()
|
|
671
|
+
)
|
|
672
|
+
return self.parse_estop_engaged(response)
|
|
673
|
+
|
|
674
|
+
async def move_in_mm(
|
|
675
|
+
self, axis: StackerAxis, distance: float, params: MoveParams | None = None
|
|
676
|
+
) -> MoveResult:
|
|
677
|
+
"""Move axis by the given distance in mm."""
|
|
678
|
+
command = self.append_move_params(
|
|
679
|
+
GCODE.MOVE_TO.build_command().add_float(
|
|
680
|
+
axis.name, distance, GCODE_ROUNDING_PRECISION
|
|
681
|
+
),
|
|
682
|
+
params,
|
|
683
|
+
)
|
|
684
|
+
try:
|
|
685
|
+
resp = await self._connection.send_command(command, timeout=FS_MOVE_TIMEOUT)
|
|
686
|
+
if not re.match(rf"^{GCODE.MOVE_TO}$", resp):
|
|
687
|
+
raise ValueError(f"Incorrect Response for move to: {resp}")
|
|
688
|
+
except MotorStallDetected:
|
|
689
|
+
self.reset_serial_buffers()
|
|
690
|
+
return MoveResult.STALL_ERROR
|
|
691
|
+
return MoveResult.NO_ERROR
|
|
692
|
+
|
|
693
|
+
async def move_to_limit_switch(
|
|
694
|
+
self, axis: StackerAxis, direction: Direction, params: MoveParams | None = None
|
|
695
|
+
) -> MoveResult:
|
|
696
|
+
"""Move until limit switch is triggered."""
|
|
697
|
+
command = self.append_move_params(
|
|
698
|
+
GCODE.MOVE_TO_SWITCH.build_command().add_int(axis.name, direction.value),
|
|
699
|
+
params,
|
|
700
|
+
)
|
|
701
|
+
try:
|
|
702
|
+
resp = await self._connection.send_command(command, timeout=FS_MOVE_TIMEOUT)
|
|
703
|
+
if not re.match(rf"^{GCODE.MOVE_TO_SWITCH}$", resp):
|
|
704
|
+
raise ValueError(f"Incorrect Response for move to switch: {resp}")
|
|
705
|
+
except MotorStallDetected:
|
|
706
|
+
self.reset_serial_buffers()
|
|
707
|
+
return MoveResult.STALL_ERROR
|
|
708
|
+
return MoveResult.NO_ERROR
|
|
709
|
+
|
|
710
|
+
async def home_axis(self, axis: StackerAxis, direction: Direction) -> MoveResult:
|
|
711
|
+
"""Home axis."""
|
|
712
|
+
command = GCODE.HOME_AXIS.build_command().add_int(axis.name, direction.value)
|
|
713
|
+
try:
|
|
714
|
+
resp = await self._connection.send_command(command, timeout=FS_MOVE_TIMEOUT)
|
|
715
|
+
except MotorStallDetected:
|
|
716
|
+
self.reset_serial_buffers()
|
|
717
|
+
return MoveResult.STALL_ERROR
|
|
718
|
+
if not re.match(rf"^{GCODE.HOME_AXIS}$", resp):
|
|
719
|
+
raise ValueError(f"Incorrect Response for home axis: {resp}")
|
|
720
|
+
return MoveResult.NO_ERROR
|
|
721
|
+
|
|
722
|
+
async def set_led(
|
|
723
|
+
self,
|
|
724
|
+
power: float,
|
|
725
|
+
color: Optional[LEDColor] = None,
|
|
726
|
+
external: Optional[bool] = None,
|
|
727
|
+
pattern: Optional[LEDPattern] = None,
|
|
728
|
+
duration: Optional[int] = None,
|
|
729
|
+
reps: Optional[int] = None,
|
|
730
|
+
) -> None:
|
|
731
|
+
"""Set LED Status bar color and pattern.
|
|
732
|
+
|
|
733
|
+
:param power: Power of the LED (0-1.0), 0 is off, 1 is full power
|
|
734
|
+
:param color: Color of the LED
|
|
735
|
+
:param external: True if external LED, False if internal LED
|
|
736
|
+
:param pattern: Animation pattern of the LED status bar
|
|
737
|
+
:param duration: Animation duration in milliseconds (25-10000), 10s max
|
|
738
|
+
:param reps: Number of times to repeat the animation (-1 - 10), -1 is forever.
|
|
739
|
+
"""
|
|
740
|
+
power = max(0, min(power, 1.0))
|
|
741
|
+
command = GCODE.SET_LED.build_command().add_float(
|
|
742
|
+
"P", power, GCODE_ROUNDING_PRECISION
|
|
743
|
+
)
|
|
744
|
+
if color is not None:
|
|
745
|
+
command.add_int("C", color.value)
|
|
746
|
+
if external is not None:
|
|
747
|
+
command.add_int("K", int(external))
|
|
748
|
+
if pattern is not None:
|
|
749
|
+
command.add_int("A", pattern.value)
|
|
750
|
+
if duration is not None:
|
|
751
|
+
duration = max(MIN_DURATION_MS, min(duration, MAX_DURATION_MS))
|
|
752
|
+
command.add_int("D", duration)
|
|
753
|
+
if reps is not None:
|
|
754
|
+
command.add_int("R", max(-1, min(reps, MAX_REPS)))
|
|
755
|
+
resp = await self._connection.send_command(command)
|
|
756
|
+
if not re.match(rf"^{GCODE.SET_LED}$", resp):
|
|
757
|
+
raise ValueError(f"Incorrect Response for set led: {resp}")
|
|
758
|
+
|
|
759
|
+
async def enter_programming_mode(self) -> None:
|
|
760
|
+
"""Reboot into programming mode"""
|
|
761
|
+
command = GCODE.ENTER_BOOTLOADER.build_command()
|
|
762
|
+
await self._connection.send_dfu_command(command)
|
|
763
|
+
await self._connection.close()
|
|
764
|
+
|
|
765
|
+
def reset_serial_buffers(self) -> None:
|
|
766
|
+
"""Reset the input and output serial buffers."""
|
|
767
|
+
self._connection._serial.reset_input_buffer()
|
|
768
|
+
self._connection._serial.reset_output_buffer()
|