-
Notifications
You must be signed in to change notification settings - Fork 178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(shared-data, robot-server, api): Pipette configuration architecture refactor to organize by nozzle map and tip type #15250
Changes from 12 commits
09b2e01
af38b12
cd11ee0
7d3d79e
6004a9a
350ebd0
45d2899
d2d8b47
cf13f9b
4364c08
8247821
939995f
a21f592
88f4f66
6e390b4
2e03700
2e19184
5e67680
1505f11
9a3d2d6
8f4040b
8ca7773
9e23a59
36aef87
49e2967
397c4ac
f4fa638
6ff32cc
4ee4853
4bda970
6702599
d33c225
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
PipetteModelVersionType, | ||
PipetteNameType, | ||
PipetteLiquidPropertiesDefinition, | ||
PressFitPickUpTipConfiguration, | ||
) | ||
from opentrons_shared_data.pipette import ( | ||
load_data as load_pipette_data, | ||
|
@@ -112,9 +113,16 @@ def __init__( | |
pipette_channels=config.channels, | ||
pipette_version=config.version, | ||
) | ||
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._nozzle_offset = self._config.nozzle_offset | ||
self._nozzle_manager = ( | ||
nozzle_manager.NozzleConfigurationManager.build_from_config(self._config) | ||
nozzle_manager.NozzleConfigurationManager.build_from_config( | ||
self._config, self._valid_nozzle_maps | ||
) | ||
) | ||
self._current_volume = 0.0 | ||
self._working_volume = float(self._liquid_class.max_volume) | ||
|
@@ -148,7 +156,9 @@ def __init__( | |
self._active_tip_settings.default_blowout_flowrate.default | ||
) | ||
|
||
self._tip_overlap_lookup = self._liquid_class.tip_overlap_dictionary | ||
self._tip_overlap_dictionary = ( | ||
self.get_nominal_tip_overlap_dictionary_by_configuration() | ||
) | ||
|
||
if use_old_aspiration_functions: | ||
self._pipetting_function_version = PIPETTING_FUNCTION_FALLBACK_VERSION | ||
|
@@ -217,7 +227,7 @@ def pipette_offset(self) -> PipetteOffsetByPipetteMount: | |
|
||
@property | ||
def tip_overlap(self) -> Dict[str, float]: | ||
return self._tip_overlap_lookup | ||
return self._tip_overlap_dictionary | ||
|
||
@property | ||
def channels(self) -> pip_types.PipetteChannelType: | ||
|
@@ -290,9 +300,14 @@ def reset_state(self) -> None: | |
self.active_tip_settings.default_blowout_flowrate.default | ||
) | ||
|
||
self._tip_overlap_lookup = self.liquid_class.tip_overlap_dictionary | ||
self._tip_overlap_dictionary = ( | ||
self.get_nominal_tip_overlap_dictionary_by_configuration() | ||
) | ||
|
||
self._nozzle_manager = ( | ||
nozzle_manager.NozzleConfigurationManager.build_from_config(self._config) | ||
nozzle_manager.NozzleConfigurationManager.build_from_config( | ||
self._config, self._valid_nozzle_maps | ||
) | ||
) | ||
|
||
def reset_pipette_offset(self, mount: Mount, to_default: bool) -> None: | ||
|
@@ -520,6 +535,93 @@ def remove_tip(self) -> None: | |
def has_tip(self) -> bool: | ||
return self._has_tip | ||
|
||
def get_pick_up_speed_by_configuration( | ||
self, | ||
config: PressFitPickUpTipConfiguration, | ||
) -> float: | ||
try: | ||
return config.configuration_by_nozzle_map[ | ||
self._nozzle_manager.current_configuration.valid_map_key | ||
][pip_types.PipetteTipType(self._liquid_class.max_volume).name].speed | ||
except KeyError: | ||
default = config.configuration_by_nozzle_map[ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this be a free function in a shared area? I think it's an identical implementation for the two machines |
||
self._nozzle_manager.current_configuration.valid_map_key | ||
].get("default") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and actually generally the task of "get data from the unified structure" might be able to be commonized further |
||
if default is not None: | ||
return default.speed | ||
raise KeyError( | ||
f"Default tip type configuration values do not exist for Nozzle Map {self._nozzle_manager.current_configuration.valid_map_key}." | ||
) | ||
|
||
def get_pick_up_distance_by_configuration( | ||
self, | ||
config: PressFitPickUpTipConfiguration, | ||
) -> float: | ||
try: | ||
return config.configuration_by_nozzle_map[ | ||
self._nozzle_manager.current_configuration.valid_map_key | ||
][pip_types.PipetteTipType(self._liquid_class.max_volume).name].distance | ||
except KeyError: | ||
default = config.configuration_by_nozzle_map[ | ||
self._nozzle_manager.current_configuration.valid_map_key | ||
].get("default") | ||
if default is not None: | ||
return default.distance | ||
raise KeyError( | ||
f"Default tip type configuration values do not exist for Nozzle Map {self._nozzle_manager.current_configuration.valid_map_key}." | ||
) | ||
|
||
def get_pick_up_current_by_configuration( | ||
self, | ||
config: PressFitPickUpTipConfiguration, | ||
) -> float: | ||
try: | ||
return config.configuration_by_nozzle_map[ | ||
self._nozzle_manager.current_configuration.valid_map_key | ||
][pip_types.PipetteTipType(self._liquid_class.max_volume).name].current | ||
except KeyError: | ||
default = config.configuration_by_nozzle_map[ | ||
self._nozzle_manager.current_configuration.valid_map_key | ||
].get("default") | ||
if default is not None: | ||
return default.current | ||
raise KeyError( | ||
f"Default tip type configuration values do not exist for Nozzle Map {self._nozzle_manager.current_configuration.valid_map_key}." | ||
) | ||
|
||
def get_nominal_tip_overlap_dictionary_by_configuration( | ||
self, | ||
) -> Dict[str, float]: | ||
for config in ( | ||
self._config.pick_up_tip_configurations.press_fit, | ||
self._config.pick_up_tip_configurations.cam_action, | ||
): | ||
if not config: | ||
continue | ||
|
||
try: | ||
return config.configuration_by_nozzle_map[ | ||
self._nozzle_manager.current_configuration.valid_map_key | ||
][ | ||
pip_types.PipetteTipType(self._liquid_class.max_volume).name | ||
].tip_overlap_dictionary | ||
except KeyError: | ||
try: | ||
default = config.configuration_by_nozzle_map[ | ||
self._nozzle_manager.current_configuration.valid_map_key | ||
].get("default") | ||
if default is not None: | ||
return default.tip_overlap_dictionary | ||
raise KeyError( | ||
f"Default tip type configuration values do not exist for Nozzle Map {self._nozzle_manager.current_configuration.valid_map_key}." | ||
) | ||
except KeyError: | ||
# No valid key found for the approved nozzle map under this configuration - try the next | ||
continue | ||
raise CommandPreconditionViolated( | ||
message="No valid tip overlap dictionary identified.", | ||
) | ||
|
||
# Cache max is chosen somewhat arbitrarily. With a float is input we don't | ||
# want this to unbounded. | ||
@functools.lru_cache(maxsize=100) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should have these errors be enumerated errors defined in shared data using an error code, like a new 4000-series "missing configuration data" or something