Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hardware-testing): add the p200_96 to production qc test scripts #16779

Merged
merged 1 commit into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions hardware-testing/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ test-production-qc:
$(python) -m hardware_testing.production_qc.robot_assembly_qc_ot3 --simulate
$(python) -m hardware_testing.production_qc.gripper_assembly_qc_ot3 --simulate
$(python) -m hardware_testing.production_qc.ninety_six_assembly_qc_ot3 --simulate
$(python) -m hardware_testing.production_qc.ninety_six_assembly_qc_ot3 --simulate --pipette 200
$(python) -m hardware_testing.production_qc.stress_test_qc_ot3 --simulate
$(python) -m hardware_testing.production_qc.firmware_check --simulate
$(python) -m hardware_testing.production_qc.belt_calibration_ot3 --simulate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ async def _main(cfg: TestConfig) -> None:
# BUILD REPORT
test_name = Path(__file__).parent.name
ui.print_title(test_name.replace("_", " ").upper())

pipette_string = "p1000_96_v3.4" if cfg.pipette == 1000 else "p200_96_v3.0"
# BUILD API
api = await helpers_ot3.build_async_ot3_hardware_api(
is_simulating=cfg.simulate,
pipette_left="p1000_96_v3.4",
pipette_left=pipette_string,
)

# CSV REPORT
Expand Down Expand Up @@ -49,7 +49,7 @@ async def _main(cfg: TestConfig) -> None:
# RUN TESTS
for section, test_run in cfg.tests.items():
ui.print_title(section.value)
await test_run(api, report, section.value)
await test_run(api, report, section.value, cfg.pipette)

# RELOAD PIPETTE
ui.print_title("DONE")
Expand All @@ -71,6 +71,7 @@ async def _main(cfg: TestConfig) -> None:
parser.add_argument(
f"--only-{s.value.lower()}".replace("_", "-"), action="store_true"
)
parser.add_argument("--pipette", type=int, choices=[200, 1000], default=1000)
args = parser.parse_args()
_t_sections = {
s: f
Expand All @@ -87,5 +88,7 @@ async def _main(cfg: TestConfig) -> None:
for s, f in TESTS
if not getattr(args, f"skip_{s.value.lower().replace('-', '_')}")
}
_config = TestConfig(simulate=args.simulate, tests=_t_sections)
_config = TestConfig(
simulate=args.simulate, tests=_t_sections, pipette=args.pipette
)
asyncio.run(_main(_config))
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Config."""
from dataclasses import dataclass
import enum
from typing import Dict, Callable
from typing import Dict, Callable, Literal

from hardware_testing.data.csv_report import CSVReport, CSVSection

Expand Down Expand Up @@ -34,6 +34,7 @@ class TestConfig:

simulate: bool
tests: Dict[TestSection, Callable]
pipette: Literal[200, 1000]


TESTS = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Test Capacitance."""
from asyncio import sleep
from typing import List, Union, Tuple, Optional, cast
from typing import List, Union, Tuple, Optional, cast, Literal

