Skip to content

Commit de69d01

Browse files
committed
fix(hardware-testing): Various fixes for the flex stacker diagnostics script for Shenzhen. (#17916)
1 parent a3ff338 commit de69d01

File tree

11 files changed

+75
-48
lines changed

11 files changed

+75
-48
lines changed

api/src/opentrons/drivers/asyncio/communication/serial_connection.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,19 @@ def raise_on_error(self, response: str, request: str) -> None:
257257
258258
Raises: SerialException
259259
"""
260+
if not response or not request:
261+
return
262+
260263
lower = response.lower()
264+
res_gcode = response.split()[0]
265+
req_gcode = request.split()[0]
266+
267+
# Make sure this is not just a normal response that happens to contain the
268+
# `err` or `alarm` keyword in the message body by checking the gcode values
269+
# for both the request and response. If the gcodes are the same then this
270+
# is not an error response.
271+
if res_gcode == req_gcode:
272+
return
261273

262274
if self._alarm_keyword in lower:
263275
raise AlarmResponse(port=self._port, response=response)

api/tests/opentrons/drivers/asyncio/communication/test_serial_connection.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,23 @@ def test_raise_on_error(
180180
subject.raise_on_error(response, "fake request")
181181

182182

183+
def test_raise_on_error_no_raise_on_keyword_in_body(
184+
subject: SerialKind,
185+
) -> None:
186+
"""It should not raise when there is a keyword in the response body."""
187+
request = "M226 Z"
188+
# This response contains `eRR` which tricks the system into thinking there is an
189+
# error, we fixed this by making sure the request and response gcodes match.
190+
response = "M226 Z I:12 D:gW2ACQuAAAAAAAAAAAAAAAAAAAABAQAAAAAAAAAAAAAAAAAAAAAAAA"
191+
"AAAAAAAAAAAAAAAAAAAACPbxeRRikcFhINCQYFBAICAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
192+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
193+
subject.raise_on_error(response, request)
194+
195+
# This should still raise
196+
with pytest.raises(expected_exception=ErrorResponse, match="error"):
197+
subject.raise_on_error("error", request)
198+
199+
183200
def test_get_error_codes_lowercase(
184201
subject: SerialKind,
185202
) -> None:

hardware-testing/hardware_testing/modules/flex_stacker_dvt_qc/__main__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import argparse
99
import asyncio
10+
import subprocess
1011
from pathlib import Path
1112
from typing import Tuple
1213

@@ -42,6 +43,8 @@ async def _main(cfg: TestConfig) -> None:
4243
report, stacker = await build_stacker_report(cfg.simulate)
4344

4445
if not cfg.simulate:
46+
print("Stopping the robot server")
47+
subprocess.run(["systemctl stop opentrons-robot-server"], shell=True)
4548
# Perform initial checks before starting tests
4649
# 1. estop should not be pressed
4750
# 2. platform should be removed
@@ -76,6 +79,11 @@ async def _main(cfg: TestConfig) -> None:
7679
report.save_to_disk()
7780
report.print_results()
7881

82+
# Restart the robot server
83+
if not cfg.simulate:
84+
print("Starting the robot server")
85+
subprocess.run(["systemctl restart opentrons-robot-server &"], shell=True)
86+
7987

8088
if __name__ == "__main__":
8189
parser = argparse.ArgumentParser()

hardware-testing/hardware_testing/modules/flex_stacker_dvt_qc/test_estop.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ async def run(stacker: FlexStacker, report: CSVReport, section: str) -> None:
101101
limit_switch_triggered = await stacker._driver.get_limit_switch(
102102
StackerAxis.L, l_limit
103103
)
104-
if not limit_switch_triggered:
104+
if limit_switch_triggered:
105105
report(
106106
section,
107107
"l-move-disabled",
@@ -111,7 +111,7 @@ async def run(stacker: FlexStacker, report: CSVReport, section: str) -> None:
111111
print("try to move L axis off the limit switch...")
112112
try:
113113
await stacker._driver.move_in_mm(
114-
StackerAxis.L, l_limit.opposite().distance(1)
114+
StackerAxis.L, l_limit.opposite().distance(5)
115115
)
116116
except EStopTriggered:
117117
print("E-Stop Error is raised")
@@ -120,7 +120,7 @@ async def run(stacker: FlexStacker, report: CSVReport, section: str) -> None:
120120
report(
121121
section,
122122
"l-move-disabled",
123-
[CSVResult.from_bool(triggered)],
123+
[CSVResult.from_bool(not triggered)],
124124
)
125125

126126
if not stacker._simulating:

hardware-testing/hardware_testing/modules/flex_stacker_dvt_qc/test_install_detection.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ async def run(stacker: FlexStacker, report: CSVReport, section: str) -> None:
2525
"""Run."""
2626
ui.print_header("Window Detected")
2727
if not stacker._simulating:
28-
ui.get_user_ready("Attach to detection pins")
28+
ui.get_user_ready("Press the window detect switch")
2929
detected = await stacker._driver.get_installation_detected()
3030
report(section, "window-detected-high", [CSVResult.from_bool(detected)])
3131

3232
ui.print_header("Window Not Detected")
3333
if not stacker._simulating:
34-
ui.get_user_ready("Remove from detection pins")
34+
ui.get_user_ready("Un-press the window detect switch")
3535
not_detected = not await stacker._driver.get_installation_detected()
3636
report(section, "window-not-detected-low", [CSVResult.from_bool(not_detected)])

hardware-testing/hardware_testing/modules/flex_stacker_dvt_qc/test_tof_basic.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from opentrons.drivers.flex_stacker.types import (
1414
Direction,
1515
StackerAxis,
16-
LEDPattern,
1716
TOFSensor,
1817
)
1918

@@ -84,11 +83,9 @@ async def test_get_tof_sensor_histogram(
8483

8584
async def run(stacker: FlexStacker, report: CSVReport, section: str) -> None:
8685
"""Run."""
87-
# Reset LEDs to off
8886
if not stacker._simulating:
8987
ui.get_user_ready("Make sure both TOF sensors are installed.")
9088
ui.get_user_ready("Make sure there is no labware in the stacker.")
91-
await stacker._driver.set_led(0, pattern=LEDPattern.STATIC)
9289

9390
print("Homing stacker X and Z axis.")
9491
await stacker.home_axis(StackerAxis.X, Direction.EXTEND)

hardware-testing/hardware_testing/modules/flex_stacker_dvt_qc/test_tof_functional.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from opentrons.drivers.flex_stacker.types import (
1717
Direction,
1818
StackerAxis,
19-
LEDPattern,
2019
TOFSensor,
2120
)
2221

@@ -95,10 +94,8 @@ async def test_tof_sensors_labware_detection(
9594

9695
async def run(stacker: FlexStacker, report: CSVReport, section: str) -> None:
9796
"""Run."""
98-
# Reset LEDs to off
9997
if not stacker._simulating:
10098
ui.get_user_ready("Make sure both TOF sensors are installed.")
101-
await stacker._driver.set_led(0, pattern=LEDPattern.STATIC)
10299

103100
print("Homing stacker X and Z axis.")
104101
await stacker.home_axis(StackerAxis.X, Direction.EXTEND)
@@ -134,3 +131,4 @@ async def run(stacker: FlexStacker, report: CSVReport, section: str) -> None:
134131
await test_tof_sensors_labware_detection(
135132
stacker, report, section, TOFSensor.Z, "tiprack"
136133
)
134+
ui.get_user_ready("Please remove all labware from the stacker.")

hardware-testing/hardware_testing/modules/flex_stacker_dvt_qc/test_ui_leds.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,9 @@ async def run(stacker: FlexStacker, report: CSVReport, section: str) -> None:
4949
else:
5050
led_on = True
5151
report(section, f"{tag}-{color}", [CSVResult.from_bool(led_on)])
52+
53+
# Turn LEDs back to green
54+
if not stacker._simulating:
55+
await stacker._driver.set_led(
56+
0.5, color=LEDColor.GREEN, pattern=LEDPattern.STATIC
57+
)

hardware-testing/hardware_testing/modules/flex_stacker_dvt_qc/test_uv_lockout_switch.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ async def run(stacker: FlexStacker, report: CSVReport, section: str) -> None:
2828
ui.get_user_ready("Open the hopper door")
2929
door_open = not await stacker._driver.get_hopper_door_closed()
3030
if door_open:
31-
ui.print_info("Meausre between J1 and J4")
32-
open = not ui.get_user_answer("Is there continuity (closed circuit)?")
31+
open = ui.get_user_answer("Is the UV lockout LED off?")
3332
# circuit should be open
3433
report(
3534
section,
@@ -45,7 +44,7 @@ async def run(stacker: FlexStacker, report: CSVReport, section: str) -> None:
4544
ui.get_user_ready("Close the hopper door")
4645
door_closed = await stacker._driver.get_hopper_door_closed()
4746
if door_closed:
48-
closed = ui.get_user_answer("Is there continuity (closed circuit)?")
47+
closed = ui.get_user_answer("Is the UV lockout LED on?")
4948
report(
5049
section,
5150
"closed-door-closed-circuit",

hardware-testing/hardware_testing/modules/flex_stacker_dvt_qc/utils.py

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Utility functions for the Flex Stacker EVT QC module."""
22
from collections import defaultdict
33
import statistics
4-
from typing import Dict, List
4+
from typing import Any, Dict, List
55
from opentrons.drivers.flex_stacker.driver import TOFSensor
66
from opentrons.drivers.flex_stacker.utils import NUMBER_OF_BINS, NUMBER_OF_ZONES
77
from hardware_testing.data import ui
@@ -14,6 +14,12 @@
1414
from opentrons.drivers.flex_stacker.types import StackerAxis, Direction
1515

1616

17+
TOF_DETECTION_CONFIG: Dict[TOFSensor, Dict[str, Any]] = {
18+
TOFSensor.X: {"zones": [5, 6, 7], "bins": list(range(10, 20)), "threshold": 30000},
19+
TOFSensor.Z: {"zones": [1], "bins": list(range(50, 56)), "threshold": 20000},
20+
}
21+
22+
1723
async def test_limit_switches_per_direction(
1824
stacker: FlexStacker,
1925
axis: StackerAxis,
@@ -115,39 +121,23 @@ def labware_detected(
115121
zones: List[int],
116122
) -> Dict[int, List[int]]:
117123
"""Detect labware by subtracting baseline from histogram."""
118-
print(f"Detect labware: {sensor}")
119124
baseline: Dict[int, List[float]] = STACKER_TOF_BASELINE[sensor]
120125
diff = defaultdict(list)
121-
if sensor == TOFSensor.Z:
122-
for zone in zones:
123-
raw_data = histogram[zone]
124-
baseline_data = baseline[zone]
125-
for bin in bins:
126-
delta = raw_data[bin] - baseline_data[bin]
127-
if delta > 0:
128-
print(
129-
f"detected: zn: {zone} bn: {bin} count: {raw_data[bin]} dt: {delta}"
130-
)
131-
diff[zone].append(delta)
132-
elif sensor == TOFSensor.X:
133-
for zone in zones:
134-
# We only care about these zones because the X sensor is angled and
135-
# most of the zones are always detecting obsticles.
136-
if zone not in [5, 6, 7]:
126+
config = TOF_DETECTION_CONFIG[sensor]
127+
for zone in zones:
128+
if zone not in config["zones"]:
129+
continue
130+
raw_data = histogram[zone]
131+
baseline_data = baseline[zone]
132+
for bin in bins:
133+
if bin not in config["bins"]:
134+
continue
135+
if raw_data[bin] < config["threshold"]:
137136
continue
138-
raw_data = histogram[zone]
139-
baseline_data = baseline[zone]
140-
for bin in bins:
141-
if bin not in range(10, 20):
142-
continue
143-
# We need to ignore raw photon count below 10000 on the X as
144-
# it becomes inconsistent to detect labware on the home position.
145-
if raw_data[bin] < 10000:
146-
continue
147-
delta = raw_data[bin] - baseline_data[bin]
148-
if delta > 0:
149-
print(
150-
f"detected: zn: {zone} bn: {bin} count: {raw_data[bin]} dt: {delta}"
151-
)
152-
diff[zone].append(delta)
137+
delta = raw_data[bin] - baseline_data[bin]
138+
if delta > 0:
139+
print(
140+
f"detected: zn: {zone} bn: {bin} count: {raw_data[bin]} dt: {delta}"
141+
)
142+
diff[zone].append(delta)
153143
return dict(diff) # type: ignore

0 commit comments

Comments
 (0)