Hardware adapter interfaces

Registration, configuration, and runtime contracts for arms, feedback, grippers, and cameras.

A hardware adapter is an independent Python package installed into the RoboAPI environment. Entry points register its components for selection in the setup wizard. They share the runtime used by the local console, HTTP API, and MCP tools. See Connect new hardware for the development workflow.

Responsibilities and data boundaries

RoboAPI providesThe adapter implements
Home and A/B/C calibration, training-frame mappingMeasurements and control at the native flange centre
Paths, action timing, and 30 Hz target dispatchSDK connections, native control frequency, interpolation, and holding
Model sessions, console, HTTP/MCPDevice faults, recovery, and resource cleanup
Component selection and configuration storageConfiguration fields, installation validation, and SDK dependencies

Driver poses use metres and a wxyz quaternion:

[x, y, z, qw, qx, qy, qz]

The eight-value model state and actions use xyzw, followed by gripper opening:

[x, y, z, qx, qy, qz, qw, gripper]

Drivers read and write native flange coordinates; the shared runtime maps them to and from model task coordinates. Control and feedback must use the same control point, native base coordinates, and flange axes, with no positional TCP offset.

Register components

Declare the components you provide in the package's pyproject.toml:

[project.entry-points."roboapi.arms"]
acme = "roboapi_acme.arm:arm_plugin"

[project.entry-points."roboapi.grippers"]
acme = "roboapi_acme.gripper:gripper_plugin"

[project.entry-points."roboapi.cameras"]
acme = "roboapi_acme.camera:camera_plugin"
Entry-point groupFactory resultDevice creation
roboapi.armsArmPlugincreate(config, tool)
roboapi.grippersComponentPlugincreate(config)
roboapi.camerasComponentPlugincreate(config)

Names are unique within a group. Different groups may use the same name, but names must not override built-in components. The wizard reports and skips external adapters that cannot load. A saved configuration selecting such an adapter fails with its load error.

Each factory provides:

FieldContract
optionsA nonempty tuple of ComponentOption, each with a display label and configuration class
createConstructs a disconnected device object
configure(option, setup)Returns the configuration for the selected component
setup_notesOptional tuple of instructions printed after setup

An ArmPlugin also requires create_feedback(config) and may provide create_guiding(config, tool) and configure_tool(setup).

When a factory supports multiple variants, distinguish them with ComponentOption.selectors, such as {"model": "a"}. Declare those fields in the configuration class and preserve them in YAML so the configuration selects exactly one option.

Configuration and setup

Component configurations extend ArmConfig, GripperConfig, or CameraConfig. This is the camera configuration structure used in a generated project:

from dataclasses import dataclass
from roboapi.hardware import CameraConfig

@dataclass
class AcmeCameraConfig(CameraConfig):
    type: str = "acme"
    address: str = ""

    @property
    def connection_id(self) -> str:
        return self.address

def configure(option, setup):
    return option.config_type(
        address=setup.ask("Camera address or device path"),
    )

Set type to the entry-point name. connection_id is a stable, nonempty device connection identifier; recheck calibration when that identity changes. Allow default construction and validate installation values in validate(). Call super().validate() when extending validation.

The wizard supplies setup:

MemberUsage
ask(label, default="")Reads a string
choose(label, choices)Displays choices and returns a zero-based index
device(label, patterns, default)Selects a device path or accepts a manually entered path
secret(label, filename)Returns a separate credential-file path; writes are deferred until setup saves. Use a single filename
configThe installation configuration, including components already selected

Configuration proceeds arm → gripper → camera, followed by tool load if required by the arm. A gripper can suggest an address from the selected arm. Use secret() for credentials and store their paths in configuration. Defer SDK imports and device connections to explicit connection operations.

Arm and read-only feedback

Interfaces are exported from roboapi.hardware. An arm implements Arm:

MemberBehavior
live, last_errorWhether control is available; provide a reason when unavailable
connect(*, calibration=False)Opens control and prepares target handling; preserve force-sensor zeros during temporary calibration returns
disconnect()Stops and joins control workers, then releases the device and control ownership
get_joints()Returns joint positions in radians; joint count depends on the device
get_eef_pose()Returns the measured native flange-centre pose, length 7, in wxyz order
servo_pose(pose7, twist=None, *, position_only=False)Updates a target without blocking; linear velocity is in m/s and angular velocity in rad/s
validate_calibration(device)Checks that control preserves the sampled device identity and flange convention
recover(should_stop=None)Restores device control and supports cancellation; the runtime handles the subsequent return Home

