Skip to content

Commit

Permalink
feat(shared-data, api, hardware-testing): add the p200_96 (#17105)
Browse files Browse the repository at this point in the history
<!--
Thanks for taking the time to open a Pull Request (PR)! Please make sure
you've read the "Opening Pull Requests" section of our Contributing
Guide:


https://github.com/Opentrons/opentrons/blob/edge/CONTRIBUTING.md#opening-pull-requests

GitHub provides robust markdown to format your PR. Links, diagrams,
pictures, and videos along with text formatting make it possible to
create a rich and informative PR. For more information on GitHub
markdown, see:


https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax

To ensure your code is reviewed quickly and thoroughly, please fill out
the sections below to the best of your ability!
-->

# Overview

This pulls in the changes from several different hardware-testing
branches/tags that have diverged in the factory and includes all the
work for the p200_96 that has happened on those branches.

<!--
Describe your PR at a high level. State acceptance criteria and how this
PR fits into other work. Link issues, PRs, and other relevant resources.
-->

## Test Plan and Hands on Testing

<!--
Describe your testing of the PR. Emphasize testing not reflected in the
code. Attach protocols, logs, screenshots and any other assets that
support your testing.
-->

## Changelog

<!--
List changes introduced by this PR considering future developers and the
end user. Give careful thought and clear documentation to breaking
changes.
-->

## Review requests

<!--
- What do you need from reviewers to feel confident this PR is ready to
merge?
- Ask questions.
-->

## Risk assessment

<!--
- Indicate the level of attention this PR needs.
- Provide context to guide reviewers.
- Discuss trade-offs, coupling, and side effects.
- Look for the possibility, even if you think it's small, that your
change may affect some other part of the system.
- For instance, changing return tip behavior may also change the
behavior of labware calibration.
- How do your unit tests and on hands on testing mitigate this PR's
risks and the risk of future regressions?
- Especially in high risk PRs, explain how you know your testing is
enough.
-->

---------

Co-authored-by: Andiiiiiiyy <[email protected]>
  • Loading branch information
ryanthecoder and Andiiiiiiyy authored Jan 14, 2025
1 parent 63a93b3 commit a95a156
Show file tree
Hide file tree
Showing 43 changed files with 2,556 additions and 178 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,11 @@ export function ProtocolInstrumentMountItem(
[]
)
const [flowType, setFlowType] = useState<string>(FLOWS.ATTACH)
const selectedPipette =
speccedName === 'p1000_96' ? NINETY_SIX_CHANNEL : SINGLE_MOUNT_PIPETTES
const is96ChannelPipette =
speccedName === 'p1000_96' || speccedName === 'p200_96'
const selectedPipette = is96ChannelPipette
? NINETY_SIX_CHANNEL
: SINGLE_MOUNT_PIPETTES

const handleCalibrate: MouseEventHandler = () => {
setFlowType(FLOWS.CALIBRATE)
Expand All @@ -95,7 +98,7 @@ export function ProtocolInstrumentMountItem(
setShowPipetteWizardFlow(true)
}
}
const is96ChannelPipette = speccedName === 'p1000_96'

const isAttachedWithCal =
attachedInstrument != null &&
attachedInstrument.ok &&
Expand Down
5 changes: 4 additions & 1 deletion app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,10 @@ export const BeforeBeginning = (
const displayName = pipetteDisplayName ?? requiredPipette.pipetteName
bodyTranslationKey = 'remove_labware'

if (requiredPipette.pipetteName === 'p1000_96') {
if (
requiredPipette.pipetteName === 'p1000_96' ||
requiredPipette.pipetteName === 'p200_96'
) {
equipmentList = [
{ ...NINETY_SIX_CHANNEL_PIPETTE, displayName },
CALIBRATION_PROBE,
Expand Down
3 changes: 2 additions & 1 deletion app/src/organisms/PipetteWizardFlows/DetachPipette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ export const DetachPipette = (props: DetachPipetteProps): JSX.Element => {
}
const memoizedAttachedPipettes = useMemo(() => attachedPipettes, [])
const is96ChannelPipette =
memoizedAttachedPipettes[mount]?.instrumentName === 'p1000_96'
memoizedAttachedPipettes[mount]?.instrumentName === 'p1000_96' ||
memoizedAttachedPipettes[mount]?.instrumentName === 'p200_96'
const pipetteName =
attachedPipettes[mount] != null
? attachedPipettes[mount]?.displayName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,11 @@ export const getPipetteWizardStepsForProtocol = (
): PipetteWizardStep[] | null => {
const requiredPipette = pipetteInfo.find(pipette => pipette.mount === mount)
const ninetySixChannelAttached =
attachedPipettes[LEFT]?.instrumentName === 'p1000_96'
const ninetySixChannelRequested = requiredPipette?.pipetteName === 'p1000_96'
attachedPipettes[LEFT]?.instrumentName === 'p1000_96' ||
attachedPipettes[LEFT]?.instrumentName === 'p200_96'
const ninetySixChannelRequested =
requiredPipette?.pipetteName === 'p1000_96' ||
requiredPipette?.pipetteName === 'p200_96'

if (requiredPipette == null) {
// return empty array if no pipette is required in the protocol
Expand Down
8 changes: 6 additions & 2 deletions app/src/organisms/PipetteWizardFlows/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,14 @@ export function usePipetteFlowWizardHeaderText(
)
} else if (
attachedPipettes[LEFT]?.data.channels === 96 &&
mountPipette?.pipetteName !== 'p1000_96'
mountPipette?.pipetteName !== 'p1000_96' &&
mountPipette?.pipetteName !== 'p200_96'
) {
return t('detach_96_attach_mount', { mount: capitalizedMount })
} else if (leftPipette?.pipetteName === 'p1000_96') {
} else if (
leftPipette?.pipetteName === 'p1000_96' ||
leftPipette?.pipetteName === 'p200_96'
) {
if (isGantryEmpty) {
return t('attach_96_channel')
} else if (
Expand Down
7 changes: 7 additions & 0 deletions hardware-testing/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ test-photometric:
$(python) -m hardware_testing.gravimetric --photometric --simulate --pipette 1000 --channels 96 --tip 50 --trials 1
$(python) -m hardware_testing.gravimetric --photometric --simulate --pipette 1000 --channels 96 --tip 200 --trials 1
$(python) -m hardware_testing.gravimetric --photometric --simulate --pipette 200 --channels 96 --tip 50 --trials 1
$(python) -m hardware_testing.gravimetric --photometric --simulate --pipette 200 --channels 96 --tip 20 --trials 1

.PHONY: test-gravimetric-single
test-gravimetric-single:
Expand All @@ -123,6 +124,7 @@ test-gravimetric-multi:
test-gravimetric-96:
$(python) -m hardware_testing.gravimetric --simulate --pipette 1000 --channels 96 --trials 2 --no-blank
$(python) -m hardware_testing.gravimetric --simulate --pipette 200 --channels 96 --trials 2 --no-blank
$(python) -m hardware_testing.gravimetric --simulate --pipette 200 --channels 96 --trials 1 --no-blank --increment --tip 20

.PHONY: test-gravimetric
test-gravimetric:
Expand Down Expand Up @@ -229,6 +231,11 @@ push-no-restart-ot3: sdist Pipfile.lock
.PHONY: push-ot3
push-ot3: push-no-restart-ot3 push-plot-webpage-ot3 push-description-ot3 push-labware-ot3

.PHONE: open-dev-app
open-dev-app:
cd .. && $(MAKE) -C app dev


.PHONY: push-all
push-all: clean wheel push-no-restart push-plot-webpage-ot3

Expand Down
28 changes: 19 additions & 9 deletions hardware-testing/hardware_testing/gravimetric/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,12 @@

GRAVIMETRIC_CFG_INCREMENT = {
50: {
1: {50: gravimetric_ot3_p50_single},
1: {20: gravimetric_ot3_p50_single, 50: gravimetric_ot3_p50_single},
8: {50: gravimetric_ot3_p50_multi_50ul_tip_increment},
},
200: {
96: {
20: gravimetric_ot3_p200_96,
50: gravimetric_ot3_p200_96,
200: gravimetric_ot3_p200_96,
},
Expand Down Expand Up @@ -117,14 +118,19 @@
PHOTOMETRIC_CFG = {
50: {
1: {
20: photometric_ot3_p50_single,
50: photometric_ot3_p50_single,
},
8: {
50: photometric_ot3_p50_multi,
},
},
200: {
96: {50: photometric_ot3_p200_96, 200: photometric_ot3_p200_96},
96: {
20: photometric_ot3_p200_96,
50: photometric_ot3_p200_96,
200: photometric_ot3_p200_96,
},
},
1000: {
1: {
Expand All @@ -137,7 +143,11 @@
200: photometric_ot3_p1000_multi,
1000: photometric_ot3_p1000_multi,
},
96: {50: photometric_ot3_p1000_96, 200: photometric_ot3_p1000_96},
96: {
20: photometric_ot3_p1000_96,
50: photometric_ot3_p1000_96,
200: photometric_ot3_p1000_96,
},
},
}

Expand Down Expand Up @@ -177,11 +187,11 @@ def _get_protocol_context(cls, args: argparse.Namespace) -> ProtocolContext:
"Starting opentrons-robot-server, so we can http GET labware offsets"
)
LABWARE_OFFSETS.extend(workarounds.http_get_all_labware_offsets())
ui.print_info(f"found {len(LABWARE_OFFSETS)} offsets:")
for offset in LABWARE_OFFSETS:
ui.print_info(f"\t{offset.createdAt}:")
ui.print_info(f"\t\t{offset.definitionUri}")
ui.print_info(f"\t\t{offset.vector}")
# ui.print_info(f"found {len(LABWARE_OFFSETS)} offsets:")
# for offset in LABWARE_OFFSETS:
# ui.print_info(f"\t{offset.createdAt}:")
# ui.print_info(f"\t\t{offset.definitionUri}")
# ui.print_info(f"\t\t{offset.vector}")
# gather the custom labware (for simulation)
custom_defs = {}
if args.simulate:
Expand Down Expand Up @@ -572,7 +582,7 @@ def _main(
parser.add_argument("--simulate", action="store_true")
parser.add_argument("--pipette", type=int, choices=[50, 200, 1000], required=True)
parser.add_argument("--channels", type=int, choices=[1, 8, 96], default=1)
parser.add_argument("--tip", type=int, choices=[0, 50, 200, 1000], default=0)
parser.add_argument("--tip", type=int, choices=[0, 20, 50, 200, 1000], default=0)
parser.add_argument("--trials", type=int, default=0)
parser.add_argument("--increment", action="store_true")
parser.add_argument("--return-tip", action="store_true")
Expand Down
66 changes: 51 additions & 15 deletions hardware-testing/hardware_testing/gravimetric/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,30 +88,40 @@ class PhotometricConfig(VolumetricConfig):
LIQUID_PROBE_SETTINGS: Dict[int, Dict[int, Dict[int, Dict[str, int]]]] = {
50: {
1: {
20: {
"mount_speed": 5,
"plunger_speed": 15,
"sensor_threshold_pascals": 15,
},
50: {
"mount_speed": 5,
"plunger_speed": 20,
"plunger_speed": 15,
"sensor_threshold_pascals": 15,
},
},
8: {
50: {
"mount_speed": 5,
"plunger_speed": 20,
"plunger_speed": 15,
"sensor_threshold_pascals": 15,
},
},
},
200: {
96: {
20: {
"mount_speed": 5,
"plunger_speed": 5,
"sensor_threshold_pascals": 15,
},
50: {
"mount_speed": 5,
"plunger_speed": 20,
"plunger_speed": 5,
"sensor_threshold_pascals": 15,
},
200: {
"mount_speed": 5,
"plunger_speed": 20,
"plunger_speed": 5,
"sensor_threshold_pascals": 15,
},
}
Expand All @@ -120,51 +130,56 @@ class PhotometricConfig(VolumetricConfig):
1: {
50: {
"mount_speed": 5,
"plunger_speed": 20,
"plunger_speed": 15,
"sensor_threshold_pascals": 15,
},
200: {
"mount_speed": 5,
"plunger_speed": 20,
"plunger_speed": 15,
"sensor_threshold_pascals": 15,
},
1000: {
"mount_speed": 5,
"plunger_speed": 20,
"plunger_speed": 15,
"sensor_threshold_pascals": 15,
},
},
8: {
50: {
"mount_speed": 5,
"plunger_speed": 20,
"plunger_speed": 15,
"sensor_threshold_pascals": 15,
},
200: {
"mount_speed": 5,
"plunger_speed": 20,
"plunger_speed": 15,
"sensor_threshold_pascals": 15,
},
1000: {
"mount_speed": 5,
"plunger_speed": 20,
"plunger_speed": 15,
"sensor_threshold_pascals": 15,
},
},
96: {
20: {
"mount_speed": 5,
"plunger_speed": 5,
"sensor_threshold_pascals": 15,
},
50: {
"mount_speed": 5,
"plunger_speed": 20,
"plunger_speed": 5,
"sensor_threshold_pascals": 15,
},
200: {
"mount_speed": 5,
"plunger_speed": 20,
"plunger_speed": 5,
"sensor_threshold_pascals": 15,
},
1000: {
"mount_speed": 5,
"plunger_speed": 20,
"plunger_speed": 5,
"sensor_threshold_pascals": 15,
},
},
Expand Down Expand Up @@ -194,6 +209,7 @@ def _get_liquid_probe_settings(
QC_VOLUMES_G: Dict[int, Dict[int, List[Tuple[int, List[float]]]]] = {
1: {
50: [ # P50
(20, [1.0, 20.0]),
(50, [1.0, 50.0]), # T50
],
1000: [ # P1000
Expand All @@ -214,10 +230,12 @@ def _get_liquid_probe_settings(
},
96: {
200: [
(20, [0.5, 1.0]), # T20
(50, [1.0, 50.0]), # T50
(200, [200.0]), # T200
],
1000: [ # P1000
(20, [5.0]),
(50, [5.0]), # T50
(200, [200.0]), # T200
(1000, [1000.0]), # T1000
Expand Down Expand Up @@ -279,7 +297,8 @@ def _get_liquid_probe_settings(
},
96: {
200: [
(50, [1.0, 5.0]), # T50
(20, [1.0, 0.5]), # T50
(50, [50.0]), # T50
(200, [200.0]), # T200
],
1000: [ # P1000
Expand Down Expand Up @@ -311,6 +330,11 @@ def _get_liquid_probe_settings(
# channels: [Pipette: [tip: [Volume: (%d, Cv)]]]
1: {
50: { # P50
20: {
1.0: (5.0, 4.0),
10.0: (1.0, 0.5),
20.0: (1, 0.4),
},
50: {
1.0: (5.0, 4.0),
10.0: (1.0, 0.5),
Expand Down Expand Up @@ -363,12 +387,16 @@ def _get_liquid_probe_settings(
},
96: {
200: {
50: { # T50
20: { # T20
0.5: (2.5, 2.0),
1.0: (2.5, 2.0),
2.0: (2.5, 2.0),
3.0: (2.5, 2.0),
5.0: (2.5, 2.0),
10.0: (3.1, 1.7),
},
50: { # T50
1.0: (2.5, 2.0),
50.0: (1.5, 0.75),
},
200: { # T200
Expand All @@ -378,6 +406,14 @@ def _get_liquid_probe_settings(
},
},
1000: { # P1000
20: { # T20
1.0: (2.5, 2.0),
2.0: (2.5, 2.0),
3.0: (2.5, 2.0),
5.0: (2.5, 2.0),
10.0: (3.1, 1.7),
20.0: (3.1, 1.7),
},
50: { # T50
1.0: (2.5, 2.0),
2.0: (2.5, 2.0),
Expand Down
2 changes: 1 addition & 1 deletion hardware-testing/hardware_testing/gravimetric/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ def run(cfg: config.GravimetricConfig, resources: TestResources) -> None: # noq
assert resources.recorder is not None
recorder = resources.recorder
if resources.ctx.is_simulating():
start_sim_mass = {50: 15, 200: 200, 1000: 200}
start_sim_mass = {20: 5, 50: 15, 200: 200, 1000: 200}
resources.recorder.set_simulation_mass(start_sim_mass[cfg.tip_volume])
os.makedirs(
f"{resources.test_report.parent}/{resources.test_report._run_id}", exist_ok=True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"B": {"min": 10, "max": 49.99},
"C": {"min": 2, "max": 9.999},
"D": {"min": 1, "max": 1.999},
"E": {"min": 0, "max": 0.9999},
}
_MIN_START_VOLUME_UL = {1: 500, 8: 3000, 96: 30000}
_MIN_END_VOLUME_UL = {1: 400, 8: 3000, 96: 10000}
Expand Down Expand Up @@ -191,6 +192,8 @@ def _record_measurement_and_store(m_type: MeasurementType) -> EnvironmentData:
)

_record_measurement_and_store(MeasurementType.ASPIRATE)
if not trial.ctx.is_simulating():
input("请记录吸液状态,并尝试拍摄清晰的吸液后的针管照片..........")
for i in range(num_dispenses):
dest_name = _get_photo_plate_dest(trial.cfg, trial.trial)
dest_well = trial.dest[dest_name]
Expand All @@ -215,6 +218,8 @@ def _record_measurement_and_store(m_type: MeasurementType) -> EnvironmentData:
touch_tip=trial.cfg.touch_tip,
)
_record_measurement_and_store(MeasurementType.DISPENSE)
if not trial.ctx.is_simulating():
input("请记录排液状态,并尝试拍摄清晰的排液后的针管照片..........")
trial.pipette._retract() # retract to top of gantry
if (i + 1) == num_dispenses:
if not trial.cfg.same_tip:
Expand Down
Loading

0 comments on commit a95a156

Please sign in to comment.