Skip to content

feat(control): per-robot JointState output streams#3130

Open
mustafab0 wants to merge 1 commit into
mainfrom
control-per-robot-joints
Open

feat(control): per-robot JointState output streams#3130
mustafab0 wants to merge 1 commit into
mainfrom
control-per-robot-joints

Conversation

@mustafab0

Copy link
Copy Markdown
Contributor

Problem

A multi-robot coordinator publishes only one merged coordinator_joint_state, so every consumer has to untangle a concatenated joint list to find the arm it cares about.

Issue: #


Solution

Coordinator subclasses can declare {hardware_id}_joints: Out[JointState] per robot. The tick loop reuses the read it and publishes outside the hardware lock.

A missing port fails loudly at start() before any adapter connects, and at runtime add_hardware.

coordinator-dual-mock is the migrated exemplar; it pins instance_name="ControlCoordinator" since a subclass otherwise serves RPCs under its own name (start() now warns).


Breaking Changes

None. Backwards support bool added with publish_robot_joint_states=True. Keeps all previous blueprints working.

Will remove this after transisitioning all blueprints to new Control Coordinator


How to Test

  1. uv run pytest dimos/control -m 'not (tool or self_hosted or mujoco or self_hosted_large)'
  2. dimos run coordinator-dual-mock
  3. Confirm left_arm_joints and right_arm_joints each carry only their own arm, alongside the unchanged coordinator_joint_state.

A deployment with several robots could only publish one merged
coordinator_joint_state, so every consumer had to untangle the concatenated
joint list to find the arm it cared about.

Coordinator subclasses can now declare one `{hardware_id}_joints: Out[JointState]`
port per robot and set publish_robot_joint_states=True. The tick loop builds each
message from the read it already performed, so there are no extra hardware reads,
and publishing happens after the hardware lock is released. The merged stream is
untouched and still gated by its own flag.

The contract is validated loudly at start() (before any adapter connects) and at
runtime add_hardware, naming the annotation to add. coordinator-dual-mock is
migrated as the exemplar; it also pins instance_name="ControlCoordinator", since
a subclass otherwise serves RPCs under its own name and the shipped clients look
for ControlCoordinator. start() now warns about that case.

Flag off is the default and unchanged. Consumer migration and a default flip are
follow-ups.
@greptile-apps

greptile-apps Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds opt-in per-robot joint-state streams to the control coordinator. The main changes are:

  • Reuses each hardware read for merged and robot-specific messages.
  • Validates required output ports during startup and dynamic hardware registration.
  • Migrates the dual-mock coordinator to robot-specific streams.
  • Adds coverage for compatibility, message routing, failures, and dynamic hardware.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
dimos/control/coordinator.py Adds feature configuration, output-port validation, callback wiring, and subclass instance-name diagnostics.
dimos/control/tick_loop.py Captures per-hardware readings and publishes robot-specific messages after releasing the hardware lock.
dimos/robot/manipulators/common/mock.py Adds the dual-mock coordinator subclass and enables its per-robot streams.
dimos/robot/all_blueprints.py Registers the dual-mock coordinator module class.
dimos/control/test_per_robot_joint_states.py Covers feature defaults, message contents, read reuse, failure isolation, validation, and dynamic hardware.
dimos/robot/manipulators/test_blueprints.py Checks the migrated blueprint configuration and output declarations.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant C as ControlCoordinator
    participant T as TickLoop
    participant H as Hardware
    participant M as Merged output
    participant R as Per-robot output

    C->>T: Configure publish callbacks
    loop Each tick
        T->>H: Read state under hardware lock
        H-->>T: Per-hardware joint readings
        T->>T: Build merged snapshot
        T->>M: Publish merged JointState
        T->>R: Publish robot-specific JointState
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant C as ControlCoordinator
    participant T as TickLoop
    participant H as Hardware
    participant M as Merged output
    participant R as Per-robot output

    C->>T: Configure publish callbacks
    loop Each tick
        T->>H: Read state under hardware lock
        H-->>T: Per-hardware joint readings
        T->>T: Build merged snapshot
        T->>M: Publish merged JointState
        T->>R: Publish robot-specific JointState
    end
Loading

Reviews (1): Last reviewed commit: "feat(control): opt-in per-robot JointSta..." | Re-trigger Greptile

@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

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

Files with missing lines Patch % Lines
dimos/control/test_per_robot_joint_states.py 99.12% 1 Missing and 1 partial ⚠️
dimos/control/tick_loop.py 90.47% 1 Missing and 1 partial ⚠️
@@            Coverage Diff             @@
##             main    #3130      +/-   ##
==========================================
+ Coverage   73.23%   73.31%   +0.08%     
==========================================
  Files        1037     1038       +1     
  Lines       93895    94174     +279     
  Branches     8528     8544      +16     
==========================================
+ Hits        68761    69043     +282     
+ Misses      22792    22787       -5     
- Partials     2342     2344       +2     
Flag Coverage Δ
OS-ubuntu-24.04-arm 66.43% <98.59%> (+0.09%) ⬆️
OS-ubuntu-latest 68.71% <98.59%> (+0.09%) ⬆️
Py-3.10 68.70% <98.59%> (+0.09%) ⬆️
Py-3.11 68.71% <98.59%> (+0.09%) ⬆️
Py-3.12 68.71% <98.59%> (+0.09%) ⬆️
Py-3.13 68.71% <98.59%> (+0.10%) ⬆️
Py-3.14 68.70% <98.59%> (+0.08%) ⬆️
Py-3.14t 68.69% <98.59%> (+0.08%) ⬆️
SelfHosted-Large 30.10% <28.87%> (+<0.01%) ⬆️
SelfHosted-Linux 37.13% <28.87%> (-0.03%) ⬇️
SelfHosted-macOS 36.03% <28.87%> (-0.03%) ⬇️

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

Files with missing lines Coverage Δ
dimos/control/coordinator.py 80.44% <100.00%> (+0.77%) ⬆️
dimos/robot/all_blueprints.py 100.00% <ø> (ø)
dimos/robot/manipulators/common/mock.py 100.00% <100.00%> (ø)
dimos/robot/manipulators/test_blueprints.py 100.00% <100.00%> (ø)
dimos/control/test_per_robot_joint_states.py 99.12% <99.12%> (ø)
dimos/control/tick_loop.py 70.09% <90.47%> (+4.27%) ⬆️

... 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 added the backport:skip Skip creating a backport to any release branches label Jul 22, 2026
@github-actions github-actions Bot added the ready-to-merge Required CI checks have passed on this PR label Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip Skip creating a backport to any release branches 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