Skip to content

Commit

Permalink
confirm all DUT serial numbers in production-qc tests
Browse files Browse the repository at this point in the history
  • Loading branch information
andySigler committed Jul 31, 2023
1 parent c7a78b7 commit 06b0df8
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 76 deletions.
27 changes: 21 additions & 6 deletions hardware-testing/hardware_testing/data/csv_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ def print_csv_result(test: str, result: CSVResult) -> None:
META_DATA_TEST_NAME = "test_name"
META_DATA_TEST_TAG = "test_tag"
META_DATA_TEST_RUN_ID = "test_run_id"
META_DATA_TEST_DEVICE_ID = "test_device_id"
META_DATA_TEST_ROBOT_ID = "test_robot_id"
META_DATA_TEST_TIME_UTC = "test_time_utc"
META_DATA_TEST_OPERATOR = "test_operator"
META_DATA_TEST_VERSION = "test_version"
Expand Down Expand Up @@ -260,8 +262,10 @@ def _generate_meta_data_section() -> CSVSection:
CSVLine(tag=META_DATA_TEST_NAME, data=[str]),
CSVLine(tag=META_DATA_TEST_TAG, data=[str]),
CSVLine(tag=META_DATA_TEST_RUN_ID, data=[str]),
CSVLine(tag=META_DATA_TEST_DEVICE_ID, data=[str, CSVResult]),
CSVLine(tag=META_DATA_TEST_ROBOT_ID, data=[str]),
CSVLine(tag=META_DATA_TEST_TIME_UTC, data=[str]),
CSVLine(tag=META_DATA_TEST_OPERATOR, data=[str]),
CSVLine(tag=META_DATA_TEST_OPERATOR, data=[str, CSVResult]),
CSVLine(tag=META_DATA_TEST_VERSION, data=[str]),
CSVLine(tag=META_DATA_TEST_FIRMWARE, data=[str]),
],
Expand Down Expand Up @@ -291,7 +295,7 @@ def __init__(
self._tag: Optional[str] = None
self._file_name: Optional[str] = None
_section_meta = _generate_meta_data_section()
_section_titles = [s.title for s in sections]
_section_titles = [META_DATA_TITLE] + [s.title for s in sections]
_section_results = _generate_results_overview_section(_section_titles)
self._sections = [_section_meta, _section_results] + sections
self._cache_start_time(start_time) # must happen before storing any data
Expand Down Expand Up @@ -330,9 +334,11 @@ def __getitem__(self, item: str) -> CSVSection:
raise ValueError(f"unexpected section title: {item}")

def _refresh_results_overview_values(self) -> None:
for s in self._sections[2:]:
section = self[RESULTS_OVERVIEW_TITLE]
line = section[f"RESULT_{s.title}"]
results_section = self[RESULTS_OVERVIEW_TITLE]
for s in self._sections:
if s == results_section:
continue
line = results_section[f"RESULT_{s.title}"]
assert isinstance(line, CSVLine)
line.store(CSVResult.PASS, print_results=False)
if s.result_passed:
Expand Down Expand Up @@ -382,9 +388,18 @@ def set_tag(self, tag: str) -> None:
)
self.save_to_disk()

def set_device_id(self, device_id: str, result: CSVResult) -> None:
"""Store DUT serial number."""
self(META_DATA_TITLE, META_DATA_TEST_DEVICE_ID, [device_id, result])

def set_robot_id(self, robot_id: str) -> None:
"""Store robot serial number."""
self(META_DATA_TITLE, META_DATA_TEST_ROBOT_ID, [robot_id])

def set_operator(self, operator: str) -> None:
"""Set operator."""
self(META_DATA_TITLE, META_DATA_TEST_OPERATOR, [operator])
result = CSVResult.from_bool(bool(operator))
self(META_DATA_TITLE, META_DATA_TEST_OPERATOR, [operator, result])

def set_version(self, version: str) -> None:
"""Set version."""
Expand Down
3 changes: 3 additions & 0 deletions hardware-testing/hardware_testing/gravimetric/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import List, Tuple, Any

