Skip to content

Control per instance addressing - #3407

Open
mustafab0 wants to merge 1 commit into
mainfrom
control-per-instance-addressing
Open

Control per instance addressing#3407
mustafab0 wants to merge 1 commit into
mainfrom
control-per-instance-addressing

Conversation

@mustafab0

Copy link
Copy Markdown
Contributor

Problem

To steer a specific arm, teleop and jogger publishers write the name of the
consuming control task into each pose/twist message's frame_id field, and the
coordinator reads it back per message to pick the task.

Issue: #


Solution

Each cartesian / EEF-twist task instance reads its own coordinator input port, connected once in the blueprint.
Single-arm deployments declare a port named after the card's input; the dual-arm quest teleop declares one port per arm and binds each task to its side with stream_bind.


Breaking Changes

The shared coordinator ports for cartesian and EEF-twist commands are deleted.
Out-of-tree blueprints composing these tasks must declare the port on a
coordinator subclass and point their producer remap at it (one line each).


How to Test

  1. pytest dimos/control dimos/teleop dimos/robot/manipulators -m 'not (tool or self_hosted or mujoco or self_hosted_large)'
  2. On the rig: quest single-arm teleop (xarm7) — engage, track, gripper trigger.
  3. Quest dual-arm — move one controller; the other arm must not move.
  4. Keyboard jog and hosted browser twist — jog, release stops motion, gripper toggle.

@mustafab0
mustafab0 force-pushed the control-per-instance-addressing branch from c2d5457 to 1d5e5f4 Compare August 8, 2026 21:11
@codecov

codecov Bot commented Aug 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.00000% with 13 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
dimos/teleop/keyboard/keyboard_teleop_module.py 37.50% 5 Missing ⚠️
dimos/control/coordinator.py 62.50% 2 Missing and 1 partial ⚠️
dimos/control/_control_test_helpers.py 50.00% 2 Missing ⚠️
dimos/control/test_coordinator_commands.py 50.00% 2 Missing ⚠️
dimos/control/test_control.py 90.90% 1 Missing ⚠️
@@            Coverage Diff             @@
##             main    #3407      +/-   ##
==========================================
- Coverage   76.09%   76.08%   -0.02%     
==========================================
  Files        1190     1190              
  Lines      115295   115276      -19     
  Branches    10367    10361       -6     
==========================================
- Hits        87729    87703      -26     
- Misses      24554    24560       +6     
- Partials     3012     3013       +1     
Flag Coverage Δ
OS-ubuntu-24.04-arm 70.14% <90.00%> (-0.02%) ⬇️
OS-ubuntu-latest 72.14% <90.00%> (-0.02%) ⬇️
Py-3.10 72.13% <90.00%> (-0.01%) ⬇️
Py-3.11 72.13% <90.00%> (-0.02%) ⬇️
Py-3.12 72.13% <90.00%> (-0.01%) ⬇️
Py-3.13 72.13% <90.00%> (-0.02%) ⬇️
Py-3.14 72.14% <90.00%> (-0.01%) ⬇️
Py-3.14t 72.13% <90.00%> (-0.02%) ⬇️
SelfHosted-Large 29.67% <37.79%> (+<0.01%) ⬆️
SelfHosted-Linux 35.84% <37.79%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
dimos/control/routing.py 100.00% <ø> (ø)
dimos/control/tasks/cartesian_ik_task/_registry.py 100.00% <100.00%> (ø)
dimos/control/tasks/eef_twist_task/_registry.py 100.00% <ø> (ø)
dimos/control/tasks/g1_groot_wbc_task/_registry.py 100.00% <ø> (ø)
dimos/control/tasks/servo_task/_registry.py 100.00% <100.00%> (ø)
dimos/control/tasks/teleop_task/_registry.py 100.00% <ø> (ø)
dimos/control/tasks/test_registry.py 88.17% <100.00%> (+0.29%) ⬆️
dimos/control/tasks/velocity_task/_registry.py 100.00% <100.00%> (ø)
dimos/control/test_coordinator_routing.py 99.41% <100.00%> (-0.01%) ⬇️
dimos/imitation/collection/test_blueprint.py 100.00% <100.00%> (ø)
... and 20 more

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mustafab0
mustafab0 marked this pull request as ready for review August 8, 2026 21:57
@mustafab0
mustafab0 force-pushed the control-per-instance-addressing branch from 1d5e5f4 to 42537cf Compare August 8, 2026 21:59
@github-actions github-actions Bot added ready-to-merge Required CI checks have passed on this PR and removed ready-to-merge Required CI checks have passed on this PR labels Aug 8, 2026
…essing

Cartesian and EEF-twist commands were addressed by writing the consuming
TASK NAME into the message's frame_id, read back per message by the
dispatcher's BY_TASK_NAME rule. Addressing is now topology: the cards
declare neutral logical inputs (cartesian_command / ee_twist_command,
routing 'direct'), each consuming task instance reads its own coordinator
port wired once at startup, and frame_id means a coordinate frame again.

Cards and deployments:
- cartesian_ik / teleop_ik / eef_twist cards: logical input names + direct.
- Single-arm deployments subclass the coordinator with a port named like
  the logical input (name-match, no stream_bind): shared private
  coordinator subclasses in manipulators/common/blueprints.py,
  instance_name='ControlCoordinator'.
- Dual-arm quest teleop gets left_cartesian/right_cartesian ports with
  stream_bind per teleop_ik task; the quest blueprint remaps each
  controller output to its side's port. This deletes the reason frame_id
  addressing existed.

Publishers stop stuffing the address. All three consumers ignore
frame_id (IK reads only position/orientation; eef_twist reads only
linear/angular), so the stamp is dropped, not replaced: quest arm teleop
loses task_names config (poses keep their handedness frame_id),
keyboard/hosted twists go out unaddressed, and the jogger publishes the
port's topic /cartesian_command.

Machinery deleted: Routing.BY_TASK_NAME, the frame_id branch and both
dispatch warnings (empty/unknown frame_id — nothing consults the field
anymore), and the base-class coordinator_cartesian_command /
coordinator_ee_twist_command ports. BREAKING for out-of-tree blueprints
composing these tasks: declare the port on a coordinator subclass and
retarget the producer remap.

Riders:
- Routes store the handler BOUND at add_task (validated there; a stub
  missing a card handler now fails registration instead of erroring per
  message). _dispatch keeps only the claim-overlap 'name' read.
- auto_start goes through task_invoke and the declared-command table;
  servo, velocity, cartesian_ik, and g1_groot_wbc declare 'start' (the
  in-tree auto_start users are servo and g1_groot_wbc).

Tests: by-name delivery pins become per-instance port isolation (left
arm's command never reaches the right task) and single-instance
name-match; unmatched-frame_id-drops becomes frame_id-not-consulted (the
intentional addressing delta). Stubs gain the card stream handlers that
add_task now resolves eagerly.
@mustafab0
mustafab0 force-pushed the control-per-instance-addressing branch from 13aff6a to 7e0972c Compare August 9, 2026 00:38
@github-actions github-actions Bot added ready-to-merge Required CI checks have passed on this PR and removed ready-to-merge Required CI checks have passed on this PR labels Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Required CI checks have passed on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant