opentrons 8.6.0a1__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.

Files changed (600) hide show
  1. opentrons/__init__.py +150 -0
  2. opentrons/_version.py +34 -0
  3. opentrons/calibration_storage/__init__.py +54 -0
  4. opentrons/calibration_storage/deck_configuration.py +62 -0
  5. opentrons/calibration_storage/encoder_decoder.py +31 -0
  6. opentrons/calibration_storage/file_operators.py +142 -0
  7. opentrons/calibration_storage/helpers.py +103 -0
  8. opentrons/calibration_storage/ot2/__init__.py +34 -0
  9. opentrons/calibration_storage/ot2/deck_attitude.py +85 -0
  10. opentrons/calibration_storage/ot2/mark_bad_calibration.py +27 -0
  11. opentrons/calibration_storage/ot2/models/__init__.py +0 -0
  12. opentrons/calibration_storage/ot2/models/v1.py +149 -0
  13. opentrons/calibration_storage/ot2/pipette_offset.py +129 -0
  14. opentrons/calibration_storage/ot2/tip_length.py +281 -0
  15. opentrons/calibration_storage/ot3/__init__.py +31 -0
  16. opentrons/calibration_storage/ot3/deck_attitude.py +83 -0
  17. opentrons/calibration_storage/ot3/gripper_offset.py +156 -0
  18. opentrons/calibration_storage/ot3/models/__init__.py +0 -0
  19. opentrons/calibration_storage/ot3/models/v1.py +122 -0
  20. opentrons/calibration_storage/ot3/module_offset.py +138 -0
  21. opentrons/calibration_storage/ot3/pipette_offset.py +95 -0
  22. opentrons/calibration_storage/types.py +45 -0
  23. opentrons/cli/__init__.py +21 -0
  24. opentrons/cli/__main__.py +5 -0
  25. opentrons/cli/analyze.py +501 -0
  26. opentrons/config/__init__.py +631 -0
  27. opentrons/config/advanced_settings.py +871 -0
  28. opentrons/config/defaults_ot2.py +214 -0
  29. opentrons/config/defaults_ot3.py +499 -0
  30. opentrons/config/feature_flags.py +86 -0
  31. opentrons/config/gripper_config.py +55 -0
  32. opentrons/config/reset.py +203 -0
  33. opentrons/config/robot_configs.py +187 -0
  34. opentrons/config/types.py +183 -0
  35. opentrons/drivers/__init__.py +0 -0
  36. opentrons/drivers/absorbance_reader/__init__.py +11 -0
  37. opentrons/drivers/absorbance_reader/abstract.py +72 -0
  38. opentrons/drivers/absorbance_reader/async_byonoy.py +352 -0
  39. opentrons/drivers/absorbance_reader/driver.py +81 -0
  40. opentrons/drivers/absorbance_reader/hid_protocol.py +161 -0
  41. opentrons/drivers/absorbance_reader/simulator.py +84 -0
  42. opentrons/drivers/asyncio/__init__.py +0 -0
  43. opentrons/drivers/asyncio/communication/__init__.py +22 -0
  44. opentrons/drivers/asyncio/communication/async_serial.py +183 -0
  45. opentrons/drivers/asyncio/communication/errors.py +88 -0
  46. opentrons/drivers/asyncio/communication/serial_connection.py +552 -0
  47. opentrons/drivers/command_builder.py +102 -0
  48. opentrons/drivers/flex_stacker/__init__.py +13 -0
  49. opentrons/drivers/flex_stacker/abstract.py +214 -0
  50. opentrons/drivers/flex_stacker/driver.py +768 -0
  51. opentrons/drivers/flex_stacker/errors.py +68 -0
  52. opentrons/drivers/flex_stacker/simulator.py +309 -0
  53. opentrons/drivers/flex_stacker/types.py +367 -0
  54. opentrons/drivers/flex_stacker/utils.py +19 -0
  55. opentrons/drivers/heater_shaker/__init__.py +5 -0
  56. opentrons/drivers/heater_shaker/abstract.py +76 -0
  57. opentrons/drivers/heater_shaker/driver.py +204 -0
  58. opentrons/drivers/heater_shaker/simulator.py +94 -0
  59. opentrons/drivers/mag_deck/__init__.py +6 -0
  60. opentrons/drivers/mag_deck/abstract.py +44 -0
  61. opentrons/drivers/mag_deck/driver.py +208 -0
  62. opentrons/drivers/mag_deck/simulator.py +63 -0
  63. opentrons/drivers/rpi_drivers/__init__.py +33 -0
  64. opentrons/drivers/rpi_drivers/dev_types.py +94 -0
  65. opentrons/drivers/rpi_drivers/gpio.py +282 -0
  66. opentrons/drivers/rpi_drivers/gpio_simulator.py +127 -0
  67. opentrons/drivers/rpi_drivers/interfaces.py +15 -0
  68. opentrons/drivers/rpi_drivers/types.py +364 -0
  69. opentrons/drivers/rpi_drivers/usb.py +102 -0
  70. opentrons/drivers/rpi_drivers/usb_simulator.py +22 -0
  71. opentrons/drivers/serial_communication.py +151 -0
  72. opentrons/drivers/smoothie_drivers/__init__.py +4 -0
  73. opentrons/drivers/smoothie_drivers/connection.py +51 -0
  74. opentrons/drivers/smoothie_drivers/constants.py +121 -0
  75. opentrons/drivers/smoothie_drivers/driver_3_0.py +1933 -0
  76. opentrons/drivers/smoothie_drivers/errors.py +49 -0
  77. opentrons/drivers/smoothie_drivers/parse_utils.py +143 -0
  78. opentrons/drivers/smoothie_drivers/simulator.py +99 -0
  79. opentrons/drivers/smoothie_drivers/types.py +16 -0
  80. opentrons/drivers/temp_deck/__init__.py +10 -0
  81. opentrons/drivers/temp_deck/abstract.py +54 -0
  82. opentrons/drivers/temp_deck/driver.py +197 -0
  83. opentrons/drivers/temp_deck/simulator.py +57 -0
  84. opentrons/drivers/thermocycler/__init__.py +12 -0
  85. opentrons/drivers/thermocycler/abstract.py +99 -0
  86. opentrons/drivers/thermocycler/driver.py +395 -0
  87. opentrons/drivers/thermocycler/simulator.py +126 -0
  88. opentrons/drivers/types.py +107 -0
  89. opentrons/drivers/utils.py +222 -0
  90. opentrons/execute.py +742 -0
  91. opentrons/hardware_control/__init__.py +65 -0
  92. opentrons/hardware_control/__main__.py +77 -0
  93. opentrons/hardware_control/adapters.py +98 -0
  94. opentrons/hardware_control/api.py +1347 -0
  95. opentrons/hardware_control/backends/__init__.py +7 -0
  96. opentrons/hardware_control/backends/controller.py +400 -0
  97. opentrons/hardware_control/backends/errors.py +9 -0
  98. opentrons/hardware_control/backends/estop_state.py +164 -0
  99. opentrons/hardware_control/backends/flex_protocol.py +497 -0
  100. opentrons/hardware_control/backends/ot3controller.py +1930 -0
  101. opentrons/hardware_control/backends/ot3simulator.py +900 -0
  102. opentrons/hardware_control/backends/ot3utils.py +664 -0
  103. opentrons/hardware_control/backends/simulator.py +442 -0
  104. opentrons/hardware_control/backends/status_bar_state.py +240 -0
  105. opentrons/hardware_control/backends/subsystem_manager.py +431 -0
  106. opentrons/hardware_control/backends/tip_presence_manager.py +173 -0
  107. opentrons/hardware_control/backends/types.py +14 -0
  108. opentrons/hardware_control/constants.py +6 -0
  109. opentrons/hardware_control/dev_types.py +125 -0
  110. opentrons/hardware_control/emulation/__init__.py +0 -0
  111. opentrons/hardware_control/emulation/abstract_emulator.py +21 -0
  112. opentrons/hardware_control/emulation/app.py +56 -0
  113. opentrons/hardware_control/emulation/connection_handler.py +38 -0
  114. opentrons/hardware_control/emulation/heater_shaker.py +150 -0
  115. opentrons/hardware_control/emulation/magdeck.py +60 -0
  116. opentrons/hardware_control/emulation/module_server/__init__.py +8 -0
  117. opentrons/hardware_control/emulation/module_server/client.py +78 -0
  118. opentrons/hardware_control/emulation/module_server/helpers.py +130 -0
  119. opentrons/hardware_control/emulation/module_server/models.py +31 -0
  120. opentrons/hardware_control/emulation/module_server/server.py +110 -0
  121. opentrons/hardware_control/emulation/parser.py +74 -0
  122. opentrons/hardware_control/emulation/proxy.py +241 -0
  123. opentrons/hardware_control/emulation/run_emulator.py +68 -0
  124. opentrons/hardware_control/emulation/scripts/__init__.py +0 -0
  125. opentrons/hardware_control/emulation/scripts/run_app.py +54 -0
  126. opentrons/hardware_control/emulation/scripts/run_module_emulator.py +72 -0
  127. opentrons/hardware_control/emulation/scripts/run_smoothie.py +37 -0
  128. opentrons/hardware_control/emulation/settings.py +119 -0
  129. opentrons/hardware_control/emulation/simulations.py +133 -0
  130. opentrons/hardware_control/emulation/smoothie.py +192 -0
  131. opentrons/hardware_control/emulation/tempdeck.py +69 -0
  132. opentrons/hardware_control/emulation/thermocycler.py +128 -0
  133. opentrons/hardware_control/emulation/types.py +10 -0
  134. opentrons/hardware_control/emulation/util.py +38 -0
  135. opentrons/hardware_control/errors.py +43 -0
  136. opentrons/hardware_control/execution_manager.py +164 -0
  137. opentrons/hardware_control/instruments/__init__.py +5 -0
  138. opentrons/hardware_control/instruments/instrument_abc.py +39 -0
  139. opentrons/hardware_control/instruments/ot2/__init__.py +0 -0
  140. opentrons/hardware_control/instruments/ot2/instrument_calibration.py +152 -0
  141. opentrons/hardware_control/instruments/ot2/pipette.py +777 -0
  142. opentrons/hardware_control/instruments/ot2/pipette_handler.py +995 -0
  143. opentrons/hardware_control/instruments/ot3/__init__.py +0 -0
  144. opentrons/hardware_control/instruments/ot3/gripper.py +420 -0
  145. opentrons/hardware_control/instruments/ot3/gripper_handler.py +173 -0
  146. opentrons/hardware_control/instruments/ot3/instrument_calibration.py +214 -0
  147. opentrons/hardware_control/instruments/ot3/pipette.py +858 -0
  148. opentrons/hardware_control/instruments/ot3/pipette_handler.py +1030 -0
  149. opentrons/hardware_control/module_control.py +332 -0
  150. opentrons/hardware_control/modules/__init__.py +69 -0
  151. opentrons/hardware_control/modules/absorbance_reader.py +373 -0
  152. opentrons/hardware_control/modules/errors.py +7 -0
  153. opentrons/hardware_control/modules/flex_stacker.py +948 -0
  154. opentrons/hardware_control/modules/heater_shaker.py +426 -0
  155. opentrons/hardware_control/modules/lid_temp_status.py +35 -0
  156. opentrons/hardware_control/modules/magdeck.py +233 -0
  157. opentrons/hardware_control/modules/mod_abc.py +245 -0
  158. opentrons/hardware_control/modules/module_calibration.py +93 -0
  159. opentrons/hardware_control/modules/plate_temp_status.py +61 -0
  160. opentrons/hardware_control/modules/tempdeck.py +299 -0
  161. opentrons/hardware_control/modules/thermocycler.py +731 -0
  162. opentrons/hardware_control/modules/types.py +417 -0
  163. opentrons/hardware_control/modules/update.py +255 -0
  164. opentrons/hardware_control/modules/utils.py +73 -0
  165. opentrons/hardware_control/motion_utilities.py +318 -0
  166. opentrons/hardware_control/nozzle_manager.py +422 -0
  167. opentrons/hardware_control/ot3_calibration.py +1171 -0
  168. opentrons/hardware_control/ot3api.py +3227 -0
  169. opentrons/hardware_control/pause_manager.py +31 -0
  170. opentrons/hardware_control/poller.py +112 -0
  171. opentrons/hardware_control/protocols/__init__.py +106 -0
  172. opentrons/hardware_control/protocols/asyncio_configurable.py +11 -0
  173. opentrons/hardware_control/protocols/calibratable.py +45 -0
  174. opentrons/hardware_control/protocols/chassis_accessory_manager.py +90 -0
  175. opentrons/hardware_control/protocols/configurable.py +48 -0
  176. opentrons/hardware_control/protocols/event_sourcer.py +18 -0
  177. opentrons/hardware_control/protocols/execution_controllable.py +33 -0
  178. opentrons/hardware_control/protocols/flex_calibratable.py +96 -0
  179. opentrons/hardware_control/protocols/flex_instrument_configurer.py +52 -0
  180. opentrons/hardware_control/protocols/gripper_controller.py +55 -0
  181. opentrons/hardware_control/protocols/hardware_manager.py +51 -0
  182. opentrons/hardware_control/protocols/identifiable.py +16 -0
  183. opentrons/hardware_control/protocols/instrument_configurer.py +206 -0
  184. opentrons/hardware_control/protocols/liquid_handler.py +266 -0
  185. opentrons/hardware_control/protocols/module_provider.py +16 -0
  186. opentrons/hardware_control/protocols/motion_controller.py +243 -0
  187. opentrons/hardware_control/protocols/position_estimator.py +45 -0
  188. opentrons/hardware_control/protocols/simulatable.py +10 -0
  189. opentrons/hardware_control/protocols/stoppable.py +9 -0
  190. opentrons/hardware_control/protocols/types.py +27 -0
  191. opentrons/hardware_control/robot_calibration.py +224 -0
  192. opentrons/hardware_control/scripts/README.md +28 -0
  193. opentrons/hardware_control/scripts/__init__.py +1 -0
  194. opentrons/hardware_control/scripts/gripper_control.py +208 -0
  195. opentrons/hardware_control/scripts/ot3gripper +7 -0
  196. opentrons/hardware_control/scripts/ot3repl +7 -0
  197. opentrons/hardware_control/scripts/repl.py +187 -0
  198. opentrons/hardware_control/scripts/tc_control.py +97 -0
  199. opentrons/hardware_control/simulator_setup.py +260 -0
  200. opentrons/hardware_control/thread_manager.py +431 -0
  201. opentrons/hardware_control/threaded_async_lock.py +97 -0
  202. opentrons/hardware_control/types.py +792 -0
  203. opentrons/hardware_control/util.py +234 -0
  204. opentrons/legacy_broker.py +53 -0
  205. opentrons/legacy_commands/__init__.py +1 -0
  206. opentrons/legacy_commands/commands.py +483 -0
  207. opentrons/legacy_commands/helpers.py +153 -0
  208. opentrons/legacy_commands/module_commands.py +215 -0
  209. opentrons/legacy_commands/protocol_commands.py +54 -0
  210. opentrons/legacy_commands/publisher.py +155 -0
  211. opentrons/legacy_commands/robot_commands.py +51 -0
  212. opentrons/legacy_commands/types.py +1115 -0
  213. opentrons/motion_planning/__init__.py +32 -0
  214. opentrons/motion_planning/adjacent_slots_getters.py +168 -0
  215. opentrons/motion_planning/deck_conflict.py +396 -0
  216. opentrons/motion_planning/errors.py +35 -0
  217. opentrons/motion_planning/types.py +42 -0
  218. opentrons/motion_planning/waypoints.py +218 -0
  219. opentrons/ordered_set.py +138 -0
  220. opentrons/protocol_api/__init__.py +105 -0
  221. opentrons/protocol_api/_liquid.py +157 -0
  222. opentrons/protocol_api/_liquid_properties.py +814 -0
  223. opentrons/protocol_api/_nozzle_layout.py +31 -0
  224. opentrons/protocol_api/_parameter_context.py +300 -0
  225. opentrons/protocol_api/_parameters.py +31 -0
  226. opentrons/protocol_api/_transfer_liquid_validation.py +108 -0
  227. opentrons/protocol_api/_types.py +43 -0
  228. opentrons/protocol_api/config.py +23 -0
  229. opentrons/protocol_api/core/__init__.py +23 -0
  230. opentrons/protocol_api/core/common.py +33 -0
  231. opentrons/protocol_api/core/core_map.py +74 -0
  232. opentrons/protocol_api/core/engine/__init__.py +22 -0
  233. opentrons/protocol_api/core/engine/_default_labware_versions.py +179 -0
  234. opentrons/protocol_api/core/engine/deck_conflict.py +348 -0
  235. opentrons/protocol_api/core/engine/exceptions.py +19 -0
  236. opentrons/protocol_api/core/engine/instrument.py +2391 -0
  237. opentrons/protocol_api/core/engine/labware.py +238 -0
  238. opentrons/protocol_api/core/engine/load_labware_params.py +73 -0
  239. opentrons/protocol_api/core/engine/module_core.py +1025 -0
  240. opentrons/protocol_api/core/engine/overlap_versions.py +20 -0
  241. opentrons/protocol_api/core/engine/pipette_movement_conflict.py +358 -0
  242. opentrons/protocol_api/core/engine/point_calculations.py +64 -0
  243. opentrons/protocol_api/core/engine/protocol.py +1153 -0
  244. opentrons/protocol_api/core/engine/robot.py +139 -0
  245. opentrons/protocol_api/core/engine/stringify.py +74 -0
  246. opentrons/protocol_api/core/engine/transfer_components_executor.py +990 -0
  247. opentrons/protocol_api/core/engine/well.py +241 -0
  248. opentrons/protocol_api/core/instrument.py +459 -0
  249. opentrons/protocol_api/core/labware.py +151 -0
  250. opentrons/protocol_api/core/legacy/__init__.py +11 -0
  251. opentrons/protocol_api/core/legacy/_labware_geometry.py +37 -0
  252. opentrons/protocol_api/core/legacy/deck.py +369 -0
  253. opentrons/protocol_api/core/legacy/labware_offset_provider.py +108 -0
  254. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +709 -0
  255. opentrons/protocol_api/core/legacy/legacy_labware_core.py +235 -0
  256. opentrons/protocol_api/core/legacy/legacy_module_core.py +592 -0
  257. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +612 -0
  258. opentrons/protocol_api/core/legacy/legacy_well_core.py +162 -0
  259. opentrons/protocol_api/core/legacy/load_info.py +67 -0
  260. opentrons/protocol_api/core/legacy/module_geometry.py +547 -0
  261. opentrons/protocol_api/core/legacy/well_geometry.py +148 -0
  262. opentrons/protocol_api/core/legacy_simulator/__init__.py +16 -0
  263. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +624 -0
  264. opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +85 -0
  265. opentrons/protocol_api/core/module.py +484 -0
  266. opentrons/protocol_api/core/protocol.py +311 -0
  267. opentrons/protocol_api/core/robot.py +51 -0
  268. opentrons/protocol_api/core/well.py +116 -0
  269. opentrons/protocol_api/core/well_grid.py +45 -0
  270. opentrons/protocol_api/create_protocol_context.py +177 -0
  271. opentrons/protocol_api/deck.py +223 -0
  272. opentrons/protocol_api/disposal_locations.py +244 -0
  273. opentrons/protocol_api/instrument_context.py +3212 -0
  274. opentrons/protocol_api/labware.py +1579 -0
  275. opentrons/protocol_api/module_contexts.py +1425 -0
  276. opentrons/protocol_api/module_validation_and_errors.py +61 -0
  277. opentrons/protocol_api/protocol_context.py +1688 -0
  278. opentrons/protocol_api/robot_context.py +303 -0
  279. opentrons/protocol_api/validation.py +761 -0
  280. opentrons/protocol_engine/__init__.py +155 -0
  281. opentrons/protocol_engine/actions/__init__.py +65 -0
  282. opentrons/protocol_engine/actions/action_dispatcher.py +30 -0
  283. opentrons/protocol_engine/actions/action_handler.py +13 -0
  284. opentrons/protocol_engine/actions/actions.py +302 -0
  285. opentrons/protocol_engine/actions/get_state_update.py +38 -0
  286. opentrons/protocol_engine/clients/__init__.py +5 -0
  287. opentrons/protocol_engine/clients/sync_client.py +174 -0
  288. opentrons/protocol_engine/clients/transports.py +197 -0
  289. opentrons/protocol_engine/commands/__init__.py +757 -0
  290. opentrons/protocol_engine/commands/absorbance_reader/__init__.py +61 -0
  291. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +154 -0
  292. opentrons/protocol_engine/commands/absorbance_reader/common.py +6 -0
  293. opentrons/protocol_engine/commands/absorbance_reader/initialize.py +151 -0
  294. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +154 -0
  295. opentrons/protocol_engine/commands/absorbance_reader/read.py +226 -0
  296. opentrons/protocol_engine/commands/air_gap_in_place.py +162 -0
  297. opentrons/protocol_engine/commands/aspirate.py +244 -0
  298. opentrons/protocol_engine/commands/aspirate_in_place.py +184 -0
  299. opentrons/protocol_engine/commands/aspirate_while_tracking.py +211 -0
  300. opentrons/protocol_engine/commands/blow_out.py +146 -0
  301. opentrons/protocol_engine/commands/blow_out_in_place.py +119 -0
  302. opentrons/protocol_engine/commands/calibration/__init__.py +60 -0
  303. opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +166 -0
  304. opentrons/protocol_engine/commands/calibration/calibrate_module.py +117 -0
  305. opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +96 -0
  306. opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +156 -0
  307. opentrons/protocol_engine/commands/command.py +308 -0
  308. opentrons/protocol_engine/commands/command_unions.py +974 -0
  309. opentrons/protocol_engine/commands/comment.py +57 -0
  310. opentrons/protocol_engine/commands/configure_for_volume.py +108 -0
  311. opentrons/protocol_engine/commands/configure_nozzle_layout.py +115 -0
  312. opentrons/protocol_engine/commands/custom.py +67 -0
  313. opentrons/protocol_engine/commands/dispense.py +194 -0
  314. opentrons/protocol_engine/commands/dispense_in_place.py +179 -0
  315. opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
  316. opentrons/protocol_engine/commands/drop_tip.py +232 -0
  317. opentrons/protocol_engine/commands/drop_tip_in_place.py +205 -0
  318. opentrons/protocol_engine/commands/flex_stacker/__init__.py +64 -0
  319. opentrons/protocol_engine/commands/flex_stacker/common.py +900 -0
  320. opentrons/protocol_engine/commands/flex_stacker/empty.py +293 -0
  321. opentrons/protocol_engine/commands/flex_stacker/fill.py +281 -0
  322. opentrons/protocol_engine/commands/flex_stacker/retrieve.py +339 -0
  323. opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +328 -0
  324. opentrons/protocol_engine/commands/flex_stacker/store.py +326 -0
  325. opentrons/protocol_engine/commands/generate_command_schema.py +61 -0
  326. opentrons/protocol_engine/commands/get_next_tip.py +134 -0
  327. opentrons/protocol_engine/commands/get_tip_presence.py +87 -0
  328. opentrons/protocol_engine/commands/hash_command_params.py +38 -0
  329. opentrons/protocol_engine/commands/heater_shaker/__init__.py +102 -0
  330. opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +83 -0
  331. opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +82 -0
  332. opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +84 -0
  333. opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +110 -0
  334. opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +125 -0
  335. opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +90 -0
  336. opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +102 -0
  337. opentrons/protocol_engine/commands/home.py +100 -0
  338. opentrons/protocol_engine/commands/identify_module.py +86 -0
  339. opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
  340. opentrons/protocol_engine/commands/liquid_probe.py +464 -0
  341. opentrons/protocol_engine/commands/load_labware.py +210 -0
  342. opentrons/protocol_engine/commands/load_lid.py +154 -0
  343. opentrons/protocol_engine/commands/load_lid_stack.py +272 -0
  344. opentrons/protocol_engine/commands/load_liquid.py +95 -0
  345. opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
  346. opentrons/protocol_engine/commands/load_module.py +223 -0
  347. opentrons/protocol_engine/commands/load_pipette.py +167 -0
  348. opentrons/protocol_engine/commands/magnetic_module/__init__.py +32 -0
  349. opentrons/protocol_engine/commands/magnetic_module/disengage.py +97 -0
  350. opentrons/protocol_engine/commands/magnetic_module/engage.py +119 -0
  351. opentrons/protocol_engine/commands/move_labware.py +546 -0
  352. opentrons/protocol_engine/commands/move_relative.py +102 -0
  353. opentrons/protocol_engine/commands/move_to_addressable_area.py +176 -0
  354. opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +198 -0
  355. opentrons/protocol_engine/commands/move_to_coordinates.py +107 -0
  356. opentrons/protocol_engine/commands/move_to_well.py +119 -0
  357. opentrons/protocol_engine/commands/movement_common.py +338 -0
  358. opentrons/protocol_engine/commands/pick_up_tip.py +241 -0
  359. opentrons/protocol_engine/commands/pipetting_common.py +443 -0
  360. opentrons/protocol_engine/commands/prepare_to_aspirate.py +121 -0
  361. opentrons/protocol_engine/commands/pressure_dispense.py +155 -0
  362. opentrons/protocol_engine/commands/reload_labware.py +90 -0
  363. opentrons/protocol_engine/commands/retract_axis.py +75 -0
  364. opentrons/protocol_engine/commands/robot/__init__.py +70 -0
  365. opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +96 -0
  366. opentrons/protocol_engine/commands/robot/common.py +18 -0
  367. opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
  368. opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
  369. opentrons/protocol_engine/commands/robot/move_to.py +94 -0
  370. opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +86 -0
  371. opentrons/protocol_engine/commands/save_position.py +109 -0
  372. opentrons/protocol_engine/commands/seal_pipette_to_tip.py +353 -0
  373. opentrons/protocol_engine/commands/set_rail_lights.py +67 -0
  374. opentrons/protocol_engine/commands/set_status_bar.py +89 -0
  375. opentrons/protocol_engine/commands/temperature_module/__init__.py +46 -0
  376. opentrons/protocol_engine/commands/temperature_module/deactivate.py +86 -0
  377. opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +97 -0
  378. opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +104 -0
  379. opentrons/protocol_engine/commands/thermocycler/__init__.py +152 -0
  380. opentrons/protocol_engine/commands/thermocycler/close_lid.py +87 -0
  381. opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +80 -0
  382. opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +80 -0
  383. opentrons/protocol_engine/commands/thermocycler/open_lid.py +87 -0
  384. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +171 -0
  385. opentrons/protocol_engine/commands/thermocycler/run_profile.py +124 -0
  386. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +140 -0
  387. opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +100 -0
  388. opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +93 -0
  389. opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +89 -0
  390. opentrons/protocol_engine/commands/touch_tip.py +189 -0
  391. opentrons/protocol_engine/commands/unsafe/__init__.py +161 -0
  392. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +100 -0
  393. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +121 -0
  394. opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +82 -0
  395. opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
  396. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_close_latch.py +94 -0
  397. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_manual_retrieve.py +295 -0
  398. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_open_latch.py +91 -0
  399. opentrons/protocol_engine/commands/unsafe/unsafe_stacker_prepare_shuttle.py +136 -0
  400. opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
  401. opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +90 -0
  402. opentrons/protocol_engine/commands/unseal_pipette_from_tip.py +153 -0
  403. opentrons/protocol_engine/commands/verify_tip_presence.py +100 -0
  404. opentrons/protocol_engine/commands/wait_for_duration.py +76 -0
  405. opentrons/protocol_engine/commands/wait_for_resume.py +75 -0
  406. opentrons/protocol_engine/create_protocol_engine.py +193 -0
  407. opentrons/protocol_engine/engine_support.py +28 -0
  408. opentrons/protocol_engine/error_recovery_policy.py +81 -0
  409. opentrons/protocol_engine/errors/__init__.py +191 -0
  410. opentrons/protocol_engine/errors/error_occurrence.py +182 -0
  411. opentrons/protocol_engine/errors/exceptions.py +1308 -0
  412. opentrons/protocol_engine/execution/__init__.py +50 -0
  413. opentrons/protocol_engine/execution/command_executor.py +216 -0
  414. opentrons/protocol_engine/execution/create_queue_worker.py +102 -0
  415. opentrons/protocol_engine/execution/door_watcher.py +119 -0
  416. opentrons/protocol_engine/execution/equipment.py +819 -0
  417. opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
  418. opentrons/protocol_engine/execution/gantry_mover.py +686 -0
  419. opentrons/protocol_engine/execution/hardware_stopper.py +147 -0
  420. opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +207 -0
  421. opentrons/protocol_engine/execution/labware_movement.py +297 -0
  422. opentrons/protocol_engine/execution/movement.py +349 -0
  423. opentrons/protocol_engine/execution/pipetting.py +607 -0
  424. opentrons/protocol_engine/execution/queue_worker.py +86 -0
  425. opentrons/protocol_engine/execution/rail_lights.py +25 -0
  426. opentrons/protocol_engine/execution/run_control.py +33 -0
  427. opentrons/protocol_engine/execution/status_bar.py +34 -0
  428. opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +188 -0
  429. opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +81 -0
  430. opentrons/protocol_engine/execution/tip_handler.py +550 -0
  431. opentrons/protocol_engine/labware_offset_standardization.py +194 -0
  432. opentrons/protocol_engine/notes/__init__.py +17 -0
  433. opentrons/protocol_engine/notes/notes.py +59 -0
  434. opentrons/protocol_engine/plugins.py +104 -0
  435. opentrons/protocol_engine/protocol_engine.py +683 -0
  436. opentrons/protocol_engine/resources/__init__.py +26 -0
  437. opentrons/protocol_engine/resources/deck_configuration_provider.py +232 -0
  438. opentrons/protocol_engine/resources/deck_data_provider.py +94 -0
  439. opentrons/protocol_engine/resources/file_provider.py +161 -0
  440. opentrons/protocol_engine/resources/fixture_validation.py +58 -0
  441. opentrons/protocol_engine/resources/labware_data_provider.py +106 -0
  442. opentrons/protocol_engine/resources/labware_validation.py +73 -0
  443. opentrons/protocol_engine/resources/model_utils.py +32 -0
  444. opentrons/protocol_engine/resources/module_data_provider.py +44 -0
  445. opentrons/protocol_engine/resources/ot3_validation.py +21 -0
  446. opentrons/protocol_engine/resources/pipette_data_provider.py +379 -0
  447. opentrons/protocol_engine/slot_standardization.py +128 -0
  448. opentrons/protocol_engine/state/__init__.py +1 -0
  449. opentrons/protocol_engine/state/_abstract_store.py +27 -0
  450. opentrons/protocol_engine/state/_axis_aligned_bounding_box.py +50 -0
  451. opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
  452. opentrons/protocol_engine/state/_move_types.py +83 -0
  453. opentrons/protocol_engine/state/_well_math.py +193 -0
  454. opentrons/protocol_engine/state/addressable_areas.py +699 -0
  455. opentrons/protocol_engine/state/command_history.py +309 -0
  456. opentrons/protocol_engine/state/commands.py +1158 -0
  457. opentrons/protocol_engine/state/config.py +39 -0
  458. opentrons/protocol_engine/state/files.py +57 -0
  459. opentrons/protocol_engine/state/fluid_stack.py +138 -0
  460. opentrons/protocol_engine/state/geometry.py +2359 -0
  461. opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
  462. opentrons/protocol_engine/state/labware.py +1459 -0
  463. opentrons/protocol_engine/state/liquid_classes.py +82 -0
  464. opentrons/protocol_engine/state/liquids.py +73 -0
  465. opentrons/protocol_engine/state/module_substates/__init__.py +45 -0
  466. opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +35 -0
  467. opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +112 -0
  468. opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +115 -0
  469. opentrons/protocol_engine/state/module_substates/magnetic_block_substate.py +17 -0
  470. opentrons/protocol_engine/state/module_substates/magnetic_module_substate.py +65 -0
  471. opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +67 -0
  472. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +163 -0
  473. opentrons/protocol_engine/state/modules.py +1500 -0
  474. opentrons/protocol_engine/state/motion.py +373 -0
  475. opentrons/protocol_engine/state/pipettes.py +905 -0
  476. opentrons/protocol_engine/state/state.py +421 -0
  477. opentrons/protocol_engine/state/state_summary.py +36 -0
  478. opentrons/protocol_engine/state/tips.py +420 -0
  479. opentrons/protocol_engine/state/update_types.py +904 -0
  480. opentrons/protocol_engine/state/wells.py +290 -0
  481. opentrons/protocol_engine/types/__init__.py +308 -0
  482. opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
  483. opentrons/protocol_engine/types/command_annotations.py +53 -0
  484. opentrons/protocol_engine/types/deck_configuration.py +81 -0
  485. opentrons/protocol_engine/types/execution.py +96 -0
  486. opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
  487. opentrons/protocol_engine/types/instrument.py +47 -0
  488. opentrons/protocol_engine/types/instrument_sensors.py +47 -0
  489. opentrons/protocol_engine/types/labware.py +131 -0
  490. opentrons/protocol_engine/types/labware_movement.py +22 -0
  491. opentrons/protocol_engine/types/labware_offset_location.py +111 -0
  492. opentrons/protocol_engine/types/labware_offset_vector.py +16 -0
  493. opentrons/protocol_engine/types/liquid.py +40 -0
  494. opentrons/protocol_engine/types/liquid_class.py +59 -0
  495. opentrons/protocol_engine/types/liquid_handling.py +13 -0
  496. opentrons/protocol_engine/types/liquid_level_detection.py +191 -0
  497. opentrons/protocol_engine/types/location.py +194 -0
  498. opentrons/protocol_engine/types/module.py +303 -0
  499. opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
  500. opentrons/protocol_engine/types/run_time_parameters.py +133 -0
  501. opentrons/protocol_engine/types/tip.py +18 -0
  502. opentrons/protocol_engine/types/util.py +21 -0
  503. opentrons/protocol_engine/types/well_position.py +124 -0
  504. opentrons/protocol_reader/__init__.py +37 -0
  505. opentrons/protocol_reader/extract_labware_definitions.py +66 -0
  506. opentrons/protocol_reader/file_format_validator.py +152 -0
  507. opentrons/protocol_reader/file_hasher.py +27 -0
  508. opentrons/protocol_reader/file_identifier.py +284 -0
  509. opentrons/protocol_reader/file_reader_writer.py +90 -0
  510. opentrons/protocol_reader/input_file.py +16 -0
  511. opentrons/protocol_reader/protocol_files_invalid_error.py +6 -0
  512. opentrons/protocol_reader/protocol_reader.py +188 -0
  513. opentrons/protocol_reader/protocol_source.py +124 -0
  514. opentrons/protocol_reader/role_analyzer.py +86 -0
  515. opentrons/protocol_runner/__init__.py +26 -0
  516. opentrons/protocol_runner/create_simulating_orchestrator.py +118 -0
  517. opentrons/protocol_runner/json_file_reader.py +55 -0
  518. opentrons/protocol_runner/json_translator.py +314 -0
  519. opentrons/protocol_runner/legacy_command_mapper.py +848 -0
  520. opentrons/protocol_runner/legacy_context_plugin.py +116 -0
  521. opentrons/protocol_runner/protocol_runner.py +530 -0
  522. opentrons/protocol_runner/python_protocol_wrappers.py +179 -0
  523. opentrons/protocol_runner/run_orchestrator.py +496 -0
  524. opentrons/protocol_runner/task_queue.py +95 -0
  525. opentrons/protocols/__init__.py +6 -0
  526. opentrons/protocols/advanced_control/__init__.py +0 -0
  527. opentrons/protocols/advanced_control/common.py +38 -0
  528. opentrons/protocols/advanced_control/mix.py +60 -0
  529. opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
  530. opentrons/protocols/advanced_control/transfers/common.py +180 -0
  531. opentrons/protocols/advanced_control/transfers/transfer.py +972 -0
  532. opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +231 -0
  533. opentrons/protocols/api_support/__init__.py +0 -0
  534. opentrons/protocols/api_support/constants.py +8 -0
  535. opentrons/protocols/api_support/deck_type.py +110 -0
  536. opentrons/protocols/api_support/definitions.py +18 -0
  537. opentrons/protocols/api_support/instrument.py +151 -0
  538. opentrons/protocols/api_support/labware_like.py +233 -0
  539. opentrons/protocols/api_support/tip_tracker.py +175 -0
  540. opentrons/protocols/api_support/types.py +32 -0
  541. opentrons/protocols/api_support/util.py +403 -0
  542. opentrons/protocols/bundle.py +89 -0
  543. opentrons/protocols/duration/__init__.py +4 -0
  544. opentrons/protocols/duration/errors.py +5 -0
  545. opentrons/protocols/duration/estimator.py +628 -0
  546. opentrons/protocols/execution/__init__.py +0 -0
  547. opentrons/protocols/execution/dev_types.py +181 -0
  548. opentrons/protocols/execution/errors.py +40 -0
  549. opentrons/protocols/execution/execute.py +84 -0
  550. opentrons/protocols/execution/execute_json_v3.py +275 -0
  551. opentrons/protocols/execution/execute_json_v4.py +359 -0
  552. opentrons/protocols/execution/execute_json_v5.py +28 -0
  553. opentrons/protocols/execution/execute_python.py +169 -0
  554. opentrons/protocols/execution/json_dispatchers.py +87 -0
  555. opentrons/protocols/execution/types.py +7 -0
  556. opentrons/protocols/geometry/__init__.py +0 -0
  557. opentrons/protocols/geometry/planning.py +297 -0
  558. opentrons/protocols/labware.py +312 -0
  559. opentrons/protocols/models/__init__.py +0 -0
  560. opentrons/protocols/models/json_protocol.py +679 -0
  561. opentrons/protocols/parameters/__init__.py +0 -0
  562. opentrons/protocols/parameters/csv_parameter_definition.py +77 -0
  563. opentrons/protocols/parameters/csv_parameter_interface.py +96 -0
  564. opentrons/protocols/parameters/exceptions.py +34 -0
  565. opentrons/protocols/parameters/parameter_definition.py +272 -0
  566. opentrons/protocols/parameters/types.py +17 -0
  567. opentrons/protocols/parameters/validation.py +267 -0
  568. opentrons/protocols/parse.py +671 -0
  569. opentrons/protocols/types.py +159 -0
  570. opentrons/py.typed +0 -0
  571. opentrons/resources/scripts/lpc21isp +0 -0
  572. opentrons/resources/smoothie-edge-8414642.hex +23010 -0
  573. opentrons/simulate.py +1065 -0
  574. opentrons/system/__init__.py +6 -0
  575. opentrons/system/camera.py +51 -0
  576. opentrons/system/log_control.py +59 -0
  577. opentrons/system/nmcli.py +856 -0
  578. opentrons/system/resin.py +24 -0
  579. opentrons/system/smoothie_update.py +15 -0
  580. opentrons/system/wifi.py +204 -0
  581. opentrons/tools/__init__.py +0 -0
  582. opentrons/tools/args_handler.py +22 -0
  583. opentrons/tools/write_pipette_memory.py +157 -0
  584. opentrons/types.py +618 -0
  585. opentrons/util/__init__.py +1 -0
  586. opentrons/util/async_helpers.py +166 -0
  587. opentrons/util/broker.py +84 -0
  588. opentrons/util/change_notifier.py +47 -0
  589. opentrons/util/entrypoint_util.py +278 -0
  590. opentrons/util/get_union_elements.py +26 -0
  591. opentrons/util/helpers.py +6 -0
  592. opentrons/util/linal.py +178 -0
  593. opentrons/util/logging_config.py +265 -0
  594. opentrons/util/logging_queue_handler.py +61 -0
  595. opentrons/util/performance_helpers.py +157 -0
  596. opentrons-8.6.0a1.dist-info/METADATA +37 -0
  597. opentrons-8.6.0a1.dist-info/RECORD +600 -0
  598. opentrons-8.6.0a1.dist-info/WHEEL +4 -0
  599. opentrons-8.6.0a1.dist-info/entry_points.txt +3 -0
  600. opentrons-8.6.0a1.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,686 @@
