Skip to content

Commit 291ae00

Browse files
committed
unify joint with/without rails
1 parent bea84ec commit 291ae00

File tree

6 files changed

+97
-257
lines changed

6 files changed

+97
-257
lines changed

pylabrobot/arms/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .precise_flex import *
2+
from .scara import *
3+
from .standard import *
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .pf_400 import *
2+
from .pf_3400 import *
3+
from .precise_flex_backend import *

pylabrobot/arms/precise_flex/joints.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
from dataclasses import dataclass
2+
from typing import Iterator
23

34

45
@dataclass
56
class PreciseFlexJointCoords:
6-
rail: float
77
base: float
88
shoulder: float
99
elbow: float
1010
wrist: float
1111
gripper: float
12+
rail: float = 0
1213

13-
def __iter__(self):
14-
# for conversion to a list
14+
def __iter__(self) -> Iterator[float]:
1515
return iter(
1616
[
1717
self.rail,
Lines changed: 1 addition & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,8 @@
1-
from typing import List
2-
3-
from pylabrobot.arms.precise_flex.joints import PreciseFlexJointCoords
41
from pylabrobot.arms.precise_flex.precise_flex_backend import PreciseFlexBackend
52

63

74
class PreciseFlex3400Backend(PreciseFlexBackend):
85
"""Backend for the PreciseFlex 3400 robotic arm."""
96

107
def __init__(self, host: str, port: int = 10100, timeout=20, has_rail: bool = False) -> None:
11-
super().__init__(host=host, port=port, timeout=timeout)
12-
self._has_rail = has_rail
13-
14-
def convert_to_joint_space(self, position: List[float]) -> PreciseFlexJointCoords:
15-
"""Convert parsed joint values to PreciseFlexJointCoords.
16-
17-
Args:
18-
position: List of 6 floats from _parse_angles_response() (always padded to 6).
19-
For has_rail=True: [rail, base, shoulder, elbow, wrist, gripper]
20-
For has_rail=False: [base, shoulder, elbow, wrist, gripper, 0.0(padding)]
21-
22-
Returns:
23-
PreciseFlexJointCoords with joint values mapped based on robot configuration.
24-
"""
25-
if len(position) < 5:
26-
raise ValueError("Position must have at least 5 joint angles.")
27-
28-
if self._has_rail:
29-
if len(position) < 6:
30-
raise ValueError("Position must have 6 joint angles for robot with rail.")
31-
return PreciseFlexJointCoords(
32-
rail=position[0],
33-
base=position[1],
34-
shoulder=position[2],
35-
elbow=position[3],
36-
wrist=position[4],
37-
gripper=position[5],
38-
)
39-
else:
40-
# No rail: positions 0-4 are [base, shoulder, elbow, wrist, gripper]
41-
# position[5] is 0.0 padding from _parse_angles_response() - ignore it
42-
return PreciseFlexJointCoords(
43-
rail=0.0,
44-
base=position[0],
45-
shoulder=position[1],
46-
elbow=position[2],
47-
wrist=position[3],
48-
gripper=position[4],
49-
)
50-
51-
def convert_to_joints_array(self, position: PreciseFlexJointCoords) -> List[float]:
52-
"""Convert a JointSpace object to a list of joint angles."""
53-
return [
54-
position.rail,
55-
position.base,
56-
position.shoulder,
57-
position.elbow,
58-
position.wrist,
59-
position.gripper,
60-
]
61-
62-
async def move_j(self, profile_index: int, joint_coords: PreciseFlexJointCoords) -> None:
63-
"""Move the robot using joint coordinates, handling rail configuration."""
64-
if self._has_rail:
65-
angles_str = (
66-
f"{joint_coords.rail} "
67-
f"{joint_coords.base} "
68-
f"{joint_coords.shoulder} "
69-
f"{joint_coords.elbow} "
70-
f"{joint_coords.wrist} "
71-
f"{joint_coords.gripper}"
72-
)
73-
else:
74-
# Exclude rail for robots without rail
75-
angles_str = (
76-
f"{joint_coords.base} "
77-
f"{joint_coords.shoulder} "
78-
f"{joint_coords.elbow} "
79-
f"{joint_coords.wrist} "
80-
f"{joint_coords.gripper}"
81-
)
82-
await self.send_command(f"moveJ {profile_index} {angles_str}")
83-
84-
async def set_joint_angles(
85-
self,
86-
location_index: int,
87-
joint_position: PreciseFlexJointCoords,
88-
) -> None:
89-
"""Set joint angles for stored location, handling rail configuration."""
90-
if self._has_rail:
91-
await self.send_command(
92-
f"locAngles {location_index} "
93-
f"{joint_position.rail} "
94-
f"{joint_position.base} "
95-
f"{joint_position.shoulder} "
96-
f"{joint_position.elbow} "
97-
f"{joint_position.wrist} "
98-
f"{joint_position.gripper}"
99-
)
100-
else:
101-
# Exclude rail for robots without rail
102-
await self.send_command(
103-
f"locAngles {location_index} "
104-
f"{joint_position.base} "
105-
f"{joint_position.shoulder} "
106-
f"{joint_position.elbow} "
107-
f"{joint_position.wrist} "
108-
f"{joint_position.gripper}"
109-
)
8+
super().__init__(host=host, port=port, timeout=timeout, has_rail=has_rail)
Lines changed: 1 addition & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,8 @@
1-
from typing import List
2-
3-
from pylabrobot.arms.precise_flex.joints import PreciseFlexJointCoords
41
from pylabrobot.arms.precise_flex.precise_flex_backend import PreciseFlexBackend
52

63

74
class PreciseFlex400Backend(PreciseFlexBackend):
85
"""Backend for the PreciseFlex 400 robotic arm."""
96

107
def __init__(self, host: str, port: int = 10100, timeout=20, has_rail: bool = False) -> None:
11-
super().__init__(host=host, port=port, timeout=timeout)
12-
self._has_rail = has_rail
13-
14-
def convert_to_joint_space(self, position: List[float]) -> PreciseFlexJointCoords:
15-
"""Convert parsed joint values to PreciseFlexJointCoords.
16-
17-
Args:
18-
position: List of 6 floats from _parse_angles_response() (always padded to 6).
19-
For has_rail=True: [rail, base, shoulder, elbow, wrist, gripper]
20-
For has_rail=False: [base, shoulder, elbow, wrist, gripper, 0.0(padding)]
21-
22-
Returns:
23-
PreciseFlexJointCoords with joint values mapped based on robot configuration.
24-
"""
25-
if len(position) < 5:
26-
raise ValueError("Position must have at least 5 joint angles.")
27-
28-
if self._has_rail:
29-
if len(position) < 6:
30-
raise ValueError("Position must have 6 joint angles for robot with rail.")
31-
return PreciseFlexJointCoords(
32-
rail=position[0],
33-
base=position[1],
34-
shoulder=position[2],
35-
elbow=position[3],
36-
wrist=position[4],
37-
gripper=position[5],
38-
)
39-
else:
40-
# No rail: positions 0-4 are [base, shoulder, elbow, wrist, gripper]
41-
# position[5] is 0.0 padding from _parse_angles_response() - ignore it
42-
return PreciseFlexJointCoords(
43-
rail=0.0,
44-
base=position[0],
45-
shoulder=position[1],
46-
elbow=position[2],
47-
wrist=position[3],
48-
gripper=position[4],
49-
)
50-
51-
def convert_to_joints_array(self, position: PreciseFlexJointCoords) -> List[float]:
52-
"""Convert a PreciseFlexJointCoords object to a list of joint angles."""
53-
return [
54-
position.rail,
55-
position.base,
56-
position.shoulder,
57-
position.elbow,
58-
position.wrist,
59-
position.gripper,
60-
]
61-
62-
async def move_j(self, profile_index: int, joint_coords: PreciseFlexJointCoords) -> None:
63-
"""Move the robot using joint coordinates, handling rail configuration."""
64-
if self._has_rail:
65-
angles_str = (
66-
f"{joint_coords.rail} "
67-
f"{joint_coords.base} "
68-
f"{joint_coords.shoulder} "
69-
f"{joint_coords.elbow} "
70-
f"{joint_coords.wrist} "
71-
f"{joint_coords.gripper}"
72-
)
73-
else:
74-
# Exclude rail for robots without rail
75-
angles_str = (
76-
f"{joint_coords.base} "
77-
f"{joint_coords.shoulder} "
78-
f"{joint_coords.elbow} "
79-
f"{joint_coords.wrist} "
80-
f"{joint_coords.gripper}"
81-
)
82-
await self.send_command(f"moveJ {profile_index} {angles_str}")
83-
84-
async def set_joint_angles(
85-
self,
86-
location_index: int,
87-
joint_position: PreciseFlexJointCoords,
88-
) -> None:
89-
"""Set joint angles for stored location, handling rail configuration."""
90-
if self._has_rail:
91-
await self.send_command(
92-
f"locAngles {location_index} "
93-
f"{joint_position.rail} "
94-
f"{joint_position.base} "
95-
f"{joint_position.shoulder} "
96-
f"{joint_position.elbow} "
97-
f"{joint_position.wrist} "
98-
f"{joint_position.gripper}"
99-
)
100-
else:
101-
# Exclude rail for robots without rail
102-
await self.send_command(
103-
f"locAngles {location_index} "
104-
f"{joint_position.base} "
105-
f"{joint_position.shoulder} "
106-
f"{joint_position.elbow} "
107-
f"{joint_position.wrist} "
108-
f"{joint_position.gripper}"
109-
)
8+
super().__init__(host=host, port=port, timeout=timeout, has_rail=has_rail)

0 commit comments

Comments
 (0)