Skip to content

Commit 1cb77b3

Browse files
authored
feat(hardware-testing,api,shared-data): Add TOF-Analysis tool to generate, plot, and validate baselines and measurements + related improvements. (#18875)
1 parent 32a5e92 commit 1cb77b3

File tree

71 files changed

+15315
-2817
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+15315
-2817
lines changed
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from .abstract import AbstractFlexStackerDriver
2-
from .driver import FlexStackerDriver, STACKER_MOTION_CONFIG, STALLGUARD_CONFIG
2+
from .driver import FlexStackerDriver
33
from .simulator import SimulatingDriver
44
from . import types as FlexStackerTypes
55
from . import utils as FlexStackerUtils
@@ -10,6 +10,4 @@
1010
"SimulatingDriver",
1111
"FlexStackerTypes",
1212
"FlexStackerUtils",
13-
"STACKER_MOTION_CONFIG",
14-
"STALLGUARD_CONFIG",
1513
]

api/src/opentrons/drivers/flex_stacker/driver.py

Lines changed: 3 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,10 @@
2525
StackerInfo,
2626
HardwareRevision,
2727
MoveParams,
28-
AxisParams,
2928
LimitSwitchStatus,
3029
LEDColor,
3130
StallGuardParams,
3231
TOFConfiguration,
33-
TOFDetection,
3432
TOFMeasurement,
3533
TOFMeasurementFrame,
3634
TOFMeasurementResult,
@@ -49,6 +47,7 @@
4947
DEFAULT_FS_TIMEOUT = 5
5048
FS_MOVE_TIMEOUT = 20
5149
FS_TOF_TIMEOUT = 20
50+
FS_TOF_FRAME_RETRIES = 1
5251
FS_TOF_INIT_TIMEOUT = 5
5352
FS_ACK = "OK\n"
5453
FS_ERROR_KEYWORD = "err"
@@ -61,103 +60,6 @@
6160
MAX_DURATION_MS = 10000 # 10s
6261
MAX_REPS = 10
6362

64-
# TOF Sensor
65-
TOF_FRAME_RETRIES = 1
66-
TOF_DETECTION_CONFIG = {
67-
TOFSensor.X: {
68-
Direction.EXTEND: TOFDetection(
69-
TOFSensor.X,
70-
zones=[5, 6, 7],
71-
bins=list(range(10, 40)),
72-
threshold=5000,
73-
),
74-
Direction.RETRACT: TOFDetection(
75-
TOFSensor.X,
76-
zones=[5, 6, 7],
77-
bins=list(range(10, 25)),
78-
threshold=15000,
79-
),
80-
},
81-
TOFSensor.Z: {
82-
Direction.EXTEND: TOFDetection(
83-
TOFSensor.Z,
84-
zones=[1, 2, 3],
85-
bins=list(range(10, 60)),
86-
threshold=5000,
87-
),
88-
},
89-
}
90-
91-
92-
# Stallguard defaults
93-
STALLGUARD_CONFIG = {
94-
StackerAxis.X: StallGuardParams(StackerAxis.X, True, 2),
95-
StackerAxis.Z: StallGuardParams(StackerAxis.Z, True, 2),
96-
}
97-
98-
STACKER_MOTION_CONFIG = {
99-
StackerAxis.X: {
100-
"home": AxisParams(
101-
run_current=1.5, # mAmps
102-
hold_current=0.75,
103-
move_params=MoveParams(
104-
max_speed=10.0, # mm/s
105-
acceleration=100.0, # mm/s^2
106-
max_speed_discont=40.0, # mm/s
107-
),
108-
),
109-
"move": AxisParams(
110-
run_current=1.2,
111-
hold_current=0.75,
112-
move_params=MoveParams(
113-
max_speed=200.0,
114-
acceleration=1500.0,
115-
max_speed_discont=40.0,
116-
),
117-
),
118-
},
119-
StackerAxis.Z: {
120-
"home": AxisParams(
121-
run_current=1.5,
122-
hold_current=1.5,
123-
move_params=MoveParams(
124-
max_speed=10.0,
125-
acceleration=100.0,
126-
max_speed_discont=25.0,
127-
),
128-
),
129-
"move": AxisParams(
130-
run_current=1.5,
131-
hold_current=1.5,
132-
move_params=MoveParams(
133-
max_speed=150.0,
134-
acceleration=500.0,
135-
max_speed_discont=25.0,
136-
),
137-
),
138-
},
139-
StackerAxis.L: {
140-
"home": AxisParams(
141-
run_current=1.2,
142-
hold_current=0.5,
143-
move_params=MoveParams(
144-
max_speed=100.0,
145-
acceleration=800.0,
146-
max_speed_discont=40.0,
147-
),
148-
),
149-
"move": AxisParams(
150-
run_current=1.2,
151-
hold_current=0.5,
152-
move_params=MoveParams(
153-
max_speed=100.0,
154-
acceleration=800.0,
155-
max_speed_discont=40.0,
156-
),
157-
),
158-
},
159-
}
160-
16163

