Skip to content

Commit

Permalink
fix(app): Debounce jog controls during DTWiz (#15968)
Browse files Browse the repository at this point in the history
Closes RQA-2951

In Error Recovery (and DTWiz in general), the pipette is z-homed before users move to a location to drop tips. Because this location is quite far from the deck, users will likely want to press their arrow keys to jog the pipette quickly, and this will in turn cause the robot to execute potentially 50+ moveRelative commands with no way of stopping it.

While not debouncing other flows with jog controls (ex, LPC) has historical context and is less prone to users over-clicking the jog buttons, we should debounce the jog controls within dt wiz.

The solution here is to allow a queue of MAX_QUEUED_JOGS. Three is reasonable after testing.
  • Loading branch information
mjhuff authored Aug 12, 2024
1 parent 1201666 commit 09ccbbc
Showing 1 changed file with 29 additions and 4 deletions.
33 changes: 29 additions & 4 deletions app/src/organisms/DropTipWizardFlows/hooks/useDropTipCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type { RunCommandByCommandTypeParams } from './useDropTipCreateCommands'

const JOG_COMMAND_TIMEOUT_MS = 10000
const MAXIMUM_BLOWOUT_FLOW_RATE_UL_PER_S = 50
const MAX_QUEUED_JOGS = 3

type UseDropTipSetupCommandsParams = UseDTWithTypeParams & {
activeMaintenanceRunId: string | null
Expand All @@ -35,18 +36,16 @@ type UseDropTipSetupCommandsParams = UseDTWithTypeParams & {
}

export interface UseDropTipCommandsResult {
/* */
handleCleanUpAndClose: (homeOnExit?: boolean) => Promise<void>
moveToAddressableArea: (addressableArea: AddressableAreaName) => Promise<void>
handleJog: (axis: Axis, dir: Sign, step: StepSize) => Promise<void>
handleJog: (axis: Axis, dir: Sign, step: StepSize) => void
blowoutOrDropTip: (
currentStep: DropTipFlowsStep,
proceed: () => void
) => Promise<void>
handleMustHome: () => Promise<void>
}

// Returns setup commands used in Drop Tip Wizard.
export function useDropTipCommands({
issuedCommandsType,
toggleIsExiting,
Expand All @@ -61,6 +60,8 @@ export function useDropTipCommands({
}: UseDropTipSetupCommandsParams): UseDropTipCommandsResult {
const isFlex = robotType === FLEX_ROBOT_TYPE
const [hasSeenClose, setHasSeenClose] = React.useState(false)
const [jogQueue, setJogQueue] = React.useState<Array<() => Promise<void>>>([])
const [isJogging, setIsJogging] = React.useState(false)

const { deleteMaintenanceRun } = useDeleteMaintenanceRunMutation({
onSuccess: () => {
Expand Down Expand Up @@ -149,7 +150,7 @@ export function useDropTipCommands({
})
}

const handleJog = (axis: Axis, dir: Sign, step: StepSize): Promise<void> => {
const executeJog = (axis: Axis, dir: Sign, step: StepSize): Promise<void> => {
return new Promise((resolve, reject) => {
return runCommand({
command: {
Expand All @@ -175,6 +176,30 @@ export function useDropTipCommands({
})
}

const processJogQueue = (): void => {
if (jogQueue.length > 0 && !isJogging) {
setIsJogging(true)
const nextJog = jogQueue[0]
setJogQueue(prevQueue => prevQueue.slice(1))
nextJog().finally(() => {
setIsJogging(false)
})
}
}

React.useEffect(() => {
processJogQueue()
}, [jogQueue.length, isJogging])

const handleJog = (axis: Axis, dir: Sign, step: StepSize): void => {
setJogQueue(prevQueue => {
if (prevQueue.length < MAX_QUEUED_JOGS) {
return [...prevQueue, () => executeJog(axis, dir, step)]
}
return prevQueue
})
}

const blowoutOrDropTip = (
currentStep: DropTipFlowsStep,
proceed: () => void
Expand Down

0 comments on commit 09ccbbc

Please sign in to comment.