Skip to content

Task: OpenArm Integration with DimOS#1897

Draft
mustafab0 wants to merge 11 commits intodevfrom
task/mustafa/open-arm-integration
Draft

Task: OpenArm Integration with DimOS#1897
mustafab0 wants to merge 11 commits intodevfrom
task/mustafa/open-arm-integration

Conversation

@mustafab0
Copy link
Copy Markdown
Contributor

Problem

OpenArm is a bimanual 7-DOF research arm built from Damiao DM-J motors. Unlike every other arm in dimos, it ships no Python SDK — only raw CAN. Need a from-scratch driver + adapter + blueprints to run it.

Closes DIM-386

Solution

From-scratch Damiao MIT-mode CAN driver (ported from enactic/openarm_can) + ManipulatorAdapter wrapper with Pinocchio gravity-comp feedforward + bimanual blueprints. Auto-writes CTRL_MODE=MIT on connect. Per-side URDFs avoid phantom-arm Drake collisions. Generic reachability tool added to dimos.utils since it works on any URDF.

Added:

  • dimos/hardware/manipulators/openarm/{driver,adapter,test_driver}.py
  • dimos/robot/catalog/openarm.py
  • dimos/robot/manipulators/openarm/blueprints.py
  • dimos/robot/manipulators/openarm/scripts/{openarm_can_up.sh, openarm_can_probe.py, openarm_set_mit_mode.py}
  • dimos/utils/workspace.py
  • docs/capabilities/manipulation/openarm_integration.md

Modified: dimos/robot/all_blueprints.py

Breaking Changes

None.

How to Test

Unit tests (no hardware):

.venv/bin/python -m pytest dimos/hardware/manipulators/openarm/ -v

Mock (no hardware, Drake viz):

dimos run openarm-mock-planner-coordinator

Real hardware:

sudo ./dimos/robot/manipulators/openarm/scripts/openarm_can_up.sh can0 can1
python ./dimos/robot/manipulators/openarm/scripts/openarm_can_probe.py --channel can0     # expect 8/8
dimos run openarm-planner-coordinator
# then in another terminal: python -i -m dimos.manipulation.planning.examples.manipulation_client

Full guide: openarm_integration.md.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 22, 2026

Greptile Summary

Adds a from-scratch Damiao MIT-mode CAN driver, OpenArmAdapter with Pinocchio gravity-comp feedforward, bimanual blueprints, and a generic workspace-reachability utility for the OpenArm v10 bimanual research arm. The driver, tests, catalog, and blueprints are well-structured; one functional defect was found in the adapter.

  • P1 — write_joint_velocities drops gravity feedforward: tau=0.0 is sent for all joints, so gravity acts as a fully uncompensated disturbance. In velocity mode, stationary or slow joints will sag under arm weight; write_joint_positions and write_stop both call _compute_gravity_torques correctly. The fix is to add tau_ff to the velocity command loop.
  • P1 — broken --classical flag in openarm_set_mit_mode.py docstring: Usage examples show --classical, but the script only defines --fd; running the example as written aborts with "unrecognized arguments".

Confidence Score: 4/5

Safe to merge after fixing gravity feedforward in write_joint_velocities and the --classical docstring error.

Two P1 findings: missing gravity compensation in velocity mode causes real hardware arm sag, and the broken --classical CLI example will block the hardware bring-up workflow for new users. Everything else — driver correctness, frame encoding, catalog, blueprints, tests — is solid.

dimos/hardware/manipulators/openarm/adapter.py (write_joint_velocities gravity comp) and dimos/robot/manipulators/openarm/scripts/openarm_set_mit_mode.py (docstring --classical flag)

Important Files Changed

Filename Overview
dimos/hardware/manipulators/openarm/adapter.py ManipulatorAdapter wrapping the CAN driver with Pinocchio gravity comp. P1: write_joint_velocities sends tau=0 (no gravity feedforward), causing arm sag in velocity mode; all other control paths correctly add gravity compensation.
dimos/hardware/manipulators/openarm/driver.py Pure Damiao MIT-mode CAN driver; frame pack/unpack, background RX thread, and TX retry logic are correct. Minor: ENOBUFS retry uses fragile string matching instead of errno comparison.
dimos/hardware/manipulators/openarm/test_driver.py Good hardware-free unit tests covering encoding roundtrips, frame parsing, virtual-bus loopback, and MIT fan-out; test_parse_state_roundtrip correctly validates the asymmetric state-frame byte layout.
dimos/robot/manipulators/openarm/scripts/openarm_set_mit_mode.py One-shot MIT-mode configuration script; docstring usage examples reference --classical flag that doesn't exist (actual flag is absence of --fd), which will confuse first-time users.
dimos/robot/catalog/openarm.py Clean catalog definitions for per-side and bimanual OpenArm configs; adapter_kwargs merging prevents overrides from clobbering the catalog's side key.
dimos/robot/manipulators/openarm/blueprints.py Well-structured blueprint file covering mock, single-arm, bimanual, and planner+coordinator configurations; LEFT_CAN/RIGHT_CAN assignment is clearly documented as potentially swapped on enumeration order.
dimos/utils/workspace.py Reachability/manipulability workspace sampler with Pinocchio; correct use of Yoshikawa metric, progressive radius fallback in query(), and optional scipy ConvexHull for volume estimation.
dimos/robot/manipulators/openarm/scripts/openarm_can_probe.py Hardware verification probe script; correctly parses state frames, handles missing motors gracefully, and exits with non-zero code when not all motors respond.
dimos/robot/manipulators/openarm/scripts/openarm_can_up.sh Minimal shell script to bring up SocketCAN interfaces; handles classical and FD modes, uses set -euo pipefail, and gracefully skips absent interfaces.
dimos/robot/all_blueprints.py Auto-generated blueprint registry; OpenArm entries correctly added for all 8 new blueprints including mock, left/right/bimanual, planner-coordinator, and keyboard teleop variants.

Sequence Diagram

sequenceDiagram
    participant App as Application
    participant Adapter as OpenArmAdapter
    participant Bus as OpenArmBus
    participant CAN as SocketCAN (hw)
    participant Motor as Damiao Motor

    App->>Adapter: connect()
    Adapter->>Bus: open() → start RX thread
    Adapter->>Bus: write_ctrl_mode(MIT) × 7
    Bus->>CAN: 0x7FF param-write frames
    Adapter->>Bus: enable_all()
    Bus->>CAN: 0xFC enable frames × 7
    Motor-->>CAN: state reply frames
    CAN-->>Bus: RX thread caches MotorState
    Adapter->>Bus: wait_all_states(0.5s)

    loop Control tick (100 Hz)
        App->>Adapter: write_joint_positions(q_target)
        Adapter->>Bus: get_states() → q_current
        Adapter->>Adapter: computeGeneralizedGravity(q_current)
        Adapter->>Bus: send_mit_many(q, dq=0, kp, kd, tau_g) × 7
        Bus->>CAN: MIT frames × 7 (0.5 ms gaps)
        Motor-->>CAN: updated state replies
    end

    App->>Adapter: disconnect()
    Adapter->>Bus: disable_all()
    Adapter->>Bus: close() → join RX thread
Loading

Reviews (1): Last reviewed commit: "reduced docstring to minimal" | Re-trigger Greptile

Comment thread dimos/hardware/manipulators/openarm/adapter.py
Comment thread dimos/robot/manipulators/openarm/scripts/openarm_set_mit_mode.py Outdated
Comment thread dimos/hardware/manipulators/openarm/driver.py
@mustafab0 mustafab0 marked this pull request as draft April 22, 2026 01:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant