Skip to content

Commit

Permalink
Merge branch 'edge' into feat_pd-unused-hardware
Browse files Browse the repository at this point in the history
  • Loading branch information
ncdiehl11 authored Oct 30, 2024
2 parents 94cb091 + 094be6e commit f95a079
Show file tree
Hide file tree
Showing 60 changed files with 1,080 additions and 208 deletions.
9 changes: 9 additions & 0 deletions api-client/src/runs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
RunTimeCommand,
RunTimeParameter,
NozzleLayoutConfig,
OnDeckLabwareLocation,
} from '@opentrons/shared-data'
import type { ResourceLink, ErrorDetails } from '../types'
export * from './commands/types'
Expand Down Expand Up @@ -117,7 +118,9 @@ export interface Runs {
}

export interface RunCurrentStateData {
estopEngaged: boolean
activeNozzleLayouts: Record<string, NozzleLayoutValues> // keyed by pipetteId
placeLabwareState?: PlaceLabwareState
}

export const RUN_ACTION_TYPE_PLAY: 'play' = 'play'
Expand Down Expand Up @@ -209,3 +212,9 @@ export interface NozzleLayoutValues {
activeNozzles: string[]
config: NozzleLayoutConfig
}

export interface PlaceLabwareState {
labwareId: string
location: OnDeckLabwareLocation
shouldPlaceDown: boolean
}
18 changes: 18 additions & 0 deletions api/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ By installing and using Opentrons software, you agree to the Opentrons End-User

---

## Opentrons Robot Software Changes in 8.2.0

Welcome to the v8.2.0 release of the Opentrons robot software! This release adds support for the Opentrons Absorbance Plate Reader Module.

### New Features

- Create and run Python protocols that use the Opentrons Absorbance Plate Reader.

### Improved Features

- Liquid presence detection no longer checks for liquid before every aspiration in a `mix()` command.

### Bug Fixes

- Error recovery no longer causes an `AssertionError` when a Python protocol changes the pipette speed.

---

## Opentrons Robot Software Changes in 8.1.0

Welcome to the v8.1.0 release of the Opentrons robot software!
Expand Down
11 changes: 4 additions & 7 deletions api/src/opentrons/hardware_control/modules/absorbance_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,8 @@ def usb_port(self) -> USBPort:
return self._usb_port

async def deactivate(self, must_be_running: bool = True) -> None:
"""Deactivate the module.
Contains an override to the `wait_for_is_running` step in cases where the
module must be deactivated regardless of context."""
await self._poller.stop()
await self._driver.disconnect()
"""Deactivate the module."""
pass

