Skip to content

Add clock sync system configurator for Unitree WebRTC #1344

@spomichter

Description

@spomichter

Problem

Unitree WebRTC connections require tight clock synchronization between the control computer and robot (within 100ms). Clock divergence affects:

  • Command timestamps
  • Sensor data correlation
  • Control loop timing
  • Telemetry synchronization

Currently, there's no automated check or sync for clock drift before connecting to hardware.


Proposed Solution

Add ClockSyncConfigurator to the system configurator framework (same pattern as LCM's multicast/buffer checks).

Implementation

File: dimos/protocol/service/system_configurator.py

class ClockSyncConfigurator(SystemConfigurator):
    """Check and sync local clock with NTP server."""
    
    critical = False
    MAX_DIVERGENCE_SECONDS = 0.1  # 100ms for WebRTC
    NTP_SERVER = "time.windows.com"
    
    def check(self) -> bool:
        # Use ntpdate -q to query clock offset
        # Return False if divergence > threshold
    
    def explanation(self) -> str | None:
        # Show offset in ms and sync command
    
    def fix(self) -> None:
        # Run: sudo ntpdate <server>

Reference implementation: Available in proposal docs (attached or can provide)


Integration Challenge

Problem: Modules/connections run in separate runner processes without STDIO access. Can't prompt for user input during module/connection initialization.

Current LCM pattern:

  • lcmservice.autoconf() runs at CLI startup (before blueprints)
  • Has STDIO access for user prompts
  • Global/early execution

Naive approach (won't work):

class UnitreeWebRTCConnection:
    def __init__(self, ip):
        self.autoconf()  # ❌ No STDIO in runner process
        # ... connect ...

Required approach:

  • Collect system config requirements before spawning runner processes
  • Run all configurators with user prompts at CLI level
  • Then proceed with blueprint execution

Proposed Integration Strategy

Option 1: Blueprint-level system config registration

Add system_config field to blueprints:

# In unitree_go2_blueprints.py
def unitree_go2(ip=None, sim=False, ...):
    system_checks = []
    if not sim and ip not in ["fake", "mock", "replay", "mujoco"]:
        system_checks.append(
            ClockSyncConfigurator(max_divergence=0.1)
        )
    
    return Blueprint(
        modules=[GO2Connection(ip=ip), ...],
        system_config=system_checks  # ← new field
    )

Then in blueprint startup (before runner spawns):

configure_system(blueprint.system_config)  # has STDIO, can prompt
# ... spawn runners, execute blueprint ...

Pros:

  • Declarative (clear what system config a blueprint needs)
  • Runs before runner processes spawn
  • Has STDIO for user prompts
  • Conditional per blueprint (hardware vs sim)

Cons:

  • Requires Blueprint infrastructure changes
  • Need to add system_config field + collection/execution logic

Option 2: Module metadata + collection phase

Add classmethod to modules that need system config:

class UnitreeWebRTCConnection:
    @classmethod
    def system_requirements(cls) -> list[SystemConfigurator]:
        return [ClockSyncConfigurator(max_divergence=0.1)]

Before executing blueprint, scan modules and collect requirements:

# In blueprint execution
requirements = []
for module in blueprint.modules:
    if hasattr(module.__class__, 'system_requirements'):
        requirements.extend(module.__class__.system_requirements())

configure_system(requirements)  # run before spawning runners

Pros:

  • Less invasive (no Blueprint schema changes)
  • Modules declare their own requirements

Cons:

  • Harder to make conditional (hardware vs sim)
  • Requires scanning all modules

Acceptance Criteria

  • ClockSyncConfigurator implemented in system_configurator.py
  • Unit tests for clock sync check/fix
  • Integration strategy chosen and implemented
  • System config runs before runner processes spawn
  • User prompted with STDIO access
  • Works for hardware Go2/G1 (skipped for sim/replay)
  • Tested on actual hardware with intentional clock skew

Related

  • Existing system config framework: dimos/protocol/service/system_configurator.py
  • LCM autoconf example: dimos/protocol/service/lcmservice.py
  • Runner process architecture: (need docs reference)

Implementation Status

  • ClockSyncConfigurator class designed and documented
  • ⏸️ Integration blocked on runner process STDIO constraint
  • ⏸️ Needs blueprint-level or pre-execution collection strategy

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions