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(ot3): add shared data support for ot3 pipettes #11704

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fe1340e
feat(ot3): add shared data support for ot3 pipettes
Laura-Danielle Jul 7, 2022
c6baf76
feat(ot3): Add skeletons of information for all new pipettes
Laura-Danielle Jul 15, 2022
252d7d9
feat(ot3): Add pipette config for ot3 pipettes
Laura-Danielle Jul 15, 2022
f44f8ca
Add data types for pipette schema
Laura-Danielle Aug 17, 2022
7580d3c
update pipette data to match hardware
Laura-Danielle Aug 17, 2022
318b576
add data types to handle json files
Laura-Danielle Aug 24, 2022
6a7865d
Handle ot3 pipette objects
Laura-Danielle Aug 24, 2022
77fcd33
wrap current pipette schemas in version 1
Laura-Danielle Aug 25, 2022
cbbe41b
feat(shared-data): add liquid handling for multiple tips
Laura-Danielle Nov 8, 2022
2f2a0f9
update geometry for low throughput pipettes
Laura-Danielle Nov 8, 2022
85735ad
feat: update geometry for high throughput pipettes
Laura-Danielle Nov 9, 2022
eb58d68
json formatting
Laura-Danielle Nov 9, 2022
6271fe6
fix js tests to use version 1 of pipette schemas
Laura-Danielle Nov 9, 2022
d66c066
add new test for version two of pipette schemas
Laura-Danielle Nov 9, 2022
7324349
get rid of unused files
Laura-Danielle Nov 9, 2022
3547105
Don't include files from other branch
Laura-Danielle Nov 9, 2022
06e306f
update configurations to match current testing values
Laura-Danielle Nov 14, 2022
9176ed0
fix js check
Laura-Danielle Nov 14, 2022
561157f
update readme
Laura-Danielle Nov 15, 2022
917e0a2
formatting
Laura-Danielle Nov 15, 2022
83f5159
make lower case keys
Laura-Danielle Nov 15, 2022
ee07df5
add supportedtips top level key
Laura-Danielle Nov 16, 2022
a036f7d
Modify available sensors object
Laura-Danielle Nov 16, 2022
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
2 changes: 1 addition & 1 deletion api/tests/opentrons/config/test_pipette_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from opentrons_shared_data import load_shared_data
from opentrons_shared_data.pipette.dev_types import PipetteModel

defs = json.loads(load_shared_data("pipette/definitions/pipetteModelSpecs.json"))
defs = json.loads(load_shared_data("pipette/definitions/1/pipetteModelSpecs.json"))


