Skip to content

Commit a344177

Browse files
Implement flow rate for Tecan EVO backend (#549)
Co-authored-by: nedru004 <david.nedrud@gmail.com>
1 parent cc3458e commit a344177

File tree

2 files changed

+65
-20
lines changed

2 files changed

+65
-20
lines changed

pylabrobot/liquid_handling/backends/tecan/EVO_backend.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ async def dispense(self, ops: List[SingleChannelDispense], use_channels: List[in
464464
x, _ = self._first_valid(x_positions)
465465
y, yi = self._first_valid(y_positions)
466466
assert x is not None and y is not None
467-
await self.liha.set_z_travel_height(z if z else self._z_range for z in z_positions["travel"])
467+
await self.liha.set_z_travel_height([z if z else self._z_range for z in z_positions["travel"]])
468468
await self.liha.position_absolute_all_axis(
469469
x,
470470
y - yi * ys,
@@ -732,11 +732,13 @@ def _aspirate_airgap(
732732
assert tlc is not None
733733
pvl[channel] = 0
734734
if airgap == "lag":
735-
sep[channel] = int(tlc.aspirate_lag_speed * 12) # 6? TODO: verify step unit
736-
ppr[channel] = int(tlc.aspirate_lag_volume * 6) # 3?
735+
sep[channel] = int(
736+
tlc.aspirate_lag_speed * 6
737+
) # 6? TODO: verify step unit (half step per second)
738+
ppr[channel] = int(tlc.aspirate_lag_volume * 3) # 3? (Relative position in full steps)
737739
elif airgap == "tag":
738-
sep[channel] = int(tlc.aspirate_tag_speed * 12) # 6?
739-
ppr[channel] = int(tlc.aspirate_tag_volume * 6) # 3?
740+
sep[channel] = int(tlc.aspirate_tag_speed * 6) # 6?
741+
ppr[channel] = int(tlc.aspirate_tag_volume * 3) # 3?
740742

741743
return pvl, sep, ppr
742744

@@ -802,10 +804,11 @@ def _aspirate_action(
802804
tlc = tecan_liquid_classes[i]
803805
z = zadd[channel]
804806
assert tlc is not None and z is not None
805-
sep[channel] = int(tlc.aspirate_speed * 12) # 6?
806-
ssz[channel] = round(z * tlc.aspirate_speed / ops[i].volume)
807+
flow_rate = ops[i].flow_rate or tlc.aspirate_speed
808+
sep[channel] = int(flow_rate * 6) # 6?
809+
ssz[channel] = round(z * flow_rate / ops[i].volume)
807810
volume = tlc.compute_corrected_volume(ops[i].volume)
808-
mtr[channel] = round(volume * 6) # 3?
811+
mtr[channel] = round(volume * 3) # 3? # Relative position in full steps
809812
ssz_r[channel] = int(tlc.aspirate_retract_speed * 10)
810813

811814
return ssz, sep, stz, mtr, ssz_r
@@ -838,15 +841,16 @@ def _dispense_action(
838841
for i, channel in enumerate(use_channels):
839842
tlc = tecan_liquid_classes[i]
840843
assert tlc is not None
841-
sep[channel] = int(tlc.dispense_speed * 12) # 6?
842-
spp[channel] = int(tlc.dispense_breakoff * 12) # 6?
844+
flow_rate = ops[i].flow_rate or tlc.dispense_speed
845+
sep[channel] = int(flow_rate * 6) # 6?
846+
spp[channel] = int(tlc.dispense_breakoff * 6) # 6? half step per second
843847
stz[channel] = 0
844848
volume = (
845849
tlc.compute_corrected_volume(ops[i].volume)
846850
+ tlc.aspirate_lag_volume
847851
+ tlc.aspirate_tag_volume
848852
)
849-
mtr[channel] = -round(volume * 6) # 3?
853+
mtr[channel] = -round(volume * 3) # 3?
850854

851855
return sep, spp, stz, mtr
852856

pylabrobot/liquid_handling/backends/tecan/EVO_tests.py

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,12 @@ async def test_aspirate(self):
178178
call(
179179
module="C5",
180180
command="SEP",
181-
params=[840, None, None, None, None, None, None, None],
181+
params=[420, None, None, None, None, None, None, None],
182182
),
183183
call(
184184
module="C5",
185185
command="PPR",
186-
params=[30, None, None, None, None, None, None, None],
186+
params=[15, None, None, None, None, None, None, None],
187187
),
188188
call(module="C5", command="SDM", params=[7, 1]),
189189
call(
@@ -234,7 +234,7 @@ async def test_aspirate(self):
234234
call(
235235
module="C5",
236236
command="SEP",
237-
params=[1200, None, None, None, None, None, None, None],
237+
params=[600, None, None, None, None, None, None, None],
238238
),
239239
call(
240240
module="C5",
@@ -244,7 +244,7 @@ async def test_aspirate(self):
244244
call(
245245
module="C5",
246246
command="MTR",
247-
params=[626, None, None, None, None, None, None, None],
247+
params=[313, None, None, None, None, None, None, None],
248248
),
249249
call(
250250
module="C5",
@@ -264,12 +264,12 @@ async def test_aspirate(self):
264264
call(
265265
module="C5",
266266
command="SEP",
267-
params=[840, None, None, None, None, None, None, None],
267+
params=[420, None, None, None, None, None, None, None],
268268
),
269269
call(
270270
module="C5",
271271
command="PPR",
272-
params=[60, None, None, None, None, None, None, None],
272+
params=[30, None, None, None, None, None, None, None],
273273
),
274274
]
275275
)
@@ -309,12 +309,12 @@ async def test_dispense(self):
309309
call(
310310
module="C5",
311311
command="SEP",
312-
params=[7200, None, None, None, None, None, None, None],
312+
params=[600, None, None, None, None, None, None, None],
313313
),
314314
call(
315315
module="C5",
316316
command="SPP",
317-
params=[4800, None, None, None, None, None, None, None],
317+
params=[2400, None, None, None, None, None, None, None],
318318
),
319319
call(
320320
module="C5",
@@ -324,11 +324,52 @@ async def test_dispense(self):
324324
call(
325325
module="C5",
326326
command="MTR",
327-
params=[-716, None, None, None, None, None, None, None],
327+
params=[-358, None, None, None, None, None, None, None],
328328
),
329329
]
330330
)
331331

332+
# async def test_aspirate_custom_flow_rate(self):
333+
# op = SingleChannelAspiration(
334+
# resource=self.plate.get_item("A1"),
335+
# offset=Coordinate.zero(),
336+
# tip=self.tr.get_tip("A1"),
337+
# volume=100,
338+
# flow_rate=200,
339+
# liquid_height=10,
340+
# blow_out_air_volume=0,
341+
# liquids=[(None, 100)],
342+
# )
343+
# await self.evo.aspirate([op], use_channels=[0])
344+
# self.evo.send_command.assert_any_call( # type: ignore[attr-defined]
345+
# module="C5",
346+
# command="SSZ",
347+
# params=[60, None, None, None, None, None, None, None],
348+
# )
349+
# self.evo.send_command.assert_any_call( # type: ignore[attr-defined]
350+
# module="C5",
351+
# command="SEP",
352+
# params=[2400, None, None, None, None, None, None, None],
353+
# )
354+
355+
# async def test_dispense_custom_flow_rate(self):
356+
# op = SingleChannelDispense(
357+
# resource=self.plate.get_item("A1"),
358+
# offset=Coordinate.zero(),
359+
# tip=self.tr.get_tip("A1"),
360+
# volume=100,
361+
# flow_rate=200,
362+
# liquid_height=10,
363+
# blow_out_air_volume=0,
364+
# liquids=[(None, 100)],
365+
# )
366+
# await self.evo.dispense([op], use_channels=[0])
367+
# self.evo.send_command.assert_any_call( # type: ignore[attr-defined]
368+
# module="C5",
369+
# command="SEP",
370+
# params=[2400, None, None, None, None, None, None, None],
371+
# )
372+
332373
async def test_move_resource(self):
333374
pickup = ResourcePickup(
334375
resource=self.plate,

0 commit comments

Comments
 (0)