diff --git a/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts b/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts index 1c1023208bc..57f04c0e7e8 100644 --- a/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts +++ b/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts @@ -220,16 +220,14 @@ mockPythonName.drop_tip() // Step c: ` mockPythonName.pick_up_tip(location=mockPythonName) -mockPythonName.aspirate(...) -mockPythonName.dispense(...) -mockPythonName.aspirate(...) -mockPythonName.dispense(...) +mockPythonName.flow_rate.aspirate = 3.78 +mockPythonName.flow_rate.dispense = 3.78 +mockPythonName.mix(...) mockPythonName.drop_tip() mockPythonName.pick_up_tip(location=mockPythonName) -mockPythonName.aspirate(...) -mockPythonName.dispense(...) -mockPythonName.aspirate(...) -mockPythonName.dispense(...) +mockPythonName.flow_rate.aspirate = 3.78 +mockPythonName.flow_rate.dispense = 3.78 +mockPythonName.mix(...) mockPythonName.drop_tip() `.trim(), ]) diff --git a/step-generation/src/__tests__/mix.test.ts b/step-generation/src/__tests__/mix.test.ts index 2a2c78e8984..715fa277f93 100644 --- a/step-generation/src/__tests__/mix.test.ts +++ b/step-generation/src/__tests__/mix.test.ts @@ -348,6 +348,7 @@ describe('mix: advanced options', () => { changeTip: 'always', wells: ['A1', 'B1', 'C1'], yOffset: 1, + finalPushOut: 2, } as MixArgs const mockWellLocationCustomXY: Partial = { wellLocation: { @@ -371,7 +372,10 @@ describe('mix: advanced options', () => { delayCommand(12), aspirateHelper(well, volume, mockWellLocationCustomXY), delayCommand(10), - dispenseHelper(well, volume, mockWellLocationCustomXY), + dispenseHelper(well, volume, { + ...mockWellLocationCustomXY, + pushOut: 2, + }), delayCommand(12), blowoutHelper(blowoutLabwareId, { wellLocation: { @@ -388,91 +392,46 @@ describe('mix: advanced options', () => { ` mockPythonName.drop_tip() mockPythonName.pick_up_tip(location=mockPythonName) -mockPythonName.aspirate( - volume=8, - location=mockPythonName["A1"].bottom(z=3.2).move(types.Point(y=1)), - rate=2.1 / mockPythonName.flow_rate.aspirate, -) -protocol.delay(seconds=10) -mockPythonName.dispense( - volume=8, - location=mockPythonName["A1"].bottom(z=3.2).move(types.Point(y=1)), - rate=2.2 / mockPythonName.flow_rate.dispense, - push_out=0, -) -protocol.delay(seconds=12) -mockPythonName.aspirate( - volume=8, - location=mockPythonName["A1"].bottom(z=3.2).move(types.Point(y=1)), - rate=2.1 / mockPythonName.flow_rate.aspirate, -) -protocol.delay(seconds=10) -mockPythonName.dispense( +mockPythonName.flow_rate.aspirate = 2.1 +mockPythonName.flow_rate.dispense = 2.2 +mockPythonName.mix( + repetitions=2, volume=8, location=mockPythonName["A1"].bottom(z=3.2).move(types.Point(y=1)), - rate=2.2 / mockPythonName.flow_rate.dispense, + aspirate_delay=10, + dispense_delay=12, + final_push_out=2, ) -protocol.delay(seconds=12) mockPythonName.flow_rate.blow_out = 2.3 mockPythonName.blow_out(mockPythonName["A1"].top(z=3.3)) mockPythonName.touch_tip(mockPythonName["A1"], v_offset=-3.4) mockPythonName.drop_tip() mockPythonName.pick_up_tip(location=mockPythonName) -mockPythonName.aspirate( - volume=8, - location=mockPythonName["B1"].bottom(z=3.2).move(types.Point(y=1)), - rate=2.1 / mockPythonName.flow_rate.aspirate, -) -protocol.delay(seconds=10) -mockPythonName.dispense( - volume=8, - location=mockPythonName["B1"].bottom(z=3.2).move(types.Point(y=1)), - rate=2.2 / mockPythonName.flow_rate.dispense, - push_out=0, -) -protocol.delay(seconds=12) -mockPythonName.aspirate( - volume=8, - location=mockPythonName["B1"].bottom(z=3.2).move(types.Point(y=1)), - rate=2.1 / mockPythonName.flow_rate.aspirate, -) -protocol.delay(seconds=10) -mockPythonName.dispense( +mockPythonName.flow_rate.aspirate = 2.1 +mockPythonName.flow_rate.dispense = 2.2 +mockPythonName.mix( + repetitions=2, volume=8, location=mockPythonName["B1"].bottom(z=3.2).move(types.Point(y=1)), - rate=2.2 / mockPythonName.flow_rate.dispense, + aspirate_delay=10, + dispense_delay=12, + final_push_out=2, ) -protocol.delay(seconds=12) mockPythonName.flow_rate.blow_out = 2.3 mockPythonName.blow_out(mockPythonName["A1"].top(z=3.3)) mockPythonName.touch_tip(mockPythonName["B1"], v_offset=-3.4) mockPythonName.drop_tip() mockPythonName.pick_up_tip(location=mockPythonName) -mockPythonName.aspirate( - volume=8, - location=mockPythonName["C1"].bottom(z=3.2).move(types.Point(y=1)), - rate=2.1 / mockPythonName.flow_rate.aspirate, -) -protocol.delay(seconds=10) -mockPythonName.dispense( - volume=8, - location=mockPythonName["C1"].bottom(z=3.2).move(types.Point(y=1)), - rate=2.2 / mockPythonName.flow_rate.dispense, - push_out=0, -) -protocol.delay(seconds=12) -mockPythonName.aspirate( - volume=8, - location=mockPythonName["C1"].bottom(z=3.2).move(types.Point(y=1)), - rate=2.1 / mockPythonName.flow_rate.aspirate, -) -protocol.delay(seconds=10) -mockPythonName.dispense( +mockPythonName.flow_rate.aspirate = 2.1 +mockPythonName.flow_rate.dispense = 2.2 +mockPythonName.mix( + repetitions=2, volume=8, location=mockPythonName["C1"].bottom(z=3.2).move(types.Point(y=1)), - rate=2.2 / mockPythonName.flow_rate.dispense, + aspirate_delay=10, + dispense_delay=12, + final_push_out=2, ) -protocol.delay(seconds=12) mockPythonName.flow_rate.blow_out = 2.3 mockPythonName.blow_out(mockPythonName["A1"].top(z=3.3)) mockPythonName.touch_tip(mockPythonName["C1"], v_offset=-3.4)`.trimStart() diff --git a/step-generation/src/commandCreators/compound/mix.ts b/step-generation/src/commandCreators/compound/mix.ts index ebccddce283..0a4eace6059 100644 --- a/step-generation/src/commandCreators/compound/mix.ts +++ b/step-generation/src/commandCreators/compound/mix.ts @@ -74,21 +74,11 @@ export function mixUtil(args: { invariantContext, finalPushOut, } = args - // If delay is specified to something other than 0, - // emit individual py commands. Otherwise, emit mix() - const hasUnsupportedMixApiArg = - (aspirateDelaySeconds != null && aspirateDelaySeconds !== 0) || - (dispenseDelaySeconds != null && dispenseDelaySeconds !== 0) || - finalPushOut != null - - const curryCreator = hasUnsupportedMixApiArg - ? curryCommandCreator - : curryWithoutPython const getDelayCommand = (seconds?: number | null): CurriedCommandCreator[] => seconds ? [ - curryCreator(delay, { + curryWithoutPython(delay, { seconds, }), ] @@ -108,8 +98,13 @@ export function mixUtil(args: { `location=${labwarePythonName}[${formatPyStr( well )}]${formatPyWellLocation(pythonWellLocation)}`, - // TODO (nd, 04/09/2025): uncomment next line once PAPI supports new `final_push_out` arg - // `final_push_out=${finalPushOut}` + ...(aspirateDelaySeconds != null && aspirateDelaySeconds !== 0 + ? [`aspirate_delay=${aspirateDelaySeconds}`] + : []), + ...(dispenseDelaySeconds != null && dispenseDelaySeconds !== 0 + ? [`dispense_delay=${dispenseDelaySeconds}`] + : []), + ...(finalPushOut != null ? [`final_push_out=${finalPushOut}`] : []), ] return { commands: [], @@ -128,7 +123,7 @@ export function mixUtil(args: { for (let i = 0; i < times; i++) { commandCreators.push( ...[ - curryCreator(aspirate, { + curryWithoutPython(aspirate, { pipetteId: pipette, volume, labwareId: labware, @@ -146,7 +141,7 @@ export function mixUtil(args: { nozzles: null, }), ...getDelayCommand(aspirateDelaySeconds), - curryCreator(dispense, { + curryWithoutPython(dispense, { pipetteId: pipette, volume, labwareId: labware, @@ -172,10 +167,7 @@ export function mixUtil(args: { ] ) } - return [ - ...commandCreators, - ...(hasUnsupportedMixApiArg ? [] : [pythonCommandCreator]), - ] + return [...commandCreators, pythonCommandCreator] } export const mix: CommandCreator = ( data,