16264
class FlexStackerDriver(AbstractFlexStackerDriver):
16365
"""FLEX Stacker driver."""
@@ -559,7 +461,7 @@ async def get_tof_histogram(self, sensor: TOFSensor) -> TOFMeasurementResult:
559461
data_len = 0
560462
next_frame_id = 0
561463
resend = False
562-
retries = TOF_FRAME_RETRIES
464+
retries = FS_TOF_FRAME_RETRIES
563465

564466
# Cancel any ongoing measurements
565467
status = await self.get_tof_sensor_status(sensor)
@@ -584,7 +486,7 @@ async def get_tof_histogram(self, sensor: TOFSensor) -> TOFMeasurementResult:
584486
assert (
585487
not data_len > start.total_bytes
586488
), f"Invalid number of bytes, expected {start.total_bytes} got {data_len}."
587-
retries = TOF_FRAME_RETRIES
489+
retries = FS_TOF_FRAME_RETRIES
588490
next_frame_id += 1
589491
resend = False
590492
except (ValueError, NoResponse):

api/src/opentrons/drivers/flex_stacker/types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ class Direction(Enum):
134134

135135
def __str__(self) -> str:
136136
"""Convert to tag for clear logging."""
137-
return "negative" if self == Direction.RETRACT else "positive"
137+
return self.name.lower()
138138

139139
def opposite(self) -> "Direction":
140140
"""Get opposite direction."""

api/src/opentrons/hardware_control/modules/flex_stacker.py

Lines changed: 112 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import asyncio
44
import logging
5-
from typing import Any, Awaitable, Callable, Dict, Optional, Mapping
5+
from typing import Any, Awaitable, Callable, Dict, Literal, Optional, Mapping, cast
66

77
from opentrons.drivers.flex_stacker.types import (
88
AxisParams,
@@ -12,6 +12,8 @@
1212
MoveParams,
1313
MoveResult,
1414
StackerAxis,
15+
StallGuardParams,
16+
TOFDetection,
1517
TOFSensor,
1618
HardwareRevision,
1719
TOFSensorMode,
@@ -20,9 +22,6 @@
2022
)
2123
from opentrons.drivers.rpi_drivers.types import USBPort
2224
from opentrons.drivers.flex_stacker.driver import (
23-
STACKER_MOTION_CONFIG,
24-
STALLGUARD_CONFIG,
25-
TOF_DETECTION_CONFIG,
2625
FlexStackerDriver,
2726
)
2827
from opentrons.drivers.flex_stacker.abstract import AbstractFlexStackerDriver
@@ -81,6 +80,108 @@
8180
# touches the +Z endstop.
8281
PLATFORM_OFFSET = 4
8382

83+
# Configs
84+
TOF_DETECTION_CONFIG = {
85+
TOFSensor.X: {
86+
Direction.EXTEND: TOFDetection(
87+
TOFSensor.X,
88+
zones=[5, 6, 7],
89+
bins=list(range(30, 40)),
90+
threshold=1000,
91+
),
92+
Direction.RETRACT: TOFDetection(
93+
TOFSensor.X,
94+
zones=[5, 6, 7],
95+
bins=list(range(17, 30)),
96+
threshold=1000,
97+
),
98+
},
99+
TOFSensor.Z: {
100+
Direction.EXTEND: TOFDetection(
101+
TOFSensor.Z,
102+
zones=[1, 2, 3],
103+
bins=list(range(15, 63)),
104+
threshold=1000,
105+
),
106+
Direction.RETRACT: TOFDetection(
107+
TOFSensor.Z,
108+
zones=[1, 2, 3],
109+
bins=list(range(15, 63)),
110+
threshold=1000,
111+
),
112+
},
113+
}
114+
115+
116+
# Stallguard defaults
117+
STALLGUARD_CONFIG = {
118+
StackerAxis.X: StallGuardParams(StackerAxis.X, True, 0),
119+
StackerAxis.Z: StallGuardParams(StackerAxis.Z, True, 0),
120+
}
121+
122+
STACKER_MOTION_CONFIG = {
123+
StackerAxis.X: {
124+
"home": AxisParams(
125+
run_current=1.5, # mAmps
126+
hold_current=0.75,
127+
move_params=MoveParams(
128+
max_speed=10.0, # mm/s
129+
acceleration=100.0, # mm/s^2
130+
max_speed_discont=40.0, # mm/s
131+
),
132+
),
133+
"move": AxisParams(
134+
run_current=1.2,
135+
hold_current=0.75,
136+
move_params=MoveParams(
137+
max_speed=200.0,
138+
acceleration=1500.0,
139+
max_speed_discont=40.0,
140+
),
141+
),
142+
},
143+
StackerAxis.Z: {
144+
"home": AxisParams(
145+
run_current=1.5,
146+
hold_current=1.5,
147+
move_params=MoveParams(
148+
max_speed=10.0,
149+
acceleration=100.0,
150+
max_speed_discont=25.0,
151+
),
152+
),
153+
"move": AxisParams(
154+
run_current=1.5,
155+
hold_current=1.5,
156+
move_params=MoveParams(
157+
max_speed=150.0,
158+
acceleration=500.0,
159+
max_speed_discont=25.0,
160+
),
161+
),
162+
},
163+
StackerAxis.L: {
164+
"home": AxisParams(
165+
run_current=1.2,
166+
hold_current=0.5,
167+
move_params=MoveParams(
168+
max_speed=100.0,
169+
acceleration=800.0,
170+
max_speed_discont=40.0,
171+
),
172+
),
173+
"move": AxisParams(
174+
run_current=1.2,
175+
hold_current=0.5,
176+
move_params=MoveParams(
177+
max_speed=100.0,
178+
acceleration=800.0,
179+
max_speed_discont=40.0,
180+
),
181+
),
182+
},
183+
}
184+
84185

85186
class FlexStacker(mod_abc.AbstractModule):
86187
"""Hardware control interface for an attached Flex-Stacker module."""
@@ -412,7 +513,7 @@ async def dispense_labware(
412513
self.verify_labware_height(labware_height)
413514
await self._prepare_for_action()
414515
if enforce_hopper_lw_sensing:
415-
await self.verify_hopper_labware_presence(True)
516+
await self.verify_hopper_labware_presence(Direction.RETRACT, True)
416517

417518
# Move platform along the X then Z axis
418519
await self._move_and_home_axis(StackerAxis.X, Direction.RETRACT, HOME_OFFSET_MD)
@@ -538,10 +639,9 @@ async def labware_detected(self, axis: StackerAxis, direction: Direction) -> boo
538639
labware on the Z, but we need to do more data collection and testing
539640
to validate this method.
540641
"""
642+
dir_str = cast(Literal["extend", "retract"], str(direction))
541643
sensor = TOFSensor.X if axis == StackerAxis.X else TOFSensor.Z
542-
# The TOF Detection configs are the same for the Z sensor
543-
direction = Direction.EXTEND if sensor == TOFSensor.Z else direction
544-
baseline = load_tof_baseline_data(self.model())[sensor.value]
644+
baseline = load_tof_baseline_data(self.model())[sensor.value][dir_str]
545645
config = TOF_DETECTION_CONFIG[sensor][direction]
546646

547647
# Take a histogram reading and determine if labware was detected
@@ -586,9 +686,11 @@ async def verify_shuttle_labware_presence(
586686
labware_expected=labware_expected,
587687
)
588688

589-
async def verify_hopper_labware_presence(self, labware_expected: bool) -> None:
689+
async def verify_hopper_labware_presence(
690+
self, direction: Direction, labware_expected: bool
691+
) -> None:
590692
"""Check whether or not a labware is detected inside the hopper."""
591-
result = await self.labware_detected(StackerAxis.Z, Direction.EXTEND)
693+
result = await self.labware_detected(StackerAxis.Z, direction)
592694
if labware_expected != result:
593695
raise FlexStackerHopperLabwareError(
594696
self.device_info["serial"],

api/tests/opentrons/hardware_control/modules/test_hc_flexstacker.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
import pytest
33
import mock
44
from typing import AsyncGenerator
5-
from opentrons.drivers.flex_stacker.driver import (
6-
STACKER_MOTION_CONFIG,
7-
)
85
from opentrons.drivers.flex_stacker.simulator import SimulatingDriver
96
from opentrons.drivers.flex_stacker.types import (
107
Direction,
@@ -22,6 +19,7 @@
2219
HOME_OFFSET_SM,
2320
PLATFORM_OFFSET,
2421
SIMULATING_POLL_PERIOD,
22+
STACKER_MOTION_CONFIG,
2523
FlexStackerReader,
2624
)
2725
from opentrons.hardware_control.modules.types import PlatformState
@@ -417,7 +415,7 @@ async def test_dispense_labware_motion_sequence(
417415
)
418416

419417
# We need to verify the move sequence
420-
verify_hopper_labware_presence.assert_called_once_with(True)
418+
verify_hopper_labware_presence.assert_called_once_with(Direction.RETRACT, True)
421419
_prepare_for_action.assert_called()
422420
_move_and_home_axis.assert_any_call(
423421
StackerAxis.X, Direction.RETRACT, HOME_OFFSET_MD
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Production QC for modules
2+
3+
This directory is for Production Diagnostics scripts + QC protocols for modules
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Production QC for the Flex Stacker Module."""

0 commit comments

Comments
 (0)