Skip to content

Commit e5f8667

Browse files
committed
MADSci 0.6 REST node tested and working, cleanup needed
1 parent bba3133 commit e5f8667

10 files changed

Lines changed: 2439 additions & 285 deletions

pyproject.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@ authors = [
77
{name = "Doga Ozgulbas", email="dozgulbas@anl.gov"},
88
{name = "Abe Stroka", email="astroka@anl.gov"},
99
{name = "Tobias Ginsburg", email = "tginsburg@anl.gov"},
10+
{name = "Casey Stone", email = "cstone@anl.gov"},
1011
]
1112
dependencies = [
1213
"fastapi>=0.103",
1314
"uvicorn>=0.14.0",
1415
"pyusb",
1516
"libusb",
1617
"pyserial",
17-
"madsci-node-module~=0.5.0",
18-
"madsci-client~=0.5.0",
19-
"madsci-common~=0.5.0",
18+
"madsci-node-module~=0.6.0",
19+
"madsci-client~=0.6.0",
20+
"madsci-common~=0.6.0",
2021
"pydantic>=2.7",
2122
"pytest"
2223
]

src/default.node.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
node_name: sciclops_node
2+
node_id: 01KMZZ7ESXANZZP024R2Y98TYP
3+
node_description: null
4+
node_type: device
5+
module_name: hudson_sciclops_node
6+
module_version: 0.0.1
7+
capabilities: null
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""This module contains the Pydantic models for the PlateCrane resource types"""
2+
3+
from typing import Optional
4+
5+
from pydantic import BaseModel
6+
7+
8+
class PlateCraneLocation(BaseModel):
9+
"""A location accessible by the PlateCrane EX"""
10+
11+
name: str
12+
"""Internal name of the location"""
13+
joint_angles: list[int]
14+
"""List of 4 joint angles (unit: integer stepper values)"""
15+
location_type: str
16+
"""Type of location, either stack or nest. This will be used to determine gripper path for interactions with the location"""
17+
safe_approach_height: Optional[int] = None
18+
"""A safe height (unit: integer stepper value for Z axis) from which
19+
to extend the arm when approaching this location."""
20+
21+
22+
class SciClopsLocation(BaseModel):
23+
"""A location accessible by the PlateCrane EX"""
24+
25+
name: str
26+
"""Internal name of the location"""
27+
joint_angles: dict
28+
"""List of 4 joint angles (unit: integer stepper values)"""
29+
location_type: str
30+
"""Type of location, either stack or nest. This will be used to determine gripper path for interactions with the location"""
31+
safe_approach_height: Optional[float] = None
32+
"""A safe height (unit: integer stepper value for Z axis) from which
33+
to extend the arm when approaching this location."""
34+
35+
36+
class PlateResource(BaseModel):
37+
"""A plate resource that can be manipulated by the PlateCrane EX"""
38+
39+
# Plate Properties
40+
41+
plate_height: float
42+
"""The height measured from the bottom of the plate to the top"""
43+
grip_height: float
44+
"""The height at which to grip the plate, measured from the bottom of the plate"""
45+
plate_height_with_lid: Optional[float] = None
46+
"""The height of the plate when lidded, measured from the bottom of the plate to the top of the lid.
47+
Only required if the resource supports lids"""
48+
49+
# Lid Properties
50+
51+
lid_height: Optional[float] = None
52+
"""The height of the lid alone, measured from the bottom of the lid to the top of the lid"""
53+
lid_grip_height: Optional[float] = None
54+
"""The height at which to grip the lid itself, measured from the bottom of the lid"""
55+
lid_removal_grip_height: Optional[float] = None
56+
"""The height at which to grip the lid when removing it, measured from the bottom of the lidded plate"""
57+
58+
@staticmethod
59+
def convert_to_steps(plate_measurement_in_mm: float) -> int:
60+
"""Converts plate measurements in mm to PlateCrane EX motor steps on the z-axis"""
61+
steps_per_mm = 80.5
62+
return int(plate_measurement_in_mm * steps_per_mm)
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
"""Resource definitions for the platecrane in BIO 350."""
2+
3+
from resource_helpers.resource_types import PlateResource, SciClopsLocation
4+
5+
# Locations accessible by the PlateCrane EX. [R (base), Z (vertical axis), P (gripper rotation), Y (arm extension)]
6+
7+
# Locations accessible by the SciClops. [Z (vertical axis), P (gripper rotation), Y (arm extension)]
8+
9+
# NOTE: THIS IS NOT THE SAME ORDER AS THE PLATE CRANE!
10+
11+
# NOTE: Running get location in the SciClops won't return the values in the right order!
12+
13+
locations = {
14+
"Safe": SciClopsLocation(
15+
name="Safe",
16+
joint_angles={"Z": 23.5188, "R": 109.2741, "Y": 32.7484, "P": 98.2955},
17+
location_type="nest",
18+
safe_approach_height=0,
19+
),
20+
"Stack1": SciClopsLocation(
21+
name="Stack1",
22+
joint_angles={"Z": -397.1688, "R": 137.1106, "Y": 173.0127, "P": 9.6875},
23+
location_type="stack",
24+
safe_approach_height=0,
25+
),
26+
"Stack2": SciClopsLocation(
27+
name="Stack2",
28+
joint_angles={"Z": -397.2875, "R": 154.9712, "Y": 172.5352, "P": 9.6875},
29+
location_type="stack",
30+
safe_approach_height=0,
31+
),
32+
"LidNest1": SciClopsLocation(
33+
name="LidNest1",
34+
joint_angles={"Z": -386.8563, "R": 173.1300, "Y": 26.1751, "P": 10.3409},
35+
location_type="nest",
36+
safe_approach_height=0,
37+
),
38+
"Home": SciClopsLocation(
39+
name="Home",
40+
joint_angles={"Z": -1.0188, "R": 0.0, "Y": 0.0, "P": -0.0284},
41+
location_type="stack",
42+
safe_approach_height=0,
43+
),
44+
}
45+
46+
47+
# OLD PLATE DEFINITIONS
48+
# # Dictionary for plate information
49+
# locations = {
50+
# "stack1": {
51+
# "pos": {"Z": -397.1688, "R": 137.1106, "Y": 173.0127, "P": 9.6875},
52+
# "type": "stack",
53+
# },
54+
# "stack2": {
55+
# "pos": {"Z": -397.2875, "R": 154.9712, "Y": 172.5352, "P": 9.6875},
56+
# "type": "stack",
57+
# },
58+
# "stack3": {
59+
# "pos": {"Z": -397.3563, "R": 173.0506, "Y": 172.7398, "P": 9.6875},
60+
# "type": "stack",
61+
# },
62+
# "stack4": {
63+
# "pos": {"Z": -396.1000, "R": 191.1141, "Y": 172.4918, "P": 9.6875},
64+
# "type": "stack",
65+
# },
66+
# "stack5": {
67+
# "pos": {"Z": -394.4875, "R": 209.0771, "Y": 172.5104, "P": 9.6875},
68+
# "type": "stack",
69+
# },
70+
# "lidnest1": { # Z:-381.0938, R:173.1300, Y:26.1751, P:10.3409
71+
# # "pos": {"Z": -388.8563, "R": 172.8812, "Y": 26.9317, "P": 10.3409},
72+
# "pos": {"Z": -386.8563, "R": 173.1300, "Y": 26.1751, "P": 10.3409},
73+
# "type": "nest",
74+
# },
75+
# "lidnest2": { # Z:-379.2313, R:205.2971, Y:26.4480, P:10.2841
76+
# # "pos": {"Z": -388.4625, "R": 205.2900, "Y": 26.8139, "P": 10.2841},
77+
# "pos": {"Z": -386.8563, "R": 205.2971, "Y": 26.4480, "P": 10.2841},
78+
# "type": "nest",
79+
# },
80+
# "exchange": {
81+
# "pos": {"Z": -416.8438, "R": 299.8747, "Y": 153.6526, "P": 21.5057},
82+
# "type": "nest",
83+
# },
84+
# "neutral": {
85+
# "pos": {"Z": 23.5188, "R": 109.2741, "Y": 32.7484, "P": 98.2955},
86+
# "type": "point",
87+
# },
88+
# }
89+
90+
# locations = {
91+
# "Safe": PlateCraneLocation(
92+
# name="Safe",
93+
# joint_angles=[182220, 2500, 460, -308],
94+
# location_type="nest",
95+
# safe_approach_height=0,
96+
# ),
97+
# "Stack1": PlateCraneLocation( # After vibration table
98+
# name="Stack1",
99+
# joint_angles=[164713, -32703, 450, 5472],
100+
# location_type="stack",
101+
# safe_approach_height=0,
102+
# ),
103+
# "Stack2": PlateCraneLocation(
104+
# name="Stack2",
105+
# joint_angles=[182201, -32703, 486, 5445],
106+
# location_type="stack",
107+
# safe_approach_height=0,
108+
# ),
109+
# "Stack3": PlateCraneLocation(
110+
# name="Stack3",
111+
# joint_angles=[199696, -32703, 486, 5445],
112+
# location_type="stack",
113+
# safe_approach_height=0,
114+
# ),
115+
# "Stack4": PlateCraneLocation( # After vibration table
116+
# name="Stack4",
117+
# joint_angles=[217301, -32703, 486, 5445],
118+
# location_type="stack",
119+
# safe_approach_height=0,
120+
# ),
121+
# "Stack5": PlateCraneLocation( # After vibration table
122+
# name="Stack5",
123+
# joint_angles=[235004, -32703, 486, 5445],
124+
# location_type="stack",
125+
# safe_approach_height=0,
126+
# ),
127+
# "LidNest1": PlateCraneLocation( # After vibration table
128+
# name="LidNest1",
129+
# joint_angles=[168367, -31725, 470, -329],
130+
# location_type="nest",
131+
# safe_approach_height=0,
132+
# ),
133+
# "LidNest2": PlateCraneLocation(
134+
# name="LidNest2",
135+
# joint_angles=[199862, -31725, 462, -328],
136+
# location_type="nest",
137+
# safe_approach_height=0,
138+
# ),
139+
# "LidNest3": PlateCraneLocation(
140+
# name="LidNest3",
141+
# joint_angles=[231449, -31800, 484, -306],
142+
# location_type="nest",
143+
# safe_approach_height=0,
144+
# ),
145+
# "Solo.Position1": PlateCraneLocation(
146+
# name="Solo.Position1",
147+
# joint_angles=[41665, -27455, -830, 5046],
148+
# location_type="nest",
149+
# safe_approach_height=0,
150+
# ),
151+
# "Solo.Position2": PlateCraneLocation( # After vibration table
152+
# name="Solo.Position2",
153+
# joint_angles=[57372, -27457, -233, 2613],
154+
# location_type="nest",
155+
# safe_approach_height=0,
156+
# ),
157+
# "Solo.Position2AfterPeeler": PlateCraneLocation( # no longer needed
158+
# name="Solo.Position2",
159+
# joint_angles=[53225, -27960, -431, 855],
160+
# location_type="nest",
161+
# safe_approach_height=0,
162+
# ),
163+
# "Hidex.Nest": PlateCraneLocation( # After vibration table
164+
# name="Hidex.Nest",
165+
# joint_angles=[102406, -31090, -5901, 2373],
166+
# location_type="nest",
167+
# safe_approach_height=-27033,
168+
# ),
169+
# "Sealer.Nest": PlateCraneLocation( # After vibration table
170+
# name="Sealer.Nest",
171+
# joint_angles=[118212, -998, -4758, 4071],
172+
# location_type="nest",
173+
# safe_approach_height=0,
174+
# ),
175+
# "Sealer.DeepWell.Nest": PlateCraneLocation( # After vibration table
176+
# name="Sealer.DeepWell.Nest",
177+
# joint_angles=[118212, -2498, -4758, 4071],
178+
# location_type="nest",
179+
# safe_approach_height=0,
180+
# ),
181+
# "Peeler.Nest": PlateCraneLocation( # After vibration table
182+
# name="Peeler.Nest",
183+
# joint_angles=[302738, -30340, -4142, 2351],
184+
# location_type="nest",
185+
# safe_approach_height=0,
186+
# ),
187+
# "Liconic.Nest": PlateCraneLocation( # After vibration table
188+
# name="Liconic.Nest",
189+
# joint_angles=[267724, -24666, -5357, 1591],
190+
# location_type="nest",
191+
# safe_approach_height=0,
192+
# ),
193+
# }
194+
195+
# Dimensions of labware used on the BIO_Workcells
196+
plate_definitions = {
197+
"flat_bottom_96well": PlateResource(
198+
plate_height=14,
199+
grip_height=1,
200+
plate_height_with_lid=16,
201+
lid_height=10,
202+
lid_grip_height=4,
203+
lid_removal_grip_height=12,
204+
),
205+
"tip_box_180uL": PlateResource(
206+
plate_height=0,
207+
grip_height=0,
208+
plate_height_with_lid=0,
209+
lid_height=0,
210+
lid_grip_height=0,
211+
lid_removal_grip_height=0,
212+
),
213+
"pcr_96well": PlateResource(
214+
plate_height=0,
215+
grip_height=0,
216+
plate_height_with_lid=0,
217+
lid_height=0,
218+
lid_grip_height=0,
219+
lid_removal_grip_height=0,
220+
),
221+
"deep_96well": PlateResource(
222+
plate_height=40,
223+
grip_height=30,
224+
plate_height_with_lid=46,
225+
lid_height=9,
226+
lid_grip_height=4,
227+
lid_removal_grip_height=42,
228+
),
229+
}

0 commit comments

Comments
 (0)