Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
55 changes: 55 additions & 0 deletions pylabrobot/brooks/precise_flex/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Brooks PreciseFlex robots.

Why one package for the family - every PreciseFlex arm runs the same Guidance/TCS controller and
speaks the same GPL command protocol, DataIDs, and error codes, so they share the bulk of this
driver. They differ only in kinematics (per geometry, e.g. the c10's R-P-R-R joint order, the c8A's
six axes) and gripper, which are handled by per-model device classes and per-geometry kinematics
modules within the package. Grouping by the shared controller keeps that common driver in one place
rather than duplicated per arm model.

Scope - the PreciseFlex robot line. Implemented:

- PreciseFlex 400 (PF400)
- PreciseFlex 3400 (PF3400)

To be added here:

- PreciseFlex 100 / 1400 (PF100 / PF1400)
- c-series: c3, c5, c8A, c10
- direct-drive: DD4, DD6
- linear rail

Everything here is PreciseFlex-specific, including the TCS controller protocol (``tcs_modules``),
``error_codes``, and the controller DataIDs (``data_ids``) - the PreciseFlex line is the only user of
the Guidance/TCS controller, so they live with it. A future, genuinely different Brooks device family
would get its own sibling package under ``brooks/``, and anything shared would be lifted up then.

Re-exports the public classes so ``from pylabrobot.brooks.precise_flex import PreciseFlex400`` keeps
working.
"""

from pylabrobot.brooks.precise_flex.precise_flex import (
Axis,
PreciseFlex400,
PreciseFlex400Backend,
PreciseFlex3400Backend,
PreciseFlexArmBackend,
PreciseFlexCartesianPose,
PreciseFlexConfiguration,
PreciseFlexDriver,
PreciseFlexError,
WorkingVolume,
)

__all__ = [
"Axis",
"PreciseFlex400",
"PreciseFlex400Backend",
"PreciseFlex3400Backend",
"PreciseFlexArmBackend",
"PreciseFlexCartesianPose",
"PreciseFlexConfiguration",
"PreciseFlexDriver",
"PreciseFlexError",
"WorkingVolume",
]
Original file line number Diff line number Diff line change
Expand Up @@ -1919,3 +1919,15 @@
"description": "A remote request to load a new vision project has failed because the current project has not been saved. Save the current project before attempting to load a new one.",
},
}


class PreciseFlexError(Exception):
def __init__(self, replycode: int, message: str):
self.replycode = replycode
self.message = message
if replycode in ERROR_CODES:
text = ERROR_CODES[replycode]["text"]
description = ERROR_CODES[replycode]["description"]
super().__init__(f"PreciseFlexError {replycode}: {text}. {description} - {message}")
else:
super().__init__(f"PreciseFlexError {replycode}: {message}")
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from pylabrobot.capabilities.arms.standard import JointPose

if TYPE_CHECKING:
from pylabrobot.brooks.precise_flex import PreciseFlexCartesianPose
from pylabrobot.brooks.precise_flex.precise_flex import PreciseFlexCartesianPose


# Known PF400 link-length configs (l1 = shoulder->elbow, l2 = elbow->wrist), in mm, per the 615287
Expand Down Expand Up @@ -78,7 +78,7 @@ def fk(joints: JointPose, p: PF400Params) -> "PreciseFlexCartesianPose":
orientation/wrist derived from the joint configuration (J3 sign and
wrapped J4 sign, respectively).
"""
from pylabrobot.brooks.precise_flex import PreciseFlexCartesianPose
from pylabrobot.brooks.precise_flex.precise_flex import PreciseFlexCartesianPose
from pylabrobot.resources import Coordinate, Rotation

j1 = joints[1]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,6 @@
from enum import IntEnum
from typing import Dict, List, Literal, Optional

from pylabrobot.brooks import kinematics
from pylabrobot.brooks.confirmed_firmware_versions import (
SUPPORTED_ROBOT_TYPES,
is_confirmed,
is_supported_model,
suggest_entry,
)
from pylabrobot.brooks.data_ids import DataID
from pylabrobot.brooks.error_codes import ERROR_CODES
from pylabrobot.brooks.tcs_modules import missing_required_modules
from pylabrobot.capabilities.arms.backend import (
CanFreedrive,
HasJoints,
Expand All @@ -30,6 +20,18 @@
from pylabrobot.resources import Coordinate, Rotation
from pylabrobot.resources.resource import Resource

# PreciseFlex-specific siblings - relative imports.
from . import kinematics
from .confirmed_firmware_versions import (
SUPPORTED_ROBOT_TYPES,
is_confirmed,
is_supported_model,
suggest_entry,
)
from .data_ids import DataID
from .errors import PreciseFlexError
from .tcs_modules import missing_required_modules

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -157,23 +159,6 @@ def working_volume(self) -> WorkingVolume:
return WorkingVolume(inner=inner, outer=outer, zmin=zmin, zmax=zmax)


# ---------------------------------------------------------------------------
# Exceptions
# ---------------------------------------------------------------------------


class PreciseFlexError(Exception):
def __init__(self, replycode: int, message: str):
self.replycode = replycode
self.message = message
if replycode in ERROR_CODES:
text = ERROR_CODES[replycode]["text"]
description = ERROR_CODES[replycode]["description"]
super().__init__(f"PreciseFlexError {replycode}: {text}. {description} - {message}")
else:
super().__init__(f"PreciseFlexError {replycode}: {message}")


# ---------------------------------------------------------------------------
# Driver — owns Socket I/O and device lifecycle
# ---------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
from typing import Tuple
from unittest.mock import AsyncMock, MagicMock

from pylabrobot.brooks import kinematics
from pylabrobot.brooks.precise_flex import Axis, PreciseFlex400Backend
from pylabrobot.brooks.precise_flex import Axis, PreciseFlex400Backend, kinematics


def _make_backend(
Expand Down