def check_sequences_close(
Expand Down
113 changes: 113 additions & 0 deletions shared-data/js/__tests__/pipetteSchemaV2.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import Ajv from 'ajv'
import glob from 'glob'
import path from 'path'

import liquidSpecsSchema from '../../pipette/schemas/2/pipetteLiquidPropertiesSchema.json'
import geometrySpecsSchema from '../../pipette/schemas/2/pipetteGeometrySchema.json'
import generalSpecsSchema from '../../pipette/schemas/2/pipettePropertiesSchema.json'

const allGeometryDefinitions = path.join(
__dirname,
'../../pipette/definitions/2/geometry/**/**/*.json'
)

const allGeneralDefinitions = path.join(
__dirname,
'../../labware/definitions/2/general/**/**/*.json'
)

const allLiquidDefinitions = path.join(
__dirname,
'../../labware/definitions/2/liquid/**/**/*.json'
)

const ajv = new Ajv({ allErrors: true, jsonPointers: true })

const validateLiquidSpecs = ajv.compile(liquidSpecsSchema)
const validateGeometrySpecs = ajv.compile(geometrySpecsSchema)
const validateGeneralSpecs = ajv.compile(generalSpecsSchema)

describe('test schema against all liquid specs definitions', () => {
const liquidPaths = glob.sync(allLiquidDefinitions)

beforeAll(() => {
// Make sure definitions path didn't break, which would give you false positives
expect(liquidPaths.length).toBeGreaterThan(0)
})

liquidPaths.forEach(liquidPath => {
const liquidDef = require(liquidPath)

it(`${liquidPath} validates against schema`, () => {
const valid = validateLiquidSpecs(liquidDef)
const validationErrors = validateLiquidSpecs.errors
expect(validationErrors).toBe(null)
expect(valid).toBe(true)
})

it(`parent dir matches pipette model: ${liquidPath}`, () => {
expect(['p50', 'p1000']).toContain(
path.basename(path.dirname(liquidPath))
)
})
})
})

describe('test schema against all geometry specs definitions', () => {
const geometryPaths = glob.sync(allGeometryDefinitions)

beforeAll(() => {
// Make sure definitions path didn't break, which would give you false positives
expect(geometryPaths.length).toBeGreaterThan(0)
})

geometryPaths.forEach(geometryPath => {
const geometryDef = require(geometryPath)
const geometryParentDir = path.dirname(geometryPath)

it(`${geometryPath} validates against schema`, () => {
const valid = validateGeometrySpecs(geometryDef)
const validationErrors = validateGeometrySpecs.errors
expect(validationErrors).toBe(null)
expect(valid).toBe(true)
})

it(`parent dir matches pipette model: ${geometryPath}`, () => {
expect(['p50', 'p1000']).toContain(
path.basename(path.dirname(geometryPath))
)
})

it(`parent directory contains a gltf file: ${geometryPath}`, () => {
const gltf_file = glob.sync(path.join(geometryParentDir, '*.gltf'))
expect(gltf_file.length).toBeGreaterThan(0)
expect(gltf_file).toBeDefined()
})
})
})

describe('test schema against all general specs definitions', () => {
const generalPaths = glob.sync(allGeneralDefinitions)

beforeAll(() => {
// Make sure definitions path didn't break, which would give you false positives
expect(generalPaths.length).toBeGreaterThan(0)
})

generalPaths.forEach(generalPath => {
const generalDef = require(generalPath)

it(`${generalPath} validates against schema`, () => {
const valid = validateGeneralSpecs(generalDef)
const validationErrors = validateGeneralSpecs.errors
expect(validationErrors).toBe(null)
expect(valid).toBe(true)
})

it(`parent dir matches pipette model: ${generalPath}`, () => {
expect(['p50', 'p1000']).toContain(
path.basename(path.dirname(generalPath))
)
})
})
})
8 changes: 4 additions & 4 deletions shared-data/js/__tests__/pipetteSpecSchemas.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Ajv from 'ajv'
import nameSpecsSchema from '../../pipette/schemas/pipetteNameSpecsSchema.json'
import modelSpecsSchema from '../../pipette/schemas/pipetteModelSpecsSchema.json'
import pipetteNameSpecs from '../../pipette/definitions/pipetteNameSpecs.json'
import pipetteModelSpecs from '../../pipette/definitions/pipetteModelSpecs.json'
import nameSpecsSchema from '../../pipette/schemas/1/pipetteNameSpecsSchema.json'
import modelSpecsSchema from '../../pipette/schemas/1/pipetteModelSpecsSchema.json'
import pipetteNameSpecs from '../../pipette/definitions/1/pipetteNameSpecs.json'
import pipetteModelSpecs from '../../pipette/definitions/1/pipetteModelSpecs.json'

const ajv = new Ajv({ allErrors: true, jsonPointers: true })

Expand Down
4 changes: 2 additions & 2 deletions shared-data/js/pipettes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pipetteNameSpecs from '../pipette/definitions/pipetteNameSpecs.json'
import pipetteModelSpecs from '../pipette/definitions/pipetteModelSpecs.json'
import pipetteNameSpecs from '../pipette/definitions/1/pipetteNameSpecs.json'
import pipetteModelSpecs from '../pipette/definitions/1/pipetteModelSpecs.json'
import { OT3_PIPETTES } from './constants'

import type { PipetteNameSpecs, PipetteModelSpecs } from './types'
Expand Down
37 changes: 33 additions & 4 deletions shared-data/pipette/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,50 @@
# Pipette Spec Data
# Pipette Configurations

## Schema Version 2

Information about our pipettes is now split into 3 different categories of data. Each data file is organized into `<configuration_type>/<pipette_type>/<pipette_model>/<pipette_version>`.

- `configuration_type` is the top level category of data (i.e. `geometry` or `liquid`)
- `pipette_type` is the type of pipette generally referred to by the channel size (i.e. `single_channel` or `eight_channel`)
- `pipette_model` is the max volume of the pipette (i.e. `p50` or `p1000`)
- `pipette_version` is the version number flashed to the pipette (i.e. `v1` or `v1.2`)

This organization is subject to change based on the model name changes that product might make.

### Geometry Configurations: `shared-data/pipette/schemas/2/pipetteGeometrySchema.json`

Pipette geometry configurations includes physical properties that map the pipette end effector in space. In this section of data, we would also like to store 3D model descriptor files that are compatible with typescript and other 3D modeling visualization software for future applications.

We are planning to use [gltf](https://www.khronos.org/gltf/) formatted files as you can choose your 3D model anchors inside solidworks and export the file.

### Liquid Configurations: `shared-data/pipette/schemas/2/pipetteLiquidPropertiesSchema.json`

Pipette liquid configurations include all pipette properties that may affect liquid handling. This includes pipetting function and default flow rates based on tip size.

We have now added in the ability to categorize liquid handling properties by tip type (which can also vary by brand). Eventually, we may need this to be more complex than just a look up dictionary of `tip_type` : `brand+liquid` but we can decide to make that change at a different time.

### General Properties Configurations: `shared-data/pipette/schemas/2/pipettePropertiesSchema.json`

Pipette general properties should be similar to schema version 1 name specs that are shared across pipette type + model.

## Schema Version 1

Information about our pipettes is split into 2 different files.

## Name Level: `shared-data/pipette/definitions/pipetteNameSpecs.json`
### Name Level: `shared-data/pipette/schemas/1/pipetteNameSpecs.json`

A pipette name is what is communicated with customers, what is listed in the store, etc. Name-level information does not vary across pipettes with the same "name", it includes: min and max volume, display name, number of channels, and default aspirate/dispense flow rates.

The "name" is all that is communicated to the average user about a pipette. Both JSON and Python protocols specify pipettes by name; they never specify the pipette model/version.

`"p10_single"` is an example of a name.

## Model Level: `shared-data/pipette/definitions/pipetteModelSpecs.json`
### Model Level: `shared-data/pipette/schemas/1/pipetteModelSpecs.json`

A "model" is synonymous with a part number. Our models / part numbers look like `"p10_single_v1.3"`. Although the name is a substring of the model string, it isn't a good idea to infer name by parsing it out of the model.

The model level contains information specific to particular pipette models. The model can be read off of a pipette's EEPROM at runtime. This information is required for protocol execution on the robot, but is not used directly in the code of JSON or Python protocols.

# JSON Schemas
## JSON Schemas

In `shared-data/pipette/schemas/` there are JSON schemas for these files, which ensure data integrity. Further descriptions about the individual fields are written into the schemas.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$otSharedSchema": "#/pipette/schemas/2/pipettePropertiesSchema.json",
"displayName": "P1000 Eight Channel GEN3",
"model": "eightChannel",
"displayCategory": "GEN3",
"pickUpTipConfigurations": {
"current": 0.5,
"presses": 1,
"speed": 10,
"increment": 0.0,
"distance": 13.0
},
"dropTipConfigurations": {
"current": 1.0,
"speed": 10
},
"plungerMotorConfigurations": {
"idle": 0.3,
"run": 1.0
},
"plungerPositionsConfigurations": {
"top": 0.5,
"bottom": 71.5,
"blowout": 76.5,
"drop": 92.5
},
"availableSensors": {
"sensors": ["pressure", "capacitive", "environment"],
"pressure": { "count": 2 },
"capacitive": { "count": 2 },
"environment": { "count": 1 }
},
"partialTipConfigurations": {
"partialTipSupported": true,
"availableConfigurations": [1, 2, 3, 4, 5, 6, 7, 8]
},
"channels": 8
}
38 changes: 38 additions & 0 deletions shared-data/pipette/definitions/2/general/eight_channel/p50/1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$otSharedSchema": "#/pipette/schemas/2/pipettePropertiesSchema.json",
"displayName": "P50 Eight Channel GEN3",
"model": "eightChannel",
"displayCategory": "GEN3",
"pickUpTipConfigurations": {
"current": 0.5,
"presses": 1,
"speed": 10,
"increment": 0.0,
"distance": 13.0
},
"dropTipConfigurations": {
"current": 1.0,
"speed": 10
},
"plungerMotorConfigurations": {
"idle": 0.3,
"run": 1.0
},
"plungerPositionsConfigurations": {
"top": 0.5,
"bottom": 71.5,
"blowout": 76.5,
"drop": 92.5
},
"availableSensors": {
"sensors": ["pressure", "capacitive", "environment"],
"pressure": { "count": 2 },
"capacitive": { "count": 2 },
"environment": { "count": 1 }
},
"partialTipConfigurations": {
"partialTipSupported": true,
"availableConfigurations": [1, 2, 3, 4, 5, 6, 7, 8]
},
"channels": 8
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$otSharedSchema": "#/pipette/schemas/2/pipettePropertiesSchema.json",
"displayName": "P1000 96 Channel GEN3",
"model": "ninetySixChannel",
"displayCategory": "GEN3",
"pickUpTipConfigurations": {
andySigler marked this conversation as resolved.
Show resolved Hide resolved
"current": 0.4,
"presses": 1,
"speed": 10,
"increment": 0.5,
"distance": 1.0
},
"dropTipConfigurations": {
"current": 1.0,
"speed": 10
},
"plungerMotorConfigurations": {
"idle": 0.3,
"run": 1.0
},
"plungerPositionsConfigurations": {
"top": 0,
"bottom": 66,
"blowout": 71,
"drop": 80
},
"availableSensors": {
"sensors": ["pressure", "capacitive", "environment"],
"pressure": { "count": 2 },
"capacitive": { "count": 2 },
"environment": { "count": 1 }
},
"partialTipConfigurations": {
"partialTipSupported": true,
"availableConfigurations": [1, 8, 12, 96]
},
"channels": 96
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"$otSharedSchema": "#/pipette/schemas/2/pipettePropertiesSchema.json",
"displayName": "P1000 One Channel GEN3",
"model": "oneChannel",
"displayCategory": "GEN3",
"pickUpTipConfigurations": {
"current": 0.15,
"presses": 1,
"speed": 10,
"increment": 0.0,
"distance": 13.0
},
"dropTipConfigurations": {
"current": 1.0,
"speed": 10
},
"plungerMotorConfigurations": {
"idle": 0.3,
"run": 1.0
},
"plungerPositionsConfigurations": {
"top": 0.5,
"bottom": 71.5,
"blowout": 76.5,
"drop": 90.5
},
"availableSensors": {
"sensors": ["pressure", "capacitive", "environment"],
"pressure": { "count": 1 },
"capacitive": { "count": 1 },
"environment": { "count": 1 }
},
"partialTipConfigurations": {
"partialTipSupported": false
},
"channels": 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"$otSharedSchema": "#/pipette/schemas/2/pipettePropertiesSchema.json",
"displayName": "P50 One Channel GEN3",
"model": "oneChannel",
"displayCategory": "GEN3",
"pickUpTipConfigurations": {
"current": 0.15,
"presses": 1,
"speed": 10,
"increment": 0.0,
"distance": 13.0
},
"dropTipConfigurations": {
"current": 1.0,
"speed": 10
},
"plungerMotorConfigurations": {
"idle": 0.3,
"run": 1.0
},
"plungerPositionsConfigurations": {
"top": 0.5,
"bottom": 71.5,
"blowout": 76.5,
"drop": 90.5
},
"availableSensors": {
"sensors": ["pressure", "capacitive", "environment"],
"pressure": { "count": 1 },
"capacitive": { "count": 1 },
"environment": { "count": 1 }
},
"partialTipConfigurations": {
"partialTipSupported": false
},
"channels": 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$otSharedSchema": "#/pipette/schemas/2/pipetteGeometrySchema.json",
"pathTo3D": "pipette/definitions/2/eight_channel/p50/placeholder.gltf",
"nozzleOffset": [-0.5, -16.0, -259.15]
Laura-Danielle marked this conversation as resolved.
Show resolved Hide resolved
}
Loading