from opentrons_hardware.hardware_control.tool_sensors import capacitive_probe
from opentrons_hardware.firmware_bindings.constants import NodeId, SensorId
Expand Down Expand Up @@ -104,7 +104,9 @@ def _get_hover_and_probe_pos(
return hover_pos + probe_offset, probe_pos + probe_offset


async def run(api: OT3API, report: CSVReport, section: str) -> None:
async def run(
api: OT3API, report: CSVReport, section: str, pipette: Literal[200, 1000]
) -> None:
"""Run."""
z_ax = Axis.Z_L
p_ax = Axis.P_L
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Test Droplets."""
from asyncio import sleep
from time import time
from typing import List, Union, Tuple, Optional, Dict
from typing import List, Union, Tuple, Optional, Dict, Literal

from opentrons.hardware_control.ot3api import OT3API
from opentrons.hardware_control.motion_utilities import target_position_from_relative
Expand All @@ -16,14 +16,11 @@
from hardware_testing.opentrons_api import helpers_ot3
from hardware_testing.opentrons_api.types import OT3Mount, Point, Axis

TIP_VOLUME = 1000
ASPIRATE_VOLUME = 1000
NUM_SECONDS_TO_WAIT = 30
HOVER_HEIGHT_MM = 50
DEPTH_INTO_RESERVOIR_FOR_ASPIRATE = -24
DEPTH_INTO_RESERVOIR_FOR_DISPENSE = DEPTH_INTO_RESERVOIR_FOR_ASPIRATE

TIP_RACK_LABWARE = f"opentrons_flex_96_tiprack_{TIP_VOLUME}ul"
RESERVOIR_LABWARE = "nest_1_reservoir_195ml"

TIP_RACK_96_SLOT = 4
Expand Down Expand Up @@ -86,31 +83,31 @@ def get_reservoir_nominal() -> Point:
return reservoir_a1_nominal


def get_tiprack_96_nominal() -> Point:
def get_tiprack_96_nominal(pipette: Literal[200, 1000]) -> Point:
"""Get nominal tiprack position for 96-tip pick-up."""
tip_rack_a1_nominal = helpers_ot3.get_theoretical_a1_position(
TIP_RACK_96_SLOT, TIP_RACK_LABWARE
TIP_RACK_96_SLOT, f"opentrons_flex_96_tiprack_{pipette}ul"
)
return tip_rack_a1_nominal + Point(z=TIP_RACK_96_ADAPTER_HEIGHT)


def get_tiprack_partial_nominal() -> Point:
def get_tiprack_partial_nominal(pipette: Literal[200, 1000]) -> Point:
"""Get nominal tiprack position for partial-tip pick-up."""
tip_rack_a1_nominal = helpers_ot3.get_theoretical_a1_position(
TIP_RACK_PARTIAL_SLOT, TIP_RACK_LABWARE
TIP_RACK_PARTIAL_SLOT, f"opentrons_flex_96_tiprack_{pipette}ul"
)
return tip_rack_a1_nominal


async def aspirate_and_wait(
api: OT3API, reservoir: Point, seconds: int = 30
api: OT3API, reservoir: Point, pipette: Literal[200, 1000], seconds: int = 30
) -> Tuple[bool, float]:
"""Aspirate and wait."""
await helpers_ot3.move_to_arched_ot3(api, OT3Mount.LEFT, reservoir)
await api.move_to(
OT3Mount.LEFT, reservoir + Point(z=DEPTH_INTO_RESERVOIR_FOR_ASPIRATE)
)
await api.aspirate(OT3Mount.LEFT, ASPIRATE_VOLUME)
await api.aspirate(OT3Mount.LEFT, pipette)
await api.move_to(OT3Mount.LEFT, reservoir + Point(z=HOVER_HEIGHT_MM))

start_time = time()
Expand All @@ -136,15 +133,15 @@ async def aspirate_and_wait(
return result, duration_seconds


async def _drop_tip(api: OT3API, trash: Point) -> None:
async def _drop_tip(api: OT3API, trash: Point, pipette: Literal[200, 1000]) -> None:
print("drop in trash")
await helpers_ot3.move_to_arched_ot3(api, OT3Mount.LEFT, trash + Point(z=20))
await api.move_to(OT3Mount.LEFT, trash)
await api.drop_tip(OT3Mount.LEFT)
# NOTE: a FW bug (as of v14) will sometimes not fully drop tips.
# so here we ask if the operator needs to try again
while not api.is_simulator and ui.get_user_answer("try dropping again"):
api.add_tip(OT3Mount.LEFT, helpers_ot3.get_default_tip_length(TIP_VOLUME))
api.add_tip(OT3Mount.LEFT, helpers_ot3.get_default_tip_length(pipette))
await api.drop_tip(OT3Mount.LEFT)
await api.home_z(OT3Mount.LEFT)

Expand All @@ -164,24 +161,28 @@ async def _partial_pick_up_z_motion(
await api._update_position_estimation([Axis.Z_L])


async def _partial_pick_up(api: OT3API, position: Point, current: float) -> None:
async def _partial_pick_up(
api: OT3API, position: Point, current: float, pipette: Literal[200, 1000]
) -> None:
await helpers_ot3.move_to_arched_ot3(
api,
OT3Mount.LEFT,
position,
safe_height=position.z + 10,
)
await _partial_pick_up_z_motion(api, current=current, distance=13, speed=5)
api.add_tip(OT3Mount.LEFT, helpers_ot3.get_default_tip_length(TIP_VOLUME))
api.add_tip(OT3Mount.LEFT, helpers_ot3.get_default_tip_length(pipette))
await api.prepare_for_aspirate(OT3Mount.LEFT)
await api.home_z(OT3Mount.LEFT)


async def run(api: OT3API, report: CSVReport, section: str) -> None:
async def run(
api: OT3API, report: CSVReport, section: str, pipette: Literal[200, 1000]
) -> None:
"""Run."""
# GATHER NOMINAL POSITIONS
trash_nominal = get_trash_nominal()
tip_rack_96_a1_nominal = get_tiprack_96_nominal()
tip_rack_96_a1_nominal = get_tiprack_96_nominal(pipette)
# tip_rack_partial_a1_nominal = get_tiprack_partial_nominal()
reservoir_a1_nominal = get_reservoir_nominal()
reservoir_a1_actual: Optional[Point] = None
Expand All @@ -208,7 +209,7 @@ async def _find_reservoir_pos() -> None:
)
await helpers_ot3.jog_mount_ot3(api, OT3Mount.LEFT)
print("picking up tips")
await api.pick_up_tip(OT3Mount.LEFT, helpers_ot3.get_default_tip_length(TIP_VOLUME))
await api.pick_up_tip(OT3Mount.LEFT, helpers_ot3.get_default_tip_length(pipette))
await api.home_z(OT3Mount.LEFT)
if not api.is_simulator:
ui.get_user_ready("about to move to RESERVOIR")
Expand All @@ -218,10 +219,13 @@ async def _find_reservoir_pos() -> None:
await _find_reservoir_pos()
assert reservoir_a1_actual
result, duration = await aspirate_and_wait(
api, reservoir_a1_actual, seconds=NUM_SECONDS_TO_WAIT
api,
reservoir_a1_actual,
pipette=pipette,
seconds=NUM_SECONDS_TO_WAIT,
)
report(section, "droplets-96-tips", [duration, CSVResult.from_bool(result)])
await _drop_tip(api, trash_nominal)
await _drop_tip(api, trash_nominal, pipette)

# if not api.is_simulator:
# ui.get_user_ready(f"REMOVE 96 tip-rack from slot #{TIP_RACK_96_SLOT}")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Test Environmental Sensor."""
from asyncio import sleep
from typing import List, Union
from typing import List, Union, Literal

from opentrons.hardware_control.ot3api import OT3API

Expand Down Expand Up @@ -33,7 +33,9 @@ def _remove_outliers_and_average(values: List[float]) -> float:
return sum(no_outliers) / len(no_outliers)


async def run(api: OT3API, report: CSVReport, section: str) -> None:
async def run(
api: OT3API, report: CSVReport, section: str, pipette: Literal[200, 1000]
) -> None:
"""Run."""
await api.home_z(OT3Mount.LEFT)
slot_5 = helpers_ot3.get_slot_calibration_square_position_ot3(5)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Test Jaws."""
from typing import List, Union, Tuple, Dict
from typing import List, Union, Tuple, Dict, Literal

from opentrons.hardware_control.ot3api import OT3API

Expand Down Expand Up @@ -98,7 +98,9 @@ async def jaw_precheck(api: OT3API, ax: Axis, speed: float) -> Tuple[bool, bool]
return led_check, jaws_aligned


async def run(api: OT3API, report: CSVReport, section: str) -> None:
async def run(
api: OT3API, report: CSVReport, section: str, pipette: Literal[200, 1000]
) -> None:
"""Run."""
ax = Axis.Q
settings = helpers_ot3.get_gantry_load_per_axis_motion_settings_ot3(api, ax)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Test Plunger."""
from typing import List, Union, Tuple, Dict
from typing import List, Union, Tuple, Dict, Literal

from opentrons.hardware_control.ot3api import OT3API

Expand Down Expand Up @@ -53,7 +53,9 @@ async def _is_plunger_still_aligned_with_encoder(
return p_enc, p_est, is_aligned


async def run(api: OT3API, report: CSVReport, section: str) -> None:
async def run(
api: OT3API, report: CSVReport, section: str, pipette: Literal[200, 1000]
) -> None:
"""Run."""
ax = Axis.P_L
mount = OT3Mount.LEFT
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Test Pressure."""
from asyncio import sleep
from typing import List, Union
from typing import List, Union, Literal

from opentrons_hardware.firmware_bindings.constants import SensorId

Expand Down Expand Up @@ -94,7 +94,9 @@ def check_value(test_value: float, test_name: str) -> CSVResult:
return CSVResult.FAIL


async def run(api: OT3API, report: CSVReport, section: str) -> None:
async def run(
api: OT3API, report: CSVReport, section: str, pipette: Literal[200, 1000]
) -> None:
"""Run."""
await api.home_z(OT3Mount.LEFT)
slot_5 = helpers_ot3.get_slot_calibration_square_position_ot3(5)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Test Tip Sensor."""
import asyncio
from typing import List, Union, cast
from typing import List, Union, cast, Literal

from opentrons_hardware.firmware_bindings import ArbitrationId
from opentrons_hardware.firmware_bindings.constants import MessageId
Expand Down Expand Up @@ -75,7 +75,9 @@ def _listener(message: MessageDefinition, arbitration_id: ArbitrationId) -> None
return result


async def run(api: OT3API, report: CSVReport, section: str) -> None:
async def run(
api: OT3API, report: CSVReport, section: str, pipette: Literal[200, 1000]
) -> None:
"""Run."""
ax = Axis.Q
await api.home_z(OT3Mount.LEFT)
Expand Down
Loading