Skip to content

feat(damiao): support native macOS CAN transport - #3465

Open
TomCC7 wants to merge 1 commit into
cc/feat/dual-yamfrom
cc/feat/openyam-macos-support
Open

feat(damiao): support native macOS CAN transport#3465
TomCC7 wants to merge 1 commit into
cc/feat/dual-yamfrom
cc/feat/openyam-macos-support

Conversation

@TomCC7

@TomCC7 TomCC7 commented Aug 14, 2026

Copy link
Copy Markdown
Member

Contribution path

Problem

Damiao-based arms could only construct Linux SocketCAN transports. The macOS workaround lived above the shared hardware layer, so it did not apply coherently to every Damiao topology.

Solution

  • Upgrade can-motor-control to 0.0.6 on Linux and macOS.
  • Select SocketCanBus on Linux and the package's native Rust GsUsbBus on macOS in DamiaoWholeBodyAdapter.
  • Treat runtime bus overrides as SocketCAN interface names on Linux and USB serial numbers on macOS.
  • Route OpenYAM, Dual OpenYAM, and OpenArm through the shared bus factory.
  • Preserve stable default bus ordering and reject undeclared or duplicate logical buses.
  • Document macOS setup and device selection.

Co-authored with @aromeoes, whose original macOS hardware work established the transport requirements.

How to Test

uv run pytest dimos/hardware/whole_body/damiao/test_adapter.py dimos/hardware/whole_body/openyam_damiao/test_adapter.py dimos/hardware/whole_body/dual_openyam_damiao/test_adapter.py dimos/hardware/whole_body/openarm_damiao/test_adapter.py dimos/robot/manipulators/openyam/test_openyam.py dimos/robot/manipulators/dual_openyam/test_config.py dimos/robot/manipulators/openarm/test_openarm_teleop.py -q

Result: 91 passed, 3 deselected.

Ruff and Mypy pass on the changed modules. The repository-wide fast suite reaches 4,110 passes but is currently blocked by three failures already present in the #3463 stack: the removed prepare_urdf_for_drake import and two case-sensitive ControlCoordinator test expectations.

AI assistance

Codex was used to inspect the existing implementation, design the shared transport seam, implement the change, resolve the rebase, and run tests. The resulting diff and test output were reviewed during the session.

Checklist

  • I have read and approved the CLA.

@TomCC7 TomCC7 changed the title cc/feat/openyam macos support feat(damiao): support native macOS CAN transport Aug 14, 2026
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

❌ 6 Tests Failed:

Tests completed Failed Passed Skipped
4661 6 4655 213
View the top 3 failed test(s) by shortest run time
dimos.codebase_checks.test_blueprint_kwargs::test_blueprint_atom_kwargs_match_module_config[teleop-quest-dual-openyam]
Stack Traces | 0.003s run time
blueprint_name = 'teleop-quest-dual-openyam'

    @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)
    
        violations: list[str] = []
        for atom in blueprint.blueprints:
            unknown_kwargs = sorted(set(atom.kwargs) - _allowed_kwarg_names(atom.module))
            if unknown_kwargs:
                violations.append(
                    f"{atom.module.__module__}.{atom.module.__name__}: unknown kwargs {unknown_kwargs}"
                )
    
        if violations:
            listing = "\n".join(f"  - {violation}" for violation in violations)
>           raise AssertionError(
                f"Blueprint {blueprint_name!r} passes unknown module kwargs:\n{listing}\n\n"
                "Blueprint kwargs are forwarded into the module constructor. For modules "
                "with an explicit `config` annotation, use fields from that config model; "
                "for legacy modules with direct constructor parameters, use the declared "
                "`__init__` keyword names."
            )
E           AssertionError: Blueprint 'teleop-quest-dual-openyam' passes unknown module kwargs:
E             - dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']
E           
E           Blueprint kwargs are forwarded into the module constructor. For modules with an explicit `config` annotation, use fields from that config model; for legacy modules with direct constructor parameters, use the declared `__init__` keyword names.

atom       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] BlueprintAtom object at 0xff661efe3ad0>
blueprint  = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] Blueprint object at 0xff661efe2e10>
blueprint_name = 'teleop-quest-dual-openyam'
listing    = "  - dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']"
unknown_kwargs = []
violations = ["dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']"]

dimos/codebase_checks/test_blueprint_kwargs.py:103: AssertionError
dimos.codebase_checks.test_blueprint_kwargs::test_blueprint_atom_kwargs_match_module_config[teleop-quest-openyam]
Stack Traces | 0.003s run time
blueprint_name = 'teleop-quest-openyam'

    @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)
    
        violations: list[str] = []
        for atom in blueprint.blueprints:
            unknown_kwargs = sorted(set(atom.kwargs) - _allowed_kwarg_names(atom.module))
            if unknown_kwargs:
                violations.append(
                    f"{atom.module.__module__}.{atom.module.__name__}: unknown kwargs {unknown_kwargs}"
                )
    
        if violations:
            listing = "\n".join(f"  - {violation}" for violation in violations)
>           raise AssertionError(
                f"Blueprint {blueprint_name!r} passes unknown module kwargs:\n{listing}\n\n"
                "Blueprint kwargs are forwarded into the module constructor. For modules "
                "with an explicit `config` annotation, use fields from that config model; "
                "for legacy modules with direct constructor parameters, use the declared "
                "`__init__` keyword names."
            )
E           AssertionError: Blueprint 'teleop-quest-openyam' passes unknown module kwargs:
E             - dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']
E           
E           Blueprint kwargs are forwarded into the module constructor. For modules with an explicit `config` annotation, use fields from that config model; for legacy modules with direct constructor parameters, use the declared `__init__` keyword names.

atom       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/yam_description.tar.gz after 3 attempt...on.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] BlueprintAtom object at 0xff6674197e00>
blueprint  = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/yam_description.tar.gz after 3 attempt...iption.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] Blueprint object at 0xff66741971d0>
blueprint_name = 'teleop-quest-openyam'
listing    = "  - dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']"
unknown_kwargs = []
violations = ["dimos.teleop.quest.quest_extensions.ArmTeleopModule: unknown kwargs ['task_names']"]

dimos/codebase_checks/test_blueprint_kwargs.py:103: AssertionError
dimos.robot.manipulators.dual_openyam.test_teleop_ik::test_quest_solver_matches_a1z_target_tracking_speed
Stack Traces | 0.003s run time
self = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')

    def __hash__(self):
        try:
>           return self._hash

self       = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')

....../github/home/.local.../uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/pathlib.py:526: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')
name = '_hash'

    def __getattribute__(self, name: str) -> object:
        # During Path.__new__(), _lfs_filename hasn't been set yet.
        # Fall through to normal Path behavior until construction is complete.
        try:
            object.__getattribute__(self, "_lfs_filename")
        except AttributeError:
            return object.__getattribute__(self, name)
    
        # After construction, allow access to our internal attributes directly
        if name in ("_lfs_filename", "_lfs_resolved_cache", "_ensure_downloaded"):
            return object.__getattribute__(self, name)
    
        # For all other attributes, ensure download first then delegate to resolved path
        resolved = object.__getattribute__(self, "_ensure_downloaded")()
>       return getattr(resolved, name)
E       AttributeError: 'PosixPath' object has no attribute '_hash'

name       = '_hash'
resolved   = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')
self       = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')

dimos/utils/data.py:371: AttributeError

During handling of the above exception, another exception occurred:

    @pytest.mark.self_hosted
    def test_quest_solver_matches_a1z_target_tracking_speed() -> None:
>       solver = _solver()


.../manipulators/dual_openyam/test_teleop_ik.py:69: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../manipulators/dual_openyam/test_teleop_ik.py:47: in _solver
    return DualOpenYamPinkPoseTargetSolver(config)
        config     = PoseTargetIKTaskConfig(joint_names=('left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_...ilter_cutoff_hz=30.0, max_command_tracking_error_deg=10.0, feedback_limit_tolerance=0.001, command_limit_margin=0.0001)
        task       = TaskConfig(name='teleop_dual_openyam', type='teleop_ik', joint_names=['left_arm/joint1', 'left_arm/joint2', 'left_arm/...nd_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, 'joint_command_filter_cutoff_hz': 30.0}, stream_bind={})
.../control/tasks/pose_target_ik.py:277: in __init__
    self._validate_frame_targets(
        __class__  = <class 'dimos.control.tasks.pose_target_ik.PinkPoseTargetSolver'>
        config     = PoseTargetIKTaskConfig(joint_names=('left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_...ilter_cutoff_hz=30.0, max_command_tracking_error_deg=10.0, feedback_limit_tolerance=0.001, command_limit_margin=0.0001)
        self       = <dimos.robot.manipulators.dual_openyam.teleop_ik.DualOpenYamPinkPoseTargetSolver object at 0x7f141050ff50>
.../control/tasks/pose_target_ik.py:491: in _validate_frame_targets
    context = self._get_control_context(robot_model, frames, joints)
        command_limit_margin = 0.0001
        controlled_joints = ('left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'left_arm/joint6', ...)
        frame_names = ('left_grasp_frame', 'right_grasp_frame')
        frames     = ('left_grasp_frame', 'right_grasp_frame')
        joints     = ('left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'left_arm/joint6', ...)
        robot_model = RobotModelConfig(rpc_transport=<class 'dimos.protocol.rpc.pubsubrpc.LCMRPC'>, default_rpc_timeout=120.0, rpc_timeouts=...extra_links=[], home_joints=[0.0, 1.047, 1.047, 0.0, 0.0, 0.0, 0.0, 1.047, 1.047, 0.0, 0.0, 0.0], pre_grasp_offset=0.1)
        self       = <dimos.robot.manipulators.dual_openyam.teleop_ik.DualOpenYamPinkPoseTargetSolver object at 0x7f141050ff50>
.../control/tasks/pose_target_ik.py:536: in _get_control_context
    if cache_key not in self._control_contexts:
        cache_key  = (RobotModel(_source_path=PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf'), _package_paths=...'left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'left_arm/joint6', ...))
        config     = RobotModelConfig(rpc_transport=<class 'dimos.protocol.rpc.pubsubrpc.LCMRPC'>, default_rpc_timeout=120.0, rpc_timeouts=...extra_links=[], home_joints=[0.0, 1.047, 1.047, 0.0, 0.0, 0.0, 0.0, 1.047, 1.047, 0.0, 0.0, 0.0], pre_grasp_offset=0.1)
        controlled_joints = ('left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'left_arm/joint6', ...)
        frame_names = ('left_grasp_frame', 'right_grasp_frame')
        frames     = ('left_grasp_frame', 'right_grasp_frame')
        self       = <dimos.robot.manipulators.dual_openyam.teleop_ik.DualOpenYamPinkPoseTargetSolver object at 0x7f141050ff50>
<string>:3: in __hash__
    ???
        self       = RobotModel(_source_path=PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf'), _package_paths=(...dimos/data/dual_openyam_abc_box_v2')),), _xacro_args=(), _fixed_frames=(), _fixed_joints=(), _joint_position_limits=())
....../github/home/.local.../uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/pathlib.py:529: in __hash__
    return self._hash
        self       = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')
name = '_hash'

    def __getattribute__(self, name: str) -> object:
        # During Path.__new__(), _lfs_filename hasn't been set yet.
        # Fall through to normal Path behavior until construction is complete.
        try:
            object.__getattribute__(self, "_lfs_filename")
        except AttributeError:
            return object.__getattribute__(self, name)
    
        # After construction, allow access to our internal attributes directly
        if name in ("_lfs_filename", "_lfs_resolved_cache", "_ensure_downloaded"):
            return object.__getattribute__(self, name)
    
        # For all other attributes, ensure download first then delegate to resolved path
        resolved = object.__getattribute__(self, "_ensure_downloaded")()
>       return getattr(resolved, name)
E       AttributeError: 'PosixPath' object has no attribute '_hash'

name       = '_hash'
resolved   = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')
self       = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')

dimos/utils/data.py:371: AttributeError
dimos.robot.manipulators.dual_openyam.test_teleop_ik::test_solver_uses_nominal_posture_without_manipulability
Stack Traces | 0.003s run time
self = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')

    def __hash__(self):
        try:
>           return self._hash

self       = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')

....../github/home/.local.../uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/pathlib.py:526: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')
name = '_hash'

    def __getattribute__(self, name: str) -> object:
        # During Path.__new__(), _lfs_filename hasn't been set yet.
        # Fall through to normal Path behavior until construction is complete.
        try:
            object.__getattribute__(self, "_lfs_filename")
        except AttributeError:
            return object.__getattribute__(self, name)
    
        # After construction, allow access to our internal attributes directly
        if name in ("_lfs_filename", "_lfs_resolved_cache", "_ensure_downloaded"):
            return object.__getattribute__(self, name)
    
        # For all other attributes, ensure download first then delegate to resolved path
        resolved = object.__getattribute__(self, "_ensure_downloaded")()
>       return getattr(resolved, name)
E       AttributeError: 'PosixPath' object has no attribute '_hash'

name       = '_hash'
resolved   = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')
self       = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')

dimos/utils/data.py:371: AttributeError

During handling of the above exception, another exception occurred:

    @pytest.mark.self_hosted
    def test_solver_uses_nominal_posture_without_manipulability() -> None:
>       solver = _solver()


.../manipulators/dual_openyam/test_teleop_ik.py:52: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../manipulators/dual_openyam/test_teleop_ik.py:47: in _solver
    return DualOpenYamPinkPoseTargetSolver(config)
        config     = PoseTargetIKTaskConfig(joint_names=('left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_...ilter_cutoff_hz=30.0, max_command_tracking_error_deg=10.0, feedback_limit_tolerance=0.001, command_limit_margin=0.0001)
        task       = TaskConfig(name='teleop_dual_openyam', type='teleop_ik', joint_names=['left_arm/joint1', 'left_arm/joint2', 'left_arm/...nd_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, 'joint_command_filter_cutoff_hz': 30.0}, stream_bind={})
.../control/tasks/pose_target_ik.py:277: in __init__
    self._validate_frame_targets(
        __class__  = <class 'dimos.control.tasks.pose_target_ik.PinkPoseTargetSolver'>
        config     = PoseTargetIKTaskConfig(joint_names=('left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_...ilter_cutoff_hz=30.0, max_command_tracking_error_deg=10.0, feedback_limit_tolerance=0.001, command_limit_margin=0.0001)
        self       = <dimos.robot.manipulators.dual_openyam.teleop_ik.DualOpenYamPinkPoseTargetSolver object at 0x7f141050e0f0>
.../control/tasks/pose_target_ik.py:491: in _validate_frame_targets
    context = self._get_control_context(robot_model, frames, joints)
        command_limit_margin = 0.0001
        controlled_joints = ('left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'left_arm/joint6', ...)
        frame_names = ('left_grasp_frame', 'right_grasp_frame')
        frames     = ('left_grasp_frame', 'right_grasp_frame')
        joints     = ('left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'left_arm/joint6', ...)
        robot_model = RobotModelConfig(rpc_transport=<class 'dimos.protocol.rpc.pubsubrpc.LCMRPC'>, default_rpc_timeout=120.0, rpc_timeouts=...extra_links=[], home_joints=[0.0, 1.047, 1.047, 0.0, 0.0, 0.0, 0.0, 1.047, 1.047, 0.0, 0.0, 0.0], pre_grasp_offset=0.1)
        self       = <dimos.robot.manipulators.dual_openyam.teleop_ik.DualOpenYamPinkPoseTargetSolver object at 0x7f141050e0f0>
.../control/tasks/pose_target_ik.py:536: in _get_control_context
    if cache_key not in self._control_contexts:
        cache_key  = (RobotModel(_source_path=PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf'), _package_paths=...'left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'left_arm/joint6', ...))
        config     = RobotModelConfig(rpc_transport=<class 'dimos.protocol.rpc.pubsubrpc.LCMRPC'>, default_rpc_timeout=120.0, rpc_timeouts=...extra_links=[], home_joints=[0.0, 1.047, 1.047, 0.0, 0.0, 0.0, 0.0, 1.047, 1.047, 0.0, 0.0, 0.0], pre_grasp_offset=0.1)
        controlled_joints = ('left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'left_arm/joint6', ...)
        frame_names = ('left_grasp_frame', 'right_grasp_frame')
        frames     = ('left_grasp_frame', 'right_grasp_frame')
        self       = <dimos.robot.manipulators.dual_openyam.teleop_ik.DualOpenYamPinkPoseTargetSolver object at 0x7f141050e0f0>
<string>:3: in __hash__
    ???
        self       = RobotModel(_source_path=PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf'), _package_paths=(...dimos/data/dual_openyam_abc_box_v2')),), _xacro_args=(), _fixed_frames=(), _fixed_joints=(), _joint_position_limits=())
....../github/home/.local.../uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/pathlib.py:529: in __hash__
    return self._hash
        self       = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')
name = '_hash'

    def __getattribute__(self, name: str) -> object:
        # During Path.__new__(), _lfs_filename hasn't been set yet.
        # Fall through to normal Path behavior until construction is complete.
        try:
            object.__getattribute__(self, "_lfs_filename")
        except AttributeError:
            return object.__getattribute__(self, name)
    
        # After construction, allow access to our internal attributes directly
        if name in ("_lfs_filename", "_lfs_resolved_cache", "_ensure_downloaded"):
            return object.__getattribute__(self, name)
    
        # For all other attributes, ensure download first then delegate to resolved path
        resolved = object.__getattribute__(self, "_ensure_downloaded")()
>       return getattr(resolved, name)
E       AttributeError: 'PosixPath' object has no attribute '_hash'

name       = '_hash'
resolved   = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')
self       = PosixPath('.../data/dual_openyam_abc_box_v2/dual_openyam.urdf')

dimos/utils/data.py:371: AttributeError
dimos.hardware.whole_body.dual_openyam_damiao.test_adapter::test_adapter_connects_complete_dual_yam_topology
Stack Traces | 3.14s run time
adapter = <dimos.hardware.whole_body.dual_openyam_damiao.adapter.DualOpenYamDamiaoAdapter object at 0xff7ce8f9e3c0>

    def test_adapter_connects_complete_dual_yam_topology(
        adapter: DualOpenYamDamiaoAdapter,
    ) -> None:
>       assert adapter.connect()
E       assert False
E        +  where False = connect()
E        +    where connect = <dimos.hardware.whole_body.dual_openyam_damiao.adapter.DualOpenYamDamiaoAdapter object at 0xff7ce8f9e3c0>.connect

adapter    = <dimos.hardware.whole_body.dual_openyam_damiao.adapter.DualOpenYamDamiaoAdapter object at 0xff7ce8f9e3c0>

.../whole_body/dual_openyam_damiao/test_adapter.py:44: AssertionError
dimos.robot.manipulators.dual_openyam.test_blueprints::test_quest_blueprint_selects_physical_hardware_from_both_can_ports
Stack Traces | 3.2s run time
value = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff661efe2480>

    def _copy_opaque(value: Any) -> Any:
        try:
>           return copy.deepcopy(value)

value      = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff661efe2480>

.../coordination/blueprint_config/values.py:148: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
........................................../usr/lib/python3.12/copy.py:162: in deepcopy
    y = _reconstruct(x, memo, *rv)
        _nil       = []
        cls        = <class 'dimos.control.coordinator.TaskConfig'>
        copier     = None
        d          = 280814071719040
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        reductor   = <built-in method __reduce_ex__ of TaskConfig object at 0xff661efe2480>
        rv         = (<function __newobj__ at 0xff6711a905e0>, (<class 'dimos.control.coordinator.TaskConfig'>,), {'auto_start': False, 'jo...lter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}, ...}, None, None)
        x          = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff661efe2480>
        y          = []
........................................../usr/lib/python3.12/copy.py:259: in _reconstruct
    state = deepcopy(state, memo)
        args       = <generator object _reconstruct.<locals>.<genexpr> at 0xff667dc793f0>
        deep       = True
        deepcopy   = <function deepcopy at 0xff671142a020>
        dictiter   = None
        func       = <function __newobj__ at 0xff6711a905e0>
        listiter   = None
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        state      = {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'lef...nt_command_filter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}, ...}
        x          = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff661efe2480>
        y          = <[AttributeError("'TaskConfig' object has no attribute 'name'") raised in repr()] TaskConfig object at 0xff667e147bf0>
........................................../usr/lib/python3.12/copy.py:136: in deepcopy
    y = copier(x, memo)
        _nil       = []
        cls        = <class 'dict'>
        copier     = <function _deepcopy_dict at 0xff6711228ae0>
        d          = 280815665325120
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        x          = {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'lef...nt_command_filter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}, ...}
        y          = []
........................................../usr/lib/python3.12/copy.py:221: in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
        deepcopy   = <function deepcopy at 0xff671142a020>
        key        = 'params'
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        value      = {'bindings': [{'hand': 'left', 'target_frame': 'left_grasp_frame'}, {'hand': 'right', 'target_frame': 'right_grasp_fra..., 'joint_command_filter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}
        x          = {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'lef...nt_command_filter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}, ...}
        y          = {'auto_start': False, 'joint_names': ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'left_arm/joint6', ...], 'name': 'teleop_dual_openyam', 'priority': 10, ...}
........................................../usr/lib/python3.12/copy.py:136: in deepcopy
    y = copier(x, memo)
        _nil       = []
        cls        = <class 'dict'>
        copier     = <function _deepcopy_dict at 0xff6711228ae0>
        d          = 280814063207360
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        x          = {'bindings': [{'hand': 'left', 'target_frame': 'left_grasp_frame'}, {'hand': 'right', 'target_frame': 'right_grasp_fra..., 'joint_command_filter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}
        y          = []
........................................../usr/lib/python3.12/copy.py:221: in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
        deepcopy   = <function deepcopy at 0xff671142a020>
        key        = 'robot_model'
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        value      = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] RobotModelConfig object at 0xff661eae1400>
        x          = {'bindings': [{'hand': 'left', 'target_frame': 'left_grasp_frame'}, {'hand': 'right', 'target_frame': 'right_grasp_fra..., 'joint_command_filter_cutoff_hz': 30.0, 'max_command_tracking_error_deg': 10.0, 'max_joint_velocity_rad_s': 2.0, ...}
        y          = {}
........................................../usr/lib/python3.12/copy.py:143: in deepcopy
    y = copier(memo)
        _nil       = []
        cls        = <class 'dimos.manipulation.planning.spec.config.RobotModelConfig'>
        copier     = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...bc_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] method object at 0xff667e1e0640>
        d          = 280814066471936
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        x          = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] RobotModelConfig object at 0xff661eae1400>
        y          = []
.venv/lib/python3.12.../site-packages/pydantic/main.py:978: in __deepcopy__
    _object_setattr(m, '__dict__', deepcopy(self.__dict__, memo=memo))
        cls        = <class 'dimos.manipulation.planning.spec.config.RobotModelConfig'>
        m          = RobotModelConfig()
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] RobotModelConfig object at 0xff661eae1400>
........................................../usr/lib/python3.12/copy.py:136: in deepcopy
    y = copier(x, memo)
        _nil       = []
        cls        = <class 'dict'>
        copier     = <function _deepcopy_dict at 0xff6711228ae0>
        d          = 280814063217600
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        x          = {'auto_convert_meshes': True, 'base_link': 'dual_openyam_base', 'base_pose': Pose(position=Vector([          0           0           0]), orientation=Quaternion(0.000000, 0.000000, 0.000000, 1.000000)), 'collision_exclusion_pairs': [], ...}
        y          = []
........................................../usr/lib/python3.12/copy.py:221: in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
        deepcopy   = <function deepcopy at 0xff671142a020>
        key        = 'model'
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        value      = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] RobotModel object at 0xff668d0adb80>
        x          = {'auto_convert_meshes': True, 'base_link': 'dual_openyam_base', 'base_pose': Pose(position=Vector([          0           0           0]), orientation=Quaternion(0.000000, 0.000000, 0.000000, 1.000000)), 'collision_exclusion_pairs': [], ...}
        y          = {'default_rpc_timeout': 120.0, 'frame_id': None, 'frame_id_prefix': None, 'g': GlobalConfig(robot_ip=None, robot_ips=N...ess=True, local_relay=False, relay_url=None, dimos_cloud_url='https://login.dimensional.org', dimos_api_key=None), ...}
........................................../usr/lib/python3.12/copy.py:162: in deepcopy
    y = _reconstruct(x, memo, *rv)
        _nil       = []
        cls        = <class 'dimos.robot.assets.model.RobotModel'>
        copier     = None
        d          = 280815918046080
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        reductor   = <built-in method __reduce_ex__ of RobotModel object at 0xff668d0adb80>
        rv         = (<function __newobj__ at 0xff6711a905e0>, (<class 'dimos.robot.assets.model.RobotModel'>,), {'_fixed_frames': (), '_fi...xclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff668cd496d0>),), ...}, None, None)
        x          = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] RobotModel object at 0xff668d0adb80>
        y          = []
........................................../usr/lib/python3.12/copy.py:259: in _reconstruct
    state = deepcopy(state, memo)
        args       = <generator object _reconstruct.<locals>.<genexpr> at 0xff667dc795d0>
        deep       = True
        deepcopy   = <function deepcopy at 0xff671142a020>
        dictiter   = None
        func       = <function __newobj__ at 0xff6711a905e0>
        listiter   = None
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        state      = {'_fixed_frames': (), '_fixed_joints': (), '_joint_position_limits': (), '_package_paths': (('dual_openyam_abc_box', <...tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff668cd496d0>),), ...}
        x          = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] RobotModel object at 0xff668d0adb80>
        y          = <[AttributeError("'RobotModel' object has no attribute '_source_path'") raised in repr()] RobotModel object at 0xff667e129820>
........................................../usr/lib/python3.12/copy.py:136: in deepcopy
    y = copier(x, memo)
        _nil       = []
        cls        = <class 'dict'>
        copier     = <function _deepcopy_dict at 0xff6711228ae0>
        d          = 280815667654400
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        x          = {'_fixed_frames': (), '_fixed_joints': (), '_joint_position_limits': (), '_package_paths': (('dual_openyam_abc_box', <...tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff668cd496d0>),), ...}
        y          = []
........................................../usr/lib/python3.12/copy.py:221: in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
        deepcopy   = <function deepcopy at 0xff671142a020>
        key        = '_source_path'
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        value      = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff668cd4bf50>
        x          = {'_fixed_frames': (), '_fixed_joints': (), '_joint_position_limits': (), '_package_paths': (('dual_openyam_abc_box', <...tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff668cd496d0>),), ...}
        y          = {}
........................................../usr/lib/python3.12/copy.py:141: in deepcopy
    copier = getattr(x, "__deepcopy__", None)
        _nil       = []
        cls        = <class 'dimos.utils.data.LfsPath'>
        copier     = None
        d          = 280815914499920
        memo       = {280814062998400: ['left_arm/joint1', 'left_arm/joint2', 'left_arm/joint3', 'left_arm/joint4', 'left_arm/joint5', 'lef...814063214912: {'build_native': False, 'can_port': None, 'detection_model': 'moondream', 'device_path': None, ...}, ...}
        x          = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff668cd4bf50>
        y          = []
dimos/utils/data.py:370: in __getattribute__
    resolved = object.__getattribute__(self, "_ensure_downloaded")()
        name       = '__deepcopy__'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff668cd4bf50>
dimos/utils/data.py:353: in _ensure_downloaded
    cache = get_data(filename)
        cache      = None
        filename   = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        self       = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...c_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] LfsPath object at 0xff668cd4bf50>
dimos/utils/data.py:310: in get_data
    archive_path = _decompress_archive(_pull_lfs_archive(archive_name))
        archive_name = 'dual_openyam_abc_box_v2'
        data_dir   = PosixPath('.../dimos/dimos/data')
        file_path  = PosixPath('.../dimos/dimos/data/dual_openyam_abc_box_v2/dual_openyam.urdf')
        name       = 'dual_openyam_abc_box_v2/dual_openyam.urdf'
        nested_path = PosixPath('dual_openyam.urdf')
        path_parts = ('dual_openyam_abc_box_v2', 'dual_openyam.urdf')
dimos/utils/data.py:254: in _pull_lfs_archive
    _lfs_pull(file_path, repo_root)
        file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
        filename   = 'dual_openyam_abc_box_v2'
        repo_root  = PosixPath('.../work/dimos/dimos')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

file_path = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.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(
                    # --exclude= overrides lfs.fetchexclude from .lfsconfig, which
                    # otherwise silently skips data/.lfs/* even when --include matches.
                    ["git", "lfs", "pull", "--include", str(relative_path), "--exclude="],
                    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/dual_openyam_abc_box_v2.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.

attempt    = 3
env        = {'ACCEPT_EULA': 'Y', 'ACTIONS_ID_TOKEN_REQUEST_TOKEN': 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjM4ODI2YjE3LTZhMzAtNWY5Yi1iMTY5LT...-version=2.0', 'ACTIONS_ORCHESTRATION_ID': 'a0549d5b-fc22-4f2a-9e75-45a18352dfad.tests.ubuntu-24_04-arm_3_14_fal', ...}
file_path  = PosixPath('.../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz')
last_err   = CalledProcessError(1, ['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude='])
relative_path = PosixPath('data/.lfs/dual_openyam_abc_box_v2.tar.gz')
repo_root  = PosixPath('.../work/dimos/dimos')
retries    = 2

dimos/utils/data.py:224: RuntimeError

The above exception was the direct cause of the following exception:

    def test_quest_blueprint_selects_physical_hardware_from_both_can_ports() -> None:
>       parsed = BlueprintConfigParser(teleop_quest_dual_openyam).parse(
            [
                "--left-can-port",
                "follower_l",
                "--right-can-port",
                "follower_r",
                "--manipulationmodule.visualization.host=0.0.0.0",
            ],
            environ={},
        )


.../manipulators/dual_openyam/test_blueprints.py:49: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../coordination/blueprint_config/parser.py:169: in parse
    key: plain(value)
        cli_tokens = ['--left-can-port', 'follower_l', '--right-can-port', 'follower_r', '--manipulationmodule.visualization.host=0.0.0.0']
        config_path = None
        environ    = {}
        global_overrides = None
        overrides  = None
        schema     = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3..._v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] ParserSchema object at 0xff667e040ac0>
        self       = <dimos.core.coordination.blueprint_config.parser.BlueprintConfigParser object at 0xff667e18b8f0>
.../coordination/blueprint_config/values.py:50: in plain
    return [plain(item) for item in value]
        value      = [<[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after ...oint5', 'right_arm/joint6'], priority=20, auto_start=False, params={'start_position_tolerance': 0.05}, stream_bind={})]
.../coordination/blueprint_config/values.py:55: in plain
    return _copy_opaque(value)
        value      = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff661efe2480>
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

value = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff661efe2480>

    def _copy_opaque(value: Any) -> Any:
        try:
            return copy.deepcopy(value)
        except Exception as error:
>           raise BlueprintConfigError(
                f"Configuration value of type {type(value).__name__} cannot be copied safely: {error}"
            ) from error
E           dimos.core.coordination.blueprint_config.errors.BlueprintConfigError: Configuration value of type TaskConfig cannot be copied safely: Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3 attempts: Command '['git', 'lfs', 'pull', '--include', 'data/.lfs/dual_openyam_abc_box_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.

value      = <[RuntimeError("Failed to pull LFS file .../dimos/data/.lfs/dual_openyam_abc_box_v2.tar.gz after 3...ox_v2.tar.gz', '--exclude=']' returned non-zero exit status 1.") raised in repr()] TaskConfig object at 0xff661efe2480>

.../coordination/blueprint_config/values.py:150: BlueprintConfigError

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

@TomCC7
TomCC7 marked this pull request as ready for review August 14, 2026 20:31
@TomCC7
TomCC7 force-pushed the cc/feat/openyam-macos-support branch from 97ee374 to f88d119 Compare August 14, 2026 21:37
@TomCC7
TomCC7 force-pushed the cc/feat/openyam-macos-support branch from e71acfc to 0a813a5 Compare August 14, 2026 21:40
@TomCC7
TomCC7 force-pushed the cc/feat/openyam-macos-support branch from 0a813a5 to 6b311db Compare August 14, 2026 21:56
@TomCC7
TomCC7 force-pushed the cc/feat/openyam-macos-support branch from 6b311db to 3dcdbfb Compare August 21, 2026 05:15
@greptile-apps

greptile-apps Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This update adds macOS gs_usb support for Damiao CAN hardware while preserving Linux SocketCAN behavior, renames runtime CAN endpoint overrides to bus_devices, and registers OpenYAM Quest teleoperation. The new OpenYAM configuration connects the right controller to the arm teleoperation task and retains complete arm and gripper task ownership.

Confidence Score: 5/5

No blocking failure remains.

The registered OpenYAM Quest configuration was exercised successfully: it resolved through discovery, accepted right-controller input, rejected the unbound left controller, and assigned all seven controlled joints.

T-Rex T-Rex Logs

What T-Rex did

  • I ran uv run --no-default-groups --extra web python trex-artifacts/quest_openyam_topology_check.py in /home/user/repo.
  • The command completed successfully and reported DISCOVERY=ok, TOPOLOGY=right-controller->teleop_openyam; claimed=7/7; unclaimed=0, and TASK_ROUTE=ok; right-input=accepted; left-input=unbound; claimed=7/7.
  • I saved the authored source and exact captured output for traceability under trex-artifacts.
  • The captured run exited with code 0 and again reported DISCOVERY=ok, TOPOLOGY=right-controller->teleop_openyam; claimed=7/7; unclaimed=0, and TASK_ROUTE=ok; right-input=accepted; left-input=unbound; claimed=7/7.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (2): Last reviewed commit: "feat(openyam): support macOS CAN and Que..." | Re-trigger Greptile

@TomCC7
TomCC7 force-pushed the cc/feat/openyam-macos-support branch from 3dcdbfb to d2c8582 Compare August 21, 2026 06:51
@TomCC7
TomCC7 force-pushed the cc/feat/openyam-macos-support branch from d2c8582 to 7dd9c3f Compare August 25, 2026 22:50
@TomCC7
TomCC7 force-pushed the cc/feat/openyam-macos-support branch 2 times, most recently from 643d6e5 to 763b4da Compare August 25, 2026 23:08
@TomCC7
TomCC7 force-pushed the cc/feat/openyam-macos-support branch 3 times, most recently from e84fa64 to d2c8582 Compare August 25, 2026 23:50
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.

1 participant