from hardware_testing.data.csv_report import (
CSVResult,
CSVReport,
CSVSection,
CSVLine,
Expand Down Expand Up @@ -310,6 +311,8 @@ def store_serial_numbers(
liquid: str,
) -> None:
"""Report serial numbers."""
report.set_robot_id(robot)
report.set_device_id(pipette, CSVResult.PASS)
report("SERIAL-NUMBERS", "robot", [robot])
report("SERIAL-NUMBERS", "pipette", [pipette])
report("SERIAL-NUMBERS", "tips", [tips])
Expand Down
10 changes: 10 additions & 0 deletions hardware-testing/hardware_testing/opentrons_api/helpers_ot3.py
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,16 @@ def get_pipette_serial_ot3(pipette: Union[PipetteOT2, PipetteOT3]) -> str:
return f"P{volume}{channels}V{version}{id}"


def get_robot_serial_ot3(api: OT3API) -> str:
"""Get robot serial number."""
if api.is_simulator:
return "FLXA1000000000000"
robot_id = api._backend.eeprom_data.serial_number
if not robot_id:
robot_id = "None"
return robot_id


def clear_pipette_ul_per_mm(api: OT3API, mount: OT3Mount) -> None:
"""Clear pipette ul-per-mm."""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,52 @@
from pathlib import Path

from hardware_testing.data import ui, get_git_description
from hardware_testing.data.csv_report import RESULTS_OVERVIEW_TITLE
from hardware_testing.data.csv_report import RESULTS_OVERVIEW_TITLE, CSVResult
from hardware_testing.opentrons_api import helpers_ot3
from hardware_testing.opentrons_api.types import OT3Mount, Axis

from .config import TestSection, TestConfig, build_report, TESTS, TESTS_INCREMENT


async def _main(cfg: TestConfig) -> None:
# BUILD REPORT
test_name = Path(__file__).parent.name
ui.print_title(test_name.replace("_", " ").upper())
report = build_report(test_name.replace("_", "-"))
version = get_git_description()
report.set_version(version)
print(f"version: {version}")
if not cfg.simulate:
report.set_operator(input("enter operator name: "))
else:
report.set_operator("simulation")

# BUILD API
api = await helpers_ot3.build_async_ot3_hardware_api(
is_simulating=cfg.simulate,
pipette_left="p1000_single_v3.3",
pipette_right="p1000_single_v3.3",
gripper="GRPV1120230323A01",
)
report.set_firmware(api.fw_version)
robot_id = helpers_ot3.get_robot_serial_ot3(api)
print(f"robot serial: {robot_id}")
report.set_robot_id(robot_id)

# GRIPPER SERIAL NUMBER
gripper = api.attached_gripper
assert gripper
gripper_id = str(gripper["gripper_id"])
report.set_tag(gripper_id)
if not api.is_simulator:
barcode = input("SCAN gripper serial number: ").strip()
else:
barcode = str(gripper_id)
barcode_pass = CSVResult.from_bool(barcode == gripper_id)
print(f"barcode: {barcode} ({barcode_pass})")
report.set_device_id(gripper_id, result=barcode_pass)

# HOME and ATTACH
await api.home_z(OT3Mount.GRIPPER)
await api.home()
home_pos = await api.gantry_position(OT3Mount.GRIPPER)
Expand All @@ -30,22 +61,6 @@ async def _main(cfg: TestConfig) -> None:
ui.get_user_ready("attach a gripper")
await api.reset()

gripper = api.attached_gripper
assert gripper
gripper_id = str(gripper["gripper_id"])

# BUILD REPORT
test_name = Path(__file__).parent.name
ui.print_title(test_name.replace("_", " ").upper())
report = build_report(test_name.replace("_", "-"))
report.set_tag(gripper_id)
if not cfg.simulate:
report.set_operator(input("enter operator name: "))
else:
report.set_operator("simulation")
report.set_version(get_git_description())
report.set_firmware(api.fw_version)

# RUN TESTS
for section, test_run in cfg.tests.items():
ui.print_title(section.value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
FORCE_GAUGE_TRIAL_SAMPLE_INTERVAL = 0.25 # seconds
FORCE_GAUGE_TRIAL_SAMPLE_COUNT = 20 # 20 samples = 5 seconds @ 4Hz

GAUGE_OFFSET = Point(x=2, y=42, z=75)
GAUGE_OFFSET = Point(x=2, y=-42, z=75)


def _get_test_tag(
Expand Down Expand Up @@ -151,7 +151,7 @@ async def _setup(api: OT3API) -> Union[Mark10, SimMark10]:
await helpers_ot3.move_to_arched_ot3(api, mount, target_pos + Point(z=15))
if not api.is_simulator:
ui.get_user_ready("please make sure the gauge in the middle of the gripper")
await api.move_to(mount, target_pos)
await helpers_ot3.jog_mount_ot3(api, OT3Mount.GRIPPER)
if not api.is_simulator:
ui.get_user_ready("about to grip")
await api.grip(20)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,47 @@
from pathlib import Path

from hardware_testing.data import ui, get_git_description
from hardware_testing.data.csv_report import RESULTS_OVERVIEW_TITLE
from hardware_testing.data.csv_report import RESULTS_OVERVIEW_TITLE, CSVResult
from hardware_testing.opentrons_api import helpers_ot3
from hardware_testing.opentrons_api.types import OT3Mount, Axis

from .config import TestSection, TestConfig, build_report, TESTS


async def _main(cfg: TestConfig) -> None:
# BUILD REPORT
test_name = Path(__file__).parent.name
ui.print_title(test_name.replace("_", " ").upper())
report = build_report(test_name.replace("_", "-"))
report.set_version(get_git_description())
if not cfg.simulate:
report.set_operator(input("enter operator name: "))
else:
report.set_operator("simulation")

# BUILD API
api = await helpers_ot3.build_async_ot3_hardware_api(
is_simulating=cfg.simulate,
pipette_left="p1000_96_v3.4",
)
await api.home()
home_pos = await api.gantry_position(OT3Mount.LEFT)
report.set_robot_id(helpers_ot3.get_robot_serial_ot3(api))

# PIPETTE SERIAL NUMBER
mount = OT3Mount.LEFT
pipette = api.hardware_pipettes[mount.to_mount()]
assert pipette
pipette_id = str(pipette.pipette_id)
report.set_tag(pipette_id)
if not api.is_simulator:
barcode = input("scan pipette barcode: ").strip()
barcode_result = CSVResult(barcode == pipette_id)
report.set_device_id(pipette_id, barcode_result)
else:
report.set_device_id(pipette_id, CSVResult.PASS)

# HOME and ATTACH
await api.home()
home_pos = await api.gantry_position(mount)
attach_pos = helpers_ot3.get_slot_calibration_square_position_ot3(5)
attach_pos = attach_pos._replace(z=home_pos.z)
if not api.hardware_pipettes[mount.to_mount()]:
Expand All @@ -30,27 +55,12 @@ async def _main(cfg: TestConfig) -> None:
while not api.hardware_pipettes[mount.to_mount()]:
ui.get_user_ready("attach a 96ch pipette")
await api.reset()
await api.home_z(OT3Mount.LEFT)

pipette = api.hardware_pipettes[mount.to_mount()]
assert pipette
pipette_id = str(pipette.pipette_id)
await api.home_z(mount)

# FIXME: remove this once the "'L' format requires 0 <= number <= 4294967295" bug is gone
await api._backend.home([Axis.P_L], api.gantry_load)
await api.refresh_positions()

# BUILD REPORT
test_name = Path(__file__).parent.name
ui.print_title(test_name.replace("_", " ").upper())
report = build_report(test_name.replace("_", "-"))
report.set_tag(pipette_id)
if not cfg.simulate:
report.set_operator(input("enter operator name: "))
else:
report.set_operator("simulation")
report.set_version(get_git_description())

# RUN TESTS
for section, test_run in cfg.tests.items():
ui.print_title(section.value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
)
from opentrons_shared_data.errors.exceptions import StallOrCollisionDetectedError

from hardware_testing.data import get_git_description
from hardware_testing.data.csv_report import (
CSVReport,
CSVResult,
Expand Down Expand Up @@ -42,17 +43,11 @@
MAX_SPEED = max(TEST_SPEEDS)


def _get_operator(is_simulating: bool) -> str:
if is_simulating:
return "simulating"
return input("enter OPERATOR name: ")


def _get_test_tag(current: float, speed: float, direction: str, pos: str) -> str:
return f"current-{current}-speed-{speed}-{direction}-{pos}"


def _build_csv_report(operator: str, pipette_sn: str) -> CSVReport:
def _build_csv_report() -> CSVReport:
_report = CSVReport(
test_name="pipette-current-speed-qc-ot3",
sections=[
Expand All @@ -74,9 +69,6 @@ def _build_csv_report(operator: str, pipette_sn: str) -> CSVReport:
),
],
)
_report.set_tag(pipette_sn)
_report.set_version("unknown")
_report.set_operator(operator)
return _report


Expand Down Expand Up @@ -239,7 +231,10 @@ async def _main(is_simulating: bool) -> None:
pipette_left="p1000_single_v3.4",
pipette_right="p1000_multi_v3.4",
)
_operator = _get_operator(api.is_simulator)
if not api.is_simulator:
operator = input("enter OPERATOR name: ")
else:
operator = "simulation"
# home and move to a safe position
await _reset_gantry(api)

Expand All @@ -252,7 +247,16 @@ async def _main(is_simulating: bool) -> None:
ui.print_title(f"{pipette_sn} - {mount.name}")
if not api.is_simulator and not ui.get_user_answer("QC this pipette"):
continue
report = _build_csv_report(_operator, pipette_sn)
report = _build_csv_report()
report.set_version(get_git_description())
report.set_operator(operator)
report.set_robot_id(helpers_ot3.get_robot_serial_ot3(api))
report.set_tag(pipette_sn)
if not api.is_simulator:
barcode = input("scan pipette barcode: ")
else:
barcode = str(pipette_sn)
report.set_device_id(pipette_sn, CSVResult.from_bool(barcode == pipette_sn))
failing_current = await _test_plunger(api, mount, report)
report(
"OVERALL",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pathlib import Path

from hardware_testing.data import ui, get_git_description
from hardware_testing.data.csv_report import RESULTS_OVERVIEW_TITLE
from hardware_testing.data.csv_report import RESULTS_OVERVIEW_TITLE, CSVResult
from hardware_testing.opentrons_api import helpers_ot3

from .config import TestSection, TestConfig, build_report, TESTS
Expand All @@ -15,17 +15,13 @@ async def _main(cfg: TestConfig) -> None:
test_name = Path(__file__).parent.name
report = build_report(test_name)
ui.print_title(test_name.replace("_", " ").upper())
report.set_version(get_git_description())

# GET INFO
# GET OPERATOR
if not cfg.simulate:
robot_id = input("enter robot serial number: ")
operator = input("enter operator name: ")
report.set_operator(input("enter operator name: "))
else:
robot_id = "ot3-simulated-A01"
operator = "simulation"
report.set_tag(robot_id)
report.set_operator(operator)
report.set_version(get_git_description())
report.set_operator("simulation")

# BUILD API
api = await helpers_ot3.build_async_ot3_hardware_api(
Expand All @@ -36,6 +32,16 @@ async def _main(cfg: TestConfig) -> None:
gripper="GRPV102",
)

# GET ROBOT SERIAL NUMBER
robot_id = helpers_ot3.get_robot_serial_ot3(api)
report.set_tag(robot_id)
report.set_robot_id(robot_id)
if not api.is_simulator:
barcode = input("scan robot barcode: ").strip()
report.set_device_id(robot_id, CSVResult.from_bool(barcode == robot_id))
else:
report.set_device_id(robot_id, CSVResult.PASS)

# RUN TESTS
for section, test_run in cfg.tests.items():
ui.print_title(section.value)
Expand Down
Loading

0 comments on commit 06b0df8

Please sign in to comment.