Skip to content

Commit 4578cb5

Browse files
committed
Merge branch 'mp.96ch.p200' into mp.pipette.25.04.08
2 parents 672cdd7 + 7b7cbf7 commit 4578cb5

File tree

14 files changed

+2523
-281
lines changed

14 files changed

+2523
-281
lines changed

hardware-testing/hardware_testing/gravimetric/increments.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,13 @@
269269
200: {
270270
20: {
271271
"default": [
272+
0.600,
273+
0.700,
272274
0.800,
275+
0.900,
273276
1.000,
277+
1.100,
278+
1.200,
274279
1.300,
275280
1.700,
276281
3.000,
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""Heat up and wait for a 96ch to reach the desired temperature."""
2+
3+
from opentrons.protocol_api import ProtocolContext, ParameterContext
4+
from opentrons.hardware_control.adapters import SynchronousAdapter
5+
from opentrons.hardware_control.ot3api import OT3API
6+
from opentrons.hardware_control.types import Axis
7+
from opentrons_hardware.sensors.sensor_driver import SensorDriver
8+
from opentrons_hardware.sensors.sensor_types import EnvironmentSensor
9+
from opentrons_hardware.firmware_bindings.constants import NodeId, SensorId
10+
11+
12+
def add_parameters(parameters: ParameterContext) -> None:
13+
"""Build the runtime parameters."""
14+
parameters.add_int(
15+
display_name="model type",
16+
variable_name="model_type",
17+
default=50,
18+
choices=[
19+
{"display_name": "50", "value": 50},
20+
{"display_name": "1000", "value": 1000},
21+
],
22+
description="Select model type.",
23+
)
24+
25+
parameters.add_float(
26+
display_name="Target Temperature",
27+
variable_name="temp",
28+
default=25.5,
29+
minimum=20,
30+
maximum=35,
31+
description="Set the target temperature for the pre-heat",
32+
)
33+
34+
35+
metadata = {"protocolName": "8ch Pre-heating protocol"}
36+
37+
requirements = {"robotType": "Flex", "apiLevel": "2.21"}
38+
39+
40+
async def change_current(self, current: float) -> None:
41+
await self._backend.set_active_current({Axis.P_L: current})
42+
43+
44+
async def read_sensor(self, sensor: EnvironmentSensor) -> float: # noqa: ANN001
45+
"""Read and return the current sensor information."""
46+
s_driver = SensorDriver()
47+
sensor_data = await s_driver.read(
48+
can_messenger=self._backend._messenger,
49+
sensor=sensor,
50+
offset=False,
51+
)
52+
assert sensor_data.temperature is not None # type: ignore [union-attr]
53+
return sensor_data.temperature.to_float() # type: ignore [union-attr]
54+
55+
56+
def get_motors_hot(ot3api: SynchronousAdapter) -> None:
57+
"""Adjust the motor hold currents to heat quicker."""
58+
axis_settings = [Axis.P_L, Axis.Q]
59+
ot3api.engage_axes(axis_settings)
60+
61+
62+
def run(ctx: ProtocolContext) -> None:
63+
"""Run."""
64+
ot3api = ctx._core.get_hardware()
65+
if not ctx.is_simulating():
66+
OT3API.read_sensor = read_sensor # type: ignore [attr-defined]
67+
OT3API.change_current = change_current # type: ignore [attr-defined]
68+
primary = EnvironmentSensor.build(
69+
sensor_id=SensorId.S0,
70+
node_id=NodeId.pipette_left,
71+
)
72+
secondary = EnvironmentSensor.build(
73+
sensor_id=SensorId.S1,
74+
node_id=NodeId.pipette_left,
75+
)
76+
_ = ctx.load_instrument(
77+
f"flex_8channel_{ctx.params.model_type}", "left" # type: ignore [attr-defined]
78+
)
79+
if not ctx.is_simulating():
80+
ot3api.change_current(1.0)
81+
current_temp_1 = ot3api.read_sensor(primary)
82+
current_temp_2 = ot3api.read_sensor(secondary)
83+
get_motors_hot(ot3api) # type: ignore [arg-type]
84+
avg_temp = (current_temp_1 + current_temp_2) / 2
85+
target = ctx.params.temp # type: ignore [attr-defined]
86+
while avg_temp < target:
87+
current_temp_1 = ot3api.read_sensor(primary)
88+
current_temp_2 = ot3api.read_sensor(secondary)
89+
avg_temp = (current_temp_1 + current_temp_2) / 2
90+
ctx.delay(seconds=15, msg=f"Current temperature {avg_temp} target={target}")
91+
ot3api.change_current(0.3)

hardware-testing/hardware_testing/protocols/96CH_LV_FILL_LIQUID_RevA1.3.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@
55
import random
66

77
metadata = {
8-
'protocolName': '96CH_LV_FILL_LIQUID_RevA1.3',
9-
'author': 'Andy Hu <[email protected]>',
10-
}
11-
requirements = {
12-
'robotType': 'Flex',
13-
'apiLevel': '2.20'
8+
"protocolName": "96CH_LV_FILL_LIQUID_RevA1.3",
9+
"author": "Andy Hu <[email protected]>",
1410
}
11+
requirements = {"robotType": "Flex", "apiLevel": "2.20"}
1512

1613

1714
def add_parameters(parameters: protocol_api.ParameterContext) -> None:
@@ -26,22 +23,35 @@ def add_parameters(parameters: protocol_api.ParameterContext) -> None:
2623
)
2724

2825

29-
3026
def run(protocol: protocol_api.ProtocolContext):
3127

32-
volume = protocol.params.dispension_volume
28+
volume = protocol.params.dispension_volume # type: ignore [attr-defined]
3329

3430
# DECK SETUP AND LABWARE
35-
pcr_plate1 = protocol.load_labware('armadillo_96_wellplate_200ul_pcr_full_skirt', "D1")
36-
pcr_plate2 = protocol.load_labware('armadillo_96_wellplate_200ul_pcr_full_skirt', "D2")
37-
pcr_plate3 = protocol.load_labware('armadillo_96_wellplate_200ul_pcr_full_skirt', "D3")
38-
pcr_plate4 = protocol.load_labware('armadillo_96_wellplate_200ul_pcr_full_skirt', "C2")
39-
pcr_plate5 = protocol.load_labware('armadillo_96_wellplate_200ul_pcr_full_skirt', "C3")
31+
pcr_plate1 = protocol.load_labware(
32+
"armadillo_96_wellplate_200ul_pcr_full_skirt", "D1"
33+
)
34+
pcr_plate2 = protocol.load_labware(
35+
"armadillo_96_wellplate_200ul_pcr_full_skirt", "D2"
36+
)
37+
pcr_plate3 = protocol.load_labware(
38+
"armadillo_96_wellplate_200ul_pcr_full_skirt", "D3"
39+
)
40+
pcr_plate4 = protocol.load_labware(
41+
"armadillo_96_wellplate_200ul_pcr_full_skirt", "C2"
42+
)
43+
pcr_plate5 = protocol.load_labware(
44+
"armadillo_96_wellplate_200ul_pcr_full_skirt", "C3"
45+
)
4046
pcrs = [pcr_plate1, pcr_plate2, pcr_plate3, pcr_plate4, pcr_plate5]
4147

42-
reservoir = protocol.load_labware('nest_1_reservoir_195ml', "C1")
48+
reservoir = protocol.load_labware("nest_1_reservoir_195ml", "C1")
4349

44-
tiprack_1000 = protocol.load_labware(load_name='opentrons_flex_96_tiprack_1000ul', location="B1", adapter="opentrons_flex_96_tiprack_adapter")
50+
tiprack_1000 = protocol.load_labware(
51+
load_name="opentrons_flex_96_tiprack_1000ul",
52+
location="B1",
53+
adapter="opentrons_flex_96_tiprack_adapter",
54+
)
4555

4656
trash_labware = protocol.load_trash_bin("A3")
4757

@@ -50,12 +60,11 @@ def run(protocol: protocol_api.ProtocolContext):
5060
p1000.trash_container = trash_labware
5161
# COMMANDS
5262

53-
p1000.pick_up_tip(tiprack_1000.wells_by_name()['A1'])
63+
p1000.pick_up_tip(tiprack_1000.wells_by_name()["A1"])
5464

5565
for pcr in pcrs:
56-
p1000.aspirate(volume, reservoir.wells_by_name()['A1'])
57-
p1000.dispense(volume, pcr.wells_by_name()['A1'])
66+
p1000.aspirate(volume, reservoir.wells_by_name()["A1"])
67+
p1000.dispense(volume, pcr.wells_by_name()["A1"])
5868
p1000.blow_out()
5969

6070
p1000.return_tip()
61-

hardware-testing/hardware_testing/protocols/96ch_preheat.py

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,10 @@
33
from opentrons.protocol_api import ProtocolContext, ParameterContext
44
from opentrons.hardware_control.adapters import SynchronousAdapter
55
from opentrons.hardware_control.ot3api import OT3API
6-
from opentrons.hardware_control.types import Axis, OT3AxisMap
6+
from opentrons.hardware_control.types import Axis
77
from opentrons_hardware.sensors.sensor_driver import SensorDriver
88
from opentrons_hardware.sensors.sensor_types import EnvironmentSensor
9-
from opentrons_hardware.sensors.utils import (
10-
ReadSensorInformation,
11-
)
12-
from opentrons_hardware.sensors.sensor_types import SensorInformation
13-
from opentrons_hardware.firmware_bindings.constants import NodeId, SensorId, SensorType
14-
import asyncio
15-
from opentrons_hardware.drivers.can_bus import CanMessenger
9+
from opentrons_hardware.firmware_bindings.constants import NodeId, SensorId
1610

1711

1812
def add_parameters(parameters: ParameterContext) -> None:
@@ -43,32 +37,29 @@ def add_parameters(parameters: ParameterContext) -> None:
4337
requirements = {"robotType": "Flex", "apiLevel": "2.21"}
4438

4539

46-
async def read_sensor(self, sensor: EnvironmentSensor) -> float:
40+
async def read_sensor(self, sensor: EnvironmentSensor) -> float: # noqa: ANN001
4741
"""Read and return the current sensor information."""
48-
4942
s_driver = SensorDriver()
5043
sensor_data = await s_driver.read(
5144
can_messenger=self._backend._messenger,
5245
sensor=sensor,
5346
offset=False,
5447
)
55-
assert sensor_data.temperature is not None
56-
return sensor_data.temperature.to_float()
48+
assert sensor_data.temperature is not None # type: ignore [union-attr]
49+
return sensor_data.temperature.to_float() # type: ignore [union-attr]
5750

5851

5952
def get_motors_hot(ot3api: SynchronousAdapter) -> None:
6053
"""Adjust the motor hold currents to heat quicker."""
61-
62-
axis_settings = {Axis.P_L: 1.5, Axis.Q: 1.5}
63-
ot3api.engage_axes([a for a in axis_settings.keys()])
54+
axis_settings = [Axis.P_L, Axis.Q]
55+
ot3api.engage_axes(axis_settings)
6456

6557

6658
def run(ctx: ProtocolContext) -> None:
6759
"""Run."""
6860
ot3api = ctx._core.get_hardware()
6961
if not ctx.is_simulating():
70-
messenger = ot3api._backend._messenger
71-
OT3API.read_sensor = read_sensor
62+
OT3API.read_sensor = read_sensor # type: ignore [attr-defined]
7263
primary = EnvironmentSensor.build(
7364
sensor_id=SensorId.S0,
7465
node_id=NodeId.pipette_left,

hardware-testing/hardware_testing/protocols/universal_photometric.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,14 @@ def add_parameters(parameters: protocol_api.ParameterContext) -> None:
155155
maximum=100,
156156
description="Set dispense exit speed.",
157157
)
158+
parameters.add_int(
159+
display_name="air gap",
160+
variable_name="air_gap",
161+
default=0,
162+
minimum=0,
163+
maximum=10,
164+
description="Set Trailing air gap.",
165+
)
158166

159167
parameters.add_float(
160168
display_name="aspirate_submerge_depth",
@@ -303,7 +311,7 @@ def _get_current_liquid_height(labware: protocol_api.Labware) -> float:
303311
return source_core_geometry.get_meniscus_height(source_labware_id, source_well_name)
304312

305313

306-
def run(ctx: protocol_api.ProtocolContext) -> None:
314+
def run(ctx: protocol_api.ProtocolContext) -> None: # noqa: C901
307315
"""Run."""
308316
ctx.load_trash_bin("A3")
309317
# tips
@@ -403,13 +411,16 @@ def _validate_dye_liquid_height() -> float:
403411
pip.pick_up_tip(tips["A1"])
404412
return src_liquid_height
405413

406-
def _set_pipettte_motion_settings() -> Tuple[float, float, float, float, float]:
414+
def _set_pipettte_motion_settings() -> Tuple[
415+
float, float, float, float, float, float
416+
]:
407417
if ctx.params.use_pip_motion_defaults: # type: ignore [attr-defined]
408418
aspirate_submerge_speed = 50
409419
dispense_submerge_speed = 50
410420
aspirate_exit_speed = 50
411421
dispense_exit_speed = 50
412-
if not ctx.is_simulating: # type: ignore [truthy-function]
422+
air_gap = 0.0
423+
if not ctx.is_simulating():
413424
from hardware_testing.gravimetric.liquid_class.defaults import (
414425
get_liquid_class,
415426
)
@@ -423,6 +434,7 @@ def _set_pipettte_motion_settings() -> Tuple[float, float, float, float, float]:
423434
pip.flow_rate.aspirate = liquid_class.aspirate.plunger_flow_rate
424435
pip.flow_rate.dispense = liquid_class.dispense.plunger_flow_rate
425436
set_push_out = liquid_class.dispense.blow_out_submerged
437+
air_gap = liquid_class.aspirate.trailing_air_gap
426438
else: # if simulating
427439
pip.flow_rate.aspirate = ctx.params.asp_flow_rate # type: ignore [attr-defined]
428440
pip.flow_rate.dispense = ctx.params.disp_flow_rate # type: ignore [attr-defined]
@@ -434,12 +446,14 @@ def _set_pipettte_motion_settings() -> Tuple[float, float, float, float, float]:
434446
pip.flow_rate.blow_out = ctx.params.blowout_flow_rate # type: ignore [attr-defined]
435447
aspirate_submerge_speed = ctx.params.asp_submerge_speed # type: ignore [attr-defined]
436448
dispense_submerge_speed = ctx.params.disp_submerge_speed # type: ignore [attr-defined]
449+
air_gap = ctx.params.air_gap # type: ignore [attr-defined]
437450
return (
438451
aspirate_submerge_speed,
439452
aspirate_exit_speed,
440453
dispense_submerge_speed,
441454
dispense_exit_speed,
442455
set_push_out,
456+
air_gap,
443457
)
444458

445459
(
@@ -448,6 +462,7 @@ def _set_pipettte_motion_settings() -> Tuple[float, float, float, float, float]:
448462
dispense_submerge_speed,
449463
dispense_exit_speed,
450464
set_push_out,
465+
air_gap,
451466
) = _set_pipettte_motion_settings()
452467
current_src_volume = ctx.params.dye_volume # type: ignore [attr-defined]
453468
current_plate_volume = 0
@@ -504,6 +519,7 @@ def _set_pipettte_motion_settings() -> Tuple[float, float, float, float, float]:
504519
location=dye_source["A1"].top(),
505520
speed=aspirate_exit_speed,
506521
)
522+
pip.air_gap(air_gap, height=0)
507523
# Retract pipette
508524
pip._retract()
509525
# Pause after aspiration

0 commit comments

Comments
 (0)