Skip to content

Commit 2a61803

Browse files
authored
fix(stacker): catch shuttle is not empty when stacker is about to retrieve (#19057)
# Overview This PR allows error recovery for when the shuttle is already occupied when the stacker is about to retrieve. This error is routed to the `stacker-stalled-and-retry` route.
1 parent 23b37a9 commit 2a61803

File tree

15 files changed

+97
-2
lines changed

15 files changed

+97
-2
lines changed

api/src/opentrons/hardware_control/modules/flex_stacker.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
FlexStackerShuttleMissingError,
6060
FlexStackerShuttleLabwareError,
6161
FlexStackerHopperLabwareError,
62+
FlexStackerShuttleNotEmptyError,
6263
)
6364
from opentrons_shared_data.module import load_tof_baseline_data
6465

@@ -711,7 +712,13 @@ async def verify_shuttle_labware_presence(
711712
"""Check whether or not a labware is detected on the shuttle."""
712713
result = await self.labware_detected(StackerAxis.X, direction)
713714
if labware_expected != result:
714-
raise FlexStackerShuttleLabwareError(
715+
if labware_expected:
716+
raise FlexStackerShuttleLabwareError(
717+
self.device_info["serial"],
718+
shuttle_state=self.platform_state,
719+
labware_expected=labware_expected,
720+
)
721+
raise FlexStackerShuttleNotEmptyError(
715722
self.device_info["serial"],
716723
shuttle_state=self.platform_state,
717724
labware_expected=labware_expected,

api/src/opentrons/protocol_engine/commands/command_unions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
FlexStackerShuttleError,
2020
FlexStackerHopperError,
2121
FlexStackerLabwareRetrieveError,
22+
FlexStackerShuttleOccupiedError,
2223
)
2324

2425
from . import absorbance_reader
@@ -946,6 +947,7 @@
946947
DefinedErrorData[FlexStackerShuttleError],
947948
DefinedErrorData[FlexStackerHopperError],
948949
DefinedErrorData[FlexStackerLabwareRetrieveError],
950+
DefinedErrorData[FlexStackerShuttleOccupiedError],
949951
]
950952

951953

api/src/opentrons/protocol_engine/commands/flex_stacker/common.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,17 @@ class FlexStackerLabwareRetrieveError(ErrorOccurrence):
148148
errorInfo: FailedLabware
149149

150150

151+
class FlexStackerShuttleOccupiedError(ErrorOccurrence):
152+
"""Returned when the Flex Stacker Shuttle is occupied when it shouldn't be."""
153+
154+
isDefined: bool = True
155+
errorType: Literal["flexStackerShuttleOccupied"] = "flexStackerShuttleOccupied"
156+
157+
errorCode: str = ErrorCodes.STACKER_SHUTTLE_OCCUPIED.value.code
158+
detail: str = ErrorCodes.STACKER_SHUTTLE_OCCUPIED.value.detail
159+
errorInfo: FailedLabware
160+
161+
151162
@dataclass
152163
class _LabwareDefPair:
153164
definition: LabwareDefinition

api/src/opentrons/protocol_engine/commands/flex_stacker/retrieve.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
FlexStackerShuttleMissingError,
1313
FlexStackerHopperLabwareError,
1414
FlexStackerShuttleLabwareError,
15+
FlexStackerShuttleNotEmptyError,
1516
)
1617

1718
from ..command import (
@@ -41,6 +42,7 @@
4142
FlexStackerShuttleError,
4243
FlexStackerHopperError,
4344
FlexStackerLabwareRetrieveError,
45+
FlexStackerShuttleOccupiedError,
4446
primary_location_sequence,
4547
adapter_location_sequence,
4648
lid_location_sequence,
@@ -57,6 +59,7 @@
5759
FlexStackerShuttleMissingError,
5860
FlexStackerHopperLabwareError,
5961
FlexStackerShuttleLabwareError,
62+
FlexStackerShuttleNotEmptyError,
6063
]
6164

6265

@@ -147,7 +150,8 @@ class RetrieveResult(BaseModel):
147150
DefinedErrorData[FlexStackerStallOrCollisionError]
148151
| DefinedErrorData[FlexStackerShuttleError]
149152
| DefinedErrorData[FlexStackerHopperError]
150-
| DefinedErrorData[FlexStackerLabwareRetrieveError],
153+
| DefinedErrorData[FlexStackerLabwareRetrieveError]
154+
| DefinedErrorData[FlexStackerShuttleOccupiedError],
151155
]
152156

153157

@@ -175,13 +179,15 @@ def handle_recoverable_error(
175179
| DefinedErrorData[FlexStackerShuttleError]
176180
| DefinedErrorData[FlexStackerHopperError]
177181
| DefinedErrorData[FlexStackerLabwareRetrieveError]
182+
| DefinedErrorData[FlexStackerShuttleOccupiedError]
178183
):
179184
"""Handle a recoverable error raised during command execution."""
180185
error_map = {
181186
FlexStackerStallError: FlexStackerStallOrCollisionError,
182187
FlexStackerShuttleMissingError: FlexStackerShuttleError,
183188
FlexStackerHopperLabwareError: FlexStackerHopperError,
184189
FlexStackerShuttleLabwareError: FlexStackerLabwareRetrieveError,
190+
FlexStackerShuttleNotEmptyError: FlexStackerShuttleOccupiedError,
185191
}
186192
return DefinedErrorData(
187193
public=error_map[type(error)](
@@ -280,6 +286,7 @@ async def execute(self, params: RetrieveParams) -> _ExecuteReturn:
280286
FlexStackerShuttleMissingError,
281287
FlexStackerHopperLabwareError,
282288
FlexStackerShuttleLabwareError,
289+
FlexStackerShuttleNotEmptyError,
283290
) as e:
284291
return self.handle_recoverable_error(
285292
e, to_retrieve.primaryLabwareId, state_update

api/tests/opentrons/protocol_engine/commands/flex_stacker/test_retrieve.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
FlexStackerShuttleError,
1515
FlexStackerHopperError,
1616
FlexStackerLabwareRetrieveError,
17+
FlexStackerShuttleOccupiedError,
1718
)
1819
from opentrons.protocol_engine.resources import ModelUtils
1920

@@ -60,6 +61,7 @@
6061
FlexStackerShuttleMissingError,
6162
FlexStackerHopperLabwareError,
6263
FlexStackerShuttleLabwareError,
64+
FlexStackerShuttleNotEmptyError,
6365
)
6466

6567

@@ -687,6 +689,12 @@ async def test_retrieve_primary_adapter_and_lid(
687689
),
688690
FlexStackerLabwareRetrieveError,
689691
),
692+
(
693+
FlexStackerShuttleNotEmptyError(
694+
serial="123", labware_expected=True, shuttle_state=""
695+
),
696+
FlexStackerShuttleOccupiedError,
697+
),
690698
],
691699
)
692700
async def test_retrieve_raises_recoverable_error(

app/src/assets/localization/en/error_recovery.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@
142142
"stacker_latch_jammed_errors_occur_when": "Stacker latch jammed errors occur when labware gets stuck in between the stacker latch. This is usually caused by improperly placed labware or inaccurate labware definitions",
143143
"stacker_latch_will_reengage": "The stacker latch will re-engage so that you can reload the stacker. Make sure that any obstructions have been cleared.",
144144
"stacker_shuttle_missing_error_occurs_when": "Stacker shuttle missing errors occur when the shuttle is not placed correctly on the track. Load the stacker shuttle onto the track to proceed.",
145+
"stacker_shuttle_not_empty": "Stacker Shuttle Not Empty",
145146
"stacker_stall_or_collision_error": "Stacker stalled",
146147
"stall_or_collision_detected_when": "A stall or collision is detected when the robot's motors are blocked",
147148
"stall_or_collision_error": "Stall or collision",

app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/SelectRecoveryOption.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,16 @@ export function getRecoveryOptions(errorKind: ErrorKind): RecoveryRoute[] {
197197
return STACKER_SHUTTLE_MISSING_OPTIONS
198198
case ERROR_KINDS.STACKER_SHUTTLE_EMPTY:
199199
return STACKER_SHUTTLE_EMPTY_OPTIONS
200+
case ERROR_KINDS.STACKER_SHUTTLE_OCCUPIED:
201+
return STACKER_SHUTTLE_OCCUPIED_OPTIONS
200202
}
201203
}
202204

