Architecture Overview
DimOS uses a Protocol-based adapter pattern — no base class inheritance required. Your adapter wraps the vendor SDK and exposes a standard interface that the rest of the system consumes:
See also: dimos/hardware/manipulators/README.md for a quick reference.
Prerequisites
- Vendor SDK — The Python SDK for your robot arm (e.g.,
xarm-python-sdk,piper-sdk) - URDF/xacro — A robot description file (only needed if you want motion planning)
- Connection info — IP address, CAN port, serial device, etc.
Step 1: Create the Adapter
Create a new directory for your arm underdimos/hardware/manipulators/:
adapter.py — Full Skeleton
Below is a complete annotated adapter. Implement each method by wrapping your vendor SDK calls. All values crossing the adapter boundary must use SI units.| Quantity | SI Unit |
|---|---|
| Angles | radians |
| Angular velocity | rad/s |
| Torque | Nm |
| Position | meters |
| Force | Newtons |
skip
_registry.py manifest next to it:
Key implementation notes
-
Unsupported features — Return
Nonefor reads andFalsefor writes. Never raise exceptions for optional features. - Velocity/effort feedback — If your SDK doesn’t provide these, return zeros. The coordinator handles this gracefully.
-
Lazy SDK import — If the vendor SDK is an optional dependency, you can import it inside
connect()instead of at module level (see Piper adapter for this pattern):
Step 2: Create Package Files
How discovery works
TheAdapterRegistry in dimos/hardware/manipulators/registry.py discovers adapters from _registry.py manifests at import time:
- It iterates over all subpackages under
dimos/hardware/manipulators/ - For each subpackage, it loads
<subpackage>._registryand records eachADAPTER_FACTORIESentry (name →"module:attr"import path) - Your adapter module is imported only when
create("yourarm")is first called
available() and a missing SDK fails loudly at create() instead of silently dropping the adapter. A CI test (dimos/hardware/test_adapter_registries.py) fails if an adapter directory has no manifest or a manifest path doesn’t resolve.
You can verify discovery works:
skip
Step 3: Create Your Robot Folder and Blueprints
Each robot in DimOS gets its own folder underdimos/robot/. This is where you define all blueprints for your arm — coordinator, planning, perception, etc. This follows the same pattern as Unitree robots (dimos/robot/unitree/).
3a. Create the robot directory
3b. Define your blueprints
Createdimos/robot/yourarm/blueprints.py with your coordinator and (optionally) planning blueprints:
skip
Blueprint field reference
| Field | Description |
|---|---|
hardware_id | Unique name for this hardware component. Used to route commands. |
adapter_type | Name registered with adapter_registry (e.g., "yourarm"). |
address | Connection info passed to adapter’s __init__ as address kwarg. |
joints | List of joint names. make_joints("arm", 6) creates ["arm_joint1", ..., "arm_joint6"]. |
auto_enable | If True, servos are enabled automatically when the coordinator starts. |
task.name | Name used by the ManipulationModule to invoke trajectory execution via RPC. |
task.type | Task type: "trajectory", "servo", "velocity", or "cartesian_ik". |
task.priority | Priority for per-joint arbitration. Higher number wins. |
Step 4: Add URDF and Planning Integration (Optional)
If you want motion planning (collision-free trajectories via Drake), you need a URDF and a planning blueprint. Add these to your robot’s ownblueprints.py.
4a. Add your URDF
Place your URDF/xacro files under LFS data so they can be resolved viaLfsPath. LfsPath is a Path subclass that lazily downloads LFS data on first access — this avoids downloading at import time when the blueprint module is loaded.
skip
4b. Create a robot model config helper
skip
4c. Create a planning blueprint
Add this to yourdimos/robot/yourarm/blueprints.py alongside the coordinator blueprint:
skip
Key config fields
| Field | Description |
|---|---|
model_path | Path to .urdf or .xacro file |
joint_names | Ordered list of controlled joints (must match URDF) |
end_effector_link | Link to use as the end-effector for IK |
base_link | Root link of the robot model |
package_paths | Maps package:// URIs to filesystem paths (for xacro) |
joint_name_mapping | Maps coordinator names (e.g., "arm_joint1") to URDF names (e.g., "joint1") |
coordinator_task_name | Must match the TaskConfig.name in your coordinator blueprint |
collision_exclusion_pairs | List of (link_a, link_b) tuples for links that may legitimately touch (e.g., gripper fingers) |
Step 5: Register Blueprints
The blueprint registry indimos/robot/all_blueprints.py is auto-generated by scanning the codebase for blueprint declarations. After adding your blueprints:
- Run the generation test to update the registry:
- Now you can run your arm via CLI:
Step 6: Testing
Verify adapter registration
skip
Unit test with mock
You can test coordinator logic without hardware by usingunittest.mock:
skip
Integration test with coordinator
skip
Test the real adapter standalone
skip
Quick Reference Checklist
Files to create:-
dimos/hardware/manipulators/yourarm/__init__.py -
dimos/hardware/manipulators/yourarm/adapter.py(implements Protocol) -
dimos/hardware/manipulators/yourarm/_registry.py(declaresADAPTER_FACTORIES) -
dimos/robot/yourarm/__init__.py -
dimos/robot/yourarm/blueprints.py(coordinator + planning blueprints)
-
pyproject.toml— Add vendor SDK to optional dependencies (if applicable)
-
adapter_registry.available()includes"yourarm" -
pytest dimos/robot/test_all_blueprints_generation.pypasses (regeneratesall_blueprints.py) -
dimos run coordinator-yourarmstarts successfully
