Repository navigation
Replies: 4 comments 19 replies
The wire: ControlValues
Names are keys of the form This is example of Control coordinator sending commands to the Go2 The following is example of Go2 sending its velocity and odom reading to the control coordinator And you would describe the contract with: It is quite useful for Manipulators that have different modes: A xarm7 moving in position mode, and gripper moves in position mode: A xarm7 moving in velocity mode, but gripper moves in position mode: |
|
Claim 1:
@leshy's response: Claim 2:
@leshy's response: |
|
commented here but can continue in this topic discussioncomment-18740734 below ⬇️ main issue, custom message, rewriting all driversI believe you are leaking an abstraction that belongs internally into a controlcoordinator, requiring a rewrite of all drivers, and causing incompatibility with any other system, to add a custom message that adds no new information, and removes individual topics, types etc that other systems understand. you are ignoring topics and frames, using a single one in dimos, then re-implementing topics and frames in your new custom message I would say you can do all above that you'd like but keep those messages internal to controlcoordinator and translate into standards externally your answers/questionsfrom discord:
in a rare case something needs a custom control message, we can add it, but in most cases these are standard messages. custom messages don't justify removing all standard messages - but adding new custom messages All your examples above carry the same (or less!) information then standard messages so I don't see why you are inventing a new type?
Yes but that's exactly why controlcoordinator exists? I send twist to controlcoordinator, and it controls driver modules with whatever language they understand, those SDKs and drivers don't have to understand global complex motion or msg type conversions
Idea is not to do this at all. you keep your abstractions internal to controlcoordinator, and drivers do driver things. for example go2 understands twist, arm understands jointstates, there is never need internally for go2 driver to understand global coordination happening, the same way that go2 twist doesn't understand navigation or trajectory control but is able to navigate.
they do describe motor/entity by frame_id or topic (you actually invented new topic/frame abstraction in your message examples, just use topics or frame ids?)
yeah, controlcoordinator, above whole section is supposed to be answering my question on "why new topics" but is justifying existance of controlcoordinator, why? we agree there should be a controlcoordinator.
but you have external modules, so your topics are still separate, this doesn't help the problem but imo also it's not a problem, our pubsub is low latency, your proposal uses separate topics, my proposal uses separate topics, and that's ok
depends on the safety layer and driver responsibilities, go2 twist should not do colision checks for example, that's a higher order operation, but it can make sure to stop if twist input stops, which is a low level driver responsibility and will stay there, low level driver should never blindly respect twist sent 5 minutes ago, even if controlcoordinator crashed. so there are different layers of safety on different layers of abstractions general on topics/frames etcit's possible that something is lacking and inconvinient here in terms of existing topics frames etc (we'll nail it down now) but then we should fix topics, frames etc instead of reimplement |
Each driver describes itself in class Go2ConnectionModule(ConnectionModule):
base_command: In[Twist]
odom: Out[PoseStamped]
def describe(self):
return twist_base_description(
"go2",
limits={"go2/base/vx": Limits(-1.0, 1.0),
"go2/base/vy": Limits(-0.6, 0.6),
"go2/base/wz": Limits(-1.5, 1.5)},
odometry=True, # reports x, y, yaw
state_rate_hz=50.0,
deadman_timeout_s=0.2,
)
class ArmConnectionModule(ConnectionModule):
position_command: In[JointState]
joint_state: Out[JointState]
def describe(self):
# joint names, units and limits come from the arm's URDF
return manipulator_description("arm", JOINTS, model=self.config.model)On blueprint launch Control Coordinator calls This can help changing robot modes in runtime. For example switch go2 from the high-level ( Its flowchart LR
G["Go2"]
A["Arm"]
subgraph CC["ControlCoordinator"]
P1["Go2: ports, limits, state rate"]
P2["Arm: ports, limits, state rate"]
end
CC -- "@rpc describe_control()" --> G
CC -- "@rpc describe_control()" --> A
G -. "description" .-> CC
A -. "description" .-> CC
code example # coordinator, at start and after every load / restart
for module in connection_modules:
info = module.describe_control() # description + session ID
for robot in info.descriptions:
ports = ports_for(robot) # go2 → go2_base_command, go2_odom
limits = robot.limits # never send past these
rate = robot.state_rate_hz # stop commanding if readings stop
deadman = robot.deadman_timeout_s # command at least this often
if info.session_id != last_session[robot.source]:
hold_where_it_is_now(robot) # driver restarted |
Uh oh!
There was an error while loading. Please reload this page.
Goal
Every robot is a connection module in its own process. The control coordinator talks to all of them with one message type, decides which controller drives which part of which robot, and owns no hardware.
All reactions