205+
export const STACKER_SHUTTLE_OCCUPIED_OPTIONS: RecoveryRoute[] = [
206+
RECOVERY_MAP.STACKER_STALLED_RETRY.ROUTE,
207+
RECOVERY_MAP.CANCEL_RUN.ROUTE,
208+
]
209+
203210
export const STACKER_SHUTTLE_EMPTY_OPTIONS: RecoveryRoute[] = [
204211
RECOVERY_MAP.STACKER_SHUTTLE_EMPTY_RETRY.ROUTE,
205212
RECOVERY_MAP.STACKER_SHUTTLE_EMPTY_SKIP.ROUTE,

app/src/organisms/ErrorRecoveryFlows/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export const DEFINED_ERROR_TYPES = {
3030
HOPPER_LABWARE_MISSING: 'flexStackerHopperLabwareFailed',
3131
STACKER_SHUTTLE_MISSING: 'flexStackerShuttleMissing',
3232
STACKER_SHUTTLE_EMPTY: 'flexStackerLabwareRetrieveFailed',
33+
STACKER_SHUTTLE_OCCUPIED: 'flexStackerShuttleOccupied',
3334
} as const
3435

3536
// Client-defined error-handling flows.
@@ -47,13 +48,15 @@ export const ERROR_KINDS = {
4748
STACKER_HOPPER_EMPTY: 'STACKER_HOPPER_EMPTY',
4849
STACKER_SHUTTLE_MISSING: 'STACKER_SHUTTLE_MISSING',
4950
STACKER_SHUTTLE_EMPTY: 'STACKER_SHUTTLE_EMPTY',
51+
STACKER_SHUTTLE_OCCUPIED: 'STACKER_SHUTTLE_OCCUPIED',
5052
} as const
5153

5254
export const STACKER_ERROR_KINDS: ErrorKind[] = [
5355
ERROR_KINDS.STACKER_STALLED,
5456
ERROR_KINDS.STACKER_SHUTTLE_MISSING,
5557
ERROR_KINDS.STACKER_HOPPER_EMPTY,
5658
ERROR_KINDS.STACKER_SHUTTLE_EMPTY,
59+
ERROR_KINDS.STACKER_SHUTTLE_OCCUPIED,
5760
] as const
5861

5962
// TODO(jh, 06-14-24): Consolidate motion routes to a single route with several steps.

app/src/organisms/ErrorRecoveryFlows/hooks/useErrorName.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ export function useErrorName(errorKind: ErrorKind): string {
3333
return t('shuttle_missing')
3434
case ERROR_KINDS.STACKER_SHUTTLE_EMPTY:
3535
return t('labware_not_retrieved')
36+
case ERROR_KINDS.STACKER_SHUTTLE_OCCUPIED:
37+
return t('stacker_shuttle_not_empty')
3638
default:
3739
return t('error')
3840
}

app/src/organisms/ErrorRecoveryFlows/hooks/useFailedLabwareUtils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ export function getRelevantFailedLabwareCmdFrom({
228228
case ERROR_KINDS.STACKER_SHUTTLE_MISSING:
229229
case ERROR_KINDS.STACKER_HOPPER_EMPTY:
230230
case ERROR_KINDS.STACKER_SHUTTLE_EMPTY:
231+
case ERROR_KINDS.STACKER_SHUTTLE_OCCUPIED:
231232
return failedCommandByRunRecord as FlexStackerRetrieveRunTimeCommand
232233
default:
233234
console.error(
@@ -375,6 +376,7 @@ export function getRelevantLabwareIdFromFailedCmd(
375376
'flexStackerShuttleMissing',
376377
'flexStackerHopperLabwareFailed',
377378
'flexStackerLabwareRetrieveFailed',
379+
'flexStackerShuttleOccupied',
378380
].includes(error.errorType)
379381
if (recentRelevantFailedLabwareCmd == null) {
380382
return null

0 commit comments

Comments
 (0)