Skip to content

Commit

Permalink
refactor(step-generation, protocol-designer): atomic command args to … (
Browse files Browse the repository at this point in the history
#17324)

…match command params

AUTH-1361

This is Pt2 of refactoring the atomic command args to match command
params. all the module atomic commands were updated in pt1 so this
refactors the remaining atomic commands
jerader authored Jan 27, 2025
1 parent 14f956d commit b5f09dd
Showing 51 changed files with 863 additions and 894 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { LabwareMovementStrategy } from '@opentrons/shared-data'
import type { HydratedMoveLabwareFormData } from '../../../form-types'
import type { MoveLabwareArgs } from '@opentrons/step-generation'

@@ -16,8 +17,10 @@ export const moveLabwareFormToArgs = (
commandCreatorFnName: 'moveLabware',
name: stepName,
description: stepDetails,
labware: labware.id,
useGripper,
labwareId: labware.id,
newLocation,
strategy: useGripper
? 'usingGripper'
: ('manualMoveWithPause' as LabwareMovementStrategy),
}
}
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ export const pauseFormToArgs = (
commandCreatorFnName: 'delay',
name: formData.stepName,
description: formData.stepDetails ?? '',
wait: totalSeconds,
seconds: totalSeconds,
message,
meta: {
hours,
@@ -48,7 +48,6 @@ export const pauseFormToArgs = (
commandCreatorFnName: 'delay',
name: formData.stepName,
description: formData.stepDetails ?? '',
wait: true,
message,
meta: {
hours,
Original file line number Diff line number Diff line change
@@ -41,7 +41,6 @@ describe('pauseFormToArgs', () => {
const expected = {
commandCreatorFnName: 'delay',
name: 'pause step',
wait: true,
message: 'some message',
description: 'some details',
meta: {
@@ -66,7 +65,7 @@ describe('pauseFormToArgs', () => {
const expected = {
commandCreatorFnName: 'delay',
name: 'pause step',
wait: 3600 + 20 * 60 + 5,
seconds: 3600 + 20 * 60 + 5,
message: 'some message',
description: 'some details',
meta: {
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import {
reduceCommandCreators,
commandCreatorsTimeline,
getPipetteIdFromCCArgs,
ZERO_OFFSET,
} from '@opentrons/step-generation'
import { commandCreatorFromStepArgs } from '../file-data/helpers'
import type { StepArgsAndErrorsById } from '../steplist/types'
@@ -95,6 +96,7 @@ export const generateRobotStateTimeline = (
curryCommandCreator(moveToAddressableArea, {
pipetteId,
addressableAreaName,
offset: ZERO_OFFSET,
}),
curryCommandCreator(dropTipInPlace, {
pipetteId,
2 changes: 1 addition & 1 deletion protocol-designer/src/ui/steps/selectors.ts
Original file line number Diff line number Diff line change
@@ -154,7 +154,7 @@ export const getHoveredStepLabware = createSelector(
}

if (stepArgs.commandCreatorFnName === 'moveLabware') {
const src = stepArgs.labware
const src = stepArgs.labwareId
return [src]
}

14 changes: 9 additions & 5 deletions protocol-designer/src/ui/steps/test/selectors.test.ts
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ import { getMockMoveLiquidStep, getMockMixStep } from '../__fixtures__'

import * as utils from '../../modules/utils'

import type { MoveLabwareArgs } from '@opentrons/step-generation'
import type { FormData } from '../../../form-types'
import type { StepArgsAndErrorsById } from '../../../steplist/types'
import type { AllTemporalPropertiesForTimelineFrame } from '../../../step-forms'
@@ -46,7 +47,6 @@ function createArgsForStepId(
const hoveredStepId = 'hoveredStepId'
const labware = 'well plate'
const mixCommand = 'mix'
const moveLabwareCommand = 'moveLabware'
describe('getHoveredStepLabware', () => {
let initialDeckState: AllTemporalPropertiesForTimelineFrame
beforeEach(() => {
@@ -135,9 +135,13 @@ describe('getHoveredStepLabware', () => {
})

it('correct labware is returned when command is moveLabware', () => {
const stepArgs = {
commandCreatorFnName: moveLabwareCommand,
labware,
const stepArgs: MoveLabwareArgs = {
labwareId: labware,
strategy: 'usingGripper',
newLocation: { slotName: 'A1' },
commandCreatorFnName: 'moveLabware',
name: 'some name',
description: 'some description',
}
const argsByStepId = createArgsForStepId(hoveredStepId, stepArgs)
const result = getHoveredStepLabware.resultFunc(
@@ -146,7 +150,7 @@ describe('getHoveredStepLabware', () => {
initialDeckState
)

expect(result).toEqual([labware])
expect(result).toEqual([stepArgs.labwareId])
})

describe('modules', () => {
2 changes: 1 addition & 1 deletion shared-data/command/types/annotation.ts
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ export interface CommentRunTimeCommand
result?: any
}

interface CommentParams {
export interface CommentParams {
message: string
}

2 changes: 1 addition & 1 deletion shared-data/command/types/gantry.ts
Original file line number Diff line number Diff line change
@@ -163,7 +163,7 @@ interface RetractAxisParams {
axis: MotorAxis
}

interface AddressableOffsetVector {
export interface AddressableOffsetVector {
x: number
y: number
z: number
2 changes: 1 addition & 1 deletion shared-data/command/types/setup.ts
Original file line number Diff line number Diff line change
@@ -199,7 +199,7 @@ interface NozzleConfigurationParams {
style: NozzleConfigurationStyle
}

interface ConfigureNozzleLayoutParams {
export interface ConfigureNozzleLayoutParams {
pipetteId: string
configurationParams: NozzleConfigurationParams
}
4 changes: 2 additions & 2 deletions shared-data/command/types/timing.ts
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ export interface WaitForResumeRunTimeCommand
result?: any
}

interface WaitForResumeParams {
export interface WaitForResumeParams {
message?: string
}

@@ -37,7 +37,7 @@ export interface WaitForDurationRunTimeCommand
result?: any
}

interface WaitForDurationParams {
export interface WaitForDurationParams {
seconds: number
message?: string
}
175 changes: 56 additions & 119 deletions step-generation/src/__tests__/aspirate.test.ts
Original file line number Diff line number Diff line change
@@ -11,7 +11,6 @@ import {
} from '@opentrons/shared-data'

import {
absorbanceReaderCollision,
pipetteIntoHeaterShakerLatchOpen,
thermocyclerPipetteCollision,
pipetteIntoHeaterShakerWhileShaking,
@@ -30,8 +29,10 @@ import {
SOURCE_LABWARE,
getInitialRobotStateWithOffDeckLabwareStandard,
} from '../fixtures'
import type { LabwareDefinition2 } from '@opentrons/shared-data'
import type { AspDispAirgapParams } from '@opentrons/shared-data/protocol/types/schemaV3'
import type {
LabwareDefinition2,
AspDispAirgapParams,
} from '@opentrons/shared-data'
import type { InvariantContext, RobotState } from '../'

const fixtureTiprack10ul = tip10 as LabwareDefinition2
@@ -54,7 +55,10 @@ describe('aspirate', () => {
robotStateWithTip = getRobotStateWithTipStandard(invariantContext)
flowRateAndOffsets = {
flowRate: 6,
offsetFromBottomMm: 5,
wellLocation: {
origin: 'bottom',
offset: { z: 5, y: 0, x: 0 },
},
}
})
afterEach(() => {
@@ -64,14 +68,12 @@ describe('aspirate', () => {
const params = {
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tiprack1Id',
xOffset: 0,
yOffset: 0,
nozzles: null,
}
const result = aspirate(params, invariantContext, robotStateWithTip)
@@ -108,14 +110,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 201,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tiprack1Id',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -138,14 +138,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 301,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -161,14 +159,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: 'badPipette',
pipetteId: 'badPipette',
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -181,14 +177,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -204,14 +198,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: 'problemaaticLabwareId',
well: 'A1',
labwareId: 'problemaaticLabwareId',
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -231,14 +223,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -266,14 +256,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -284,41 +272,6 @@ describe('aspirate', () => {
type: 'THERMOCYCLER_LID_CLOSED',
})
})
it('should return an error when aspirating from absorbance with pipette collision', () => {
vi.mocked(absorbanceReaderCollision).mockImplementationOnce(
(
modules: RobotState['modules'],
labware: RobotState['labware'],
labwareId: string
) => {
expect(modules).toBe(robotStateWithTip.modules)
expect(labware).toBe(robotStateWithTip.labware)
expect(labwareId).toBe(SOURCE_LABWARE)
return true
}
)
const result = aspirate(
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
robotStateWithTip
)
expect(getErrorResult(result).errors).toHaveLength(1)
expect(getErrorResult(result).errors[0]).toMatchObject({
type: 'ABSORBANCE_READER_LID_CLOSED',
})
})
it('should return an error when aspirating from heaterShaker with latch opened', () => {
vi.mocked(pipetteIntoHeaterShakerLatchOpen).mockImplementationOnce(
(
@@ -336,14 +289,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -377,14 +328,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -412,14 +361,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -453,14 +400,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -484,14 +429,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -514,14 +457,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -545,14 +486,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
@@ -577,14 +516,12 @@ describe('aspirate', () => {
{
...({
...flowRateAndOffsets,
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
} as AspDispAirgapParams),
tipRack: 'tipRack',
xOffset: 0,
yOffset: 0,
nozzles: null,
},
invariantContext,
1 change: 1 addition & 0 deletions step-generation/src/__tests__/blowout.test.ts
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@ describe('blowout', () => {
wellName: 'A1',
flowRate: 21.1,
wellLocation: {
origin: 'top',
offset: {
z: -1.3,
},
12 changes: 8 additions & 4 deletions step-generation/src/__tests__/blowoutUtil.test.ts
Original file line number Diff line number Diff line change
@@ -22,15 +22,15 @@ import {
getInitialRobotStateStandard,
} from '../fixtures'
import type { RobotState, InvariantContext } from '../types'
import type { BlowoutParams } from '@opentrons/shared-data/protocol/types/schemaV3'
import type { BlowoutParams } from '@opentrons/shared-data'
vi.mock('../utils/curryCommandCreator')

let blowoutArgs: {
pipette: BlowoutParams['pipette']
pipette: BlowoutParams['pipetteId']
sourceLabwareId: string
sourceWell: BlowoutParams['well']
sourceWell: BlowoutParams['wellName']
destLabwareId: string
destWell: BlowoutParams['well']
destWell: BlowoutParams['wellName']
blowoutLocation: string | null | undefined
flowRate: number
offsetFromTopMm: number
@@ -68,6 +68,7 @@ describe('blowoutUtil', () => {
wellName: blowoutArgs.sourceWell,
flowRate: blowoutArgs.flowRate,
wellLocation: {
origin: 'top',
offset: {
z: expect.any(Number),
},
@@ -96,6 +97,7 @@ describe('blowoutUtil', () => {
expect(curryCommandCreator).toHaveBeenCalledWith(moveToAddressableArea, {
addressableAreaName: ONE_CHANNEL_WASTE_CHUTE_ADDRESSABLE_AREA,
pipetteId: blowoutArgs.pipette,
offset: { x: 0, y: 0, z: 0 },
})
expect(curryCommandCreator).toHaveBeenCalledWith(blowOutInPlace, {
flowRate: 2.3,
@@ -113,6 +115,7 @@ describe('blowoutUtil', () => {
wellName: blowoutArgs.destWell,
flowRate: blowoutArgs.flowRate,
wellLocation: {
origin: 'top',
offset: {
z: expect.any(Number),
},
@@ -130,6 +133,7 @@ describe('blowoutUtil', () => {
wellName: 'A1',
flowRate: blowoutArgs.flowRate,
wellLocation: {
origin: 'top',
offset: {
z: expect.any(Number),
},
16 changes: 14 additions & 2 deletions step-generation/src/__tests__/configureNozzleLayout.test.ts
Original file line number Diff line number Diff line change
@@ -14,7 +14,13 @@ const mockPipette = 'mockPipette'
describe('configureNozzleLayout', () => {
it('should call configureNozzleLayout with correct params for full tip', () => {
const result = configureNozzleLayout(
{ nozzles: ALL, pipetteId: mockPipette },
{
configurationParams: {
primaryNozzle: undefined,
style: ALL,
},
pipetteId: mockPipette,
},
invariantContext,
robotInitialState
)
@@ -32,7 +38,13 @@ describe('configureNozzleLayout', () => {
})
it('should call configureNozzleLayout with correct params for column tip', () => {
const result = configureNozzleLayout(
{ nozzles: COLUMN, pipetteId: mockPipette },
{
configurationParams: {
primaryNozzle: 'A12',
style: COLUMN,
},
pipetteId: mockPipette,
},
invariantContext,
robotInitialState
)
15 changes: 3 additions & 12 deletions step-generation/src/__tests__/delay.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { beforeEach, describe, it, expect } from 'vitest'
import { describe, it, expect } from 'vitest'
import { delay } from '../commandCreators/atomic/delay'
import { getSuccessResult } from '../fixtures'
import type { PauseArgs } from '../types'
@@ -11,21 +11,12 @@ const getRobotInitialState = (): any => {
// neither should InvariantContext
const invariantContext: any = {}
let mixInArgs: PauseArgs
beforeEach(() => {
mixInArgs = {
commandCreatorFnName: 'delay',
meta: null,
name: 'Delay Test',
description: 'test blah blah',
wait: true,
}
})
describe('delay', () => {
it('should delay until the user clicks resume', () => {
const robotInitialState = getRobotInitialState()
const message = 'delay indefinitely message'
const result = delay(
{ ...mixInArgs, message, wait: true },
{ ...mixInArgs, message },
invariantContext,
robotInitialState
)
@@ -45,7 +36,7 @@ describe('delay', () => {
const robotInitialState = getRobotInitialState()
const message = 'delay 95.5 secs message'
const result = delay(
{ ...mixInArgs, message, wait: 95.5 },
{ ...mixInArgs, message, seconds: 95.5 },
invariantContext,
robotInitialState
)
32 changes: 17 additions & 15 deletions step-generation/src/__tests__/dispense.test.ts
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ import {
SOURCE_LABWARE,
} from '../fixtures'
import { dispense } from '../commandCreators/atomic/dispense'
import type { ExtendedDispenseParams } from '../commandCreators/atomic/dispense'
import type { DispenseAtomicCommandParams } from '../commandCreators/atomic/dispense'
import type { InvariantContext, RobotState } from '../types'

vi.mock('../utils/absorbanceReaderCollision')
@@ -45,17 +45,18 @@ describe('dispense', () => {
vi.resetAllMocks()
})
describe('tip tracking & commands:', () => {
let params: ExtendedDispenseParams
let params: DispenseAtomicCommandParams
beforeEach(() => {
params = {
pipette: DEFAULT_PIPETTE,
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
offsetFromBottomMm: 5,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
wellLocation: {
origin: 'bottom',
offset: { z: 5, x: 0, y: 0 },
},
flowRate: 6,
xOffset: 0,
yOffset: 0,
tipRack: 'tiprack1Id',
nozzles: null,
}
@@ -99,13 +100,14 @@ describe('dispense', () => {
const result = dispense(
{
flowRate: 10,
offsetFromBottomMm: 5,
pipette: DEFAULT_PIPETTE,
wellLocation: {
origin: 'bottom',
offset: { z: 5, x: 0, y: 0 },
},
pipetteId: DEFAULT_PIPETTE,
volume: 50,
labware: SOURCE_LABWARE,
well: 'A1',
xOffset: 0,
yOffset: 0,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
tipRack: 'tiprack1Id',
nozzles: null,
},
@@ -119,7 +121,7 @@ describe('dispense', () => {
})
it('dispense to nonexistent labware should throw error', () => {
const result = dispense(
{ ...params, labware: 'someBadLabwareId' },
{ ...params, labwareId: 'someBadLabwareId' },
invariantContext,
robotStateWithTip
)
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ const mockCutout = 'cutoutA3'
const mockMoveToAddressableAreaParams = {
pipetteId: mockId,
addressableAreaName: 'movableTrashA3',
offset: { x: 0, y: 0, z: 0 },
}
const invariantContext = makeContext()

@@ -88,7 +89,10 @@ describe('movableTrashCommandsUtil', () => {
})
expect(curryCommandCreator).toHaveBeenCalledWith(
moveToAddressableAreaForDropTip,
mockMoveToAddressableAreaParams
{
pipetteId: mockId,
addressableAreaName: 'movableTrashA3',
}
)
expect(curryCommandCreator).toHaveBeenCalledWith(dropTipInPlace, {
pipetteId: mockId,
125 changes: 55 additions & 70 deletions step-generation/src/__tests__/moveLabware.test.ts
Original file line number Diff line number Diff line change
@@ -15,9 +15,11 @@ import {
} from '../fixtures'
import { moveLabware } from '..'

import type { LabwareDefinition2 } from '@opentrons/shared-data'
import type {
LabwareDefinition2,
MoveLabwareParams,
} from '@opentrons/shared-data'
import type { InvariantContext, RobotState } from '../types'
import type { MoveLabwareArgs } from '..'

const mockWasteChuteId = 'mockWasteChuteId'
const mockGripperId = 'mockGripperId'
@@ -44,11 +46,10 @@ describe('moveLabware', () => {
})
it('should return a moveLabware command for manualMoveWithPause given only the required params', () => {
const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: false,
labwareId: SOURCE_LABWARE,
strategy: 'manualMoveWithPause',
newLocation: { slotName: 'A1' },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, invariantContext, robotState)
expect(getSuccessResult(result).commands).toEqual([
@@ -65,11 +66,10 @@ describe('moveLabware', () => {
})
it('should return a moveLabware command for moving with a gripper given only the required params', () => {
const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: true,
labwareId: SOURCE_LABWARE,
strategy: 'usingGripper',
newLocation: { slotName: 'A1' },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, invariantContext, robotState)
expect(getSuccessResult(result).commands).toEqual([
@@ -86,11 +86,10 @@ describe('moveLabware', () => {
})
it('should return an error for labware does not exist with bad labwareid', () => {
const params = {
commandCreatorFnName: 'moveLabware',
labware: 'badLabware',
useGripper: true,
labwareId: 'badLabware',
strategy: 'usingGripper',
newLocation: { slotName: 'A1' },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, invariantContext, robotState)
expect(getErrorResult(result).errors).toHaveLength(1)
@@ -103,11 +102,10 @@ describe('moveLabware', () => {
invariantContext
)
const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: true,
labwareId: SOURCE_LABWARE,
strategy: 'usingGripper',
newLocation: { slotName: 'A1' },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, invariantContext, robotState)
expect(getErrorResult(result).errors).toHaveLength(1)
@@ -117,11 +115,10 @@ describe('moveLabware', () => {
})
it('should return an error for trying to move the labware to an occupied slot', () => {
const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: true,
labwareId: SOURCE_LABWARE,
strategy: 'usingGripper',
newLocation: { slotName: '1' },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, invariantContext, robotState)
expect(getErrorResult(result).errors).toHaveLength(1)
@@ -146,11 +143,10 @@ describe('moveLabware', () => {
[SOURCE_LABWARE]: { slot: 'gripperWasteChute' },
}
const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: true,
labwareId: SOURCE_LABWARE,
strategy: 'usingGripper',
newLocation: { slotName: 'A1' },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, wasteChuteInvariantContext, robotState)
expect(getErrorResult(result).errors).toHaveLength(1)
@@ -160,11 +156,10 @@ describe('moveLabware', () => {
})
it('should return an error for trying to move the labware off deck with a gripper', () => {
const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: true,
labwareId: SOURCE_LABWARE,
strategy: 'usingGripper',
newLocation: 'offDeck',
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, invariantContext, robotState)
expect(getErrorResult(result).errors).toHaveLength(1)
@@ -195,11 +190,10 @@ describe('moveLabware', () => {
}

const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: true,
labwareId: SOURCE_LABWARE,
strategy: 'usingGripper',
newLocation: { slotName: 'A1' },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, invariantContext, robotState)
expect(getErrorResult(result).errors).toHaveLength(1)
@@ -219,11 +213,10 @@ describe('moveLabware', () => {
const tcRobotState = stateAndContext.robotState

const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: false,
labwareId: SOURCE_LABWARE,
strategy: 'manualMoveWithPause',
newLocation: { moduleId: thermocyclerId },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, tcInvariantContext, tcRobotState)
expect(getErrorResult(result).errors).toHaveLength(1)
@@ -251,11 +244,10 @@ describe('moveLabware', () => {
},
}
const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: true,
labwareId: SOURCE_LABWARE,
strategy: 'usingGripper',
newLocation: { moduleId: HEATER_SHAKER_ID },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, invariantContext, robotState)
expect(getErrorResult(result).errors).toHaveLength(1)
@@ -290,11 +282,10 @@ describe('moveLabware', () => {
},
}
const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: true,
labwareId: SOURCE_LABWARE,
strategy: 'usingGripper',
newLocation: { labwareId: ADAPTER_ID },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, invariantContext, robotState)
expect(getErrorResult(result).errors).toHaveLength(1)
@@ -322,11 +313,10 @@ describe('moveLabware', () => {
},
}
const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: true,
labwareId: SOURCE_LABWARE,
strategy: 'usingGripper',
newLocation: { moduleId: HEATER_SHAKER_ID },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, invariantContext, robotState)
expect(getErrorResult(result).errors).toHaveLength(1)
@@ -359,11 +349,10 @@ describe('moveLabware', () => {
},
} as any) as RobotState
const params = {
commandCreatorFnName: 'moveLabware',
labware: TIPRACK_1,
useGripper: true,
labwareId: TIPRACK_1,
strategy: 'usingGripper',
newLocation: { addressableAreaName: 'gripperWasteChute' },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(
params,
@@ -398,11 +387,10 @@ describe('moveLabware', () => {
},
} as any) as RobotState
const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: true,
labwareId: SOURCE_LABWARE,
strategy: 'usingGripper',
newLocation: { addressableAreaName: 'gripperWasteChute' },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(
params,
@@ -423,11 +411,10 @@ describe('moveLabware', () => {
} as InvariantContext

const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: true,
labwareId: SOURCE_LABWARE,
strategy: 'usingGripper',
newLocation: { slotName: 'A1' },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, invariantContext, robotState)
expect(getErrorResult(result).errors).toHaveLength(1)
@@ -449,11 +436,10 @@ describe('moveLabware', () => {
} as InvariantContext

const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: false,
labwareId: SOURCE_LABWARE,
strategy: 'manualMoveWithPause',
newLocation: { addressableAreaName: 'gripperWasteChute' },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, invariantContext, robotState)
expect(getErrorResult(result).errors).toHaveLength(1)
@@ -475,11 +461,10 @@ describe('moveLabware', () => {
} as any) as RobotState

const params = {
commandCreatorFnName: 'moveLabware',
labware: SOURCE_LABWARE,
useGripper: true,
labwareId: SOURCE_LABWARE,
strategy: 'usingGripper',
newLocation: { addressableAreaName: 'gripperWasteChute' },
} as MoveLabwareArgs
} as MoveLabwareParams

const result = moveLabware(params, invariantContext, robotStateWithTipOnPip)
expect(getErrorResult(result).errors).toHaveLength(1)
6 changes: 5 additions & 1 deletion step-generation/src/__tests__/moveToAddressableArea.test.ts
Original file line number Diff line number Diff line change
@@ -20,7 +20,11 @@ describe('moveToAddressableArea', () => {
const robotInitialState = getRobotInitialState()
const mockName = '1ChannelWasteChute'
const result = moveToAddressableArea(
{ pipetteId: mockId, addressableAreaName: mockName },
{
pipetteId: mockId,
addressableAreaName: mockName,
offset: { x: 0, y: 0, z: 0 },
},
invariantContext,
robotInitialState
)
119 changes: 61 additions & 58 deletions step-generation/src/__tests__/moveToWell.test.ts
Original file line number Diff line number Diff line change
@@ -43,9 +43,9 @@ describe('moveToWell', () => {
})
it('should return a moveToWell command given only the required params', () => {
const params = {
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
}
const result = moveToWell(params, invariantContext, robotStateWithTip)
expect(getSuccessResult(result).commands).toEqual([
@@ -62,13 +62,16 @@ describe('moveToWell', () => {
})
it('should apply the optional params to the command', () => {
const params = {
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
offset: {
x: 1,
y: 2,
z: 3,
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
wellLocation: {
origin: 'bottom' as any,
offset: {
x: 1,
y: 2,
z: 3,
},
},
minimumZHeight: 5,
forceDirect: true,
@@ -99,9 +102,9 @@ describe('moveToWell', () => {
it('should return an error if pipette does not exist', () => {
const result = moveToWell(
{
pipette: 'badPipette',
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: 'badPipette',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -111,9 +114,9 @@ describe('moveToWell', () => {
it('should return error if labware does not exist', () => {
const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: 'problematicLabwareId',
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: 'problematicLabwareId',
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -129,9 +132,9 @@ describe('moveToWell', () => {
)
const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
initialRobotState
@@ -150,9 +153,9 @@ describe('moveToWell', () => {
}
const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -177,9 +180,9 @@ describe('moveToWell', () => {
)
const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -204,9 +207,9 @@ describe('moveToWell', () => {
)
const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -232,9 +235,9 @@ describe('moveToWell', () => {
)
const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -266,9 +269,9 @@ describe('moveToWell', () => {
)
const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -307,9 +310,9 @@ describe('moveToWell', () => {

const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -348,9 +351,9 @@ describe('moveToWell', () => {

const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -395,9 +398,9 @@ describe('moveToWell', () => {

const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -437,9 +440,9 @@ describe('moveToWell', () => {

const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -462,9 +465,9 @@ describe('moveToWell', () => {

const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -485,9 +488,9 @@ describe('moveToWell', () => {

const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -508,9 +511,9 @@ describe('moveToWell', () => {

const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
@@ -532,9 +535,9 @@ describe('moveToWell', () => {

const result = moveToWell(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
},
invariantContext,
robotStateWithTip
2 changes: 1 addition & 1 deletion step-generation/src/__tests__/replaceTip.test.ts
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ import {
DEFAULT_PIPETTE,
PIPETTE_96,
} from '../fixtures'
import { replaceTip } from '../commandCreators/atomic/replaceTip'
import { replaceTip } from '../commandCreators/compound/replaceTip'
import { FIXED_TRASH_ID } from '../constants'
import type { LabwareDefinition2 } from '@opentrons/shared-data'
import type { InvariantContext, RobotState } from '../types'
29 changes: 17 additions & 12 deletions step-generation/src/__tests__/touchTip.test.ts
Original file line number Diff line number Diff line change
@@ -12,6 +12,11 @@ import {
} from '../fixtures'
import type { InvariantContext, RobotState } from '../types'

const wellLocation: any = {
origin: 'bottom',
offset: { z: 10 },
}

describe('touchTip', () => {
let invariantContext: InvariantContext
let initialRobotState: RobotState
@@ -26,10 +31,10 @@ describe('touchTip', () => {
it('touchTip with tip, specifying offsetFromBottomMm', () => {
const result = touchTip(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
offsetFromBottomMm: 10,
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
wellLocation,
},
invariantContext,
robotStateWithTip
@@ -58,10 +63,10 @@ describe('touchTip', () => {
it('touchTip with invalid pipette ID should throw error', () => {
const result = touchTip(
{
pipette: 'badPipette',
labware: SOURCE_LABWARE,
well: 'A1',
offsetFromBottomMm: 10,
pipetteId: 'badPipette',
labwareId: SOURCE_LABWARE,
wellName: 'A1',
wellLocation,
},
invariantContext,
robotStateWithTip
@@ -74,10 +79,10 @@ describe('touchTip', () => {
it('touchTip with no tip should throw error', () => {
const result = touchTip(
{
pipette: DEFAULT_PIPETTE,
labware: SOURCE_LABWARE,
well: 'A1',
offsetFromBottomMm: 10,
pipetteId: DEFAULT_PIPETTE,
labwareId: SOURCE_LABWARE,
wellName: 'A1',
wellLocation,
},
invariantContext,
initialRobotState
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ const args = {
const mockMoveToAddressableAreaParams = {
pipetteId: mockId,
addressableAreaName: mockAddressableAreaName,
offset: { x: 0, y: 0, z: 0 },
}

const mockPipEntities: PipetteEntities = {
82 changes: 36 additions & 46 deletions step-generation/src/commandCreators/atomic/aspirate.ts
Original file line number Diff line number Diff line change
@@ -19,15 +19,14 @@ import { COLUMN_4_SLOTS } from '../../constants'
import type {
CreateCommand,
NozzleConfigurationStyle,
AspDispAirgapParams,
} from '@opentrons/shared-data'
import type { AspirateParams } from '@opentrons/shared-data/protocol/types/schemaV3'
import type { CommandCreator, CommandCreatorError } from '../../types'

export interface ExtendedAspirateParams extends AspirateParams {
xOffset: number
yOffset: number
import type { Point } from '../../utils'
export interface ExtendedAspirateParams extends AspDispAirgapParams {
tipRack: string
nozzles: NozzleConfigurationStyle | null
isAirGap?: boolean
}
/** Aspirate with given args. Requires tip. */
export const aspirate: CommandCreator<ExtendedAspirateParams> = (
@@ -36,48 +35,46 @@ export const aspirate: CommandCreator<ExtendedAspirateParams> = (
prevRobotState
) => {
const {
pipette,
pipetteId,
volume,
labware,
well,
offsetFromBottomMm,
labwareId,
wellName,
flowRate,
isAirGap,
tipRack,
xOffset,
yOffset,
wellLocation,
nozzles,
} = args
const actionName = 'aspirate'
const labwareState = prevRobotState.labware
const errors: CommandCreatorError[] = []
const pipetteSpec = invariantContext.pipetteEntities[pipette]?.spec
const pipetteSpec = invariantContext.pipetteEntities[pipetteId]?.spec
const isFlexPipette =
(pipetteSpec?.displayCategory === 'FLEX' || pipetteSpec?.channels === 96) ??
false

const slotName = getLabwareSlot(
labware,
labwareId,
prevRobotState.labware,
prevRobotState.modules
)

if (!pipetteSpec) {
errors.push(
errorCreators.pipetteDoesNotExist({
pipette,
pipette: pipetteId,
})
)
}

if (!labware || !prevRobotState.labware[labware]) {
if (!labwareId || !prevRobotState.labware[labwareId]) {
errors.push(
errorCreators.labwareDoesNotExist({
actionName,
labware,
labware: labwareId,
})
)
} else if (prevRobotState.labware[labware].slot === 'offDeck') {
} else if (prevRobotState.labware[labwareId].slot === 'offDeck') {
errors.push(errorCreators.labwareOffDeck())
}

@@ -94,40 +91,40 @@ export const aspirate: CommandCreator<ExtendedAspirateParams> = (

if (
modulePipetteCollision({
pipette,
labware,
pipette: pipetteId,
labware: labwareId,
invariantContext,
prevRobotState,
})
) {
errors.push(errorCreators.modulePipetteCollisionDanger())
}

if (!prevRobotState.tipState.pipettes[pipette]) {
if (!prevRobotState.tipState.pipettes[pipetteId]) {
errors.push(
errorCreators.noTipOnPipette({
actionName,
pipette,
labware,
well,
pipette: pipetteId,
labware: labwareId,
well: wellName,
})
)
}

const is96Channel =
invariantContext.pipetteEntities[args.pipette]?.spec.channels === 96
invariantContext.pipetteEntities[pipetteId]?.spec.channels === 96

if (
is96Channel &&
nozzles === COLUMN &&
!getIsSafePipetteMovement(
prevRobotState,
invariantContext,
args.pipette,
args.labware,
args.tipRack,
{ x: xOffset, y: yOffset, z: offsetFromBottomMm },
args.well
pipetteId,
labwareId,
tipRack,
(wellLocation?.offset as Point) ?? { x: 0, y: 0, z: 0 },
wellName
)
) {
errors.push(errorCreators.possiblePipetteCollision())
@@ -137,7 +134,7 @@ export const aspirate: CommandCreator<ExtendedAspirateParams> = (
thermocyclerPipetteCollision(
prevRobotState.modules,
prevRobotState.labware,
labware
labwareId
)
) {
errors.push(errorCreators.thermocyclerLidClosed())
@@ -147,7 +144,7 @@ export const aspirate: CommandCreator<ExtendedAspirateParams> = (
absorbanceReaderCollision(
prevRobotState.modules,
prevRobotState.labware,
labware
labwareId
)
) {
errors.push(errorCreators.absorbanceReaderLidClosed())
@@ -157,7 +154,7 @@ export const aspirate: CommandCreator<ExtendedAspirateParams> = (
pipetteIntoHeaterShakerLatchOpen(
prevRobotState.modules,
prevRobotState.labware,
labware
labwareId
)
) {
errors.push(errorCreators.heaterShakerLatchOpen())
@@ -167,7 +164,7 @@ export const aspirate: CommandCreator<ExtendedAspirateParams> = (
pipetteIntoHeaterShakerWhileShaking(
prevRobotState.modules,
prevRobotState.labware,
labware
labwareId
)
) {
errors.push(errorCreators.heaterShakerIsShaking())
@@ -203,7 +200,7 @@ export const aspirate: CommandCreator<ExtendedAspirateParams> = (
prevRobotState.modules,
slotName,
pipetteSpec,
invariantContext.labwareEntities[labware]
invariantContext.labwareEntities[labwareId]
)
) {
errors.push(
@@ -227,7 +224,7 @@ export const aspirate: CommandCreator<ExtendedAspirateParams> = (

if (errors.length === 0 && pipetteSpec) {
const tipMaxVolume = getPipetteWithTipMaxVol(
pipette,
pipetteId,
invariantContext,
tipRack
)
@@ -253,18 +250,11 @@ export const aspirate: CommandCreator<ExtendedAspirateParams> = (
commandType: 'aspirate',
key: uuid(),
params: {
pipetteId: pipette,
pipetteId,
volume,
labwareId: labware,
wellName: well,
wellLocation: {
origin: 'bottom',
offset: {
z: offsetFromBottomMm,
x: xOffset,
y: yOffset,
},
},
labwareId,
wellName,
wellLocation,
flowRate,
},
...(isAirGap && { meta: { isAirGap } }),
7 changes: 1 addition & 6 deletions step-generation/src/commandCreators/atomic/blowout.ts
Original file line number Diff line number Diff line change
@@ -193,12 +193,7 @@ export const blowout: CommandCreator<BlowoutParams> = (
labwareId,
wellName,
flowRate,
wellLocation: {
origin: 'top',
offset: {
z: wellLocation?.offset?.z,
},
},
wellLocation,
},
},
]
4 changes: 2 additions & 2 deletions step-generation/src/commandCreators/atomic/comment.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { uuid } from '../../utils'
import type { CommentCreateCommand } from '@opentrons/shared-data'
import type { CommentParams } from '@opentrons/shared-data'
import type { CommandCreator } from '../../types'

export const comment: CommandCreator<CommentCreateCommand['params']> = (
export const comment: CommandCreator<CommentParams> = (
args,
invariantContext,
prevRobotState
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { uuid } from '../../utils'
import type { ConfigureForVolumeParams } from '@opentrons/shared-data'
import type { CommandCreator } from '../../types'
interface configureForVolumeArgs {
pipetteId: string
volume: number
}

export const configureForVolume: CommandCreator<configureForVolumeArgs> = (
export const configureForVolume: CommandCreator<ConfigureForVolumeParams> = (
args,
invariantContext,
prevRobotState
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
import { COLUMN } from '@opentrons/shared-data'
import { uuid } from '../../utils'
import type { ConfigureNozzleLayoutParams } from '@opentrons/shared-data'
import type { CommandCreator } from '../../types'
import type { NozzleConfigurationStyle } from '@opentrons/shared-data'

interface configureNozzleLayoutArgs {
pipetteId: string
nozzles: NozzleConfigurationStyle
}

export const configureNozzleLayout: CommandCreator<configureNozzleLayoutArgs> = (
export const configureNozzleLayout: CommandCreator<ConfigureNozzleLayoutParams> = (
args,
invariantContext,
prevRobotState
) => {
const { pipetteId, nozzles } = args
const { pipetteId, configurationParams } = args

const commands = [
{
commandType: 'configureNozzleLayout' as const,
key: uuid(),
params: {
pipetteId,
configurationParams: {
primaryNozzle: nozzles === COLUMN ? 'A12' : undefined,
style: nozzles,
},
configurationParams,
},
},
]
24 changes: 13 additions & 11 deletions step-generation/src/commandCreators/atomic/delay.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
import { uuid } from '../../utils'
import type { PauseArgs, CommandCreator } from '../../types'
import type {
WaitForDurationCreateCommand,
WaitForDurationParams,
WaitForResumeCreateCommand,
WaitForResumeParams,
} from '@opentrons/shared-data'
export const delay: CommandCreator<PauseArgs> = (
args,
invariantContext,
prevRobotState
) => {
import type { CommandCreator } from '../../types'

export const delay: CommandCreator<
WaitForResumeParams | WaitForDurationParams
> = (args, invariantContext, prevRobotState) => {
const { message } = args
// delay is deprecated and now is either waitForResume or waitForDuration
let command: WaitForResumeCreateCommand | WaitForDurationCreateCommand
if (args.wait === true) {
if ('seconds' in args) {
command = {
commandType: 'waitForResume',
commandType: 'waitForDuration',
key: uuid(),
params: { message: args.message },
params: { seconds: args.seconds, message },
}
} else {
command = {
commandType: 'waitForDuration',
commandType: 'waitForResume',
key: uuid(),
params: { seconds: args.wait, message: args.message },
params: { message },
}
}
return {
84 changes: 38 additions & 46 deletions step-generation/src/commandCreators/atomic/dispense.ts
Original file line number Diff line number Diff line change
@@ -17,86 +17,85 @@ import {
import { COLUMN_4_SLOTS } from '../../constants'
import type {
CreateCommand,
DispenseParams,
NozzleConfigurationStyle,
} from '@opentrons/shared-data'
import type { DispenseParams } from '@opentrons/shared-data/protocol/types/schemaV3'
import type { Point } from '../../utils'
import type { CommandCreator, CommandCreatorError } from '../../types'

export interface ExtendedDispenseParams extends DispenseParams {
xOffset: number
yOffset: number
tipRack: string
export interface DispenseAtomicCommandParams extends DispenseParams {
nozzles: NozzleConfigurationStyle | null
tipRack: string
isAirGap?: boolean
}
/** Dispense with given args. Requires tip. */
export const dispense: CommandCreator<ExtendedDispenseParams> = (
export const dispense: CommandCreator<DispenseAtomicCommandParams> = (
args,
invariantContext,
prevRobotState
) => {
const {
pipette,
pipetteId,
volume,
labware,
well,
offsetFromBottomMm,
labwareId,
wellName,
flowRate,
isAirGap,
xOffset,
yOffset,
wellLocation,
nozzles,
tipRack,
} = args
const actionName = 'dispense'
const labwareState = prevRobotState.labware
const errors: CommandCreatorError[] = []
const pipetteSpec = invariantContext.pipetteEntities[pipette]?.spec
const pipetteSpec = invariantContext.pipetteEntities[pipetteId]?.spec
const isFlexPipette =
(pipetteSpec?.displayCategory === 'FLEX' || pipetteSpec?.channels === 96) ??
false
const slotName = getLabwareSlot(
labware,
labwareId,
prevRobotState.labware,
prevRobotState.modules
)

if (!pipetteSpec) {
errors.push(
errorCreators.pipetteDoesNotExist({
pipette,
pipette: pipetteId,
})
)
}

if (
modulePipetteCollision({
pipette,
labware,
pipette: pipetteId,
labware: labwareId,
invariantContext,
prevRobotState,
})
) {
errors.push(errorCreators.modulePipetteCollisionDanger())
}

if (!prevRobotState.tipState.pipettes[pipette]) {
if (!prevRobotState.tipState.pipettes[pipetteId]) {
errors.push(
errorCreators.noTipOnPipette({
actionName,
pipette,
labware,
well,
pipette: pipetteId,
labware: labwareId,
well: wellName,
})
)
}

if (!labware || !prevRobotState.labware[labware]) {
if (!labwareId || !prevRobotState.labware[labwareId]) {
errors.push(
errorCreators.labwareDoesNotExist({
actionName,
labware,
labware: labwareId,
})
)
} else if (prevRobotState.labware[labware]?.slot === 'offDeck') {
} else if (prevRobotState.labware[labwareId]?.slot === 'offDeck') {
errors.push(errorCreators.labwareOffDeck())
}

@@ -112,19 +111,19 @@ export const dispense: CommandCreator<ExtendedDispenseParams> = (
}

const is96Channel =
invariantContext.pipetteEntities[args.pipette]?.spec.channels === 96
invariantContext.pipetteEntities[pipetteId]?.spec.channels === 96

if (
is96Channel &&
nozzles === COLUMN &&
!getIsSafePipetteMovement(
prevRobotState,
invariantContext,
args.pipette,
args.labware,
args.tipRack,
{ x: xOffset, y: yOffset, z: offsetFromBottomMm },
args.well
pipetteId,
labwareId,
tipRack,
(wellLocation?.offset as Point) ?? { x: 0, y: 0, z: 0 },
wellName
)
) {
errors.push(errorCreators.possiblePipetteCollision())
@@ -134,7 +133,7 @@ export const dispense: CommandCreator<ExtendedDispenseParams> = (
thermocyclerPipetteCollision(
prevRobotState.modules,
prevRobotState.labware,
labware
labwareId
)
) {
errors.push(errorCreators.thermocyclerLidClosed())
@@ -144,7 +143,7 @@ export const dispense: CommandCreator<ExtendedDispenseParams> = (
absorbanceReaderCollision(
prevRobotState.modules,
prevRobotState.labware,
labware
labwareId
)
) {
errors.push(errorCreators.absorbanceReaderLidClosed())
@@ -154,7 +153,7 @@ export const dispense: CommandCreator<ExtendedDispenseParams> = (
pipetteIntoHeaterShakerLatchOpen(
prevRobotState.modules,
prevRobotState.labware,
labware
labwareId
)
) {
errors.push(errorCreators.heaterShakerLatchOpen())
@@ -164,7 +163,7 @@ export const dispense: CommandCreator<ExtendedDispenseParams> = (
pipetteIntoHeaterShakerWhileShaking(
prevRobotState.modules,
prevRobotState.labware,
labware
labwareId
)
) {
errors.push(errorCreators.heaterShakerIsShaking())
@@ -199,7 +198,7 @@ export const dispense: CommandCreator<ExtendedDispenseParams> = (
prevRobotState.modules,
slotName,
pipetteSpec,
invariantContext.labwareEntities[labware]
invariantContext.labwareEntities[labwareId]
)
) {
errors.push(
@@ -218,18 +217,11 @@ export const dispense: CommandCreator<ExtendedDispenseParams> = (
commandType: 'dispense',
key: uuid(),
params: {
pipetteId: pipette,
pipetteId,
volume,
labwareId: labware,
wellName: well,
wellLocation: {
origin: 'bottom',
offset: {
z: offsetFromBottomMm,
x: xOffset,
y: yOffset,
},
},
labwareId,
wellName,
wellLocation,
flowRate,
// pushOut will always be undefined in step-generation for now
// since there is no easy way to allow users to for it in PD
7 changes: 4 additions & 3 deletions step-generation/src/commandCreators/atomic/index.ts
Original file line number Diff line number Diff line change
@@ -21,10 +21,11 @@ import { moveLabware } from './moveLabware'
import { moveToAddressableArea } from './moveToAddressableArea'
import { moveToAddressableAreaForDropTip } from './moveToAddressableAreaForDropTip'
import { moveToWell } from './moveToWell'
import { replaceTip } from './replaceTip'
import { setTemperature } from './setTemperature'
import { touchTip } from './touchTip'
import { waitForTemperature } from './waitForTemperature'
import { pickUpTip } from './pickUpTip'

export {
absorbanceReaderCloseLid,
absorbanceReaderInitialize,
@@ -34,9 +35,9 @@ export {
aspirateInPlace,
blowout,
blowOutInPlace,
comment,
configureForVolume,
configureNozzleLayout,
comment,
deactivateTemperature,
delay,
disengageMagnet,
@@ -49,7 +50,7 @@ export {
moveToAddressableArea,
moveToAddressableAreaForDropTip,
moveToWell,
replaceTip,
pickUpTip,
setTemperature,
touchTip,
waitForTemperature,
34 changes: 16 additions & 18 deletions step-generation/src/commandCreators/atomic/moveLabware.ts
Original file line number Diff line number Diff line change
@@ -11,33 +11,30 @@ import {
getLabwareHasLiquid,
uuid,
} from '../../utils'
import type {
CreateCommand,
LabwareMovementStrategy,
} from '@opentrons/shared-data'
import type { CreateCommand, MoveLabwareParams } from '@opentrons/shared-data'
import type {
CommandCreator,
CommandCreatorError,
MoveLabwareArgs,
CommandCreatorWarning,
} from '../../types'

/** Move labware from one location to another, manually or via a gripper. */
export const moveLabware: CommandCreator<MoveLabwareArgs> = (
export const moveLabware: CommandCreator<MoveLabwareParams> = (
args,
invariantContext,
prevRobotState
) => {
const { labware, useGripper, newLocation } = args
const { labwareId, strategy, newLocation } = args
const useGripper = strategy === 'usingGripper'
const { additionalEquipmentEntities, labwareEntities } = invariantContext
const hasWasteChute = getHasWasteChute(additionalEquipmentEntities)
const tiprackHasTip =
prevRobotState.tipState != null
? getTiprackHasTips(prevRobotState.tipState, labware)
? getTiprackHasTips(prevRobotState.tipState, labwareId)
: false
const labwareHasLiquid =
prevRobotState.liquidState != null
? getLabwareHasLiquid(prevRobotState.liquidState, labware)
? getLabwareHasLiquid(prevRobotState.liquidState, labwareId)
: false
const hasTipOnPipettes = Object.values(
prevRobotState.tipState.pipettes
@@ -72,14 +69,17 @@ export const moveLabware: CommandCreator<MoveLabwareArgs> = (
prevRobotState.modules
).find(module => module.slot === newLocationSlot)

if (!labware || !prevRobotState.labware[labware]) {
if (!labwareId || !prevRobotState.labware[labwareId]) {
errors.push(
errorCreators.labwareDoesNotExist({
actionName,
labware,
labware: labwareId,
})
)
} else if (prevRobotState.labware[labware].slot === 'offDeck' && useGripper) {
} else if (
prevRobotState.labware[labwareId].slot === 'offDeck' &&
useGripper
) {
errors.push(errorCreators.labwareOffDeck())
} else if (
multipleObjectsInSameSlotLabware ||
@@ -89,7 +89,7 @@ export const moveLabware: CommandCreator<MoveLabwareArgs> = (
}

const isAluminumBlock =
labwareEntities[labware]?.def.metadata.displayCategory === 'aluminumBlock'
labwareEntities[labwareId]?.def.metadata.displayCategory === 'aluminumBlock'

if (useGripper && isAluminumBlock) {
errors.push(errorCreators.cannotMoveWithGripper())
@@ -106,7 +106,7 @@ export const moveLabware: CommandCreator<MoveLabwareArgs> = (
errors.push(errorCreators.pipetteHasTip())
}

const initialLabwareSlot = prevRobotState.labware[labware]?.slot
const initialLabwareSlot = prevRobotState.labware[labwareId]?.slot

if (hasWasteChute && initialLabwareSlot === 'gripperWasteChute') {
errors.push(errorCreators.labwareDiscarded())
@@ -198,10 +198,8 @@ export const moveLabware: CommandCreator<MoveLabwareArgs> = (
}

const params = {
labwareId: labware,
strategy: useGripper
? 'usingGripper'
: ('manualMoveWithPause' as LabwareMovementStrategy),
labwareId,
strategy,
newLocation,
}

Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import type { AddressableAreaName } from '@opentrons/shared-data'

import { uuid } from '../../utils'
import type { MoveToAddressableAreaParams } from '@opentrons/shared-data'
import type { CommandCreator } from '../../types'

export interface MoveToAddressableAreaArgs {
pipetteId: string
addressableAreaName: AddressableAreaName
}
export const moveToAddressableArea: CommandCreator<MoveToAddressableAreaArgs> = (
export const moveToAddressableArea: CommandCreator<MoveToAddressableAreaParams> = (
args,
invariantContext,
prevRobotState
) => {
const { pipetteId, addressableAreaName } = args
const { pipetteId, addressableAreaName, offset } = args

const commands = [
{
@@ -21,7 +16,7 @@ export const moveToAddressableArea: CommandCreator<MoveToAddressableAreaArgs> =
params: {
pipetteId,
addressableAreaName,
offset: { x: 0, y: 0, z: 0 },
offset,
},
},
]
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import type { AddressableAreaName } from '@opentrons/shared-data'

import { uuid } from '../../utils'
import type { MoveToAddressableAreaForDropTipParams } from '@opentrons/shared-data'
import type { CommandCreator } from '../../types'

export interface MoveToAddressableAreaForDropTipArgs {
pipetteId: string
addressableAreaName: AddressableAreaName
}
export const moveToAddressableAreaForDropTip: CommandCreator<MoveToAddressableAreaForDropTipArgs> = (
export const moveToAddressableAreaForDropTip: CommandCreator<MoveToAddressableAreaForDropTipParams> = (
args,
invariantContext,
prevRobotState
77 changes: 31 additions & 46 deletions step-generation/src/commandCreators/atomic/moveToWell.ts
Original file line number Diff line number Diff line change
@@ -14,50 +14,55 @@ import {
uuid,
} from '../../utils'
import { COLUMN_4_SLOTS } from '../../constants'
import type { CreateCommand } from '@opentrons/shared-data'
import type { MoveToWellParams as v5MoveToWellParams } from '@opentrons/shared-data/protocol/types/schemaV5'
import type { MoveToWellParams as v6MoveToWellParams } from '@opentrons/shared-data/protocol/types/schemaV6/command/gantry'
import type { CreateCommand, MoveToWellParams } from '@opentrons/shared-data'
import type { CommandCreator, CommandCreatorError } from '../../types'

/** Move to specified well of labware, with optional offset and pathing options. */
export const moveToWell: CommandCreator<v5MoveToWellParams> = (
export const moveToWell: CommandCreator<MoveToWellParams> = (
args,
invariantContext,
prevRobotState
) => {
const { pipette, labware, well, offset, minimumZHeight, forceDirect } = args
const {
pipetteId,
labwareId,
wellName,
wellLocation,
minimumZHeight,
forceDirect,
} = args
const actionName = 'moveToWell'
const errors: CommandCreatorError[] = []
const labwareState = prevRobotState.labware
// TODO(2020-07-30, IL): the below is duplicated or at least similar
// across aspirate/dispense/blowout, we can probably DRY it up
const pipetteSpec = invariantContext.pipetteEntities[pipette]?.spec
const pipetteSpec = invariantContext.pipetteEntities[pipetteId]?.spec
const isFlexPipette =
(pipetteSpec?.displayCategory === 'FLEX' || pipetteSpec?.channels === 96) ??
false

const slotName = getLabwareSlot(
labware,
labwareId,
prevRobotState.labware,
prevRobotState.modules
)

if (!pipetteSpec) {
errors.push(
errorCreators.pipetteDoesNotExist({
pipette,
pipette: pipetteId,
})
)
}

if (!labware || !prevRobotState.labware[labware]) {
if (!labwareId || !prevRobotState.labware[labwareId]) {
errors.push(
errorCreators.labwareDoesNotExist({
actionName,
labware,
labware: labwareId,
})
)
} else if (prevRobotState.labware[labware].slot === 'offDeck') {
} else if (prevRobotState.labware[labwareId].slot === 'offDeck') {
errors.push(errorCreators.labwareOffDeck())
}

@@ -76,8 +81,8 @@ export const moveToWell: CommandCreator<v5MoveToWellParams> = (

if (
modulePipetteCollision({
pipette,
labware,
pipette: pipetteId,
labware: labwareId,
invariantContext,
prevRobotState,
})
@@ -89,7 +94,7 @@ export const moveToWell: CommandCreator<v5MoveToWellParams> = (
thermocyclerPipetteCollision(
prevRobotState.modules,
prevRobotState.labware,
labware
labwareId
)
) {
errors.push(errorCreators.thermocyclerLidClosed())
@@ -99,7 +104,7 @@ export const moveToWell: CommandCreator<v5MoveToWellParams> = (
pipetteIntoHeaterShakerLatchOpen(
prevRobotState.modules,
prevRobotState.labware,
labware
labwareId
)
) {
errors.push(errorCreators.heaterShakerLatchOpen())
@@ -109,7 +114,7 @@ export const moveToWell: CommandCreator<v5MoveToWellParams> = (
absorbanceReaderCollision(
prevRobotState.modules,
prevRobotState.labware,
labware
labwareId
)
) {
errors.push(errorCreators.absorbanceReaderLidClosed())
@@ -119,7 +124,7 @@ export const moveToWell: CommandCreator<v5MoveToWellParams> = (
pipetteIntoHeaterShakerWhileShaking(
prevRobotState.modules,
prevRobotState.labware,
labware
labwareId
)
) {
errors.push(errorCreators.heaterShakerIsShaking())
@@ -155,7 +160,7 @@ export const moveToWell: CommandCreator<v5MoveToWellParams> = (
prevRobotState.modules,
slotName,
pipetteSpec,
invariantContext.labwareEntities[labware]
invariantContext.labwareEntities[labwareId]
)
) {
errors.push(
@@ -169,38 +174,18 @@ export const moveToWell: CommandCreator<v5MoveToWellParams> = (
}
}

const requiredParams: v6MoveToWellParams = {
pipetteId: pipette,
labwareId: labware,
wellName: well,
}

const wellLocationParams: Pick<v6MoveToWellParams, 'wellLocation'> = {
wellLocation: {
origin: 'bottom',
offset,
},
}

const params = {
...requiredParams,
...(offset != null && wellLocationParams),
}

// add optional fields only if specified
if (forceDirect != null) {
params.forceDirect = forceDirect
}

if (minimumZHeight != null) {
params.minimumZHeight = minimumZHeight
}

const commands: CreateCommand[] = [
{
commandType: 'moveToWell',
key: uuid(),
params,
params: {
pipetteId,
labwareId,
wellName,
wellLocation,
forceDirect,
minimumZHeight,
},
},
]
return {
72 changes: 72 additions & 0 deletions step-generation/src/commandCreators/atomic/pickUpTip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { COLUMN } from '@opentrons/shared-data'
import {
pipettingIntoColumn4,
possiblePipetteCollision,
} from '../../errorCreators'
import { COLUMN_4_SLOTS } from '../../constants'
import { uuid, getIsSafePipetteMovement } from '../../utils'
import type {
NozzleConfigurationStyle,
PickUpTipParams,
} from '@opentrons/shared-data'
import type { CommandCreator, CommandCreatorError } from '../../types'

interface PickUpTipAtomicParams extends PickUpTipParams {
nozzles?: NozzleConfigurationStyle
}

export const pickUpTip: CommandCreator<PickUpTipAtomicParams> = (
args,
invariantContext,
prevRobotState
) => {
const { pipetteId, labwareId, wellName, nozzles } = args
const errors: CommandCreatorError[] = []

const is96Channel =
invariantContext.pipetteEntities[pipetteId]?.spec.channels === 96

if (
is96Channel &&
nozzles === COLUMN &&
!getIsSafePipetteMovement(
prevRobotState,
invariantContext,
pipetteId,
labwareId,
labwareId,
// we don't adjust the offset when moving to the tiprack
{ x: 0, y: 0 },
wellName
)
) {
errors.push(possiblePipetteCollision())
}

const tiprackSlot = prevRobotState.labware[labwareId].slot
if (COLUMN_4_SLOTS.includes(tiprackSlot)) {
errors.push(pipettingIntoColumn4({ typeOfStep: 'pick up tip' }))
} else if (prevRobotState.labware[tiprackSlot] != null) {
const adapterSlot = prevRobotState.labware[tiprackSlot].slot
if (COLUMN_4_SLOTS.includes(adapterSlot)) {
errors.push(pipettingIntoColumn4({ typeOfStep: 'pick up tip' }))
}
}

if (errors.length > 0) {
return { errors }
}
return {
commands: [
{
commandType: 'pickUpTip',
key: uuid(),
params: {
pipetteId,
labwareId,
wellName,
},
},
],
}
}
30 changes: 12 additions & 18 deletions step-generation/src/commandCreators/atomic/touchTip.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { uuid } from '../../utils'
import { noTipOnPipette, pipetteDoesNotExist } from '../../errorCreators'
import type { CreateCommand, TouchTipParams } from '@opentrons/shared-data'
import type { CommandCreator, CommandCreatorError } from '../../types'
import type { CreateCommand } from '@opentrons/shared-data'
import type { TouchTipParams } from '@opentrons/shared-data/protocol/types/schemaV3'

export const touchTip: CommandCreator<TouchTipParams> = (
args,
@@ -11,25 +10,25 @@ export const touchTip: CommandCreator<TouchTipParams> = (
) => {
/** touchTip with given args. Requires tip. */
const actionName = 'touchTip'
const { pipette, labware, well, offsetFromBottomMm } = args
const pipetteData = prevRobotState.pipettes[pipette]
const { pipetteId, labwareId, wellName, wellLocation } = args
const pipetteData = prevRobotState.pipettes[pipetteId]
const errors: CommandCreatorError[] = []

if (!pipetteData) {
errors.push(
pipetteDoesNotExist({
pipette,
pipette: pipetteId,
})
)
}

if (!prevRobotState.tipState.pipettes[pipette]) {
if (!prevRobotState.tipState.pipettes[pipetteId]) {
errors.push(
noTipOnPipette({
actionName,
pipette,
labware,
well,
pipette: pipetteId,
labware: labwareId,
well: wellName,
})
)
}
@@ -45,15 +44,10 @@ export const touchTip: CommandCreator<TouchTipParams> = (
commandType: 'touchTip',
key: uuid(),
params: {
pipetteId: pipette,
labwareId: labware,
wellName: well,
wellLocation: {
origin: 'bottom',
offset: {
z: offsetFromBottomMm,
},
},
pipetteId,
labwareId,
wellName,
wellLocation,
},
},
]
105 changes: 55 additions & 50 deletions step-generation/src/commandCreators/compound/consolidate.ts
Original file line number Diff line number Diff line change
@@ -29,10 +29,10 @@ import {
delay,
dropTip,
moveToWell,
replaceTip,
touchTip,
} from '../atomic'
import { mixUtil } from './mix'
import { replaceTip } from './replaceTip'

import type {
ConsolidateArgs,
@@ -222,26 +222,27 @@ export const consolidate: CommandCreator<ConsolidateArgs> = (
const airGapAfterAspirateCommands = aspirateAirGapVolume
? [
curryCommandCreator(aspirate, {
pipette: args.pipette,
pipetteId: args.pipette,
volume: aspirateAirGapVolume,
labware: args.sourceLabware,
well: sourceWell,
labwareId: args.sourceLabware,
wellName: sourceWell,
flowRate: aspirateFlowRateUlSec,
offsetFromBottomMm: airGapOffsetSourceWell,
wellLocation: {
origin: 'bottom',
offset: {
z: airGapOffsetSourceWell,
x: 0,
y: 0,
},
},
isAirGap: true,
tipRack: args.tipRack,
xOffset: 0,
yOffset: 0,
nozzles,
}),
...(aspirateDelay != null
? [
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: aspirateDelay.seconds,
seconds: aspirateDelay.seconds,
}),
]
: []),
@@ -251,47 +252,55 @@ export const consolidate: CommandCreator<ConsolidateArgs> = (
aspirateDelay != null
? [
curryCommandCreator(moveToWell, {
pipette: args.pipette,
labware: args.sourceLabware,
well: sourceWell,
offset: {
x: 0,
y: 0,
z: aspirateDelay.mmFromBottom,
pipetteId: args.pipette,
labwareId: args.sourceLabware,
wellName: sourceWell,
wellLocation: {
origin: 'bottom',
offset: {
x: 0,
y: 0,
z: aspirateDelay.mmFromBottom,
},
},
}),
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: aspirateDelay.seconds,
seconds: aspirateDelay.seconds,
}),
]
: []
const touchTipAfterAspirateCommand = args.touchTipAfterAspirate
? [
curryCommandCreator(touchTip, {
pipette: args.pipette,
labware: args.sourceLabware,
well: sourceWell,
offsetFromBottomMm:
args.touchTipAfterAspirateOffsetMmFromBottom,
pipetteId: args.pipette,
labwareId: args.sourceLabware,
wellName: sourceWell,
wellLocation: {
origin: 'bottom',
offset: {
z: args.touchTipAfterAspirateOffsetMmFromBottom,
},
},
}),
]
: []

return [
curryCommandCreator(aspirate, {
pipette: args.pipette,
pipetteId: args.pipette,
volume: args.volume,
labware: args.sourceLabware,
well: sourceWell,
labwareId: args.sourceLabware,
wellName: sourceWell,
flowRate: aspirateFlowRateUlSec,
offsetFromBottomMm: aspirateOffsetFromBottomMm,
wellLocation: {
origin: 'bottom',
offset: {
z: aspirateOffsetFromBottomMm,
x: aspirateXOffset,
y: aspirateYOffset,
},
},
tipRack: args.tipRack,
xOffset: aspirateXOffset,
yOffset: aspirateYOffset,
nozzles,
}),
...delayAfterAspirateCommands,
@@ -320,11 +329,15 @@ export const consolidate: CommandCreator<ConsolidateArgs> = (
args.touchTipAfterDispense && destinationWell != null
? [
curryCommandCreator(touchTip, {
pipette: args.pipette,
labware: args.destLabware,
well: destinationWell,
offsetFromBottomMm:
args.touchTipAfterDispenseOffsetMmFromBottom,
pipetteId: args.pipette,
labwareId: args.destLabware,
wellName: destinationWell,
wellLocation: {
origin: 'bottom',
offset: {
z: args.touchTipAfterDispenseOffsetMmFromBottom,
},
},
}),
]
: []
@@ -434,11 +447,7 @@ export const consolidate: CommandCreator<ConsolidateArgs> = (
zOffset: dispenseDelay.mmFromBottom,
}),
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: dispenseDelay.seconds,
seconds: dispenseDelay.seconds,
}),
]
: []
@@ -473,11 +482,7 @@ export const consolidate: CommandCreator<ConsolidateArgs> = (
...(aspirateDelay != null
? [
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: aspirateDelay.seconds,
seconds: aspirateDelay.seconds,
}),
]
: []),
180 changes: 101 additions & 79 deletions step-generation/src/commandCreators/compound/distribute.ts
Original file line number Diff line number Diff line change
@@ -28,10 +28,11 @@ import {
dispense,
dropTip,
moveToWell,
replaceTip,
touchTip,
} from '../atomic'
import { mixUtil } from './mix'
import { replaceTip } from './replaceTip'

import type {
DistributeArgs,
CommandCreator,
@@ -215,50 +216,52 @@ export const distribute: CommandCreator<DistributeArgs> = (
const airGapAfterAspirateCommands = aspirateAirGapVolume
? [
curryCommandCreator(aspirate, {
pipette: args.pipette,
pipetteId: args.pipette,
volume: aspirateAirGapVolume,
labware: args.sourceLabware,
well: args.sourceWell,
labwareId: args.sourceLabware,
wellName: args.sourceWell,
flowRate: aspirateFlowRateUlSec,
offsetFromBottomMm: airGapOffsetSourceWell,
wellLocation: {
origin: 'bottom',
offset: {
z: airGapOffsetSourceWell,
x: 0,
y: 0,
},
},
isAirGap: true,
xOffset: 0,
yOffset: 0,
tipRack: args.tipRack,
nozzles,
}),
...(aspirateDelay != null
? [
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: aspirateDelay.seconds,
seconds: aspirateDelay.seconds,
}),
]
: []),
curryCommandCreator(dispense, {
pipette: args.pipette,
pipetteId: args.pipette,
volume: aspirateAirGapVolume,
labware: args.destLabware,
well: firstDestWell,
labwareId: args.destLabware,
wellName: firstDestWell,
flowRate: dispenseFlowRateUlSec,
offsetFromBottomMm: airGapOffsetDestWell,
wellLocation: {
origin: 'bottom',
offset: {
z: airGapOffsetDestWell,
x: 0,
y: 0,
},
},
isAirGap: true,
xOffset: 0,
yOffset: 0,
nozzles,
tipRack: args.tipRack,
}),
...(dispenseDelay != null
? [
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: dispenseDelay.seconds,
seconds: dispenseDelay.seconds,
}),
]
: []),
@@ -271,45 +274,53 @@ export const distribute: CommandCreator<DistributeArgs> = (
dispenseDelay != null
? [
curryCommandCreator(moveToWell, {
pipette: args.pipette,
labware: args.destLabware,
well: destWell,
offset: {
x: 0,
y: 0,
z: dispenseDelay.mmFromBottom,
pipetteId: args.pipette,
labwareId: args.destLabware,
wellName: destWell,
wellLocation: {
origin: 'bottom',
offset: {
x: 0,
y: 0,
z: dispenseDelay.mmFromBottom,
},
},
}),
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: dispenseDelay.seconds,
seconds: dispenseDelay.seconds,
}),
]
: []
const touchTipAfterDispenseCommand = args.touchTipAfterDispense
? [
curryCommandCreator(touchTip, {
pipette,
labware: args.destLabware,
well: destWell,
offsetFromBottomMm:
args.touchTipAfterDispenseOffsetMmFromBottom,
pipetteId: pipette,
labwareId: args.destLabware,
wellName: destWell,
wellLocation: {
origin: 'bottom',
offset: {
z: args.touchTipAfterDispenseOffsetMmFromBottom,
},
},
}),
]
: []
return [
curryCommandCreator(dispense, {
pipette,
pipetteId: pipette,
volume: args.volume,
labware: args.destLabware,
well: destWell,
labwareId: args.destLabware,
wellName: destWell,
flowRate: dispenseFlowRateUlSec,
offsetFromBottomMm: dispenseOffsetFromBottomMm,
xOffset: dispenseXOffset,
yOffset: dispenseYOffset,
wellLocation: {
origin: 'bottom',
offset: {
z: dispenseOffsetFromBottomMm,
x: dispenseXOffset,
y: dispenseYOffset,
},
},
nozzles,
tipRack: args.tipRack,
}),
@@ -352,26 +363,28 @@ export const distribute: CommandCreator<DistributeArgs> = (
dispenseAirGapVolume && !willReuseTip
? [
curryCommandCreator(aspirate, {
pipette: args.pipette,
pipetteId: args.pipette,
volume: dispenseAirGapVolume,
labware: dispenseAirGapLabware,
well: dispenseAirGapWell,
labwareId: dispenseAirGapLabware,
wellName: dispenseAirGapWell,
flowRate: aspirateFlowRateUlSec,
offsetFromBottomMm: airGapOffsetDestWell,
wellLocation: {
origin: 'bottom',
offset: {
z: airGapOffsetDestWell,
x: 0,
y: 0,
},
},
isAirGap: true,
tipRack: args.tipRack,
xOffset: 0,
yOffset: 0,

nozzles,
}),
...(aspirateDelay != null
? [
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: aspirateDelay.seconds,
seconds: aspirateDelay.seconds,
}),
]
: []),
@@ -422,31 +435,35 @@ export const distribute: CommandCreator<DistributeArgs> = (
aspirateDelay != null
? [
curryCommandCreator(moveToWell, {
pipette: args.pipette,
labware: args.sourceLabware,
well: args.sourceWell,
offset: {
x: 0,
y: 0,
z: aspirateDelay.mmFromBottom,
pipetteId: args.pipette,
labwareId: args.sourceLabware,
wellName: args.sourceWell,
wellLocation: {
origin: 'bottom',
offset: {
x: 0,
y: 0,
z: aspirateDelay.mmFromBottom,
},
},
}),
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: aspirateDelay.seconds,
seconds: aspirateDelay.seconds,
}),
]
: []
const touchTipAfterAspirateCommand = args.touchTipAfterAspirate
? [
curryCommandCreator(touchTip, {
pipette: args.pipette,
labware: args.sourceLabware,
well: args.sourceWell,
offsetFromBottomMm: args.touchTipAfterAspirateOffsetMmFromBottom,
pipetteId: args.pipette,
labwareId: args.sourceLabware,
wellName: args.sourceWell,
wellLocation: {
origin: 'bottom',
offset: {
z: args.touchTipAfterAspirateOffsetMmFromBottom,
},
},
}),
]
: []
@@ -489,21 +506,26 @@ export const distribute: CommandCreator<DistributeArgs> = (
...configureForVolumeCommand,
...mixBeforeAspirateCommands,
curryCommandCreator(aspirate, {
pipette,
pipetteId: pipette,
volume:
args.volume * destWellChunk.length +
// only add disposal volume if its the 1st chunk and changing tip once
// and not blowing out after dispenses
(args.changeTip === 'once' && blowoutLocation == null
? aspirateDisposalVolumeOnce
: disposalVolume),
labware: args.sourceLabware,
well: args.sourceWell,
labwareId: args.sourceLabware,
wellName: args.sourceWell,
flowRate: aspirateFlowRateUlSec,
offsetFromBottomMm: aspirateOffsetFromBottomMm,
wellLocation: {
origin: 'bottom',
offset: {
z: aspirateOffsetFromBottomMm,
x: aspirateXOffset,
y: aspirateYOffset,
},
},
tipRack: args.tipRack,
xOffset: aspirateXOffset,
yOffset: aspirateYOffset,
nozzles,
}),
...delayAfterAspirateCommands,
6 changes: 1 addition & 5 deletions step-generation/src/commandCreators/compound/heaterShaker.ts
Original file line number Diff line number Diff line change
@@ -87,11 +87,7 @@ export const heaterShaker: CommandCreator<HeaterShakerArgs> = (
(args.timerSeconds ?? 0) + (args.timerMinutes ?? 0) * 60
commandCreators.push(
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: totalSeconds,
seconds: totalSeconds,
})
)
commandCreators.push(
3 changes: 2 additions & 1 deletion step-generation/src/commandCreators/compound/index.ts
Original file line number Diff line number Diff line change
@@ -2,8 +2,9 @@ export { absorbanceReaderCloseInitialize } from './absorbanceReaderCloseInitiali
export { absorbanceReaderCloseRead } from './absorbanceReaderCloseRead'
export { consolidate } from './consolidate'
export { distribute } from './distribute'
export { heaterShaker } from './heaterShaker'
export { mix } from './mix'
export { replaceTip } from './replaceTip'
export { thermocyclerProfileStep } from './thermocyclerProfileStep'
export { thermocyclerStateStep } from './thermocyclerStateStep'
export { transfer } from './transfer'
export { heaterShaker } from './heaterShaker'
55 changes: 33 additions & 22 deletions step-generation/src/commandCreators/compound/mix.ts
Original file line number Diff line number Diff line change
@@ -18,9 +18,9 @@ import {
configureForVolume,
delay,
dispense,
replaceTip,
touchTip,
} from '../atomic'
import { replaceTip } from './replaceTip'

import type { NozzleConfigurationStyle } from '@opentrons/shared-data'
import type {
@@ -72,39 +72,45 @@ export function mixUtil(args: {
seconds
? [
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: seconds,
seconds,
}),
]
: []

return repeatArray(
[
curryCommandCreator(aspirate, {
pipette,
pipetteId: pipette,
volume,
labware,
well,
offsetFromBottomMm: aspirateOffsetFromBottomMm,
labwareId: labware,
wellName: well,
flowRate: aspirateFlowRateUlSec,
tipRack,
xOffset: aspirateXOffset,
yOffset: aspirateYOffset,
wellLocation: {
origin: 'bottom',
offset: {
z: aspirateOffsetFromBottomMm,
x: aspirateXOffset,
y: aspirateYOffset,
},
},
nozzles: null,
}),
...getDelayCommand(aspirateDelaySeconds),
curryCommandCreator(dispense, {
pipette,
pipetteId: pipette,
volume,
labware,
well,
offsetFromBottomMm: dispenseOffsetFromBottomMm,
labwareId: labware,
wellName: well,
wellLocation: {
origin: 'bottom',
offset: {
z: dispenseOffsetFromBottomMm,
x: dispenseXOffset,
y: dispenseYOffset,
},
},
flowRate: dispenseFlowRateUlSec,
xOffset: dispenseXOffset,
yOffset: dispenseYOffset,
tipRack,
nozzles: nozzles,
}),
@@ -254,10 +260,15 @@ export const mix: CommandCreator<MixArgs> = (
const touchTipCommands = data.touchTip
? [
curryCommandCreator(touchTip, {
pipette,
labware,
well,
offsetFromBottomMm: data.touchTipMmFromBottom,
pipetteId: pipette,
labwareId: labware,
wellName: well,
wellLocation: {
origin: 'bottom',
offset: {
z: data.touchTipMmFromBottom,
},
},
}),
]
: []
Original file line number Diff line number Diff line change
@@ -6,96 +6,25 @@ import {
} from '@opentrons/shared-data'
import { getNextTiprack } from '../../robotStateSelectors'
import * as errorCreators from '../../errorCreators'
import { COLUMN_4_SLOTS } from '../../constants'
import { movableTrashCommandsUtil } from '../../utils/movableTrashCommandsUtil'
import {
curryCommandCreator,
getIsHeaterShakerEastWestMultiChannelPipette,
getIsHeaterShakerEastWestWithLatchOpen,
getIsSafePipetteMovement,
getLabwareSlot,
modulePipetteCollision,
pipetteAdjacentHeaterShakerWhileShaking,
reduceCommandCreators,
uuid,
wasteChuteCommandsUtil,
getWasteChuteAddressableAreaNamePip,
PRIMARY_NOZZLE,
} from '../../utils'
import { dropTip } from './dropTip'
import { configureNozzleLayout } from './configureNozzleLayout'
import { dropTip } from '../atomic/dropTip'
import { pickUpTip } from '../atomic/pickUpTip'
import { configureNozzleLayout } from '../atomic/configureNozzleLayout'

import type { NozzleConfigurationStyle } from '@opentrons/shared-data'
import type {
CommandCreator,
CommandCreatorError,
CurriedCommandCreator,
} from '../../types'

interface PickUpTipArgs {
pipette: string
tiprack: string
well: string
nozzles?: NozzleConfigurationStyle
}

const _pickUpTip: CommandCreator<PickUpTipArgs> = (
args,
invariantContext,
prevRobotState
) => {
const errors: CommandCreatorError[] = []

const is96Channel =
invariantContext.pipetteEntities[args.pipette]?.spec.channels === 96

if (
is96Channel &&
args.nozzles === COLUMN &&
!getIsSafePipetteMovement(
prevRobotState,
invariantContext,
args.pipette,
args.tiprack,
args.tiprack,
// we don't adjust the offset when moving to the tiprack
{ x: 0, y: 0 },
args.well
)
) {
errors.push(errorCreators.possiblePipetteCollision())
}

const tiprackSlot = prevRobotState.labware[args.tiprack].slot
if (COLUMN_4_SLOTS.includes(tiprackSlot)) {
errors.push(
errorCreators.pipettingIntoColumn4({ typeOfStep: 'pick up tip' })
)
} else if (prevRobotState.labware[tiprackSlot] != null) {
const adapterSlot = prevRobotState.labware[tiprackSlot].slot
if (COLUMN_4_SLOTS.includes(adapterSlot)) {
errors.push(
errorCreators.pipettingIntoColumn4({ typeOfStep: 'pick up tip' })
)
}
}

if (errors.length > 0) {
return { errors }
}
return {
commands: [
{
commandType: 'pickUpTip',
key: uuid(),
params: {
pipetteId: args.pipette,
labwareId: args.tiprack,
wellName: args.well,
},
},
],
}
}
import type { CommandCreator, CurriedCommandCreator } from '../../types'

interface ReplaceTipArgs {
pipette: string
@@ -254,7 +183,11 @@ export const replaceTip: CommandCreator<ReplaceTipArgs> = (
channels === 96 && args.nozzles != null && args.nozzles !== stateNozzles
? [
curryCommandCreator(configureNozzleLayout, {
nozzles: args.nozzles,
configurationParams: {
primaryNozzle:
args.nozzles === COLUMN ? PRIMARY_NOZZLE : undefined,
style: args.nozzles,
},
pipetteId: args.pipette,
}),
]
@@ -266,10 +199,10 @@ export const replaceTip: CommandCreator<ReplaceTipArgs> = (
dropTipLocation,
}),
...configureNozzleLayoutCommand,
curryCommandCreator(_pickUpTip, {
pipette,
tiprack: nextTiprack.tiprackId,
well: nextTiprack.well,
curryCommandCreator(pickUpTip, {
pipetteId: pipette,
labwareId: nextTiprack.tiprackId,
wellName: nextTiprack.well,
nozzles: args.nozzles,
}),
]
@@ -282,10 +215,10 @@ export const replaceTip: CommandCreator<ReplaceTipArgs> = (
prevRobotState,
}),
...configureNozzleLayoutCommand,
curryCommandCreator(_pickUpTip, {
pipette,
tiprack: nextTiprack.tiprackId,
well: nextTiprack.well,
curryCommandCreator(pickUpTip, {
pipetteId: pipette,
labwareId: nextTiprack.tiprackId,
wellName: nextTiprack.well,
nozzles: args.nozzles,
}),
]
@@ -299,10 +232,10 @@ export const replaceTip: CommandCreator<ReplaceTipArgs> = (
invariantContext,
}),
...configureNozzleLayoutCommand,
curryCommandCreator(_pickUpTip, {
pipette,
tiprack: nextTiprack.tiprackId,
well: nextTiprack.well,
curryCommandCreator(pickUpTip, {
pipetteId: pipette,
labwareId: nextTiprack.tiprackId,
wellName: nextTiprack.well,
nozzles: args.nozzles,
}),
]
129 changes: 68 additions & 61 deletions step-generation/src/commandCreators/compound/transfer.ts
Original file line number Diff line number Diff line change
@@ -28,17 +28,18 @@ import {
dispense,
dropTip,
moveToWell,
replaceTip,
touchTip,
} from '../atomic'
import { mixUtil } from './mix'
import { replaceTip } from './replaceTip'

import type {
TransferArgs,
CurriedCommandCreator,
CommandCreator,
CommandCreatorError,
} from '../../types'

export const transfer: CommandCreator<TransferArgs> = (
args,
invariantContext,
@@ -326,32 +327,35 @@ export const transfer: CommandCreator<TransferArgs> = (
aspirateDelay != null
? [
curryCommandCreator(moveToWell, {
pipette: args.pipette,
labware: args.sourceLabware,
well: sourceWell,
offset: {
x: 0,
y: 0,
z: aspirateDelay.mmFromBottom,
pipetteId: args.pipette,
labwareId: args.sourceLabware,
wellName: sourceWell,
wellLocation: {
origin: 'bottom',
offset: {
x: 0,
y: 0,
z: aspirateDelay.mmFromBottom,
},
},
}),
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: aspirateDelay.seconds,
seconds: aspirateDelay.seconds,
}),
]
: []
const touchTipAfterAspirateCommands = args.touchTipAfterAspirate
? [
curryCommandCreator(touchTip, {
pipette: args.pipette,
labware: args.sourceLabware,
well: sourceWell,
offsetFromBottomMm:
args.touchTipAfterAspirateOffsetMmFromBottom,
pipetteId: args.pipette,
labwareId: args.sourceLabware,
wellName: sourceWell,
wellLocation: {
origin: 'bottom',
offset: {
z: args.touchTipAfterAspirateOffsetMmFromBottom,
},
},
}),
]
: []
@@ -360,11 +364,15 @@ export const transfer: CommandCreator<TransferArgs> = (
args.touchTipAfterDispense && destinationWell != null
? [
curryCommandCreator(touchTip, {
pipette: args.pipette,
labware: args.destLabware,
well: destinationWell,
offsetFromBottomMm:
args.touchTipAfterDispenseOffsetMmFromBottom,
pipetteId: args.pipette,
labwareId: args.destLabware,
wellName: destinationWell,
wellLocation: {
origin: 'bottom',
offset: {
z: args.touchTipAfterDispenseOffsetMmFromBottom,
},
},
}),
]
: []
@@ -396,50 +404,52 @@ export const transfer: CommandCreator<TransferArgs> = (
aspirateAirGapVolume && destinationWell != null
? [
curryCommandCreator(aspirate, {
pipette: args.pipette,
pipetteId: args.pipette,
volume: aspirateAirGapVolume,
labware: args.sourceLabware,
well: sourceWell,
labwareId: args.sourceLabware,
wellName: sourceWell,
flowRate: aspirateFlowRateUlSec,
offsetFromBottomMm: airGapOffsetSourceWell,
wellLocation: {
origin: 'bottom',
offset: {
z: airGapOffsetSourceWell,
x: 0,
y: 0,
},
},
isAirGap: true,
tipRack,
xOffset: 0,
yOffset: 0,
nozzles: args.nozzles,
}),
...(aspirateDelay != null
? [
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: aspirateDelay.seconds,
seconds: aspirateDelay.seconds,
}),
]
: []),
curryCommandCreator(dispense, {
pipette: args.pipette,
pipetteId: args.pipette,
volume: aspirateAirGapVolume,
labware: args.destLabware,
well: destinationWell,
labwareId: args.destLabware,
wellName: destinationWell,
flowRate: dispenseFlowRateUlSec,
offsetFromBottomMm: airGapOffsetDestWell,
wellLocation: {
origin: 'bottom',
offset: {
z: airGapOffsetDestWell,
x: 0,
y: 0,
},
},
isAirGap: true,
xOffset: 0,
yOffset: 0,
tipRack: args.tipRack,
nozzles: args.nozzles,
}),
...(dispenseDelay != null
? [
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: dispenseDelay.seconds,
seconds: dispenseDelay.seconds,
}),
]
: []),
@@ -465,15 +475,20 @@ export const transfer: CommandCreator<TransferArgs> = (

const aspirateCommand = [
curryCommandCreator(aspirate, {
pipette: args.pipette,
pipetteId: args.pipette,
volume: subTransferVol,
labware: args.sourceLabware,
well: sourceWell,
labwareId: args.sourceLabware,
wellName: sourceWell,
flowRate: aspirateFlowRateUlSec,
offsetFromBottomMm: aspirateOffsetFromBottomMm,
wellLocation: {
origin: 'bottom',
offset: {
z: aspirateOffsetFromBottomMm,
x: aspirateXOffset,
y: aspirateYOffset,
},
},
tipRack,
xOffset: aspirateXOffset,
yOffset: aspirateYOffset,
nozzles: args.nozzles,
}),
]
@@ -502,11 +517,7 @@ export const transfer: CommandCreator<TransferArgs> = (
zOffset: dispenseDelay.mmFromBottom,
}),
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: dispenseDelay.seconds,
seconds: dispenseDelay.seconds,
}),
]
: []
@@ -543,11 +554,7 @@ export const transfer: CommandCreator<TransferArgs> = (
...(aspirateDelay != null
? [
curryCommandCreator(delay, {
commandCreatorFnName: 'delay',
description: null,
name: null,
meta: null,
wait: aspirateDelay.seconds,
seconds: aspirateDelay.seconds,
}),
]
: []),
20 changes: 10 additions & 10 deletions step-generation/src/commandCreators/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
export {
transfer,
mix,
absorbanceReaderCloseInitialize,
absorbanceReaderCloseRead,
consolidate,
distribute,
heaterShaker,
mix,
replaceTip,
thermocyclerProfileStep,
thermocyclerStateStep,
heaterShaker,
absorbanceReaderCloseInitialize,
absorbanceReaderCloseRead,
transfer,
} from './compound'

export {
@@ -16,19 +17,18 @@ export {
absorbanceReaderOpenLid,
absorbanceReaderRead,
aspirate,
waitForTemperature,
blowout,
comment,
deactivateTemperature,
delay,
disengageMagnet,
dispense,
dropTip,
dropTipInPlace,
engageMagnet,
replaceTip,
setTemperature,
touchTip,
moveLabware,
moveToAddressableArea,
comment,
setTemperature,
touchTip,
waitForTemperature,
} from './atomic'
8 changes: 6 additions & 2 deletions step-generation/src/constants.ts
Original file line number Diff line number Diff line change
@@ -9,7 +9,11 @@ import {
MAGNETIC_BLOCK_TYPE,
} from '@opentrons/shared-data'

import type { ModuleType, ModuleModel } from '@opentrons/shared-data'
import type {
ModuleType,
ModuleModel,
AddressableOffsetVector,
} from '@opentrons/shared-data'
import type {
MagneticModuleState,
TemperatureModuleState,
@@ -73,10 +77,10 @@ export const MODULE_INITIAL_STATE_BY_TYPE: {
[TEMPERATURE_MODULE_TYPE]: TEMPERATURE_MODULE_INITIAL_STATE,
[THERMOCYCLER_MODULE_TYPE]: THERMOCYCLER_MODULE_INITIAL_STATE,
[HEATERSHAKER_MODULE_TYPE]: HEATERSHAKER_MODULE_INITIAL_STATE,
// TODO(jr, 6/24/24): add the initial state for absorabance reader
[ABSORBANCE_READER_TYPE]: ABSORBANCE_READER_INITIAL_STATE,
[MAGNETIC_BLOCK_TYPE]: MAGNETIC_BLOCK_INITIAL_STATE,
}
export const OT_2_TRASH_DEF_URI = 'opentrons/opentrons_1_trash_1100ml_fixed/1'
export const FLEX_TRASH_DEF_URI = 'opentrons/opentrons_1_trash_3200ml_fixed/1'
export const COLUMN_4_SLOTS = ['A4', 'B4', 'C4', 'D4']
export const ZERO_OFFSET: AddressableOffsetVector = { x: 0, y: 0, z: 0 }
10 changes: 4 additions & 6 deletions step-generation/src/types.ts
Original file line number Diff line number Diff line change
@@ -15,17 +15,15 @@ import type {
PipetteMount as Mount,
PipetteV2Specs,
ShakeSpeedParams,
LabwareMovementStrategy,
} from '@opentrons/shared-data'
import type { AtomicProfileStep } from '@opentrons/shared-data/protocol/types/schemaV4'
import type { Command } from '@opentrons/shared-data/protocol/types/schemaV5Addendum'
import type {
TEMPERATURE_DEACTIVATED,
TEMPERATURE_AT_TARGET,
TEMPERATURE_APPROACHING_TARGET,
} from './constants'

export type { Command }

// Copied from PD
export type DeckSlot = string
type THERMOCYCLER_STATE = 'thermocyclerState'
@@ -327,7 +325,7 @@ export type MixArgs = CommonArgs & {
export type PauseArgs = CommonArgs & {
commandCreatorFnName: 'delay'
message?: string
wait: number | true
seconds?: number
pauseTemperature?: number | null
meta:
| {
@@ -464,9 +462,9 @@ export type AbsorbanceReaderArgs =

export interface MoveLabwareArgs extends CommonArgs {
commandCreatorFnName: 'moveLabware'
labware: string
useGripper: boolean
labwareId: string
newLocation: LabwareLocation
strategy: LabwareMovementStrategy
}

export interface CommentArgs extends CommonArgs {
66 changes: 42 additions & 24 deletions step-generation/src/utils/misc.ts
Original file line number Diff line number Diff line change
@@ -301,6 +301,7 @@ export const blowoutUtil = (args: {
wellName: well,
flowRate,
wellLocation: {
origin: 'top',
offset: {
z: offsetFromTopMm,
},
@@ -518,14 +519,19 @@ export const dispenseLocationHelper: CommandCreator<DispenseLocationHelperArgs>
) {
commands = [
curryCommandCreator(dispense, {
pipette: pipetteId,
pipetteId,
volume,
labware: destinationId,
well,
labwareId: destinationId,
wellName: well,
flowRate,
offsetFromBottomMm,
xOffset,
yOffset,
wellLocation: {
origin: 'bottom',
offset: {
z: offsetFromBottomMm,
x: xOffset,
y: yOffset,
},
},
tipRack,
nozzles,
}),
@@ -580,11 +586,13 @@ export const moveHelper: CommandCreator<MoveHelperArgs> = (
if (trashOrLabware === 'labware' && well != null) {
commands = [
curryCommandCreator(moveToWell, {
pipette: pipetteId,
labware: destinationId,

well,
offset: { x: 0, y: 0, z: zOffset },
pipetteId: pipetteId,
labwareId: destinationId,
wellName: well,
wellLocation: {
origin: 'bottom',
offset: { x: 0, y: 0, z: zOffset },
},
}),
]
} else if (trashOrLabware === 'wasteChute') {
@@ -596,6 +604,7 @@ export const moveHelper: CommandCreator<MoveHelperArgs> = (
addressableAreaName: getWasteChuteAddressableAreaNamePip(
pipetteChannels
),
offset: { x: 0, y: 0, z: 0 },
}),
]
} else {
@@ -666,34 +675,43 @@ export const airGapHelper: CommandCreator<AirGapArgs> = (

commands = [
curryCommandCreator(aspirate, {
pipette: pipetteId,
pipetteId: pipetteId,
volume,
labware: dispenseAirGapLabware,
well: dispenseAirGapWell,
labwareId: dispenseAirGapLabware,
wellName: dispenseAirGapWell,
flowRate,
offsetFromBottomMm,
wellLocation: {
origin: 'bottom',
offset: {
z: offsetFromBottomMm,
x: 0,
y: 0,
},
},
isAirGap: true,
tipRack,
xOffset: 0,
yOffset: 0,
nozzles,
}),
]
// when aspirating out of multi wells for consolidate
} else {
commands = [
curryCommandCreator(aspirate, {
pipette: pipetteId,
pipetteId: pipetteId,
volume,
labware: destinationId,
well: destWell,
labwareId: destinationId,
wellName: destWell,
flowRate,
offsetFromBottomMm,
wellLocation: {
origin: 'bottom',
offset: {
z: offsetFromBottomMm,
x: 0,
y: 0,
},
},
isAirGap: true,
tipRack,
// NOTE: airgap aspirates happen at default x/y offset
xOffset: 0,
yOffset: 0,
nozzles,
}),
]
6 changes: 6 additions & 0 deletions step-generation/src/utils/movableTrashCommandsUtil.ts
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ import {
moveToAddressableArea,
moveToAddressableAreaForDropTip,
} from '../commandCreators/atomic'
import { ZERO_OFFSET } from '../constants'
import { curryCommandCreator } from './curryCommandCreator'
import type { AddressableAreaName, CutoutId } from '@opentrons/shared-data'
import type {
@@ -46,6 +47,7 @@ export const movableTrashCommandsUtil = (
volume,
flowRate,
} = args
const offset = ZERO_OFFSET
const trash = Object.values(
invariantContext.additionalEquipmentEntities
).find(aE => aE.name === 'trashBin')
@@ -89,6 +91,7 @@ export const movableTrashCommandsUtil = (
curryCommandCreator(moveToAddressableArea, {
pipetteId,
addressableAreaName,
offset,
}),
curryCommandCreator(aspirateInPlace, {
pipetteId,
@@ -123,6 +126,7 @@ export const movableTrashCommandsUtil = (
curryCommandCreator(moveToAddressableArea, {
pipetteId,
addressableAreaName,
offset,
}),
curryCommandCreator(dispenseInPlace, {
pipetteId,
@@ -140,6 +144,7 @@ export const movableTrashCommandsUtil = (
curryCommandCreator(moveToAddressableArea, {
pipetteId,
addressableAreaName,
offset,
}),
curryCommandCreator(blowOutInPlace, {
pipetteId,
@@ -154,6 +159,7 @@ export const movableTrashCommandsUtil = (
curryCommandCreator(moveToAddressableArea, {
pipetteId,
addressableAreaName,
offset,
}),
]
}
4 changes: 2 additions & 2 deletions step-generation/src/utils/safePipetteMovements.ts
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ import type {

const A12_column_front_left_bound = { x: -11.03, y: 2 }
const A12_column_back_right_bound = { x: 526.77, y: 506.2 }
const PRIMARY_NOZZLE = 'A12'
export const PRIMARY_NOZZLE = 'A12'
const NOZZLE_CONFIGURATION = 'COLUMN'
const FLEX_TC_LID_COLLISION_ZONE = {
back_left: { x: -43.25, y: 454.9, z: 211.91 },
@@ -44,7 +44,7 @@ interface SlotInfo {
addressableArea: AddressableArea | null
position: CoordinateTuple | null
}
interface Point {
export interface Point {
x: number
y: number
z?: number
7 changes: 6 additions & 1 deletion step-generation/src/utils/wasteChuteCommandsUtil.ts
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import {
dropTipInPlace,
moveToAddressableArea,
} from '../commandCreators/atomic'
import { ZERO_OFFSET } from '../constants'
import { curryCommandCreator } from './curryCommandCreator'
import type { AddressableAreaName } from '@opentrons/shared-data'
import type { RobotState, CurriedCommandCreator } from '../types'
@@ -35,7 +36,7 @@ export const wasteChuteCommandsUtil = (
volume,
flowRate,
} = args

const offset = ZERO_OFFSET
let commands: CurriedCommandCreator[] = []
switch (type) {
case 'dropTip': {
@@ -45,6 +46,7 @@ export const wasteChuteCommandsUtil = (
curryCommandCreator(moveToAddressableArea, {
pipetteId,
addressableAreaName,
offset,
}),
curryCommandCreator(dropTipInPlace, {
pipetteId,
@@ -60,6 +62,7 @@ export const wasteChuteCommandsUtil = (
curryCommandCreator(moveToAddressableArea, {
pipetteId,
addressableAreaName,
offset,
}),
curryCommandCreator(dispenseInPlace, {
pipetteId,
@@ -77,6 +80,7 @@ export const wasteChuteCommandsUtil = (
curryCommandCreator(moveToAddressableArea, {
pipetteId,
addressableAreaName,
offset,
}),
curryCommandCreator(blowOutInPlace, {
pipetteId,
@@ -93,6 +97,7 @@ export const wasteChuteCommandsUtil = (
curryCommandCreator(moveToAddressableArea, {
pipetteId,
addressableAreaName,
offset,
}),
curryCommandCreator(aspirateInPlace, {
pipetteId,

0 comments on commit b5f09dd

Please sign in to comment.