1
+ """Gantry movement wrapper for hardware and simulation based movement."""
2
+ from logging import getLogger
3
+ from opentrons.config.types import OT3Config
4
+ from functools import partial
5
+ from typing import Optional, List, Dict, Tuple
6
+ from typing_extensions import Protocol as TypingProtocol
7
+
8
+ from opentrons.types import Point, Mount, MountType
9
+
10
+ from opentrons.hardware_control import HardwareControlAPI
11
+ from opentrons.hardware_control.types import Axis as HardwareAxis, CriticalPoint
12
+ from opentrons.hardware_control.motion_utilities import (
13
+ target_axis_map_from_relative,
14
+ target_axis_map_from_absolute,
15
+ )
16
+ from opentrons_shared_data.errors.exceptions import PositionUnknownError
17
+
18
+ from opentrons.motion_planning import Waypoint
19
+
20
+ from ..state.state import StateView
21
+ from ..types import MotorAxis, CurrentWell
22
+ from ..errors import MustHomeError, InvalidAxisForRobotType
23
+
24
+ log = getLogger(__name__)
25
+
26
+
27
+ _MOTOR_AXIS_TO_HARDWARE_AXIS: Dict[MotorAxis, HardwareAxis] = {
28
+ MotorAxis.X: HardwareAxis.X,
29
+ MotorAxis.Y: HardwareAxis.Y,
30
+ MotorAxis.LEFT_Z: HardwareAxis.Z,
31
+ MotorAxis.RIGHT_Z: HardwareAxis.A,
32
+ MotorAxis.LEFT_PLUNGER: HardwareAxis.B,
33
+ MotorAxis.RIGHT_PLUNGER: HardwareAxis.C,
34
+ MotorAxis.EXTENSION_Z: HardwareAxis.Z_G,
35
+ MotorAxis.EXTENSION_JAW: HardwareAxis.G,
36
+ MotorAxis.AXIS_96_CHANNEL_CAM: HardwareAxis.Q,
37
+ }
38
+
39
+ _MOTOR_AXIS_TO_HARDWARE_MOUNT: Dict[MotorAxis, Mount] = {
40
+ MotorAxis.LEFT_Z: Mount.LEFT,
41
+ MotorAxis.RIGHT_Z: Mount.RIGHT,
42
+ MotorAxis.EXTENSION_Z: Mount.EXTENSION,
43
+ }
44
+
45
+ _HARDWARE_MOUNT_MOTOR_AXIS_TO: Dict[Mount, MotorAxis] = {
46
+ Mount.LEFT: MotorAxis.LEFT_Z,
47
+ Mount.RIGHT: MotorAxis.RIGHT_Z,
48
+ Mount.EXTENSION: MotorAxis.EXTENSION_Z,
49
+ }
50
+
51
+ _HARDWARE_AXIS_TO_MOTOR_AXIS: Dict[HardwareAxis, MotorAxis] = {
52
+ HardwareAxis.X: MotorAxis.X,
53
+ HardwareAxis.Y: MotorAxis.Y,
54
+ HardwareAxis.Z: MotorAxis.LEFT_Z,
55
+ HardwareAxis.A: MotorAxis.RIGHT_Z,
56
+ HardwareAxis.B: MotorAxis.LEFT_PLUNGER,
57
+ HardwareAxis.C: MotorAxis.RIGHT_PLUNGER,
58
+ HardwareAxis.P_L: MotorAxis.LEFT_PLUNGER,
59
+ HardwareAxis.P_R: MotorAxis.RIGHT_PLUNGER,
60
+ HardwareAxis.Z_L: MotorAxis.LEFT_Z,
61
+ HardwareAxis.Z_R: MotorAxis.RIGHT_Z,
62
+ HardwareAxis.Z_G: MotorAxis.EXTENSION_Z,
63
+ HardwareAxis.G: MotorAxis.EXTENSION_JAW,
64
+ HardwareAxis.Q: MotorAxis.AXIS_96_CHANNEL_CAM,
65
+ }
66
+
67
+
68
+ # The height of the bottom of the pipette nozzle at home position without any tips.
69
+ # We rely on this being the same for every OT-3 pipette.
70
+ #
71
+ # We found this number by peeking at the height that OT3Simulator returns for these pipettes:
72
+ # * Flex Single- and 8-Channel P50
73
+ # * Flex Single-, 8-, and 96-channel P1000
74
+ #
75
+ # That OT3Simulator return value is what Protocol Engine uses for simulation when Protocol Engine
76
+ # is configured to not virtualize pipettes, so this number should match it.
77
+ VIRTUAL_MAX_OT3_HEIGHT = 248.0
78
+ # This number was found by using the longest pipette's P1000V2 default configuration values.
79
+ VIRTUAL_MAX_OT2_HEIGHT = 268.14
80
+
81
+
82
+ class GantryMover(TypingProtocol):
83
+ """Abstract class for gantry movement handler."""
84
+
85
+ async def get_position(
86
+ self,
87
+ pipette_id: str,
88
+ current_well: Optional[CurrentWell] = None,
89
+ fail_on_not_homed: bool = False,
90
+ ) -> Point:
91
+ """Get the current position of the gantry."""
92
+ ...
93
+
94
+ async def get_position_from_mount(
95
+ self,
96
+ mount: Mount,
97
+ critical_point: Optional[CriticalPoint] = None,
98
+ fail_on_not_homed: bool = False,
99
+ ) -> Point:
100
+ """Get the current position of the gantry based on the given mount."""
101
+ ...
102
+
103
+ def get_max_travel_z(self, pipette_id: str) -> float:
104
+ """Get the maximum allowed z-height for pipette movement."""
105
+ ...
106
+
107
+ def get_max_travel_z_from_mount(self, mount: MountType) -> float:
108
+ """Get the maximum allowed z-height for mount movement."""
109
+ ...
110
+
111
+ async def move_axes(
112
+ self,
113
+ axis_map: Dict[MotorAxis, float],
114
+ critical_point: Optional[Dict[MotorAxis, float]] = None,
115
+ speed: Optional[float] = None,
116
+ relative_move: bool = False,
117
+ expect_stalls: bool = False,
118
+ ) -> Dict[MotorAxis, float]:
119
+ """Move a set of axes a given distance."""
120
+ ...
121
+
122
+ async def move_to(
123
+ self, pipette_id: str, waypoints: List[Waypoint], speed: Optional[float]
124
+ ) -> Point:
125
+ """Move the hardware gantry to a waypoint."""
126
+ ...
127
+
128
+ async def move_mount_to(
129
+ self, mount: Mount, waypoints: List[Waypoint], speed: Optional[float]
130
+ ) -> Point:
131
+ """Move the provided hardware mount to a waypoint."""
132
+ ...
133
+
134
+ async def move_relative(
135
+ self,
136
+ pipette_id: str,
137
+ delta: Point,
138
+ speed: Optional[float],
139
+ ) -> Point:
140
+ """Move the hardware gantry in a relative direction by delta."""
141
+ ...
142
+
143
+ async def home(self, axes: Optional[List[MotorAxis]]) -> None:
144
+ """Home the gantry."""
145
+ ...
146
+
147
+ async def retract_axis(self, axis: MotorAxis) -> None:
148
+ """Retract the specified axis to its home position."""
149
+ ...
150
+
151
+ async def prepare_for_mount_movement(self, mount: Mount) -> None:
152
+ """Retract the 'idle' mount if necessary."""
153
+ ...
154
+
155
+ def motor_axis_to_hardware_axis(self, motor_axis: MotorAxis) -> HardwareAxis:
156
+ """Transform an engine motor axis into a hardware axis."""
157
+ ...
158
+
159
+ def pick_mount_from_axis_map(self, axis_map: Dict[MotorAxis, float]) -> Mount:
160
+ """Find a mount axis in the axis_map if it exists otherwise default to left mount."""
161
+ ...
162
+
163
+ def motor_axes_to_present_hardware_axes(
164
+ self, motor_axes: List[MotorAxis]
165
+ ) -> List[HardwareAxis]:
166
+ """Transform a list of engine axes into a list of hardware axes, filtering out non-present axes."""
167
+ ...
168
+
169
+
170
+ class HardwareGantryMover(GantryMover):
171
+ """Hardware API based gantry movement handler."""
172
+
173
+ def __init__(self, hardware_api: HardwareControlAPI, state_view: StateView) -> None:
174
+ self._hardware_api = hardware_api
175
+ self._state_view = state_view
176
+
177
+ def motor_axes_to_present_hardware_axes(
178
+ self, motor_axes: List[MotorAxis]
179
+ ) -> List[HardwareAxis]:
180
+ """Get hardware axes from engine axes while filtering out non-present axes."""
181
+ return [
182
+ self.motor_axis_to_hardware_axis(motor_axis)
183
+ for motor_axis in motor_axes
184
+ if self._hardware_api.axis_is_present(
185
+ self.motor_axis_to_hardware_axis(motor_axis)
186
+ )
187
+ ]
188
+
189
+ def motor_axis_to_hardware_axis(self, motor_axis: MotorAxis) -> HardwareAxis:
190
+ """Transform an engine motor axis into a hardware axis."""
191
+ return _MOTOR_AXIS_TO_HARDWARE_AXIS[motor_axis]
192
+
193
+ def _hardware_axis_to_motor_axis(self, motor_axis: HardwareAxis) -> MotorAxis:
194
+ """Transform an hardware axis into a engine motor axis."""
195
+ return _HARDWARE_AXIS_TO_MOTOR_AXIS[motor_axis]
196
+
197
+ def _convert_axis_map_for_hw(
198
+ self, axis_map: Dict[MotorAxis, float]
199
+ ) -> Dict[HardwareAxis, float]:
200
+ """Transform an engine motor axis map to a hardware axis map."""
201
+ return {_MOTOR_AXIS_TO_HARDWARE_AXIS[ax]: dist for ax, dist in axis_map.items()}
202
+
203
+ def _critical_point_for(
204
+ self, mount: Mount, cp_override: Optional[Dict[MotorAxis, float]] = None
205
+ ) -> Point:
206
+ if cp_override:
207
+ return Point(
208
+ x=cp_override[MotorAxis.X],
209
+ y=cp_override[MotorAxis.Y],
210
+ z=cp_override[_HARDWARE_MOUNT_MOTOR_AXIS_TO[mount]],
211
+ )
212
+ else:
213
+ return self._hardware_api.critical_point_for(mount)
214
+
215
+ def _get_gantry_offsets_for_robot_type(
216
+ self,
217
+ ) -> Tuple[Point, Point, Optional[Point]]:
218
+ if isinstance(self._hardware_api.config, OT3Config):
219
+ return (
220
+ Point(*self._hardware_api.config.left_mount_offset),
221
+ Point(*self._hardware_api.config.right_mount_offset),
222
+ Point(*self._hardware_api.config.gripper_mount_offset),
223
+ )
224
+ else:
225
+ return (
226
+ Point(*self._hardware_api.config.left_mount_offset),
227
+ Point(0, 0, 0),
228
+ None,
229
+ )
230
+
231
+ def pick_mount_from_axis_map(self, axis_map: Dict[MotorAxis, float]) -> Mount:
232
+ """Find a mount axis in the axis_map if it exists otherwise default to left mount."""
233
+ found_mount = Mount.LEFT
234
+ mounts = list(_MOTOR_AXIS_TO_HARDWARE_MOUNT.keys())
235
+ for k in axis_map.keys():
236
+ if k in mounts:
237
+ found_mount = _MOTOR_AXIS_TO_HARDWARE_MOUNT[k]
238
+ break
239
+ return found_mount
240
+
241
+ async def get_position(
242
+ self,
243
+ pipette_id: str,
244
+ current_well: Optional[CurrentWell] = None,
245
+ fail_on_not_homed: bool = False,
246
+ ) -> Point:
247
+ """Get the current position of the gantry.
248
+
249
+ Args:
250
+ pipette_id: Pipette ID to get location data for.
251
+ current_well: Optional parameter for getting pipette location data, effects critical point.
252
+ fail_on_not_homed: Raise PositionUnknownError if gantry position is not known.
253
+ """
254
+ pipette_location = self._state_view.motion.get_pipette_location(
255
+ pipette_id=pipette_id,
256
+ current_location=current_well,
257
+ )
258
+ point = await self.get_position_from_mount(
259
+ mount=pipette_location.mount.to_hw_mount(),
260
+ critical_point=pipette_location.critical_point,
261
+ fail_on_not_homed=fail_on_not_homed,
262
+ )
263
+ return point
264
+
265
+ async def get_position_from_mount(
266
+ self,
267
+ mount: Mount,
268
+ critical_point: Optional[CriticalPoint] = None,
269
+ fail_on_not_homed: bool = False,
270
+ ) -> Point:
271
+ """Get the current position of the gantry based on the mount.
272
+
273
+ Args:
274
+ mount: The mount to get the position for.
275
+ critical_point: Optional parameter for getting instrument location data, effects critical point.
276
+ fail_on_not_homed: Raise PositionUnknownError if gantry position is not known.
277
+ """
278
+ try:
279
+ point = await self._hardware_api.gantry_position(
280
+ mount=mount,
281
+ critical_point=critical_point,
282
+ fail_on_not_homed=fail_on_not_homed,
283
+ )
284
+ return point
285
+ except PositionUnknownError as e:
286
+ raise MustHomeError(message=str(e), wrapping=[e])
287
+
288
+ def get_max_travel_z(self, pipette_id: str) -> float:
289
+ """Get the maximum allowed z-height for pipette movement.
290
+
291
+ Args:
292
+ pipette_id: Pipette ID to get max travel z-height for.
293
+ """
294
+ mount = self._state_view.pipettes.get_mount(pipette_id)
295
+ return self.get_max_travel_z_from_mount(mount=mount)
296
+
297
+ def get_max_travel_z_from_mount(self, mount: MountType) -> float:
298
+ """Get the maximum allowed z-height for any mount movement.
299
+
300
+ Args:
301
+ mount: Mount to get max travel z-height for.
302
+ """
303
+ return self._hardware_api.get_instrument_max_height(mount=mount.to_hw_mount())
304
+
305
+ async def move_to(
306
+ self, pipette_id: str, waypoints: List[Waypoint], speed: Optional[float]
307
+ ) -> Point:
308
+ """Move the hardware gantry to a waypoint."""
309
+ assert len(waypoints) > 0, "Must have at least one waypoint"
310
+
311
+ hw_mount = self._state_view.pipettes.get_mount(pipette_id).to_hw_mount()
312
+
313
+ for waypoint in waypoints:
314
+ await self._hardware_api.move_to(
315
+ mount=hw_mount,
316
+ abs_position=waypoint.position,
317
+ critical_point=waypoint.critical_point,
318
+ speed=speed,
319
+ )
320
+
321
+ return waypoints[-1].position
322
+
323
+ async def move_mount_to(
324
+ self, mount: Mount, waypoints: List[Waypoint], speed: Optional[float]
325
+ ) -> Point:
326
+ """Move the given hardware mount to a waypoint."""
327
+ assert len(waypoints) > 0, "Must have at least one waypoint"
328
+ for waypoint in waypoints:
329
+ log.info(f"The current waypoint moving is {waypoint}")
330
+ await self._hardware_api.move_to(
331
+ mount=mount,
332
+ abs_position=waypoint.position,
333
+ critical_point=waypoint.critical_point,
334
+ speed=speed,
335
+ )
336
+
337
+ return waypoints[-1].position
338
+
339
+ async def move_axes(
340
+ self,
341
+ axis_map: Dict[MotorAxis, float],
342
+ critical_point: Optional[Dict[MotorAxis, float]] = None,
343
+ speed: Optional[float] = None,
344
+ relative_move: bool = False,
345
+ expect_stalls: bool = False,
346
+ ) -> Dict[MotorAxis, float]:
347
+ """Move a set of axes a given distance.
348
+
349
+ Args:
350
+ axis_map: The mapping of axes to command.
351
+ critical_point: A critical point override for axes
352
+ speed: Optional speed parameter for the move.
353
+ relative_move: Whether the axis map needs to be converted from a relative to absolute move.
354
+ expect_stalls: Whether it is expected that the move triggers a stall error.
355
+ """
356
+ try:
357
+ pos_hw = self._convert_axis_map_for_hw(axis_map)
358
+ mount = self.pick_mount_from_axis_map(axis_map)
359
+ if relative_move:
360
+ current_position = await self._hardware_api.current_position(
361
+ mount, refresh=True
362
+ )
363
+ log.info(f"The current position of the robot is: {current_position}.")
364
+ converted_current_position_deck = (
365
+ self._hardware_api.get_deck_from_machine(current_position)
366
+ )
367
+ log.info(f"The current position of the robot is: {current_position}.")
368
+
369
+ pos_hw = target_axis_map_from_relative(pos_hw, current_position)
370
+ log.info(
371
+ f"The absolute position is: {pos_hw} and hw pos map is {pos_hw}."
372
+ )
373
+ log.info(f"The calculated move {pos_hw} and {mount}")
374
+ (
375
+ left_offset,
376
+ right_offset,
377
+ gripper_offset,
378
+ ) = self._get_gantry_offsets_for_robot_type()
379
+ absolute_pos = target_axis_map_from_absolute(
380
+ mount,
381
+ pos_hw,
382
+ partial(self._critical_point_for, cp_override=critical_point),
383
+ left_mount_offset=left_offset,
384
+ right_mount_offset=right_offset,
385
+ gripper_mount_offset=gripper_offset,
386
+ )
387
+ log.info(f"The prepped abs {absolute_pos}")
388
+ await self._hardware_api.move_axes(
389
+ position=absolute_pos,
390
+ speed=speed,
391
+ expect_stalls=expect_stalls,
392
+ )
393
+
394
+ except PositionUnknownError as e:
395
+ raise MustHomeError(message=str(e), wrapping=[e])
396
+
397
+ current_position = await self._hardware_api.current_position(
398
+ mount, refresh=True
399
+ )
400
+ converted_current_position_deck = self._hardware_api.get_deck_from_machine(
401
+ current_position
402
+ )
403
+ return {
404
+ self._hardware_axis_to_motor_axis(ax): pos
405
+ for ax, pos in converted_current_position_deck.items()
406
+ }
407
+
408
+ async def move_relative(
409
+ self,
410
+ pipette_id: str,
411
+ delta: Point,
412
+ speed: Optional[float],
413
+ ) -> Point:
414
+ """Move the hardware gantry in a relative direction by delta.
415
+
416
+ Args:
417
+ pipette_id: Not used in hardware implementation.
418
+ delta: Relative X/Y/Z distance to move gantry.
419
+ speed: Optional speed parameter for the move.
420
+ """
421
+ pipette_location = self._state_view.motion.get_pipette_location(
422
+ pipette_id=pipette_id,
423
+ )
424
+ critical_point = pipette_location.critical_point
425
+ hw_mount = pipette_location.mount.to_hw_mount()
426
+ try:
427
+ await self._hardware_api.move_rel(
428
+ mount=hw_mount,
429
+ delta=delta,
430
+ fail_on_not_homed=True,
431
+ speed=speed,
432
+ )
433
+ point = await self._hardware_api.gantry_position(
434
+ mount=hw_mount,
435
+ critical_point=critical_point,
436
+ fail_on_not_homed=True,
437
+ )
438
+ except PositionUnknownError as e:
439
+ raise MustHomeError(message=str(e), wrapping=[e])
440
+
441
+ return point
442
+
443
+ async def home(self, axes: Optional[List[MotorAxis]]) -> None:
444
+ """Home the gantry."""
445
+ # TODO(mc, 2022-12-01): this is overly complicated
446
+ # https://opentrons.atlassian.net/browse/RET-1287
447
+ if axes is None:
448
+ await self._hardware_api.home()
449
+ elif axes == [MotorAxis.LEFT_PLUNGER]:
450
+ await self._hardware_api.home_plunger(Mount.LEFT)
451
+ elif axes == [MotorAxis.RIGHT_PLUNGER]:
452
+ await self._hardware_api.home_plunger(Mount.RIGHT)
453
+ elif axes == [MotorAxis.LEFT_Z, MotorAxis.LEFT_PLUNGER]:
454
+ await self._hardware_api.home_z(Mount.LEFT)
455
+ await self._hardware_api.home_plunger(Mount.LEFT)
456
+ elif axes == [MotorAxis.RIGHT_Z, MotorAxis.RIGHT_PLUNGER]:
457
+ await self._hardware_api.home_z(Mount.RIGHT)
458
+ await self._hardware_api.home_plunger(Mount.RIGHT)
459
+ else:
460
+ hardware_axes = [_MOTOR_AXIS_TO_HARDWARE_AXIS[a] for a in axes]
461
+ if self._state_view.config.robot_type == "OT-2 Standard" and any(
462
+ axis not in HardwareAxis.ot2_axes() for axis in hardware_axes
463
+ ):
464
+ raise InvalidAxisForRobotType(
465
+ f"{axes} includes axes that are not valid for OT-2 Standard robot type"
466
+ )
467
+ # Hardware API will raise error if invalid axes are passed for the type of robot
468
+ await self._hardware_api.home(axes=hardware_axes)
469
+
470
+ async def retract_axis(self, axis: MotorAxis) -> None:
471
+ """Retract specified axis."""
472
+ hardware_axis = _MOTOR_AXIS_TO_HARDWARE_AXIS[axis]
473
+ if (
474
+ self._state_view.config.robot_type == "OT-2 Standard"
475
+ and hardware_axis not in HardwareAxis.ot2_axes()
476
+ ):
477
+ raise InvalidAxisForRobotType(
478
+ f"{axis} is not valid for OT-2 Standard robot type"
479
+ )
480
+ await self._hardware_api.retract_axis(axis=hardware_axis)
481
+
482
+ async def prepare_for_mount_movement(self, mount: Mount) -> None:
483
+ """Retract the 'idle' mount if necessary."""
484
+ await self._hardware_api.prepare_for_mount_movement(mount)
485
+
486
+
487
+ class VirtualGantryMover(GantryMover):
488
+ """State store based gantry movement handler for simulation/analysis."""
489
+
490
+ def __init__(self, state_view: StateView) -> None:
491
+ self._state_view = state_view
492
+
493
+ def motor_axis_to_hardware_axis(self, motor_axis: MotorAxis) -> HardwareAxis:
494
+ """Transform an engine motor axis into a hardware axis."""
495
+ return _MOTOR_AXIS_TO_HARDWARE_AXIS[motor_axis]
496
+
497
+ def pick_mount_from_axis_map(self, axis_map: Dict[MotorAxis, float]) -> Mount:
498
+ """Find a mount axis in the axis_map if it exists otherwise default to left mount."""
499
+ found_mount = Mount.LEFT
500
+ mounts = list(_MOTOR_AXIS_TO_HARDWARE_MOUNT.keys())
501
+ for k in axis_map.keys():
502
+ if k in mounts:
503
+ found_mount = _MOTOR_AXIS_TO_HARDWARE_MOUNT[k]
504
+ break
505
+ return found_mount
506
+
507
+ async def get_position(
508
+ self,
509
+ pipette_id: str,
510
+ current_well: Optional[CurrentWell] = None,
511
+ fail_on_not_homed: bool = False,
512
+ ) -> Point:
513
+ """Get the current position of the gantry.
514
+
515
+ Args:
516
+ pipette_id: Pipette ID to get position for.
517
+ current_well: Not used in virtual implementation.
518
+ fail_on_not_homed: Not used in virtual implementation.
519
+ """
520
+ origin_deck_point = self._state_view.pipettes.get_deck_point(pipette_id)
521
+ if origin_deck_point is not None:
522
+ origin = Point(
523
+ x=origin_deck_point.x, y=origin_deck_point.y, z=origin_deck_point.z
524
+ )
525
+ else:
526
+ origin = Point(x=0, y=0, z=0)
527
+ return origin
528
+
529
+ async def get_position_from_mount(
530
+ self,
531
+ mount: Mount,
532
+ critical_point: Optional[CriticalPoint] = None,
533
+ fail_on_not_homed: bool = False,
534
+ ) -> Point:
535
+ """Get the current position of the gantry based on the mount.
536
+
537
+ Args:
538
+ mount: The mount to get the position for.
539
+ critical_point: Optional parameter for getting instrument location data, effects critical point.
540
+ fail_on_not_homed: Raise PositionUnknownError if gantry position is not known.
541
+ """
542
+ pipette = self._state_view.pipettes.get_by_mount(MountType[mount.name])
543
+ origin_deck_point = (
544
+ self._state_view.pipettes.get_deck_point(pipette.id) if pipette else None
545
+ )
546
+ if origin_deck_point is not None:
547
+ origin = Point(
548
+ x=origin_deck_point.x, y=origin_deck_point.y, z=origin_deck_point.z
549
+ )
550
+ else:
551
+ origin = Point(x=0, y=0, z=0)
552
+ return origin
553
+
554
+ def get_max_travel_z(self, pipette_id: str) -> float:
555
+ """Get the maximum allowed z-height for pipette movement.
556
+
557
+ Args:
558
+ pipette_id: Pipette ID to get instrument height and tip length for.
559
+ """
560
+ if self._state_view.config.robot_type == "OT-2 Standard":
561
+ instrument_height = self._state_view.pipettes.get_instrument_max_height_ot2(
562
+ pipette_id
563
+ )
564
+ else:
565
+ instrument_height = VIRTUAL_MAX_OT3_HEIGHT
566
+
567
+ tip = self._state_view.pipettes.get_attached_tip(pipette_id=pipette_id)
568
+ tip_length = tip.length if tip is not None else 0
569
+ return instrument_height - tip_length
570
+
571
+ def get_max_travel_z_from_mount(self, mount: MountType) -> float:
572
+ """Get the maximum allowed z-height for mount."""
573
+ pipette = self._state_view.pipettes.get_by_mount(mount)
574
+ if self._state_view.config.robot_type == "OT-2 Standard":
575
+ instrument_height = (
576
+ self._state_view.pipettes.get_instrument_max_height_ot2(pipette.id)
577
+ if pipette
578
+ else VIRTUAL_MAX_OT2_HEIGHT
579
+ )
580
+ else:
581
+ instrument_height = VIRTUAL_MAX_OT3_HEIGHT
582
+ if pipette:
583
+ tip = self._state_view.pipettes.get_attached_tip(pipette_id=pipette.id)
584
+ tip_length = tip.length if tip is not None else 0.0
585
+ else:
586
+ tip_length = 0.0
587
+ return instrument_height - tip_length
588
+
589
+ async def move_axes(
590
+ self,
591
+ axis_map: Dict[MotorAxis, float],
592
+ critical_point: Optional[Dict[MotorAxis, float]] = None,
593
+ speed: Optional[float] = None,
594
+ relative_move: bool = False,
595
+ expect_stalls: bool = False,
596
+ ) -> Dict[MotorAxis, float]:
597
+ """Move the give axes map. No-op in virtual implementation."""
598
+ mount = self.pick_mount_from_axis_map(axis_map)
599
+ current_position = await self.get_position_from_mount(mount)
600
+ updated_position = {}
601
+ if relative_move:
602
+ updated_position[MotorAxis.X] = (
603
+ axis_map.get(MotorAxis.X, 0.0) + current_position[0]
604
+ )
605
+ updated_position[MotorAxis.Y] = (
606
+ axis_map.get(MotorAxis.Y, 0.0) + current_position[1]
607
+ )
608
+ if mount == Mount.RIGHT:
609
+ updated_position[MotorAxis.RIGHT_Z] = (
610
+ axis_map.get(MotorAxis.RIGHT_Z, 0.0) + current_position[2]
611
+ )
612
+ elif mount == Mount.EXTENSION:
613
+ updated_position[MotorAxis.EXTENSION_Z] = (
614
+ axis_map.get(MotorAxis.EXTENSION_Z, 0.0) + current_position[2]
615
+ )
616
+ else:
617
+ updated_position[MotorAxis.LEFT_Z] = (
618
+ axis_map.get(MotorAxis.LEFT_Z, 0.0) + current_position[2]
619
+ )
620
+ else:
621
+ critical_point = critical_point or {}
622
+ updated_position = {
623
+ ax: pos - critical_point.get(ax, 0.0) for ax, pos in axis_map.items()
624
+ }
625
+ return updated_position
626
+
627
+ async def move_mount_to(
628
+ self, mount: Mount, waypoints: List[Waypoint], speed: Optional[float]
629
+ ) -> Point:
630
+ """Move the hardware mount to a waypoint. No-op in virtual implementation."""
631
+ assert len(waypoints) > 0, "Must have at least one waypoint"
632
+ return waypoints[-1].position
633
+
634
+ async def move_to(
635
+ self, pipette_id: str, waypoints: List[Waypoint], speed: Optional[float]
636
+ ) -> Point:
637
+ """Move the hardware gantry to a waypoint. No-op in virtual implementation."""
638
+ assert len(waypoints) > 0, "Must have at least one waypoint"
639
+ return waypoints[-1].position
640
+
641
+ async def move_relative(
642
+ self,
643
+ pipette_id: str,
644
+ delta: Point,
645
+ speed: Optional[float],
646
+ ) -> Point:
647
+ """Move the hardware gantry in a relative direction by delta.
648
+
649
+ Args:
650
+ pipette_id: Pipette ID to get position of for virtual move.
651
+ delta: Relative X/Y/Z distance to move gantry.
652
+ speed: Not used in virtual implementation.
653
+ """
654
+ origin = await self.get_position(pipette_id)
655
+ return origin + delta
656
+
657
+ async def home(self, axes: Optional[List[MotorAxis]]) -> None:
658
+ """Home the gantry. No-op in virtual implementation."""
659
+ pass
660
+
661
+ async def retract_axis(self, axis: MotorAxis) -> None:
662
+ """Retract the specified axis. No-op in virtual implementation."""
663
+ pass
664
+
665
+ async def prepare_for_mount_movement(self, mount: Mount) -> None:
666
+ """Retract the 'idle' mount if necessary."""
667
+ pass
668
+
669
+ def motor_axes_to_present_hardware_axes(
670
+ self, motor_axes: List[MotorAxis]
671
+ ) -> List[HardwareAxis]:
672
+ """Get present hardware axes from a list of engine axes. In simulation, all axes are present."""
673
+ return [
674
+ self.motor_axis_to_hardware_axis(motor_axis) for motor_axis in motor_axes
675
+ ]
676
+
677
+
678
+ def create_gantry_mover(
679
+ state_view: StateView, hardware_api: HardwareControlAPI
680
+ ) -> GantryMover:
681
+ """Create a gantry mover."""
682
+ return (
683
+ HardwareGantryMover(hardware_api=hardware_api, state_view=state_view)
684
+ if state_view.config.use_virtual_pipettes is False
685
+ else VirtualGantryMover(state_view=state_view)
686
+ )