feat(control): per-robot JointState output streams#3130
Open
mustafab0 wants to merge 1 commit into
Open
Conversation
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.
mustafab0
requested review from
leshy,
paul-nechifor and
spomichter
as code owners
July 21, 2026 23:49
Contributor
Codecov Report❌ Patch coverage is
@@ 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
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 3 files with indirect coverage changes 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 runtimeadd_hardware.coordinator-dual-mockis the migrated exemplar; it pinsinstance_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
uv run pytest dimos/control -m 'not (tool or self_hosted or mujoco or self_hosted_large)'dimos run coordinator-dual-mockleft_arm_jointsandright_arm_jointseach carry only their own arm, alongside the unchangedcoordinator_joint_state.