opentrons 8.3.0a0__py2.py3-none-any.whl → 8.3.0a2__py2.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.
Files changed (229) hide show
  1. opentrons/calibration_storage/deck_configuration.py +3 -3
  2. opentrons/calibration_storage/file_operators.py +3 -3
  3. opentrons/calibration_storage/helpers.py +3 -1
  4. opentrons/calibration_storage/ot2/models/v1.py +16 -29
  5. opentrons/calibration_storage/ot2/tip_length.py +7 -4
  6. opentrons/calibration_storage/ot3/models/v1.py +14 -23
  7. opentrons/cli/analyze.py +18 -6
  8. opentrons/drivers/asyncio/communication/__init__.py +2 -0
  9. opentrons/drivers/asyncio/communication/errors.py +16 -3
  10. opentrons/drivers/asyncio/communication/serial_connection.py +24 -9
  11. opentrons/drivers/command_builder.py +2 -2
  12. opentrons/drivers/flex_stacker/__init__.py +9 -0
  13. opentrons/drivers/flex_stacker/abstract.py +89 -0
  14. opentrons/drivers/flex_stacker/driver.py +260 -0
  15. opentrons/drivers/flex_stacker/simulator.py +109 -0
  16. opentrons/drivers/flex_stacker/types.py +138 -0
  17. opentrons/drivers/heater_shaker/driver.py +18 -3
  18. opentrons/drivers/temp_deck/driver.py +13 -3
  19. opentrons/drivers/thermocycler/driver.py +17 -3
  20. opentrons/execute.py +3 -1
  21. opentrons/hardware_control/__init__.py +1 -2
  22. opentrons/hardware_control/api.py +28 -20
  23. opentrons/hardware_control/backends/flex_protocol.py +4 -6
  24. opentrons/hardware_control/backends/ot3controller.py +177 -59
  25. opentrons/hardware_control/backends/ot3simulator.py +10 -8
  26. opentrons/hardware_control/backends/ot3utils.py +3 -13
  27. opentrons/hardware_control/dev_types.py +2 -0
  28. opentrons/hardware_control/emulation/heater_shaker.py +4 -0
  29. opentrons/hardware_control/emulation/module_server/client.py +1 -1
  30. opentrons/hardware_control/emulation/module_server/server.py +5 -3
  31. opentrons/hardware_control/emulation/settings.py +3 -4
  32. opentrons/hardware_control/instruments/ot2/instrument_calibration.py +2 -1
  33. opentrons/hardware_control/instruments/ot2/pipette.py +9 -21
  34. opentrons/hardware_control/instruments/ot2/pipette_handler.py +8 -1
  35. opentrons/hardware_control/instruments/ot3/gripper.py +2 -2
  36. opentrons/hardware_control/instruments/ot3/pipette.py +13 -22
  37. opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -1
  38. opentrons/hardware_control/modules/mod_abc.py +2 -2
  39. opentrons/hardware_control/motion_utilities.py +68 -0
  40. opentrons/hardware_control/nozzle_manager.py +39 -41
  41. opentrons/hardware_control/ot3_calibration.py +1 -1
  42. opentrons/hardware_control/ot3api.py +34 -22
  43. opentrons/hardware_control/protocols/gripper_controller.py +3 -0
  44. opentrons/hardware_control/protocols/hardware_manager.py +5 -1
  45. opentrons/hardware_control/protocols/liquid_handler.py +18 -0
  46. opentrons/hardware_control/protocols/motion_controller.py +6 -0
  47. opentrons/hardware_control/robot_calibration.py +1 -1
  48. opentrons/hardware_control/types.py +61 -0
  49. opentrons/protocol_api/__init__.py +20 -1
  50. opentrons/protocol_api/_liquid.py +24 -49
  51. opentrons/protocol_api/_liquid_properties.py +754 -0
  52. opentrons/protocol_api/_types.py +24 -0
  53. opentrons/protocol_api/core/common.py +2 -0
  54. opentrons/protocol_api/core/engine/instrument.py +67 -10
  55. opentrons/protocol_api/core/engine/labware.py +29 -7
  56. opentrons/protocol_api/core/engine/protocol.py +130 -5
  57. opentrons/protocol_api/core/engine/robot.py +139 -0
  58. opentrons/protocol_api/core/engine/well.py +4 -1
  59. opentrons/protocol_api/core/instrument.py +42 -4
  60. opentrons/protocol_api/core/labware.py +13 -4
  61. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +34 -3
  62. opentrons/protocol_api/core/legacy/legacy_labware_core.py +13 -4
  63. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +32 -1
  64. opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
  65. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +34 -3
  66. opentrons/protocol_api/core/protocol.py +34 -1
  67. opentrons/protocol_api/core/robot.py +51 -0
  68. opentrons/protocol_api/instrument_context.py +145 -43
  69. opentrons/protocol_api/labware.py +231 -7
  70. opentrons/protocol_api/module_contexts.py +21 -17
  71. opentrons/protocol_api/protocol_context.py +125 -4
  72. opentrons/protocol_api/robot_context.py +204 -32
  73. opentrons/protocol_api/validation.py +261 -3
  74. opentrons/protocol_engine/__init__.py +4 -0
  75. opentrons/protocol_engine/actions/actions.py +2 -3
  76. opentrons/protocol_engine/clients/sync_client.py +18 -0
  77. opentrons/protocol_engine/commands/__init__.py +81 -0
  78. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +0 -2
  79. opentrons/protocol_engine/commands/absorbance_reader/initialize.py +19 -5
  80. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +0 -1
  81. opentrons/protocol_engine/commands/absorbance_reader/read.py +32 -9
  82. opentrons/protocol_engine/commands/air_gap_in_place.py +160 -0
  83. opentrons/protocol_engine/commands/aspirate.py +103 -53
  84. opentrons/protocol_engine/commands/aspirate_in_place.py +55 -51
  85. opentrons/protocol_engine/commands/blow_out.py +44 -39
  86. opentrons/protocol_engine/commands/blow_out_in_place.py +21 -32
  87. opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +13 -6
  88. opentrons/protocol_engine/commands/calibration/calibrate_module.py +1 -1
  89. opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +3 -3
  90. opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +1 -1
  91. opentrons/protocol_engine/commands/command.py +73 -66
  92. opentrons/protocol_engine/commands/command_unions.py +101 -1
  93. opentrons/protocol_engine/commands/comment.py +1 -1
  94. opentrons/protocol_engine/commands/configure_for_volume.py +10 -3
  95. opentrons/protocol_engine/commands/configure_nozzle_layout.py +6 -4
  96. opentrons/protocol_engine/commands/custom.py +6 -12
  97. opentrons/protocol_engine/commands/dispense.py +82 -48
  98. opentrons/protocol_engine/commands/dispense_in_place.py +71 -51
  99. opentrons/protocol_engine/commands/drop_tip.py +52 -31
  100. opentrons/protocol_engine/commands/drop_tip_in_place.py +13 -3
  101. opentrons/protocol_engine/commands/generate_command_schema.py +4 -11
  102. opentrons/protocol_engine/commands/get_next_tip.py +134 -0
  103. opentrons/protocol_engine/commands/get_tip_presence.py +1 -1
  104. opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +1 -1
  105. opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +1 -1
  106. opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +1 -1
  107. opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +1 -1
  108. opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +1 -1
  109. opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +1 -1
  110. opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +10 -4
  111. opentrons/protocol_engine/commands/home.py +13 -4
  112. opentrons/protocol_engine/commands/liquid_probe.py +60 -25
  113. opentrons/protocol_engine/commands/load_labware.py +29 -7
  114. opentrons/protocol_engine/commands/load_lid.py +146 -0
  115. opentrons/protocol_engine/commands/load_lid_stack.py +189 -0
  116. opentrons/protocol_engine/commands/load_liquid.py +12 -4
  117. opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
  118. opentrons/protocol_engine/commands/load_module.py +31 -10
  119. opentrons/protocol_engine/commands/load_pipette.py +19 -8
  120. opentrons/protocol_engine/commands/magnetic_module/disengage.py +1 -1
  121. opentrons/protocol_engine/commands/magnetic_module/engage.py +1 -1
  122. opentrons/protocol_engine/commands/move_labware.py +19 -6
  123. opentrons/protocol_engine/commands/move_relative.py +35 -25
  124. opentrons/protocol_engine/commands/move_to_addressable_area.py +40 -27
  125. opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +53 -32
  126. opentrons/protocol_engine/commands/move_to_coordinates.py +36 -22
  127. opentrons/protocol_engine/commands/move_to_well.py +40 -24
  128. opentrons/protocol_engine/commands/movement_common.py +338 -0
  129. opentrons/protocol_engine/commands/pick_up_tip.py +49 -27
  130. opentrons/protocol_engine/commands/pipetting_common.py +169 -87
  131. opentrons/protocol_engine/commands/prepare_to_aspirate.py +24 -33
  132. opentrons/protocol_engine/commands/reload_labware.py +1 -1
  133. opentrons/protocol_engine/commands/retract_axis.py +1 -1
  134. opentrons/protocol_engine/commands/robot/__init__.py +69 -0
  135. opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +86 -0
  136. opentrons/protocol_engine/commands/robot/common.py +18 -0
  137. opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
  138. opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
  139. opentrons/protocol_engine/commands/robot/move_to.py +94 -0
  140. opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +77 -0
  141. opentrons/protocol_engine/commands/save_position.py +14 -5
  142. opentrons/protocol_engine/commands/set_rail_lights.py +1 -1
  143. opentrons/protocol_engine/commands/set_status_bar.py +1 -1
  144. opentrons/protocol_engine/commands/temperature_module/deactivate.py +1 -1
  145. opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +1 -1
  146. opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +10 -4
  147. opentrons/protocol_engine/commands/thermocycler/close_lid.py +1 -1
  148. opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +1 -1
  149. opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +1 -1
  150. opentrons/protocol_engine/commands/thermocycler/open_lid.py +1 -1
  151. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +8 -2
  152. opentrons/protocol_engine/commands/thermocycler/run_profile.py +9 -3
  153. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +11 -4
  154. opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +1 -1
  155. opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +1 -1
  156. opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +1 -1
  157. opentrons/protocol_engine/commands/touch_tip.py +65 -16
  158. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +4 -1
  159. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -3
  160. opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +1 -4
  161. opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +1 -4
  162. opentrons/protocol_engine/commands/verify_tip_presence.py +11 -4
  163. opentrons/protocol_engine/commands/wait_for_duration.py +10 -3
  164. opentrons/protocol_engine/commands/wait_for_resume.py +10 -3
  165. opentrons/protocol_engine/errors/__init__.py +8 -0
  166. opentrons/protocol_engine/errors/error_occurrence.py +19 -20
  167. opentrons/protocol_engine/errors/exceptions.py +50 -0
  168. opentrons/protocol_engine/execution/command_executor.py +1 -1
  169. opentrons/protocol_engine/execution/equipment.py +73 -5
  170. opentrons/protocol_engine/execution/gantry_mover.py +364 -8
  171. opentrons/protocol_engine/execution/movement.py +27 -0
  172. opentrons/protocol_engine/execution/pipetting.py +5 -1
  173. opentrons/protocol_engine/execution/tip_handler.py +4 -6
  174. opentrons/protocol_engine/notes/notes.py +1 -1
  175. opentrons/protocol_engine/protocol_engine.py +7 -6
  176. opentrons/protocol_engine/resources/labware_data_provider.py +1 -1
  177. opentrons/protocol_engine/resources/labware_validation.py +5 -0
  178. opentrons/protocol_engine/resources/module_data_provider.py +1 -1
  179. opentrons/protocol_engine/resources/pipette_data_provider.py +12 -0
  180. opentrons/protocol_engine/slot_standardization.py +9 -9
  181. opentrons/protocol_engine/state/_move_types.py +9 -5
  182. opentrons/protocol_engine/state/_well_math.py +193 -0
  183. opentrons/protocol_engine/state/addressable_areas.py +25 -61
  184. opentrons/protocol_engine/state/command_history.py +12 -0
  185. opentrons/protocol_engine/state/commands.py +17 -13
  186. opentrons/protocol_engine/state/files.py +10 -12
  187. opentrons/protocol_engine/state/fluid_stack.py +138 -0
  188. opentrons/protocol_engine/state/frustum_helpers.py +57 -32
  189. opentrons/protocol_engine/state/geometry.py +47 -1
  190. opentrons/protocol_engine/state/labware.py +79 -25
  191. opentrons/protocol_engine/state/liquid_classes.py +82 -0
  192. opentrons/protocol_engine/state/liquids.py +16 -4
  193. opentrons/protocol_engine/state/modules.py +52 -70
  194. opentrons/protocol_engine/state/motion.py +6 -1
  195. opentrons/protocol_engine/state/pipettes.py +135 -58
  196. opentrons/protocol_engine/state/state.py +21 -2
  197. opentrons/protocol_engine/state/state_summary.py +4 -2
  198. opentrons/protocol_engine/state/tips.py +11 -44
  199. opentrons/protocol_engine/state/update_types.py +343 -48
  200. opentrons/protocol_engine/state/wells.py +19 -11
  201. opentrons/protocol_engine/types.py +176 -28
  202. opentrons/protocol_reader/extract_labware_definitions.py +5 -2
  203. opentrons/protocol_reader/file_format_validator.py +5 -5
  204. opentrons/protocol_runner/json_file_reader.py +9 -3
  205. opentrons/protocol_runner/json_translator.py +51 -25
  206. opentrons/protocol_runner/legacy_command_mapper.py +66 -64
  207. opentrons/protocol_runner/protocol_runner.py +35 -4
  208. opentrons/protocol_runner/python_protocol_wrappers.py +1 -1
  209. opentrons/protocol_runner/run_orchestrator.py +13 -3
  210. opentrons/protocols/advanced_control/common.py +38 -0
  211. opentrons/protocols/advanced_control/mix.py +1 -1
  212. opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
  213. opentrons/protocols/advanced_control/transfers/common.py +56 -0
  214. opentrons/protocols/advanced_control/{transfers.py → transfers/transfer.py} +10 -85
  215. opentrons/protocols/api_support/definitions.py +1 -1
  216. opentrons/protocols/api_support/instrument.py +1 -1
  217. opentrons/protocols/api_support/util.py +10 -0
  218. opentrons/protocols/labware.py +70 -8
  219. opentrons/protocols/models/json_protocol.py +5 -9
  220. opentrons/simulate.py +3 -1
  221. opentrons/types.py +162 -2
  222. opentrons/util/entrypoint_util.py +2 -5
  223. opentrons/util/logging_config.py +1 -1
  224. {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/METADATA +16 -15
  225. {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/RECORD +229 -202
  226. {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/WHEEL +1 -1
  227. {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/LICENSE +0 -0
  228. {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/entry_points.txt +0 -0
  229. {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/top_level.txt +0 -0
@@ -46,7 +46,6 @@ from opentrons.config.types import (
46
46
  LiquidProbeSettings,
47
47
  )
48
48
  from opentrons.drivers.rpi_drivers.types import USBPort, PortGroup
49
- from opentrons.hardware_control.nozzle_manager import NozzleConfigurationType
50
49
  from opentrons_shared_data.errors.exceptions import (
51
50
  EnumeratedError,
52
51
  PythonException,
@@ -99,6 +98,7 @@ from .types import (
99
98
  EstopState,
100
99
  HardwareFeatureFlags,
101
100
  FailedTipStateCheck,
101
+ PipetteSensorResponseQueue,
102
102
  )
103
103
  from .errors import (
104
104
  UpdateOngoingError,
@@ -144,8 +144,6 @@ from .backends.types import HWStopCondition
144
144
  from .backends.flex_protocol import FlexBackend
145
145
  from .backends.ot3simulator import OT3Simulator
146
146
  from .backends.errors import SubsystemUpdating
147
- from opentrons_hardware.firmware_bindings.constants import SensorId
148
- from opentrons_hardware.sensors.types import SensorDataType
149
147
 
150
148
  mod_log = logging.getLogger(__name__)
151
149
 
@@ -357,7 +355,9 @@ class OT3API(
357
355
  def _reset_last_mount(self) -> None:
358
356
  self._last_moved_mount = None
359
357
 
360
- def _deck_from_machine(self, machine_pos: Dict[Axis, float]) -> Dict[Axis, float]:
358
+ def get_deck_from_machine(
359
+ self, machine_pos: Dict[Axis, float]
360
+ ) -> Dict[Axis, float]:
361
361
  return deck_from_machine(
362
362
  machine_pos=machine_pos,
363
363
  attitude=self._robot_calibration.deck_calibration.attitude,
@@ -800,6 +800,8 @@ class OT3API(
800
800
  """
801
801
  Function to update motor estimation for a set of axes
802
802
  """
803
+ await self._backend.update_motor_status()
804
+
803
805
  if axes is None:
804
806
  axes = [ax for ax in Axis]
805
807
 
@@ -968,8 +970,8 @@ class OT3API(
968
970
  ):
969
971
  # move toward home until a safe distance
970
972
  await self._backend.tip_action(
971
- origin={Axis.Q: current_pos_float},
972
- targets=[({Axis.Q: self._config.safe_home_distance}, 400)],
973
+ origin=current_pos_float,
974
+ targets=[(self._config.safe_home_distance, 400)],
973
975
  )
974
976
 
975
977
  # update current position
@@ -1046,14 +1048,14 @@ class OT3API(
1046
1048
 
1047
1049
  async def _cache_current_position(self) -> Dict[Axis, float]:
1048
1050
  """Cache current position from backend and return in absolute deck coords."""
1049
- self._current_position = self._deck_from_machine(
1051
+ self._current_position = self.get_deck_from_machine(
1050
1052
  await self._backend.update_position()
1051
1053
  )
1052
1054
  return self._current_position
1053
1055
 
1054
1056
  async def _cache_encoder_position(self) -> Dict[Axis, float]:
1055
1057
  """Cache encoder position from backend and return in absolute deck coords."""
1056
- self._encoder_position = self._deck_from_machine(
1058
+ self._encoder_position = self.get_deck_from_machine(
1057
1059
  await self._backend.update_encoder_position()
1058
1060
  )
1059
1061
  if self.has_gripper():
@@ -1253,7 +1255,9 @@ class OT3API(
1253
1255
  message=f"{axis} is not present", detail={"axis": str(axis)}
1254
1256
  )
1255
1257
 
1258
+ self._log.info(f"Attempting to move {position} with speed {speed}.")
1256
1259
  if not self._backend.check_encoder_status(list(position.keys())):
1260
+ self._log.info("Calling home in move_axes")
1257
1261
  await self.home()
1258
1262
  self._assert_motor_ok(list(position.keys()))
1259
1263
 
@@ -1464,6 +1468,10 @@ class OT3API(
1464
1468
  check_motion_bounds(to_check, target_position, bounds, check_bounds)
1465
1469
  self._log.info(f"Move: deck {target_position} becomes machine {machine_pos}")
1466
1470
  origin = await self._backend.update_position()
1471
+
1472
+ if self._gantry_load == GantryLoad.HIGH_THROUGHPUT:
1473
+ origin[Axis.Q] = self._backend.gear_motor_position or 0.0
1474
+
1467
1475
  async with contextlib.AsyncExitStack() as stack:
1468
1476
  if acquire_lock:
1469
1477
  await stack.enter_async_context(self._motion_lock)
@@ -1665,7 +1673,12 @@ class OT3API(
1665
1673
  await self._backend.disengage_axes(which)
1666
1674
 
1667
1675
  async def engage_axes(self, which: List[Axis]) -> None:
1668
- await self._backend.engage_axes(which)
1676
+ await self._backend.engage_axes(
1677
+ [axis for axis in which if self._backend.axis_is_present(axis)]
1678
+ )
1679
+
1680
+ def axis_is_present(self, axis: Axis) -> bool:
1681
+ return self._backend.axis_is_present(axis)
1669
1682
 
1670
1683
  async def get_limit_switches(self) -> Dict[Axis, bool]:
1671
1684
  res = await self._backend.get_limit_switches()
@@ -1851,7 +1864,7 @@ class OT3API(
1851
1864
  if (
1852
1865
  self.gantry_load == GantryLoad.HIGH_THROUGHPUT
1853
1866
  and instrument.nozzle_manager.current_configuration.configuration
1854
- == NozzleConfigurationType.FULL
1867
+ == top_types.NozzleConfigurationType.FULL
1855
1868
  ):
1856
1869
  spec = self._pipette_handler.plan_ht_pick_up_tip(
1857
1870
  instrument.nozzle_manager.current_configuration.tip_count
@@ -2181,8 +2194,8 @@ class OT3API(
2181
2194
  # only move tip motors if they are not already below the sensor
2182
2195
  if tip_motor_pos_float < tip_presence_check_target:
2183
2196
  await self._backend.tip_action(
2184
- origin={Axis.Q: tip_motor_pos_float},
2185
- targets=[({Axis.Q: tip_presence_check_target}, 400)],
2197
+ origin=tip_motor_pos_float,
2198
+ targets=[(tip_presence_check_target, 400)],
2186
2199
  )
2187
2200
  try:
2188
2201
  yield
@@ -2253,11 +2266,11 @@ class OT3API(
2253
2266
  gear_origin_float = self._backend.gear_motor_position or 0.0
2254
2267
 
2255
2268
  move_targets = [
2256
- ({Axis.Q: move_segment.distance}, move_segment.speed or 400)
2269
+ (move_segment.distance, move_segment.speed or 400)
2257
2270
  for move_segment in pipette_spec
2258
2271
  ]
2259
2272
  await self._backend.tip_action(
2260
- origin={Axis.Q: gear_origin_float}, targets=move_targets
2273
+ origin=gear_origin_float, targets=move_targets
2261
2274
  )
2262
2275
  await self.home_gear_motors()
2263
2276
 
@@ -2582,7 +2595,7 @@ class OT3API(
2582
2595
  mount: Union[top_types.Mount, OT3Mount],
2583
2596
  critical_point: Optional[CriticalPoint] = None,
2584
2597
  ) -> float:
2585
- carriage_pos = self._deck_from_machine(self._backend.home_position())
2598
+ carriage_pos = self.get_deck_from_machine(self._backend.home_position())
2586
2599
  pos_at_home = self._effector_pos_from_carriage_pos(
2587
2600
  OT3Mount.from_mount(mount), carriage_pos, critical_point
2588
2601
  )
@@ -2664,10 +2677,9 @@ class OT3API(
2664
2677
  probe_settings: LiquidProbeSettings,
2665
2678
  probe: InstrumentProbeType,
2666
2679
  p_travel: float,
2680
+ z_offset_for_plunger_prep: float,
2667
2681
  force_both_sensors: bool = False,
2668
- response_queue: Optional[
2669
- asyncio.Queue[Dict[SensorId, List[SensorDataType]]]
2670
- ] = None,
2682
+ response_queue: Optional[PipetteSensorResponseQueue] = None,
2671
2683
  ) -> float:
2672
2684
  plunger_direction = -1 if probe_settings.aspirate_while_sensing else 1
2673
2685
  end_z = await self._backend.liquid_probe(
@@ -2678,13 +2690,14 @@ class OT3API(
2678
2690
  probe_settings.sensor_threshold_pascals,
2679
2691
  probe_settings.plunger_impulse_time,
2680
2692
  probe_settings.samples_for_baselining,
2693
+ z_offset_for_plunger_prep,
2681
2694
  probe=probe,
2682
2695
  force_both_sensors=force_both_sensors,
2683
2696
  response_queue=response_queue,
2684
2697
  )
2685
2698
  machine_pos = await self._backend.update_position()
2686
2699
  machine_pos[Axis.by_mount(mount)] = end_z
2687
- deck_end_z = self._deck_from_machine(machine_pos)[Axis.by_mount(mount)]
2700
+ deck_end_z = self.get_deck_from_machine(machine_pos)[Axis.by_mount(mount)]
2688
2701
  offset = offset_for_mount(
2689
2702
  mount,
2690
2703
  top_types.Point(*self._config.left_mount_offset),
@@ -2701,9 +2714,7 @@ class OT3API(
2701
2714
  probe_settings: Optional[LiquidProbeSettings] = None,
2702
2715
  probe: Optional[InstrumentProbeType] = None,
2703
2716
  force_both_sensors: bool = False,
2704
- response_queue: Optional[
2705
- asyncio.Queue[Dict[SensorId, List[SensorDataType]]]
2706
- ] = None,
2717
+ response_queue: Optional[PipetteSensorResponseQueue] = None,
2707
2718
  ) -> float:
2708
2719
  """Search for and return liquid level height.
2709
2720
 
@@ -2829,6 +2840,7 @@ class OT3API(
2829
2840
  probe_settings,
2830
2841
  checked_probe,
2831
2842
  plunger_travel_mm + sensor_baseline_plunger_move_mm,
2843
+ z_offset_for_plunger_prep,
2832
2844
  force_both_sensors,
2833
2845
  response_queue,
2834
2846
  )
@@ -14,6 +14,9 @@ class GripperController(Protocol):
14
14
  ) -> None:
15
15
  ...
16
16
 
17
+ async def home_gripper_jaw(self) -> None:
18
+ ...
19
+
17
20
  async def ungrip(self, force_newtons: Optional[float] = None) -> None:
18
21
  """Release gripped object.
19
22
 
@@ -1,7 +1,7 @@
1
1
  from typing import Dict, Optional
2
2
  from typing_extensions import Protocol
3
3
 
4
- from ..types import SubSystem, SubSystemState
4
+ from ..types import SubSystem, SubSystemState, Axis
5
5
 
6
6
 
7
7
  class HardwareManager(Protocol):
@@ -45,3 +45,7 @@ class HardwareManager(Protocol):
45
45
  async def get_serial_number(self) -> Optional[str]:
46
46
  """Get the robot serial number, if provisioned. If not provisioned, will be None."""
47
47
  ...
48
+
49
+ def axis_is_present(self, axis: Axis) -> bool:
50
+ """Get whether a motor axis is present on the machine."""
51
+ ...
@@ -1,6 +1,8 @@
1
1
  from typing import Optional
2
2
  from typing_extensions import Protocol
3
3
 
4
+ from opentrons.types import Point
5
+ from opentrons.hardware_control.types import CriticalPoint
4
6
  from .types import MountArgType, CalibrationType, ConfigType
5
7
 
6
8
  from .instrument_configurer import InstrumentConfigurer
@@ -16,6 +18,22 @@ class LiquidHandler(
16
18
  Calibratable[CalibrationType],
17
19
  Protocol[CalibrationType, MountArgType, ConfigType],
18
20
  ):
21
+ def critical_point_for(
22
+ self,
23
+ mount: MountArgType,
24
+ cp_override: Optional[CriticalPoint] = None,
25
+ ) -> Point:
26
+ """
27
+ Determine the current critical point for the specified mount.
28
+
29
+ :param mount: A robot mount that the instrument is on.
30
+ :param cp_override: The critical point override to use.
31
+
32
+ If no critical point override is specified, the robot defaults to nozzle location `A1` or the mount critical point.
33
+ :return: Point.
34
+ """
35
+ ...
36
+
19
37
  async def update_nozzle_configuration_for_mount(
20
38
  self,
21
39
  mount: MountArgType,
@@ -9,6 +9,12 @@ from .types import MountArgType
9
9
  class MotionController(Protocol[MountArgType]):
10
10
  """Protocol specifying fundamental motion controls."""
11
11
 
12
+ def get_deck_from_machine(
13
+ self, machine_pos: Dict[Axis, float]
14
+ ) -> Dict[Axis, float]:
15
+ """Convert machine coordinates to deck coordinates."""
16
+ ...
17
+
12
18
  async def halt(self, disengage_before_stopping: bool = False) -> None:
13
19
  """Immediately stop motion.
14
20
 
@@ -154,7 +154,7 @@ def load_attitude_matrix() -> DeckCalibration:
154
154
  return DeckCalibration(
155
155
  attitude=calibration_data.attitude,
156
156
  source=calibration_data.source,
157
- status=types.CalibrationStatus(**calibration_data.status.dict()),
157
+ status=types.CalibrationStatus(**calibration_data.status.model_dump()),
158
158
  last_modified=calibration_data.last_modified,
159
159
  pipette_calibrated_with=calibration_data.pipette_calibrated_with,
160
160
  tiprack=calibration_data.tiprack,
@@ -1,3 +1,4 @@
1
+ from asyncio import Queue
1
2
  import enum
2
3
  import logging
3
4
  from dataclasses import dataclass
@@ -712,3 +713,63 @@ class FailedTipStateCheck(RuntimeError):
712
713
  super().__init__(
713
714
  f"Expected tip state {expected_state}, but received {actual_state}."
714
715
  )
716
+
717
+
718
+ @enum.unique
719
+ class PipetteSensorId(int, enum.Enum):
720
+ """Sensor IDs available.
721
+
722
+ Not to be confused with SensorType. This is the ID value that separate
723
+ two or more of the same type of sensor within a system.
724
+
725
+ Note that this is a copy of an enum defined in opentrons_hardware.firmware_bindings.constants. That version
726
+ is authoritative; this version is here because this data is exposed above the hardware control layer and
727
+ therefore needs a typing source here so that we don't create a dependency on the internal hardware package.
728
+ """
729
+
730
+ S0 = 0x0
731
+ S1 = 0x1
732
+ UNUSED = 0x2
733
+ BOTH = 0x3
734
+
735
+
736
+ @enum.unique
737
+ class PipetteSensorType(int, enum.Enum):
738
+ """Sensor types available.
739
+
740
+ Note that this is a copy of an enum defined in opentrons_hardware.firmware_bindings.constants. That version
741
+ is authoritative; this version is here because this data is exposed above the hardware control layer and
742
+ therefore needs a typing source here so that we don't create a dependency on the internal hardware package.
743
+ """
744
+
745
+ tip = 0x00
746
+ capacitive = 0x01
747
+ environment = 0x02
748
+ pressure = 0x03
749
+ pressure_temperature = 0x04
750
+ humidity = 0x05
751
+ temperature = 0x06
752
+
753
+
754
+ @dataclass(frozen=True)
755
+ class PipetteSensorData:
756
+ """Sensor data from a monitored sensor.
757
+
758
+ Note that this is a copy of an enum defined in opentrons_hardware.firmware_bindings.constants. That version
759
+ is authoritative; this version is here because this data is exposed above the hardware control layer and
760
+ therefore needs a typing source here so that we don't create a dependency on the internal hardware package.
761
+ """
762
+
763
+ sensor_type: PipetteSensorType
764
+ _as_int: int
765
+ _as_float: float
766
+
767
+ def to_float(self) -> float:
768
+ return self._as_float
769
+
770
+ @property
771
+ def to_int(self) -> int:
772
+ return self._as_int
773
+
774
+
775
+ PipetteSensorResponseQueue = Queue[Dict[PipetteSensorId, List[PipetteSensorData]]]
@@ -30,7 +30,16 @@ from .module_contexts import (
30
30
  )
31
31
  from .disposal_locations import TrashBin, WasteChute
32
32
  from ._liquid import Liquid, LiquidClass
33
- from ._types import OFF_DECK
33
+ from ._types import (
34
+ OFF_DECK,
35
+ PLUNGER_BLOWOUT,
36
+ PLUNGER_TOP,
37
+ PLUNGER_BOTTOM,
38
+ PLUNGER_DROPTIP,
39
+ ASPIRATE_ACTION,
40
+ DISPENSE_ACTION,
41
+ BLOWOUT_ACTION,
42
+ )
34
43
  from ._nozzle_layout import (
35
44
  COLUMN,
36
45
  PARTIAL_COLUMN,
@@ -69,12 +78,22 @@ __all__ = [
69
78
  "Liquid",
70
79
  "LiquidClass",
71
80
  "Parameters",
81
+ # Partial Tip types
72
82
  "COLUMN",
73
83
  "PARTIAL_COLUMN",
74
84
  "SINGLE",
75
85
  "ROW",
76
86
  "ALL",
87
+ # Deck location types
77
88
  "OFF_DECK",
89
+ # Pipette plunger types
90
+ "PLUNGER_BLOWOUT",
91
+ "PLUNGER_TOP",
92
+ "PLUNGER_BOTTOM",
93
+ "PLUNGER_DROPTIP",
94
+ "ASPIRATE_ACTION",
95
+ "DISPENSE_ACTION",
96
+ "BLOWOUT_ACTION",
78
97
  "RuntimeParameterRequiredError",
79
98
  "CSVParameter",
80
99
  # For internal Opentrons use only:
@@ -1,13 +1,15 @@
1
+ from __future__ import annotations
2
+
1
3
  from dataclasses import dataclass
2
- from typing import Optional, Sequence
4
+ from typing import Optional, Dict
3
5
 
4
6
  from opentrons_shared_data.liquid_classes.liquid_class_definition import (
5
7
  LiquidClassSchemaV1,
6
- AspirateProperties,
7
- SingleDispenseProperties,
8
- MultiDispenseProperties,
9
- ByPipetteSetting,
10
- ByTipTypeSetting,
8
+ )
9
+
10
+ from ._liquid_properties import (
11
+ TransferProperties,
12
+ build_transfer_properties,
11
13
  )
12
14
 
13
15
 
@@ -29,46 +31,29 @@ class Liquid:
29
31
  display_color: Optional[str]
30
32
 
31
33
 
32
- # TODO (spp, 2024-10-17): create PAPI-equivalent types for all the properties
33
- # and have validation on value updates with user-facing error messages
34
- @dataclass
35
- class TransferProperties:
36
- _aspirate: AspirateProperties
37
- _dispense: SingleDispenseProperties
38
- _multi_dispense: Optional[MultiDispenseProperties]
39
-
40
- @property
41
- def aspirate(self) -> AspirateProperties:
42
- """Aspirate properties."""
43
- return self._aspirate
44
-
45
- @property
46
- def dispense(self) -> SingleDispenseProperties:
47
- """Single dispense properties."""
48
- return self._dispense
49
-
50
- @property
51
- def multi_dispense(self) -> Optional[MultiDispenseProperties]:
52
- """Multi dispense properties."""
53
- return self._multi_dispense
54
-
55
-
56
34
  @dataclass
57
35
  class LiquidClass:
58
36
  """A data class that contains properties of a specific class of liquids."""
59
37
 
60
38
  _name: str
61
39
  _display_name: str
62
- _by_pipette_setting: Sequence[ByPipetteSetting]
40
+ _by_pipette_setting: Dict[str, Dict[str, TransferProperties]]
63
41
 
64
42
  @classmethod
65
43
  def create(cls, liquid_class_definition: LiquidClassSchemaV1) -> "LiquidClass":
66
44
  """Liquid class factory method."""
67
45
 
46
+ by_pipette_settings: Dict[str, Dict[str, TransferProperties]] = {}
47
+ for by_pipette in liquid_class_definition.byPipette:
48
+ tip_settings: Dict[str, TransferProperties] = {}
49
+ for tip_type in by_pipette.byTipType:
50
+ tip_settings[tip_type.tiprack] = build_transfer_properties(tip_type)
51
+ by_pipette_settings[by_pipette.pipetteModel] = tip_settings
52
+
68
53
  return cls(
69
54
  _name=liquid_class_definition.liquidClassName,
70
55
  _display_name=liquid_class_definition.displayName,
71
- _by_pipette_setting=liquid_class_definition.byPipette,
56
+ _by_pipette_setting=by_pipette_settings,
72
57
  )
73
58
 
74
59
  @property
@@ -81,26 +66,16 @@ class LiquidClass:
81
66
 
82
67
  def get_for(self, pipette: str, tiprack: str) -> TransferProperties:
83
68
  """Get liquid class transfer properties for the specified pipette and tip."""
84
- settings_for_pipette: Sequence[ByPipetteSetting] = [
85
- pip_setting
86
- for pip_setting in self._by_pipette_setting
87
- if pip_setting.pipetteModel == pipette
88
- ]
89
- if len(settings_for_pipette) == 0:
69
+ try:
70
+ settings_for_pipette = self._by_pipette_setting[pipette]
71
+ except KeyError:
90
72
  raise ValueError(
91
73
  f"No properties found for {pipette} in {self._name} liquid class"
92
74
  )
93
- settings_for_tip: Sequence[ByTipTypeSetting] = [
94
- tip_setting
95
- for tip_setting in settings_for_pipette[0].byTipType
96
- if tip_setting.tiprack == tiprack
97
- ]
98
- if len(settings_for_tip) == 0:
75
+ try:
76
+ transfer_properties = settings_for_pipette[tiprack]
77
+ except KeyError:
99
78
  raise ValueError(
100
79
  f"No properties found for {tiprack} in {self._name} liquid class"
101
80
  )
102
- return TransferProperties(
103
- _aspirate=settings_for_tip[0].aspirate,
104
- _dispense=settings_for_tip[0].singleDispense,
105
- _multi_dispense=settings_for_tip[0].multiDispense,
106
- )
81
+ return transfer_properties