Feature: go2 control coordinator TwistBase adapter#1357
Feature: go2 control coordinator TwistBase adapter#1357
Conversation
Greptile SummaryAdds Unitree Go2 quadruped control through the ControlCoordinator via a new Key Changes:
The implementation follows existing patterns and maintains backward compatibility. Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant KeyboardTeleop
participant Coordinator as ControlCoordinator
participant Adapter as UnitreeGo2Adapter
participant SDK as Unitree SDK2
participant Go2 as Go2 Hardware
Note over User,Go2: Initialization Phase
User->>Coordinator: start()
Coordinator->>Adapter: connect()
Adapter->>SDK: ChannelFactoryInitialize(0)
SDK-->>Adapter: DDS initialized
Adapter->>SDK: SportClient.Init()
SDK-->>Adapter: Client ready
Adapter->>SDK: StandUp()
SDK->>Go2: Stand command
Go2-->>SDK: Standing (3s)
Adapter->>SDK: FreeWalk()
SDK->>Go2: Activate locomotion
Go2-->>SDK: Ready (2s)
Adapter-->>Coordinator: Connected & Ready
Coordinator->>Adapter: write_enable(true)
Adapter-->>Coordinator: Enabled
Note over User,Go2: Runtime Control Loop
User->>KeyboardTeleop: Press W (forward)
KeyboardTeleop->>Coordinator: Twist(/cmd_vel) [vx, vy, wz]
Coordinator->>Coordinator: _on_twist_command()
Coordinator->>Adapter: write_velocities([vx, vy, wz])
Adapter->>SDK: Move(vx, vy, wz)
SDK->>Go2: DDS velocity command
Go2-->>SDK: SportModeState (actual velocities)
SDK-->>Adapter: State callback
Adapter->>Adapter: Update _latest_state
Coordinator->>Adapter: read_velocities()
Adapter-->>Coordinator: [actual vx, vy, wz]
Coordinator->>Coordinator: Publish joint_state
Note over User,Go2: Shutdown Phase
User->>Coordinator: stop()
Coordinator->>Adapter: disconnect()
Adapter->>SDK: StopMove()
SDK->>Go2: Zero velocities
Adapter->>SDK: StandDown()
SDK->>Go2: Sit down
Adapter-->>Coordinator: Disconnected
Last reviewed commit: 20b9e29 |
5ea0ca9 to
f6ef415
Compare
|
sorry haven't had the chance to review in detail yet, give me a chance before merging |
92f071d to
344de19
Compare
| if global_config.simulation: | ||
| from dimos.robot.unitree.go2.connection import go2_connection | ||
|
|
||
| # go2_connection automatically uses MujocoConnection when simulation=True. | ||
| # keyboard_teleop.cmd_vel is wired directly to go2_connection.cmd_vel | ||
| # by autoconnect — no LCM needed. | ||
| _go2 = go2_connection() | ||
| _teleop = keyboard_teleop() |
There was a problem hiding this comment.
This already exists as dimos --simulation run go2-connection keyboard-teleop.
Running dimos --simulation run unitree-go2-keyboard-teleop implies that the unitree-go2-keyboard-teleop modules are being simulated, but it's just running an entirely different set of modules.
I would just remove this, or add a sim for control_coordinator.
|
|
||
| @runtime_checkable | ||
| class ManipulatorAdapter(Protocol): | ||
| class ManipulatorAdapter(HardwareAdapter, Protocol): |
There was a problem hiding this comment.
Since it now inherits HardwareAdapter you can remove this from here:
# --- Connection ---
def connect(self) -> bool:
"""Connect to hardware. Returns True on success."""
...
def disconnect(self) -> None:
"""Disconnect from hardware."""
...
def is_connected(self) -> bool:
"""Check if connected."""
...
|
|
||
|
|
||
| @runtime_checkable | ||
| class TwistBaseAdapter(HardwareAdapter, Protocol): |
There was a problem hiding this comment.
Also remove connect/disconnect/is_connected from here.
| class _Session: | ||
| """Active connection state for a Go2.""" | ||
|
|
||
| client: Any # SportClient |
There was a problem hiding this comment.
Why Any instead of SportClient?
There was a problem hiding this comment.
Because unitree sdk is an optional dependency.
but makes sense to be more explicit. Will update
| session.client.StandDown() | ||
| time.sleep(2) | ||
| except Exception as e: | ||
| logger.error(f"Error during disconnect: {e}") |
There was a problem hiding this comment.
I think you're missing:
if session.state_sub is not None:
try:
session.state_sub.Close()
except Exception as e:
logger.error(f"Error closing state subscriber: {e}")
… reported by the go2
…ubscriptiuoin fails
…onnected hardware
cb157ca to
18f5e26
Compare
Problem
The ControlCoordinator ocannot control unitree go2 using Twist (cmd_vel)
Solution
Added
UnitreeGo2Adapterimplementing theTwistBaseAdapterprotocol, enabling the Go2 quadruped to be driven through the ControlCoordinator. Key changes:UnitreeGo2Adapter: Wraps Unitree SDK2SportClientwith DDS state feedback. Reads actual velocities fromSportModeState(not command echo). Handles the Go2's init sequence (StandUp → FreeWalk → Move).HardwareAdapterbase protocol: Extractedconnect/disconnect/is_connectedinto a shared base soManipulatorAdapterandTwistBaseAdaptershare a common ancestor, eliminatingtype: ignore[override]on the adapter property.unitree-go2-keyboard-teleopblueprint: Dual-mode — simulation usesgo2_connection(MujocoConnection), real hardware uses ControlCoordinator with the Go2 adapter._subscribe_if()with list-based cleanup. Gripper methods useisinstancenarrowing forManipulatorAdapter.Breaking Changes
None
How to Test
Simulation ( ONLY verifies blueprint wiring, keyboard input, MuJoCo physics — does NOT exercise the coordinator or Go2 adapter):
dimos --simulation run unitree-go2-keyboard-teleopReal hardware (verifies the full coordinator → adapter → SDK path):
unitree-sdk2py):dimos run unitree-go2-keyboard-teleopcloses DIM-550