Skip to content

Adventure x - #3138

Draft
Nabla7 wants to merge 57 commits into
mainfrom
adventure_x
Draft

Adventure x#3138
Nabla7 wants to merge 57 commits into
mainfrom
adventure_x

Conversation

@Nabla7

@Nabla7 Nabla7 commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Contribution path

  • Small, safe change that does not need a tracking issue
  • Linked issue or discussion: DIM-XXX / #XXX / URL

Problem

Solution

How to Test

AI assistance

Checklist

  • I have read and approved the CLA.

jetsonearth and others added 30 commits July 15, 2026 00:13
GalaxeaA1ZAdapter implements the ManipulatorAdapter protocol on top of the
vendor a1z SDK (CAN bus, MIT PD + gravity comp at 250 Hz). POSITION
(min-jerk planned moves) and SERVO_POSITION (streaming) control modes,
latching soft e-stop, FK-based cartesian reads, G1Z gripper support
(requires the vendor SDK's 'gripper' branch; meters API, 10 cm measured
stroke), and teach-and-play recording exposed as adapter extensions.

Startup is a verified zero-force sequence: motors enable at kp=0, every
motor must report fresh in-limit feedback before hold gains engage at the
measured pose - the vendor's stock start() position-holds a single 50 ms
read and snaps the arm to zero if feedback is late (reproduced on
hardware). Shutdown re-sends disable frames to all motors including the
gripper, whose single vendor disable frame can be lost on a busy bus.
Opt out with safe_start=False for vendor-stock behavior.

Hardware-validated on a physical A1Z + G1Z.
…sport

GsUsbMacBus is a python-can BusABC driving the bundled HHS USB-CANFD
adapter over libusb - no SocketCAN, no Linux host. The adapter selects it
automatically on macOS (transport="auto"); Linux keeps socketcan.

Handles this device's quirks: TX endpoint discovered from descriptors
(device uses 0x01, gs_usb lib assumes 0x02), no-op kernel-driver detach,
TX echo filtering, RX queue flush on open (the device retains stale
frames across sessions, which parse as garbage feedback), and up-to-5s
discovery retry (the device drops off the USB bus briefly after a close).

Validated on an M4 Pro against a live A1Z: 30 s sustained 250 Hz control
loop (p99 cycle 5.2 ms, 0/7500 over the SDK's 12.5 ms watchdog limit),
~100% feedback from all 7 motors. Requires pyusb + gs_usb + libusb.
coordinator-galaxea-a1z runs the arm under the ControlCoordinator with a
trajectory task. Hardware-certified end to end: coordinator boot,
client-submitted multi-joint trajectories over LCM RPC, 0.07 rad return
drift.

Defaults to the stable arm-only configuration (SDK main branch). The
vendor gripper branch ships a G1Z gravity model that mismatches at least
some mountings - it pushes the arm during the zero-force startup window,
and disabling gravity compensation as a workaround leaves the vendor's
soft e-stop unable to catch the arm. Flip gripper=True after gravity/
zero-point calibration (vendor tools/set_zero.py).
…dware

Wire the galaxea_a1z hardware adapter into the a1z planning model that
landed on main (dimos/robot/manipulators/a1z): a planner+coordinator
blueprint for ManipulationModule-driven motion and a keyboard teleop
blueprint using the eef twist task. Both run the arm-only stable
configuration (gripper=False, A1Z_Flange model) consistent with
coordinator-galaxea-a1z; the mock-based a1z-* blueprints are untouched.
…available

The A1Z ships with an HHS USB-CANFD adapter that the kernel gs_usb
driver cannot actually drive: the adapter's VID/PID (a8fa:8598) is not
in the driver's device table, and its bulk OUT endpoint is 0x01 where
kernels before 6.x hardcode 0x02, so every transmit fails even if the
driver is force-bound. On such machines (found on a JetPack 6 Jetson,
kernel 5.15) the arm is unreachable over socketcan no matter what,
even though the adapter is plugged in and healthy.

Teach transport="auto" to handle this: keep socketcan whenever the
channel exists and is up, so stock kernels that bind the adapter keep
working exactly as before, and only otherwise fall back to the
userspace gs_usb bus already used on macOS, with a log line saying so.
A channel that merely exists is not enough to pick socketcan: an
unrelated on-board CAN controller can expose can0 with nothing wired
to it, which is exactly what the Jetson does.

Verified on hardware: zero-force scan reads all 7 motors, the
coordinator blueprint boots and holds pose, and the first-trajectory
script passes with 0.066 rad settled drift.
Keep the gripper powered during hand-teaching and toggle it open/closed
with a single g keypress, so the operator's hand stays out of the wrist
camera footage. The legacy pinch-by-hand behavior remains available via
--gripper-free-drive. Prompts now read single keypresses (cbreak) with a
line-based fallback for non-tty stdin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The HHS adapter is a Full-Speed USB device read one frame per libusb
round-trip. Draining it synchronously from the SDK's 250 Hz control
loop (~1 ms budget per cycle) cannot sustain the ~3500 frames/s the
bus carries (7 motors' feedback plus TX echoes), so the device FIFO
overflowed and feedback froze for 0.3-2.4 s at a time - poisoning
teach recordings with stale-then-jump positions and tripping the
SDK's stale-feedback watchdog during replay.

A dedicated reader thread now drains USB continuously (libusb
releases the GIL while blocked), filters TX echoes, and queues real
frames; recv() becomes an instant pop that always meets the SDK's
drain budget. Validated on hardware: teach recordings are freeze-free
and replay runs without stale warnings.
Two changes so a hand-taught demonstration replays at 1.0x instead of
being silently time-scaled to a crawl:

- Smooth on the uniform resampled grid instead of the raw samples.
  The recorder's sample spacing is irregular (10-100 ms under load);
  differentiating linear interpolation across those gaps manufactured
  acceleration spikes an order of magnitude above the real motion
  (74 rad/s^2 measured vs ~14 real), which throttled the safety
  time-scaler and put velocity ripple into the streamed commands.
  Two moving-average passes give a continuous velocity profile.

- Size the replay caps to measured reality: natural hand teaching
  peaks ~3.5 rad/s (old cap 1.5 rescaled every demo), staying under
  the SDK's 4.0 rad/s streaming cap and 7-20 rad/s watchdogs. The
  gripper is commanded through the SDK's own controller (measured
  ~0.28 m/s, ~9 m/s^2), so its caps now cover the SDK's own motion.

Validated on hardware: a 33.5 s natural-speed episode preflights at
1.00x and replays smoothly at 0.5x and 1.0x.
Single-purpose keys with a persistent status line: SPACE starts and
saves episodes, g toggles the gripper, d discards, q quits with a
save/discard confirmation when an episode is in progress.

Denoise the session by fixing root causes: publish the camera transform
immediately at start (first-second frames also gain poses), rate-limit
the recorder's poseless-message warning, drop in-flight recording
callbacks during shutdown to avoid the closed-database error, and treat
disabling an already-disconnected A1Z adapter as success.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
TomCC7 and others added 10 commits July 21, 2026 12:24
Peers only form a transport link when they share the secret, so other
machines on the network can't see or collide with this host's zenoh
traffic. The password defaults to the machine id (derivable by any
on-machine process, so local peers auto-share) and can be overridden
with DIMOS_ZENOH_PASSWORD.
@mintlify

mintlify Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
dimensional 🟢 Ready View Preview Jul 22, 2026, 9:15 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

def _password_dictionary_file(user: str, password: str) -> str:
directory = CACHE_DIR / "zenoh_auth"
directory.mkdir(parents=True, exist_ok=True)
digest = hashlib.sha256(f"{user}:{password}".encode()).hexdigest()[:16]
directory.mkdir(parents=True, exist_ok=True)
digest = hashlib.sha256(f"{user}:{password}".encode()).hexdigest()[:16]
path = directory / f"{digest}.txt"
path.write_text(f"{user}:{password}\n")
@mintlify

mintlify Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
dimensional 🟡 Building Jul 22, 2026, 9:14 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@codecov

codecov Bot commented Jul 22, 2026

Copy link
Copy Markdown

❌ 3 Tests Failed:

Tests completed Failed Passed Skipped
3359 3 3356 179
View the top 3 failed test(s) by shortest run time
::dimos.robot.manipulators.galaxea_a1z.test_teach_replay
Stack Traces | 0s run time
.../manipulators/galaxea_a1z/test_teach_replay.py:31: in <module>
    from dimos.robot.manipulators.galaxea_a1z.blueprints.basic import (
        CameraModule = <class 'dimos.hardware.sensors.camera.module.CameraModule'>
        CollectionRecorder = <class 'dimos.imitation.collection.recorder.CollectionRecorder'>
        ControlCoordinator = <class 'dimos.control.coordinator.ControlCoordinator'>
        Episode    = <class 'dimos.imitation.dataprep.core.Episode'>
        EpisodeStatus = <class 'dimos.imitation.collection.episode_monitor.EpisodeStatus'>
        JointState = <class 'dimos.msgs.sensor_msgs.JointState.JointState'>
        LeRobotPolicyConfig = <class 'dimos.imitation.lerobot_policy.LeRobotPolicyConfig'>
        LeRobotPolicyModule = <class 'dimos.imitation.lerobot_policy.LeRobotPolicyModule'>
        Path       = <class 'pathlib.Path'>
        SqliteStore = <class 'dimos.memory2.store.sqlite.SqliteStore'>
        Webcam     = <class 'dimos.hardware.sensors.camera.webcam.Webcam'>
        __builtins__ = <builtins>
        __cached__ = '.../galaxea_a1z/__pycache__/test_teach_replay.cpython-312.pyc'
        __doc__    = None
        __file__   = '.../work/dimos/dimos/.../manipulators/galaxea_a1z/test_teach_replay.py'
        __loader__ = <_pytest.assertion.rewrite.AssertionRewritingHook object at 0xff2b4b964a10>
        __name__   = 'dimos.robot.manipulators.galaxea_a1z.test_teach_replay'
        __package__ = 'dimos.robot.manipulators.galaxea_a1z'
        __spec__   = ModuleSpec(name='dimos.robot.manipulators.galaxea_a1z.test_teach_replay', loader=<_pytest.assertion.rewrite.AssertionR...t at 0xff2b4b964a10>, origin='.../work/dimos/dimos/.../manipulators/galaxea_a1z/test_teach_replay.py')
        annotations = _Feature((3, 7, 0, 'beta', 1), None, 16777216)
        np         = <module 'numpy' from '.../dimos/dimos/.venv/lib/python3.12.../site-packages/numpy/__init__.py'>
        pytest     = <module 'pytest' from '.../dimos/dimos/.venv/lib/python3.12.../site-packages/pytest/__init__.py'>
.../galaxea_a1z/blueprints/basic.py:43: in <module>
    _A1Z_DYNAMICS_URDF = str(A1Z_G1Z_MODEL_PATH)
        A1Z_G1Z_MODEL_PATH = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempt...a/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff2a627ff4d0>
        A1Z_POLICY_TASK_NAME = 'lerobot_servo_arm'
        A1Z_REPLAY_TASK_NAME = 'teach_replay_arm'
        A1Z_TEACH_CAMERA_FPS = 15.0
        A1Z_TEACH_CAMERA_HEIGHT = 480
        A1Z_TEACH_CAMERA_WIDTH = 640
        Blueprint  = <class 'dimos.core.coordination.blueprints.Blueprint'>
        CameraModule = <class 'dimos.hardware.sensors.camera.module.CameraModule'>
        CollectionRecorder = <class 'dimos.imitation.collection.recorder.CollectionRecorder'>
        ControlCoordinator = <class 'dimos.control.coordinator.ControlCoordinator'>
        EpisodeMonitorModule = <class 'dimos.imitation.collection.episode_monitor.EpisodeMonitorModule'>
        LeRobotPolicyConfig = <class 'dimos.imitation.lerobot_policy.LeRobotPolicyConfig'>
        LeRobotPolicyModule = <class 'dimos.imitation.lerobot_policy.LeRobotPolicyModule'>
        OnExisting = <enum 'OnExisting'>
        Path       = <class 'pathlib.Path'>
        TaskConfig = <class 'dimos.control.coordinator.TaskConfig'>
        Transform  = <class 'dimos.msgs.geometry_msgs.Transform.Transform'>
        Webcam     = <class 'dimos.hardware.sensors.camera.webcam.Webcam'>
        __builtins__ = <builtins>
        __cached__ = '.../blueprints/__pycache__/basic.cpython-312.pyc'
        __doc__    = 'Basic Galaxea A1Z coordinator blueprint.'
        __file__   = '.../work/dimos/dimos/.../galaxea_a1z/blueprints/basic.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0xff2a627166c0>
        __name__   = 'dimos.robot.manipulators.galaxea_a1z.blueprints.basic'
        __package__ = 'dimos.robot.manipulators.galaxea_a1z.blueprints'
        __spec__   = ModuleSpec(name='dimos.robot.manipulators.galaxea_a1z.blueprints.basic', loader=<_frozen_importlib_external.SourceFile...ct at 0xff2a627166c0>, origin='.../work/dimos/dimos/.../galaxea_a1z/blueprints/basic.py')
        annotations = _Feature((3, 7, 0, 'beta', 1), None, 16777216)
        autoconnect = <function autoconnect at 0xff2b32584540>
        galaxea_a1z_hardware = <function galaxea_a1z_hardware at 0xff2a6271e020>
        partial    = <class 'functools.partial'>
dimos/utils/data.py:369: in __str__
    return str(self._ensure_downloaded())
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempt...a/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff2a627ff4d0>
dimos/utils/data.py:347: in _ensure_downloaded
    cache = get_data(filename)
        cache      = None
        filename   = '.../A1Z_G1Z/urdf/A1Z_G1Z.urdf'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempt...a/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff2a627ff4d0>
dimos/utils/data.py:304: in get_data
    archive_path = _decompress_archive(_pull_lfs_archive(archive_name))
        archive_name = 'a1z_description'
        data_dir   = PosixPath('.../dimos/dimos/data')
        file_path  = PosixPath('.../dimos/dimos/data/.../A1Z_G1Z/urdf/A1Z_G1Z.urdf')
        name       = '.../A1Z_G1Z/urdf/A1Z_G1Z.urdf'
        nested_path = PosixPath('A1Z_G1Z/urdf/A1Z_G1Z.urdf')
        path_parts = ('a1z_description', 'A1Z_G1Z', 'urdf', 'A1Z_G1Z.urdf')
dimos/utils/data.py:248: in _pull_lfs_archive
    _lfs_pull(file_path, repo_root)
        file_path  = PosixPath('.../dimos/data/.lfs/a1z_description.tar.gz')
        filename   = 'a1z_description'
        repo_root  = PosixPath('.../work/dimos/dimos')
dimos/utils/data.py:216: in _lfs_pull
    raise RuntimeError(
E   RuntimeError: Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1.
        attempt    = 3
        env        = {'ACCEPT_EULA': 'Y', 'ACTIONS_ID_TOKEN_REQUEST_TOKEN': 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjM4ODI2YjE3LTZhMzAtNWY5Yi1iMTY5LT...-version=2.0', 'ACTIONS_ORCHESTRATION_ID': 'f7a9c1a3-76d6-4f3a-9238-38d72f3db6e3.tests.ubuntu-24_04-arm_3_14_fal', ...}
        file_path  = PosixPath('.../dimos/data/.lfs/a1z_description.tar.gz')
        last_err   = CalledProcessError(1, ['git', 'lfs', 'pull', '--include', 'data/.lfs/a1z_description.tar.gz'])
        relative_path = PosixPath('data/.lfs/a1z_description.tar.gz')
        repo_root  = PosixPath('.../work/dimos/dimos')
        retries    = 2
dimos.robot.test_all_blueprints::test_blueprint_is_valid[coordinator-galaxea-a1z]
Stack Traces | 3.16s run time
blueprint_name = 'coordinator-galaxea-a1z'

    @pytest.mark.parametrize("blueprint_name", UBUNTU_BLUEPRINTS)
    def test_blueprint_is_valid(blueprint_name: str) -> None:
        """Validate blueprints that should import on the ubuntu-latest runner."""
>       _check_blueprint(blueprint_name)

blueprint_name = 'coordinator-galaxea-a1z'

dimos/robot/test_all_blueprints.py:105: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
dimos/robot/test_all_blueprints.py:81: in _check_blueprint
    blueprint = get_blueprint_by_name(blueprint_name)
        blueprint_name = 'coordinator-galaxea-a1z'
        message    = "Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1."
dimos/robot/get_all_blueprints.py:51: in get_blueprint_by_name
    module = __import__(module_path, fromlist=[attr])
        attr       = 'coordinator_galaxea_a1z'
        module_path = 'dimos.robot.manipulators.galaxea_a1z.blueprints.basic'
        name       = 'coordinator-galaxea-a1z'
.../galaxea_a1z/blueprints/basic.py:43: in <module>
    _A1Z_DYNAMICS_URDF = str(A1Z_G1Z_MODEL_PATH)
        A1Z_G1Z_MODEL_PATH = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempt...a/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffabc544d050>
        A1Z_POLICY_TASK_NAME = 'lerobot_servo_arm'
        A1Z_REPLAY_TASK_NAME = 'teach_replay_arm'
        A1Z_TEACH_CAMERA_FPS = 15.0
        A1Z_TEACH_CAMERA_HEIGHT = 480
        A1Z_TEACH_CAMERA_WIDTH = 640
        Blueprint  = <class 'dimos.core.coordination.blueprints.Blueprint'>
        CameraModule = <class 'dimos.hardware.sensors.camera.module.CameraModule'>
        CollectionRecorder = <class 'dimos.imitation.collection.recorder.CollectionRecorder'>
        ControlCoordinator = <class 'dimos.control.coordinator.ControlCoordinator'>
        EpisodeMonitorModule = <class 'dimos.imitation.collection.episode_monitor.EpisodeMonitorModule'>
        LeRobotPolicyConfig = <class 'dimos.imitation.lerobot_policy.LeRobotPolicyConfig'>
        LeRobotPolicyModule = <class 'dimos.imitation.lerobot_policy.LeRobotPolicyModule'>
        OnExisting = <enum 'OnExisting'>
        Path       = <class 'pathlib.Path'>
        TaskConfig = <class 'dimos.control.coordinator.TaskConfig'>
        Transform  = <class 'dimos.msgs.geometry_msgs.Transform.Transform'>
        Webcam     = <class 'dimos.hardware.sensors.camera.webcam.Webcam'>
        __builtins__ = <builtins>
        __cached__ = '.../blueprints/__pycache__/basic.cpython-312.pyc'
        __doc__    = 'Basic Galaxea A1Z coordinator blueprint.'
        __file__   = '.../work/dimos/dimos/.../galaxea_a1z/blueprints/basic.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0xffac24d27d40>
        __name__   = 'dimos.robot.manipulators.galaxea_a1z.blueprints.basic'
        __package__ = 'dimos.robot.manipulators.galaxea_a1z.blueprints'
        __spec__   = ModuleSpec(name='dimos.robot.manipulators.galaxea_a1z.blueprints.basic', loader=<_frozen_importlib_external.SourceFile...ct at 0xffac24d27d40>, origin='.../work/dimos/dimos/.../galaxea_a1z/blueprints/basic.py')
        annotations = _Feature((3, 7, 0, 'beta', 1), None, 16777216)
        autoconnect = <function autoconnect at 0xffac95788540>
        galaxea_a1z_hardware = <function galaxea_a1z_hardware at 0xffabc570ef20>
        partial    = <class 'functools.partial'>
dimos/utils/data.py:369: in __str__
    return str(self._ensure_downloaded())
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempt...a/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffabc544d050>
dimos/utils/data.py:347: in _ensure_downloaded
    cache = get_data(filename)
        cache      = None
        filename   = '.../A1Z_G1Z/urdf/A1Z_G1Z.urdf'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempt...a/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xffabc544d050>
dimos/utils/data.py:304: in get_data
    archive_path = _decompress_archive(_pull_lfs_archive(archive_name))
        archive_name = 'a1z_description'
        data_dir   = PosixPath('.../dimos/dimos/data')
        file_path  = PosixPath('.../dimos/dimos/data/.../A1Z_G1Z/urdf/A1Z_G1Z.urdf')
        name       = '.../A1Z_G1Z/urdf/A1Z_G1Z.urdf'
        nested_path = PosixPath('A1Z_G1Z/urdf/A1Z_G1Z.urdf')
        path_parts = ('a1z_description', 'A1Z_G1Z', 'urdf', 'A1Z_G1Z.urdf')
dimos/utils/data.py:248: in _pull_lfs_archive
    _lfs_pull(file_path, repo_root)
        file_path  = PosixPath('.../dimos/data/.lfs/a1z_description.tar.gz')
        filename   = 'a1z_description'
        repo_root  = PosixPath('.../work/dimos/dimos')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

file_path = PosixPath('.../dimos/data/.lfs/a1z_description.tar.gz')
repo_root = PosixPath('.../work/dimos/dimos')

    def _lfs_pull(file_path: Path, repo_root: Path, *, retries: int = 2) -> None:
        relative_path = file_path.relative_to(repo_root)
    
        env = os.environ.copy()
        env["GIT_LFS_FORCE_PROGRESS"] = "1"
    
        last_err: subprocess.CalledProcessError | None = None
        for attempt in range(1, retries + 2):  # retries + 1 total attempts
            try:
                subprocess.run(
                    ["git", "lfs", "pull", "--include", str(relative_path)],
                    cwd=repo_root,
                    check=True,
                    env=env,
                )
                return
            except subprocess.CalledProcessError as e:
                last_err = e
                if attempt <= retries:
                    time.sleep(attempt)  # 1s, 2s backoff
    
>       raise RuntimeError(
            f"Failed to pull LFS file {file_path} after {retries + 1} attempts: {last_err}"
        )
E       RuntimeError: Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1.

attempt    = 3
env        = {'ACCEPT_EULA': 'Y', 'ACTIONS_ID_TOKEN_REQUEST_TOKEN': 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjM4ODI2YjE3LTZhMzAtNWY5Yi1iMTY5LT...-version=2.0', 'ACTIONS_ORCHESTRATION_ID': 'f7a9c1a3-76d6-4f3a-9238-38d72f3db6e3.tests.ubuntu-24_04-arm_3_14_fal', ...}
file_path  = PosixPath('.../dimos/data/.lfs/a1z_description.tar.gz')
last_err   = CalledProcessError(1, ['git', 'lfs', 'pull', '--include', 'data/.lfs/a1z_description.tar.gz'])
relative_path = PosixPath('data/.lfs/a1z_description.tar.gz')
repo_root  = PosixPath('.../work/dimos/dimos')
retries    = 2

dimos/utils/data.py:216: RuntimeError
dimos.codebase_checks.test_blueprint_kwargs::test_blueprint_atom_kwargs_match_module_config[coordinator-galaxea-a1z]
Stack Traces | 3.17s run time
blueprint_name = 'coordinator-galaxea-a1z'

    @pytest.mark.parametrize("blueprint_name", _blueprint_params())
    def test_blueprint_atom_kwargs_match_module_config(blueprint_name: str) -> None:
        """Fail when blueprint kwargs cannot be consumed by their target module."""
>       blueprint = _get_blueprint_or_skip(blueprint_name)

blueprint_name = 'coordinator-galaxea-a1z'

dimos/codebase_checks/test_blueprint_kwargs.py:91: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
dimos/codebase_checks/test_blueprint_kwargs.py:36: in _get_blueprint_or_skip
    return get_blueprint_by_name(blueprint_name)
        blueprint_name = 'coordinator-galaxea-a1z'
        message    = "Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1."
dimos/robot/get_all_blueprints.py:51: in get_blueprint_by_name
    module = __import__(module_path, fromlist=[attr])
        attr       = 'coordinator_galaxea_a1z'
        module_path = 'dimos.robot.manipulators.galaxea_a1z.blueprints.basic'
        name       = 'coordinator-galaxea-a1z'
.../galaxea_a1z/blueprints/basic.py:43: in <module>
    _A1Z_DYNAMICS_URDF = str(A1Z_G1Z_MODEL_PATH)
        A1Z_G1Z_MODEL_PATH = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempt...a/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xfff19c64ebd0>
        A1Z_POLICY_TASK_NAME = 'lerobot_servo_arm'
        A1Z_REPLAY_TASK_NAME = 'teach_replay_arm'
        A1Z_TEACH_CAMERA_FPS = 15.0
        A1Z_TEACH_CAMERA_HEIGHT = 480
        A1Z_TEACH_CAMERA_WIDTH = 640
        Blueprint  = <class 'dimos.core.coordination.blueprints.Blueprint'>
        CameraModule = <class 'dimos.hardware.sensors.camera.module.CameraModule'>
        CollectionRecorder = <class 'dimos.imitation.collection.recorder.CollectionRecorder'>
        ControlCoordinator = <class 'dimos.control.coordinator.ControlCoordinator'>
        EpisodeMonitorModule = <class 'dimos.imitation.collection.episode_monitor.EpisodeMonitorModule'>
        LeRobotPolicyConfig = <class 'dimos.imitation.lerobot_policy.LeRobotPolicyConfig'>
        LeRobotPolicyModule = <class 'dimos.imitation.lerobot_policy.LeRobotPolicyModule'>
        OnExisting = <enum 'OnExisting'>
        Path       = <class 'pathlib.Path'>
        TaskConfig = <class 'dimos.control.coordinator.TaskConfig'>
        Transform  = <class 'dimos.msgs.geometry_msgs.Transform.Transform'>
        Webcam     = <class 'dimos.hardware.sensors.camera.webcam.Webcam'>
        __builtins__ = <builtins>
        __cached__ = '.../blueprints/__pycache__/basic.cpython-312.pyc'
        __doc__    = 'Basic Galaxea A1Z coordinator blueprint.'
        __file__   = '.../work/dimos/dimos/.../galaxea_a1z/blueprints/basic.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0xfff201d1bfe0>
        __name__   = 'dimos.robot.manipulators.galaxea_a1z.blueprints.basic'
        __package__ = 'dimos.robot.manipulators.galaxea_a1z.blueprints'
        __spec__   = ModuleSpec(name='dimos.robot.manipulators.galaxea_a1z.blueprints.basic', loader=<_frozen_importlib_external.SourceFile...ct at 0xfff201d1bfe0>, origin='.../work/dimos/dimos/.../galaxea_a1z/blueprints/basic.py')
        annotations = _Feature((3, 7, 0, 'beta', 1), None, 16777216)
        autoconnect = <function autoconnect at 0xfff26c258540>
        galaxea_a1z_hardware = <function galaxea_a1z_hardware at 0xfff19c40b240>
        partial    = <class 'functools.partial'>
dimos/utils/data.py:369: in __str__
    return str(self._ensure_downloaded())
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempt...a/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xfff19c64ebd0>
dimos/utils/data.py:347: in _ensure_downloaded
    cache = get_data(filename)
        cache      = None
        filename   = '.../A1Z_G1Z/urdf/A1Z_G1Z.urdf'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempt...a/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xfff19c64ebd0>
dimos/utils/data.py:304: in get_data
    archive_path = _decompress_archive(_pull_lfs_archive(archive_name))
        archive_name = 'a1z_description'
        data_dir   = PosixPath('.../dimos/dimos/data')
        file_path  = PosixPath('.../dimos/dimos/data/.../A1Z_G1Z/urdf/A1Z_G1Z.urdf')
        name       = '.../A1Z_G1Z/urdf/A1Z_G1Z.urdf'
        nested_path = PosixPath('A1Z_G1Z/urdf/A1Z_G1Z.urdf')
        path_parts = ('a1z_description', 'A1Z_G1Z', 'urdf', 'A1Z_G1Z.urdf')
dimos/utils/data.py:248: in _pull_lfs_archive
    _lfs_pull(file_path, repo_root)
        file_path  = PosixPath('.../dimos/data/.lfs/a1z_description.tar.gz')
        filename   = 'a1z_description'
        repo_root  = PosixPath('.../work/dimos/dimos')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

file_path = PosixPath('.../dimos/data/.lfs/a1z_description.tar.gz')
repo_root = PosixPath('.../work/dimos/dimos')

    def _lfs_pull(file_path: Path, repo_root: Path, *, retries: int = 2) -> None:
        relative_path = file_path.relative_to(repo_root)
    
        env = os.environ.copy()
        env["GIT_LFS_FORCE_PROGRESS"] = "1"
    
        last_err: subprocess.CalledProcessError | None = None
        for attempt in range(1, retries + 2):  # retries + 1 total attempts
            try:
                subprocess.run(
                    ["git", "lfs", "pull", "--include", str(relative_path)],
                    cwd=repo_root,
                    check=True,
                    env=env,
                )
                return
            except subprocess.CalledProcessError as e:
                last_err = e
                if attempt <= retries:
                    time.sleep(attempt)  # 1s, 2s backoff
    
>       raise RuntimeError(
            f"Failed to pull LFS file {file_path} after {retries + 1} attempts: {last_err}"
        )
E       RuntimeError: Failed to pull LFS file .../dimos/data/.lfs/a1z_description.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/a1z_description.tar.gz']' returned non-zero exit status 1.

attempt    = 3
env        = {'ACCEPT_EULA': 'Y', 'ACTIONS_ID_TOKEN_REQUEST_TOKEN': 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjM4ODI2YjE3LTZhMzAtNWY5Yi1iMTY5LT...-version=2.0', 'ACTIONS_ORCHESTRATION_ID': 'f7a9c1a3-76d6-4f3a-9238-38d72f3db6e3.tests.ubuntu-24_04-arm_3_14_fal', ...}
file_path  = PosixPath('.../dimos/data/.lfs/a1z_description.tar.gz')
last_err   = CalledProcessError(1, ['git', 'lfs', 'pull', '--include', 'data/.lfs/a1z_description.tar.gz'])
relative_path = PosixPath('data/.lfs/a1z_description.tar.gz')
repo_root  = PosixPath('.../work/dimos/dimos')
retries    = 2

dimos/utils/data.py:216: RuntimeError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@Nabla7

Nabla7 commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator Author

@jeff-hykin can you explain a bit here the changes to core/zenoh that were made?

TomCC7 and others added 2 commits July 22, 2026 14:15
jeff-hykin and others added 2 commits July 22, 2026 16:07
Brings the branch up to date with 66 commits of main. Two restructures on
main drove most of the work:

- dimos/learning/ became dimos/imitation/ (#3194). Git followed the rename
  for edited files, but not for the module paths inside them; the A1Z
  teach/replay code, the LeRobot policy module and their tests referenced
  dimos.learning.* and were rewritten.
- dimos/robot/cli/ became dimos/cli/ (#3256). The A1Z teach CLI is rewired
  there; the Piper CLI this branch added is dropped because an identical
  copy already landed on main as
  dimos/robot/manipulators/piper/cli.py.

Conflict resolutions of note:

- memory2: main changed the record callback to take (recv_ts, msg) and tag
  samples with reception_ts. Kept that, plus this branch's rate-limited
  poseless warning and _closing guards, now also gated on main's
  poseless_streams config.
- zenoh: kept main's _default_connect_endpoints and scouting, plus this
  branch's usrpwd auth; session_key covers both.
- piper teleop: main removed RobotModelConfig.coordinator_task_name and
  made trajectory_task() derive the name from hardware_id. Dropped the
  explicit name= - trajectory_task_name("arm") is "traj_arm", identical to
  the old behavior - and the now-redundant test assertion.
- docs: kept this branch's restructured manipulation index and ported
  main's API corrections into the new planning.md (planner_name became
  planner.backend; RoboPlan is now the default world and planner).
- uv.lock regenerated from main's; all_blueprints.py regenerated.

Fixed while running the suite:

- test_blueprints: main deleted this file when it extracted the plan
  execution manager (#3183), dropping the xarm and planner-helper cases
  along with the blueprints they covered - xarm6_planner_only no longer
  exists and dual_xarm6_planner is now dual_xarm6_planner_coordinator.
  Kept only this branch's Piper teleop coverage rather than resurrecting
  tests main removed on purpose. Its _module_kwargs matched blueprint
  atoms on class identity, which stopped finding the coordinator once main
  introduced the _PiperTeleopCoordinator subclass; it now matches exactly
  first, then by subclass.
- galaxea_a1z adapter: dropped two "# --- section ---" markers that
  dimos/codebase_checks/test_no_sections.py rejects. That check predates
  this branch, so it was already failing before the merge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GJRrxtKynzzJx43THcHsTn
@Nabla7
Nabla7 marked this pull request as ready for review July 31, 2026 06:17
@TomCC7

TomCC7 commented Jul 31, 2026

Copy link
Copy Markdown
Member

Changing to draft, will split to smaller ones

@TomCC7
TomCC7 marked this pull request as draft July 31, 2026 06:36
@TomCC7 TomCC7 mentioned this pull request Aug 1, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants