Skip to content

Commit

Permalink
feat(shared-data): Add support for PEEK pipettes (#17036)
Browse files Browse the repository at this point in the history
<!--
Thanks for taking the time to open a Pull Request (PR)! Please make sure
you've read the "Opening Pull Requests" section of our Contributing
Guide:

https://github.com/Opentrons/opentrons/blob/edge/CONTRIBUTING.md#opening-pull-requests

GitHub provides robust markdown to format your PR. Links, diagrams,
pictures, and videos along with text formatting make it possible to
create a rich and informative PR. For more information on GitHub
markdown, see:

https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax

To ensure your code is reviewed quickly and thoroughly, please fill out
the sections below to the best of your ability!
-->

This Adds support for the new oem pipette by doing the following:

- Add support for the flashing and factory testing pipettes with the new
serial number prefix P1KP
- Add the shared data definitions with updated max flowrates
- Add ability to change the max speed when the pipette definition has
the new "highSpeed" quirk
- Disable support for the pressure sensor
  - Don't monitor for over pressure
- Throw errors if trying to enable liquid presence detection on a
pipette
  - Throw errors if trying to explicitly use LLD
  - Support UI differences for the new pipette name

<!--
Describe your PR at a high level. State acceptance criteria and how this
PR fits into other work. Link issues, PRs, and other relevant resources.
-->

<!--
Describe your testing of the PR. Emphasize testing not reflected in the
code. Attach protocols, logs, screenshots and any other assets that
support your testing.
-->

<!--
List changes introduced by this PR considering future developers and the
end user. Give careful thought and clear documentation to breaking
changes.
-->

<!--
- What do you need from reviewers to feel confident this PR is ready to
merge?
- Ask questions.
-->

<!--
- Indicate the level of attention this PR needs.
- Provide context to guide reviewers.
- Discuss trade-offs, coupling, and side effects.
- Look for the possibility, even if you think it's small, that your
change may affect some other part of the system.
- For instance, changing return tip behavior may also change the
behavior of labware calibration.
- How do your unit tests and on hands on testing mitigate this PR's
risks and the risk of future regressions?
- Especially in high risk PRs, explain how you know your testing is
enough.
-->

---------

Co-authored-by: Caila Marashaj <[email protected]>
Co-authored-by: Jethary <[email protected]>
  • Loading branch information
3 people committed Dec 20, 2024
1 parent efac75b commit fe0fc7d
Show file tree
Hide file tree
Showing 30 changed files with 1,190 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,7 @@ def _build_attached_pip(
converted_name.pipette_type,
converted_name.pipette_channels,
converted_name.pipette_version,
converted_name.oem_type,
),
"id": OT3Controller._combine_serial_number(attached),
}
Expand Down
3 changes: 3 additions & 0 deletions api/src/opentrons/hardware_control/backends/ot3simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ def _attached_pipette_to_mount(
converted_name.pipette_type,
converted_name.pipette_channels,
converted_name.pipette_version,
converted_name.oem_type,
),
"id": None,
}
Expand All @@ -533,6 +534,7 @@ def _attached_pipette_to_mount(
converted_name.pipette_type,
converted_name.pipette_channels,
converted_name.pipette_version,
converted_name.oem_type,
),
"id": init_instr["id"],
}
Expand All @@ -544,6 +546,7 @@ def _attached_pipette_to_mount(
converted_name.pipette_type,
converted_name.pipette_channels,
converted_name.pipette_version,
converted_name.oem_type,
),
"id": None,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
UlPerMmAction,
PipetteName,
PipetteModel,
PipetteOEMType,
)
from opentrons.hardware_control.dev_types import InstrumentHardwareConfigs

Expand Down Expand Up @@ -112,17 +113,20 @@ def __init__(
pipette_type=config.pipette_type,
pipette_channels=config.channels,
pipette_generation=config.display_category,
oem_type=PipetteOEMType.OT,
)
self._acting_as = self._pipette_name
self._pipette_model = PipetteModelVersionType(
pipette_type=config.pipette_type,
pipette_channels=config.channels,
pipette_version=config.version,
oem_type=PipetteOEMType.OT,
)
self._valid_nozzle_maps = load_pipette_data.load_valid_nozzle_maps(
self._pipette_model.pipette_type,
self._pipette_model.pipette_channels,
self._pipette_model.pipette_version,
PipetteOEMType.OT,
)
self._nozzle_offset = self._config.nozzle_offset
self._nozzle_manager = (
Expand Down Expand Up @@ -189,7 +193,7 @@ def act_as(self, name: PipetteNameType) -> None:
], f"{self.name} is not back-compatible with {name}"

liquid_model = load_pipette_data.load_liquid_model(
name.pipette_type, name.pipette_channels, name.get_version()
name.pipette_type, name.pipette_channels, name.get_version(), name.oem_type
)
# TODO need to grab name config here to deal with act as test
self._liquid_class.max_volume = liquid_model["default"].max_volume
Expand Down Expand Up @@ -280,6 +284,7 @@ def reload_configurations(self) -> None:
self._pipette_model.pipette_type,
self._pipette_model.pipette_channels,
self._pipette_model.pipette_version,
self._pipette_model.oem_type,
)
self._config_as_dict = self._config.model_dump()

Expand Down
6 changes: 6 additions & 0 deletions api/src/opentrons/hardware_control/instruments/ot3/pipette.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
PipetteName,
PipetteModel,
Quirks,
PipetteOEMType,
)
from opentrons_shared_data.pipette import (
load_data as load_pipette_data,
Expand Down Expand Up @@ -93,22 +94,26 @@ def __init__(
self._liquid_class_name = pip_types.LiquidClasses.default
self._liquid_class = self._config.liquid_properties[self._liquid_class_name]

oem = PipetteOEMType.get_oem_from_quirks(config.quirks)
# TODO (lc 12-05-2022) figure out how we can safely deprecate "name" and "model"
self._pipette_name = PipetteNameType(
pipette_type=config.pipette_type,
pipette_channels=config.channels,
pipette_generation=config.display_category,
oem_type=oem,
)
self._acting_as = self._pipette_name
self._pipette_model = PipetteModelVersionType(
pipette_type=config.pipette_type,
pipette_channels=config.channels,
pipette_version=config.version,
oem_type=oem,
)
self._valid_nozzle_maps = load_pipette_data.load_valid_nozzle_maps(
self._pipette_model.pipette_type,
self._pipette_model.pipette_channels,
self._pipette_model.pipette_version,
self._pipette_model.oem_type,
)
self._nozzle_offset = self._config.nozzle_offset
self._nozzle_manager = (
Expand Down Expand Up @@ -250,6 +255,7 @@ def reload_configurations(self) -> None:
self._pipette_model.pipette_type,
self._pipette_model.pipette_channels,
self._pipette_model.pipette_version,
self._pipette_model.oem_type,
)
self._config_as_dict = self._config.model_dump()

Expand Down
1 change: 1 addition & 0 deletions api/src/opentrons/protocol_api/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"flex_8channel_50": PipetteNameType.P50_MULTI_FLEX,
"flex_1channel_1000": PipetteNameType.P1000_SINGLE_FLEX,
"flex_8channel_1000": PipetteNameType.P1000_MULTI_FLEX,
"flex_8channel_1000_em": PipetteNameType.P1000_MULTI_EM,
"flex_96channel_1000": PipetteNameType.P1000_96,
"flex_96channel_200": PipetteNameType.P200_96,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def configure_virtual_pipette_nozzle_layout(
config.pipette_type,
config.channels,
config.version,
pip_types.PipetteOEMType.OT,
)
new_nozzle_manager = NozzleConfigurationManager.build_from_config(
config, valid_nozzle_maps
Expand Down Expand Up @@ -130,6 +131,7 @@ def configure_virtual_pipette_for_volume(
pipette_model.pipette_type,
pipette_model.pipette_channels,
pipette_model.pipette_version,
pipette_model.oem_type,
)

liquid_class = pipette_definition.liquid_class_for_volume_between_default_and_defaultlowvolume(
Expand Down Expand Up @@ -163,6 +165,7 @@ def _get_virtual_pipette_full_config_by_model_string(
pipette_model.pipette_type,
pipette_model.pipette_channels,
pipette_model.pipette_version,
pipette_model.oem_type,
)

def _get_virtual_pipette_static_config_by_model( # noqa: C901
Expand All @@ -179,6 +182,7 @@ def _get_virtual_pipette_static_config_by_model( # noqa: C901
pipette_model.pipette_type,
pipette_model.pipette_channels,
pipette_model.pipette_version,
pipette_model.oem_type,
)
try:
tip_type = pip_types.PipetteTipType(
Expand All @@ -195,6 +199,7 @@ def _get_virtual_pipette_static_config_by_model( # noqa: C901
pipette_model.pipette_type,
pipette_model.pipette_channels,
pipette_model.pipette_version,
pipette_model.oem_type,
)
if pipette_id not in self._nozzle_manager_layout_by_id:
nozzle_manager = NozzleConfigurationManager.build_from_config(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1434,7 +1434,7 @@ async def test_pressure_disable(
mock_check_overpressure: None,
pipette_has_sensor: bool,
) -> None:
config = {"run.side_effect": move_group_run_side_effect_home(controller, axes)}
config = {"run.side_effect": move_group_run_side_effect(controller, axes)}
with mock.patch( # type: ignore [call-overload]
"opentrons.hardware_control.backends.ot3controller.MoveGroupRunner",
spec=MoveGroupRunner,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
PipetteModelType,
PipetteChannelType,
PipetteVersionType,
PipetteOEMType,
)
from opentrons_shared_data.pipette.pipette_definition import (
PipetteConfigurations,
Expand Down Expand Up @@ -261,7 +262,10 @@ def test_single_pipettes_always_full(
pipette_details: Tuple[PipetteModelType, PipetteVersionType],
) -> None:
config = load_definition(
pipette_details[0], PipetteChannelType.SINGLE_CHANNEL, pipette_details[1]
pipette_details[0],
PipetteChannelType.SINGLE_CHANNEL,
pipette_details[1],
PipetteOEMType.OT,
)
subject = nozzle_manager.NozzleConfigurationManager.build_from_config(
config, ValidNozzleMaps(maps=A1)
Expand Down Expand Up @@ -289,7 +293,10 @@ def test_single_pipette_map_entries(
pipette_details: Tuple[PipetteModelType, PipetteVersionType],
) -> None:
config = load_definition(
pipette_details[0], PipetteChannelType.SINGLE_CHANNEL, pipette_details[1]
pipette_details[0],
PipetteChannelType.SINGLE_CHANNEL,
pipette_details[1],
PipetteOEMType.OT,
)
subject = nozzle_manager.NozzleConfigurationManager.build_from_config(
config, ValidNozzleMaps(maps=A1)
Expand Down Expand Up @@ -326,7 +333,10 @@ def test_single_pipette_map_geometry(
pipette_details: Tuple[PipetteModelType, PipetteVersionType],
) -> None:
config = load_definition(
pipette_details[0], PipetteChannelType.SINGLE_CHANNEL, pipette_details[1]
pipette_details[0],
PipetteChannelType.SINGLE_CHANNEL,
pipette_details[1],
PipetteOEMType.OT,
)
subject = nozzle_manager.NozzleConfigurationManager.build_from_config(
config, ValidNozzleMaps(maps=A1)
Expand Down Expand Up @@ -359,7 +369,10 @@ def test_multi_config_identification(
pipette_details: Tuple[PipetteModelType, PipetteVersionType],
) -> None:
config = load_definition(
pipette_details[0], PipetteChannelType.EIGHT_CHANNEL, pipette_details[1]
pipette_details[0],
PipetteChannelType.EIGHT_CHANNEL,
pipette_details[1],
PipetteOEMType.OT,
)
subject = nozzle_manager.NozzleConfigurationManager.build_from_config(
config,
Expand Down Expand Up @@ -419,7 +432,10 @@ def test_multi_config_map_entries(
pipette_details: Tuple[PipetteModelType, PipetteVersionType],
) -> None:
config = load_definition(
pipette_details[0], PipetteChannelType.EIGHT_CHANNEL, pipette_details[1]
pipette_details[0],
PipetteChannelType.EIGHT_CHANNEL,
pipette_details[1],
PipetteOEMType.OT,
)
subject = nozzle_manager.NozzleConfigurationManager.build_from_config(
config,
Expand Down Expand Up @@ -485,7 +501,10 @@ def test_multi_config_geometry(
pipette_details: Tuple[PipetteModelType, PipetteVersionType],
) -> None:
config = load_definition(
pipette_details[0], PipetteChannelType.EIGHT_CHANNEL, pipette_details[1]
pipette_details[0],
PipetteChannelType.EIGHT_CHANNEL,
pipette_details[1],
PipetteOEMType.OT,
)
subject = nozzle_manager.NozzleConfigurationManager.build_from_config(
config,
Expand Down Expand Up @@ -536,7 +555,10 @@ def test_96_config_identification(
pipette_details: Tuple[PipetteModelType, PipetteVersionType],
) -> None:
config = load_definition(
pipette_details[0], PipetteChannelType.NINETY_SIX_CHANNEL, pipette_details[1]
pipette_details[0],
PipetteChannelType.NINETY_SIX_CHANNEL,
pipette_details[1],
PipetteOEMType.OT,
)
subject = nozzle_manager.NozzleConfigurationManager.build_from_config(
config,
Expand Down Expand Up @@ -651,7 +673,10 @@ def test_96_config_map_entries(
pipette_details: Tuple[PipetteModelType, PipetteVersionType],
) -> None:
config = load_definition(
pipette_details[0], PipetteChannelType.NINETY_SIX_CHANNEL, pipette_details[1]
pipette_details[0],
PipetteChannelType.NINETY_SIX_CHANNEL,
pipette_details[1],
PipetteOEMType.OT,
)
subject = nozzle_manager.NozzleConfigurationManager.build_from_config(
config,
Expand Down Expand Up @@ -988,7 +1013,10 @@ def test_96_config_geometry(
pipette_details: Tuple[PipetteModelType, PipetteVersionType],
) -> None:
config = load_definition(
pipette_details[0], PipetteChannelType.NINETY_SIX_CHANNEL, pipette_details[1]
pipette_details[0],
PipetteChannelType.NINETY_SIX_CHANNEL,
pipette_details[1],
PipetteOEMType.OT,
)
subject = nozzle_manager.NozzleConfigurationManager.build_from_config(
config,
Expand Down
Loading

0 comments on commit fe0fc7d

Please sign in to comment.