position_only=True requests target tracking without added force-driven offsets. The driver owns interpolation, control timing, and holding between target updates. Return measurements rather than the last commanded target.

create_feedback(config) returns an independent FeedbackReader. Feedback must remain readable during teaching and calibration sampling without taking motion control.

MemberBehavior
live, last_errorFeedback connection state and error
connect(), disconnect()Opens and releases the read-only connection
snapshot()Returns a dictionary with pose, timestamp, and device, optionally has_errors
validate_device(device)Checks saved device identity and settings

pose is the measured native flange pose. timestamp increases with actual samples; repeated device samples must not receive new timestamps. device contains stable, JSON-compatible identity and settings used when checking saved calibration.

Optional native hand guiding

create_guiding(config, tool) returns a GuidingSession:

MemberBehavior
activeWhether native guiding is active
start(axis=None)Starts guiding; None allows Home adjustment
set_axis(axis=None)x, y, or z permits only that translation, constraining rotation and other translation axes
check_stopped()Confirms guiding has stopped before sampling or mode changes
close()Ends guiding and releases its resources

Without native guiding, users capture Home and A/B/C through the robot's own teaching controls. Read-only feedback is still required.

Gripper

A gripper implements Gripper with one parallel-gripper opening ratio: 0 means closed and 1 means open.

MemberBehavior
live, last_errorConnection and fault state
connect(), disconnect()Connects the device and releases resources
get_ratio()Returns the measured normalized opening
set_ratio(ratio)Updates the opening target without blocking
move_blocking(ratio, should_stop=None)Waits for motion completion and supports cancellation
recover()Restores gripper operation after a fault

Set full opening or closing travel time in GripperConfig.full_travel_s, in seconds, as a finite positive number. Shared motion scheduling uses it to time gripper moves. Keep device communication inside the driver so it does not block 30 Hz target dispatch.

Camera

A camera implements Camera:

MemberBehavior
live, last_errorConnection, capture, and frame-expiry state
connect(), disconnect()Starts capture and releases capture resources
read()Returns (image, age_s)
read_after(after, timeout_s, should_stop=None)Waits within the timeout for a capture newer than after; after=None means latest. Returns None on cancellation

image is a uint8 RGB array with shape (720, 1280, 3), captured at 30 FPS. age_s is the actual elapsed time since capture, in seconds. Preserve raw orientation, view, and fisheye distortion without cropping, padding, or mirroring. Convert transport formats such as BGR to RGB.

after is a monotonic timestamp; correlate device capture time correctly. Reading a cached frame must not reset its age to zero. Configure a finite positive expiry threshold in CameraConfig.stale_after_s.

Tool load

Register configure_tool(setup) only when the arm needs external inertial data. It runs after component selection and returns a ToolLoad or None. Without the callback, setup does not prompt for load data. The control and guiding factories receive the load, and the driver applies or verifies it.

ToolLoad fieldMeaning and units
mass_kgMass of the complete flange assembly, kg
com_flange_mThree-dimensional centre of mass relative to the flange, m
inertia_kg_m23×3 inertia about the centre of mass, with flange-parallel axes, kg·m²

Mass is non-negative, values are finite, and inertia is symmetric and positive semidefinite. Include the complete gripper, camera, and adapter assembly without double-counting parts already represented in the controller's dynamics model.

Franka uses local tool load data; UR configures loads in PolyScope. Use standard assembly data only for matching hardware. Load, flange TCP, and spatial calibration are separate settings; updating load data does not replace recalibration.

Connection and runtime behavior

  • Registration and construction do not access devices. Defer optional SDK imports until connection.
  • The runtime dispatches targets at 30 Hz. The driver maintains its native control loop and holds position while the next inference is pending.
  • Optionally implement hold() for stopping. Without an arm-specific hold(), the runtime sends the measured pose as a holding target. A gripper that must interrupt motion immediately should provide its own hold().
  • Stop and recovery operations support cancellation. Cleanup is repeatable and handles partially established connections.
  • When components share a CAN connection or SDK session, the adapter package coordinates access and lifetime, closing it after all users have released it.

Check discovery and configuration storage, actual feedback and device identity, calibration and returns, continuous actions, holding during inference, stopping, and recovery. Start with Connect new hardware.

On this page