Skip to content

Commit 1464fdd

Browse files
committed
Merge branch 'feature/preciseflex-nest-type-discovery' into dev-precise-flex-pf400
2 parents b6b5a10 + 87f36ee commit 1464fdd

File tree

3 files changed

+294
-50
lines changed

3 files changed

+294
-50
lines changed

pylabrobot/arms/arm.py

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from typing import Union
1+
from typing import Optional, Union
22

3-
from pylabrobot.arms.backend import ArmBackend
3+
from pylabrobot.arms.backend import AccessPattern, ArmBackend
44
from pylabrobot.arms.coords import CartesianCoords, JointCoords
55
from pylabrobot.machines.machine import Machine
66

@@ -56,16 +56,44 @@ async def move_to_safe(self):
5656
"""Move the arm to a predefined safe position."""
5757
return await self.backend.move_to_safe()
5858

59-
async def approach(self, position: Union[CartesianCoords, JointCoords], approach_height: float):
60-
"""Move the arm to a position above the specified coordinates by a certain distance."""
61-
return await self.backend.approach(position, approach_height)
59+
async def approach(
60+
self,
61+
position: Union[CartesianCoords, JointCoords],
62+
access: Optional[AccessPattern] = None
63+
):
64+
"""Move the arm to an approach position (offset from target).
65+
66+
Args:
67+
position: Target position (CartesianCoords or JointCoords)
68+
access: Access pattern defining how to approach the target.
69+
Defaults to VerticalAccess() if not specified.
70+
"""
71+
return await self.backend.approach(position, access)
72+
73+
async def pick_plate(
74+
self,
75+
position: Union[CartesianCoords, JointCoords],
76+
access: Optional[AccessPattern] = None
77+
):
78+
"""Pick a plate from the specified position.
6279
63-
async def pick_plate(self, position: Union[CartesianCoords, JointCoords], approach_height: float):
64-
"""Pick a plate from the specified position."""
65-
return await self.backend.pick_plate(position, approach_height)
80+
Args:
81+
position: Target position for pickup
82+
access: Access pattern defining how to approach and retract.
83+
Defaults to VerticalAccess() if not specified.
84+
"""
85+
return await self.backend.pick_plate(position, access)
6686

6787
async def place_plate(
68-
self, position: Union[CartesianCoords, JointCoords], approach_height: float
88+
self,
89+
position: Union[CartesianCoords, JointCoords],
90+
access: Optional[AccessPattern] = None
6991
):
70-
"""Place a plate at the specified position."""
71-
return await self.backend.place_plate(position, approach_height)
92+
"""Place a plate at the specified position.
93+
94+
Args:
95+
position: Target position for placement
96+
access: Access pattern defining how to approach and retract.
97+
Defaults to VerticalAccess() if not specified.
98+
"""
99+
return await self.backend.place_plate(position, access)

pylabrobot/arms/backend.py

Lines changed: 82 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,57 @@
11
from abc import ABCMeta, abstractmethod
2-
from typing import Union
2+
from dataclasses import dataclass
3+
from typing import Optional, Union
34

45
from pylabrobot.arms.coords import CartesianCoords, JointCoords
56
from pylabrobot.machines.backend import MachineBackend
67

78

9+
@dataclass
10+
class VerticalAccess:
11+
"""Access location from above (most common pattern for stacks and tube racks).
12+
13+
This access pattern is used when approaching a location from above, such as
14+
picking from a plate stack or tube rack on the deck.
15+
16+
Args:
17+
approach_height_mm: Height above the target position to move to before
18+
descending to grip (default: 100mm)
19+
clearance_mm: Vertical distance to retract after gripping before lateral
20+
movement (default: 100mm)
21+
gripper_offset_mm: Additional vertical offset added when holding a plate,
22+
accounts for gripper thickness (default: 10mm)
23+
"""
24+
approach_height_mm: float = 100
25+
clearance_mm: float = 100
26+
gripper_offset_mm: float = 10
27+
28+
29+
@dataclass
30+
class HorizontalAccess:
31+
"""Access location from the side (for hotel-style plate carriers).
32+
33+
This access pattern is used when approaching a location horizontally, such as
34+
accessing plates in a hotel-style storage system.
35+
36+
Args:
37+
approach_distance_mm: Horizontal distance in front of the target to stop
38+
before moving in to grip (default: 50mm)
39+
clearance_mm: Horizontal distance to retract after gripping before lifting
40+
(default: 50mm)
41+
lift_height_mm: Vertical distance to lift the plate after horizontal retract,
42+
before lateral movement (default: 100mm)
43+
gripper_offset_mm: Additional vertical offset added when holding a plate,
44+
accounts for gripper thickness (default: 10mm)
45+
"""
46+
approach_distance_mm: float = 50
47+
clearance_mm: float = 50
48+
lift_height_mm: float = 100
49+
gripper_offset_mm: float = 10
50+
51+
52+
AccessPattern = Union[VerticalAccess, HorizontalAccess]
53+
54+
855
class ArmBackend(MachineBackend, metaclass=ABCMeta):
956
"""Backend for a robotic arm"""
1057

@@ -49,20 +96,48 @@ async def move_to_safe(self):
4996
...
5097

5198
@abstractmethod
52-
async def approach(self, position: Union[CartesianCoords, JointCoords], approach_height: float):
53-
"""Move the arm to a position above the specified coordinates by a certain distance."""
99+
async def approach(
100+
self,
101+
position: Union[CartesianCoords, JointCoords],
102+
access: Optional[AccessPattern] = None
103+
):
104+
"""Move the arm to an approach position (offset from target).
105+
106+
Args:
107+
position: Target position (CartesianCoords or JointCoords)
108+
access: Access pattern defining how to approach the target.
109+
Defaults to VerticalAccess() if not specified.
110+
"""
54111
...
55112

56113
@abstractmethod
57-
async def pick_plate(self, position: Union[CartesianCoords, JointCoords], approach_height: float):
58-
"""Pick a plate from the specified position."""
114+
async def pick_plate(
115+
self,
116+
position: Union[CartesianCoords, JointCoords],
117+
access: Optional[AccessPattern] = None
118+
):
119+
"""Pick a plate from the specified position.
120+
121+
Args:
122+
position: Target position for pickup
123+
access: Access pattern defining how to approach and retract.
124+
Defaults to VerticalAccess() if not specified.
125+
"""
59126
...
60127

61128
@abstractmethod
62129
async def place_plate(
63-
self, position: Union[CartesianCoords, JointCoords], approach_height: float
130+
self,
131+
position: Union[CartesianCoords, JointCoords],
132+
access: Optional[AccessPattern] = None
64133
):
65-
"""Place a plate at the specified position."""
134+
"""Place a plate at the specified position.
135+
136+
Args:
137+
position: Target position for placement
138+
access: Access pattern defining how to approach and retract.
139+
Defaults to VerticalAccess() if not specified.
140+
"""
66141
...
67142

68143
@abstractmethod

0 commit comments

Comments
 (0)