########################################################################
### FILE: fluidicsarm.mod
### PURPOSE: Composite commands for FLUidics:ARMx branches
### SCOPE: "FLUidics:ARM:" branch.
###
### Copyrights (C) 2010-2011 Life Technologies. All rights reserved.
########################################################################
ALIAS MESSage :PUBLish Fluidics
DEFine RinseInside $closeDelay$=0.5 $dropletTouchOff$=False $location$=Rinse $duration$
IF $[ "$location$" != "" ] LOCation $location$
### Update Rinse tank volume with dispensed volume
SYRinge:FACTor?
SET volumeFactor $1
SET dispenseVolume $[ $(SYRinge:POSition?) * ${volumeFactor} ]
### Update Rinse Tank volume with rinse volume
SET rate $(CONFiguration? -default=0 fluidics_specs.ini RinseRates InteriorWash)
SET rinseVolume $[ ${rate} * max(0, $duration$) ]
### Wait for any previous rinse operation to complete before closing valves
SYNC RinseClose
TRY
:FLUidics:SOLenoid:DrainPump1:CONTrol 3
:FLUidics:SOLenoid:InteriorWashValve:CONTrol 3
FLAG -asynchronous EmptySyringe
MESSage "RinseInside: Emptying ${dispenseVolume}uL from syringe, rinsing for $duration$s"
TRY
SYRinge:POSition 0 -pattern=4
SYRinge:HOME
WAIT $duration$
VARiable LastRinse $(:SYSTem:TIME?)
# Close wash valve, then drain after syringe has been homed
:FLUidics:SOLenoid:InteriorWashValve:CONTrol 0
WAIT $closeDelay$
SYNC EmptySyringe
:FLUidics:SOLenoid:DrainPump1:CONTrol 0
TRY ":FLUidics:SOLenoid:ExteriorWashValve:CONTrol 0" PASS
SYNC -ignoreErrors RinseClose
TRY ":FLUidics:SOLenoid:DrainPump1:CONTrol 0" PASS
TRY ":FLUidics:SOLenoid:DrainPump2:CONTrol 0" PASS
ERRor -id=$error$ $arguments$ "$message$"
### Update volume counts in System Liquid and Rinse tanks; set states
SET totalVolume $[ ${dispenseVolume} + ${rinseVolume} ]
:FLUidics:RemoveSystemLiquid ${rinseVolume}
IF $[ "rinse" in "$location$".lower() ]
:FLUidics:AddRinseVolume ${totalVolume}
ELIF $[ "waste" in "$location$".lower() ]
:FLUidics:AddWasteVolume ${totalVolume}
#In some cases, after the rinse, a droplet forms on the tip. To remove
#this droplet, this code touches the tip to the plastic poll extending
#from the nozzle. The touch is done with the liquid level sensor.
IF $dropletTouchOff$
#Activate liquid level sense.
:flu:motion:z:liquidlevelsensoractive 0
:flu:motion:z:liquidlevelsensoractive 1
MESSage "RinseInside: DropletTouchOff: Moving 40 counts down"
:flu:arm:z:position -relative 40
:flu:motion:z:liquidlevelsensoractive 0
DEFine RinseOutside $closeDelay$=0.5 $pullTime$=1.0 $pullRate$=50 $dropletTouchOff$=False $location$=Rinse $duration$
IF $[ "$location$" != "" ]
LOCation $location$
### Determine how long to stay put, and how many steps to then move
SET pulltime $[ min($pullTime$, $duration$) ]
ELSE
SET pulltime 0
SET staytime $[ $duration$ - ${pulltime} ]
SET pullsteps $[ -(abs($pullRate$) * ${pulltime}) ]
SYNC RinseClose # Wait for any previous rinse operation to close valves
TRY
:FLUidics:SOLenoid:DrainPump2:CONTrol 3 # For now open both Drains
:FLUidics:SOLenoid:DrainPump1:CONTrol 3
:FLUidics:SOLenoid:ExteriorWashValve:CONTrol 3
:FLUidics:Motion:Z:MPN 5
Wait 0.1
SET Vel $(:FLUidics:Motion:Z:VEL?)
SET iVel $(:FLUidics:Motion:Z:IVEL?)
FLAG -asynchronous RinsePull
MESSage "RinseOutside: Staying for ${staytime}s of total $duration$s rinse time, then pulling up ${pullsteps} steps at $pullRate$ steps/s"
WAIT ${staytime}
:FLUidics:Motion:Z:VEL $pullRate$
:FLUidics:Motion:Z:IVEL $pullRate$
:FLUidics:ARM:Z:POSition ${pullsteps} -relative -pattern=5
WAIT $duration$ # Wait for the specified duration with valves open
# Close wash valve, then asynchronously wait and close drains
:FLUidics:SOLenoid:ExteriorWashValve:CONTrol 0
FLAG -asynchronous RinseClose
WAIT $closeDelay$
:FLUidics:SOLenoid:DrainPump1:CONTrol 0
:FLUidics:SOLenoid:DrainPump2:CONTrol 0 # And Close both Drains
SYNC RinsePull
:FLUidics:Motion:Z:MPN 5
Wait 0.1
:FLUidics:Motion:Z:VEL ${Vel}
:FLUidics:Motion:Z:IVEL ${iVel}
TRY ":FLUidics:SOLenoid:ExteriorWashValve:CONTrol 0" PASS
SYNC -ignoreErrors RinseClose
TRY ":FLUidics:SOLenoid:DrainPump1:CONTrol 0" PASS
TRY ":FLUidics:SOLenoid:DrainPump2:CONTrol 0" PASS
ERRor -id=$error$ $arguments$ "$message$"
### Update Rinse Tank volume with rinse volume
SET rate $(CONFiguration? -default=0 fluidics_specs.ini RinseRates ExteriorWash)
SET rinseVolume $[ ${rate} * max(0, $duration$) ]
### Update volume counts in System Liquid and Rinse tanks; set states
:FLUidics:RemoveSystemLiquid ${rinseVolume}
IF $[ "rinse" in "$location$".lower() ]
:FLUidics:AddRinseVolume ${rinseVolume}
ELIF $[ "waste" in "$location$".lower() ]
:FLUidics:AddWasteVolume ${rinseVolume}
#In some cases, after the rinse, a droplet forms on the tip. To remove
#this droplet, this code touches the tip to the plastic poll extending
#from the nozzle. The touch is done with the liquid level sensor active.
IF $dropletTouchOff$
#Activate liquid level sense.
:flu:motion:z:liquidlevelsensoractive 0
:flu:motion:z:liquidlevelsensoractive 1
SET offset $[($pullDistance$ * -1) + 40]
MESSage "RinseOutside: DropletTouchOff: Moving ${offset} counts"
:flu:arm:z:position -relative ${offset}
:flu:motion:z:liquidlevelsensoractive 0
DEFine EmptySyringe $location$=Waste $closeDelay$=0.5 $force$=False
SET position $(SYRinge:POSition?)
IF $[ ${position} or $force$ ]
LOCation $location$
TRY
:FLUidics:DrainPump2Open
TRY
SYRinge:POSition 0 -pattern=4
SYRinge:HOME
WAIT $closeDelay$
:FLUidics:DrainPump2Close
:FLUidics:DrainPump2Close
ERRor -id=$error$ $arguments$ "$message$"
### Update Waste tank volume with dispensed volume
SYRinge:FACTor?
SET volumeFactor $1
SET dispenseVolume $[ ${position} * ${volumeFactor} ]
:FLUidics:AddWasteVolume ${dispenseVolume}
DEFine HomeSyringe $force$=False
SET Found False
IF $[ ($force$ or not $(SYRinge:HOME?) or not $(SYRinge:HOMED?)) ]
TRY
LOCation Waste
SET Found True
WARNing "Could not move to 'Waste' location -- not homing syringe"
SET Found False
IF ${found}
IF $(SYRinge:HOMED?)
SYRinge:FACTor?
SET volumeFactor $1
SET dispenseVolume $[ $(SYRinge:POSition?) * ${volumeFactor} ]
:FLUidics:AddWasteVolume ${dispenseVolume}
TRY
:FLUidics:DrainPump2Open
MESSage "HomeSyringe: Homing"
TRY SYRinge:HOME SYRinge:HOME SYRinge:HOME
WAIT 1
:FLUidics:DrainPump2Close
IF ${Open} :FLUidics:DrainPump2Close
ERRor -id=$error$ $arguments$ "$message$"
ALIas TipCalibrationCheck :FLUidics:CalCheck1
########################################################################
### LINE PRIMING
DEFine PrimeLine
SET IdleTime $[ round($(:SYSTem:TIME?) - ${LastRinse:-0}, 1) ]
SET PrimeTime $[ round(min(${PrimeMax}, ${IdleTime} / ${PrimeFactor}), 1) ]
IF $[ ${PrimeTime} >= ${PrimeMin} ]
SET howlong ${LastRinse:+for ${IdleTime} seconds}
SET howlong ${howlong:-since the beginning of time}
MESSage "PrimeLine: Delivery line has been idle ${howlong}; priming for ${PrimeTime} seconds"
RinseInside ${PrimeTime}
DESCribe PrimeLine
Prime the delivery line by performing an inside tip rinse.
The duration of the priming depends on the elapsed time since the
last inside rinse operation, divided by a priming factor and
constrained by a minimum threshold and maximum priming time, all
of which can be specified with the "PrimeLine=" command.
DEFine PrimeLine= $min$ $max$ $factor$
VAR PrimeMin $min$
VAR PrimeMax $max$
VAR PrimeFactor $factor$
DESCribe PrimeLine=
Specify how long lines should be primed when the PrimeLines
command is invoked (i.e. prior to SURVEY as well as prior to
running fluidics script).
The inputs are:
- Only prime if the priming time exceeds this threshold.
Default: 0.5s
- Maximum priming time. Default: 30s.
- Ratio between elapsed time since the last inside rinse
and the desired priming time.
Default: 900 (1 second per 1/2 hour idle time).
PrimeLine= -min=0.5 -max=30 -factor=1800
DEFine PrimeLine?
RETurn -min=${PrimeMin} -max=${PrimeMax} -factor=${PrimeFactor}
DESCribe PrimeLine
Return the minmum/maximum priming time as well as the ratio between
idle time and priming time.
########################################################################
### Axis test script
DEFine AxisTest $min$='' $max$='' $axis$ $count$
SET min $[ "$min$" or "$($axis$:REGISTERS:TRAVELLIMITNEGATIVE?)" ]
SET max $[ "$max$" or "$($axis$:REGISTERS:TRAVELLIMITPOSITIVE?)" ]
FLAG -asynchronous AxisTest
REPeat -counter=count -start=1 $count$
:PUBLish AxisTest "Iteration ${count} of $count$; moving $axis$ to ${min}, then ${max}..."
$axis$:POSition ${min}
$axis$:POSition ${max}
NEXT
TRY
FLAG- -ignoreMissing AxisTest
:PUBLish AxisText "Completed; parking $axis$"
PARK $axis$
IF $[ "$error$" == "Aborted" ]
PUBLish AxisTest "Aborted; parking $axis$"
PARK $axis$
:PUBLish AxisText "Failed; parking $axis$"
PARK $axis$
ERRor -id=$error$ $arguments$ $message$
DEFine AxisTest~
FLAG- -abort -ignoreMissing AxisTest
### Force line priming after removing system liquid tank
:STATE:TRIGGER -states=SystemLiquid:Installed -edge=Clear ForcePrime
FLUidics:ARM:VARiable- -ignoreMissing LastRinse