async def wait_for_is_running(self) -> None:
if not self.is_simulated:
Expand Down Expand Up @@ -336,7 +332,8 @@ async def cleanup(self) -> None:
Clean up, i.e. stop pollers, disconnect serial, etc in preparation for
object destruction.
"""
await self.deactivate()
await self._poller.stop()
await self._driver.disconnect()

async def set_sample_wavelength(
self,
Expand Down
2 changes: 2 additions & 0 deletions api/src/opentrons/motion_planning/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
MINIMUM_Z_MARGIN,
get_waypoints,
get_gripper_labware_movement_waypoints,
get_gripper_labware_placement_waypoints,
)

from .types import Waypoint, MoveType
Expand All @@ -27,4 +28,5 @@
"ArcOutOfBoundsError",
"get_waypoints",
"get_gripper_labware_movement_waypoints",
"get_gripper_labware_placement_waypoints",
]
32 changes: 32 additions & 0 deletions api/src/opentrons/motion_planning/waypoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,35 @@ def get_gripper_labware_movement_waypoints(
)
)
return waypoints_with_jaw_status


def get_gripper_labware_placement_waypoints(
to_labware_center: Point,
gripper_home_z: float,
drop_offset: Optional[Point],
) -> List[GripperMovementWaypointsWithJawStatus]:
"""Get waypoints for placing labware using a gripper."""
drop_offset = drop_offset or Point()

drop_location = to_labware_center + Point(
drop_offset.x, drop_offset.y, drop_offset.z
)

post_drop_home_pos = Point(drop_location.x, drop_location.y, gripper_home_z)

return [
GripperMovementWaypointsWithJawStatus(
position=Point(drop_location.x, drop_location.y, gripper_home_z),
jaw_open=False,
dropping=False,
),
GripperMovementWaypointsWithJawStatus(
position=drop_location, jaw_open=False, dropping=False
),
# Gripper ungrips here
GripperMovementWaypointsWithJawStatus(
position=post_drop_home_pos,
jaw_open=True,
dropping=True,
),
]
9 changes: 8 additions & 1 deletion api/src/opentrons/protocol_api/core/engine/module_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ class AbsorbanceReaderCore(ModuleCore, AbstractAbsorbanceReaderCore):

_sync_module_hardware: SynchronousAdapter[hw_modules.AbsorbanceReader]
_initialized_value: Optional[List[int]] = None
_ready_to_initialize: bool = False

def initialize(
self,
Expand All @@ -575,6 +576,11 @@ def initialize(
reference_wavelength: Optional[int] = None,
) -> None:
"""Initialize the Absorbance Reader by taking zero reading."""
if not self._ready_to_initialize:
raise CannotPerformModuleAction(
"Cannot perform Initialize action on Absorbance Reader without calling `.close_lid()` first."
)

# TODO: check that the wavelengths are within the supported wavelengths
self._engine_client.execute_command(
cmd.absorbance_reader.InitializeParams(
Expand All @@ -586,7 +592,7 @@ def initialize(
)
self._initialized_value = wavelengths

def read(self, filename: Optional[str]) -> Dict[int, Dict[str, float]]:
def read(self, filename: Optional[str] = None) -> Dict[int, Dict[str, float]]:
"""Initiate a read on the Absorbance Reader, and return the results. During Analysis, this will return a measurement of zero for all wells."""
wavelengths = self._engine_client.state.modules.get_absorbance_reader_substate(
self.module_id
Expand Down Expand Up @@ -633,6 +639,7 @@ def close_lid(
moduleId=self.module_id,
)
)
self._ready_to_initialize = True

def open_lid(self) -> None:
"""Close the Absorbance Reader's lid."""
Expand Down
35 changes: 20 additions & 15 deletions api/src/opentrons/protocol_api/core/engine/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,9 +449,10 @@ def load_module(

# When the protocol engine is created, we add Module Lids as part of the deck fixed labware
# If a valid module exists in the deck config. For analysis, we add the labware here since
# deck fixed labware is not created under the same conditions.
if self._engine_client.state.config.use_virtual_modules:
self._load_virtual_module_lid(module_core)
# deck fixed labware is not created under the same conditions. We also need to inject the Module
# lids when the module isnt already on the deck config, like when adding a new
# module during a protocol setup.
self._load_virtual_module_lid(module_core)

self._module_cores_by_id[module_core.module_id] = module_core

Expand All @@ -461,20 +462,24 @@ def _load_virtual_module_lid(
self, module_core: Union[ModuleCore, NonConnectedModuleCore]
) -> None:
if isinstance(module_core, AbsorbanceReaderCore):
lid = self._engine_client.execute_command_without_recovery(
cmd.LoadLabwareParams(
loadName="opentrons_flex_lid_absorbance_plate_reader_module",
location=ModuleLocation(moduleId=module_core.module_id),
namespace="opentrons",
version=1,
displayName="Absorbance Reader Lid",
)
substate = self._engine_client.state.modules.get_absorbance_reader_substate(
module_core.module_id
)
if substate.lid_id is None:
lid = self._engine_client.execute_command_without_recovery(
cmd.LoadLabwareParams(
loadName="opentrons_flex_lid_absorbance_plate_reader_module",
location=ModuleLocation(moduleId=module_core.module_id),
namespace="opentrons",
version=1,
displayName="Absorbance Reader Lid",
)
)

self._engine_client.add_absorbance_reader_lid(
module_id=module_core.module_id,
lid_id=lid.labwareId,
)
self._engine_client.add_absorbance_reader_lid(
module_id=module_core.module_id,
lid_id=lid.labwareId,
)

def _create_non_connected_module_core(
self, load_module_result: LoadModuleResult
Expand Down
2 changes: 1 addition & 1 deletion api/src/opentrons/protocol_api/core/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ def initialize(
"""Initialize the Absorbance Reader by taking zero reading."""

@abstractmethod
def read(self, filename: Optional[str]) -> Dict[int, Dict[str, float]]:
def read(self, filename: Optional[str] = None) -> Dict[int, Dict[str, float]]:
"""Get an absorbance reading from the Absorbance Reader."""

@abstractmethod
Expand Down
4 changes: 3 additions & 1 deletion api/src/opentrons/protocol_api/module_contexts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1035,7 +1035,9 @@ def initialize(
)

@requires_version(2, 21)
def read(self, export_filename: Optional[str]) -> Dict[int, Dict[str, float]]:
def read(
self, export_filename: Optional[str] = None
) -> Dict[int, Dict[str, float]]:
"""Initiate read on the Absorbance Reader.
Returns a dictionary of wavelengths to dictionary of values ordered by well name.
Expand Down
5 changes: 5 additions & 0 deletions api/src/opentrons/protocol_engine/commands/command_unions.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@
unsafe.UpdatePositionEstimators,
unsafe.UnsafeEngageAxes,
unsafe.UnsafeUngripLabware,
unsafe.UnsafePlaceLabware,
],
Field(discriminator="commandType"),
]
Expand Down Expand Up @@ -469,6 +470,7 @@
unsafe.UpdatePositionEstimatorsParams,
unsafe.UnsafeEngageAxesParams,
unsafe.UnsafeUngripLabwareParams,
unsafe.UnsafePlaceLabwareParams,
]

CommandType = Union[
Expand Down Expand Up @@ -544,6 +546,7 @@
unsafe.UpdatePositionEstimatorsCommandType,
unsafe.UnsafeEngageAxesCommandType,
unsafe.UnsafeUngripLabwareCommandType,
unsafe.UnsafePlaceLabwareCommandType,
]

CommandCreate = Annotated[
Expand Down Expand Up @@ -620,6 +623,7 @@
unsafe.UpdatePositionEstimatorsCreate,
unsafe.UnsafeEngageAxesCreate,
unsafe.UnsafeUngripLabwareCreate,
unsafe.UnsafePlaceLabwareCreate,
],
Field(discriminator="commandType"),
]
Expand Down Expand Up @@ -697,6 +701,7 @@
unsafe.UpdatePositionEstimatorsResult,
unsafe.UnsafeEngageAxesResult,
unsafe.UnsafeUngripLabwareResult,
unsafe.UnsafePlaceLabwareResult,
]


Expand Down
15 changes: 15 additions & 0 deletions api/src/opentrons/protocol_engine/commands/unsafe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@
)


from .unsafe_place_labware import (
UnsafePlaceLabwareCommandType,
UnsafePlaceLabwareParams,
UnsafePlaceLabwareResult,
UnsafePlaceLabware,
UnsafePlaceLabwareCreate,
)


__all__ = [
# Unsafe blow-out-in-place command models
"UnsafeBlowOutInPlaceCommandType",
Expand Down Expand Up @@ -71,4 +80,10 @@
"UnsafeUngripLabwareResult",
"UnsafeUngripLabware",
"UnsafeUngripLabwareCreate",
# Unsafe place labware
"UnsafePlaceLabwareCommandType",
"UnsafePlaceLabwareParams",
"UnsafePlaceLabwareResult",
"UnsafePlaceLabware",
"UnsafePlaceLabwareCreate",
]
Loading

0 comments on commit f95a079

Please sign in to comment.