Skip to content

Ship the assets together in the lite_description package - #20

Merged
T-K-233 merged 1 commit into
mainfrom
ship-assets-in-package
Sep 29, 2026
Merged

T-K-233 merged 1 commit into
mainfrom
ship-assets-in-package

Conversation

@T-K-233

@T-K-233 T-K-233 commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

A consumer's lock did not pin the robot model

robot_assets.load() downloaded the default branch of this repository into a data/ directory relative to the working directory, and never refreshed it. The uv.lock of a consumer pinned only the loader code, so the model depended on when and where the cache was first made. Two machines on one commit of lite-motion-tracking could train on different robots. The lite_biped feet show the problem: since ff02069, they went from two box soles to eleven contact spheres per foot, and ankle_yaw went from ±45° to ±90°. A machine with an older cache kept the old model.

The package now carries the assets

robots/ moves to lite_description/robots/, inside the Python package, so the wheel carries the assets and a consumer's lock pins them. mjlab (mjlab/asset_zoo/robots/) and specialist_description use the same layout. The module returns paths, not loaded models:

import mujoco
from lite_description import VARIANTS, get_mjcf_path, get_urdf_path

model = mujoco.MjModel.from_xml_path(str(get_mjcf_path("lite_biped")))
  • The functions carry a get_ prefix, because mjcf_path and urdf_path are the names that callers, and this repository in about ten places, give to the paths they return. mjcf_path = mjcf_path("lite") would fail with UnboundLocalError inside a function. ament_index_python.get_package_share_directory() uses the same form. specialist-ai/specialist_description#8 makes the same renames, so the two description packages keep one API.

  • A URDF or MJCF reaches its meshes by a relative path, so a consumer loads the file where it lies.

  • ROBOTS_DIR names that robots/ directory, and VARIANTS comes from it, so no second list can drift. The plural keeps it apart from robot_dir, which names one variant's directory throughout the generator. test_package.py checks it against the CMake list.

  • The wheel is 30.5 MB, and leaves cad/ out.

The generator stays in the package

This repository owns the conversion logic, so the generator stays importable as lite_description.workflow. The CAD toolchain stays behind the cad extra, so a plain install has no dependencies. stretch_urdf and mjlab also ship their tools with their assets.

  • The commands are renamed robot-assets-* → lite-description-*.
  • A variant name now resolves through the package, so the generator no longer depends on the working directory. An installed package has no cad/, so the generator stops with an error there instead of writing into site-packages.

Breaking change for Python consumers

The distribution is renamed from robot-assets to lite-description (0.5.0), to match the import name and the ament package. load() is gone:

-from robot_assets import load
-LITE_BIPED_XML = Path(load("robots/lite_biped/mjcf/lite_biped.xml"))
+from lite_description import get_mjcf_path
+LITE_BIPED_XML = get_mjcf_path("lite_biped")

lite_description.actuators.func becomes lite_description.actuators.modeling. Its functions take the armature and the effort limit as floats instead of a whole spec table, so each signature names what the function reads. The results do not change for any of the 15 tables in the package.

-compute_stiffness(ROBSTRIDE_06_ACTUATOR_PARAMS, natural_frequency)
+compute_stiffness(ROBSTRIDE_06_ACTUATOR_PARAMS["armature"], natural_frequency)

lite-motion-tracking moves in berkeley-humanoids/lite-motion-tracking#4. Lite-RL-Finetune and any other code that imports robot_assets must move too.

Nothing changes for ROS

  • The ament install destination stays share/lite_description/robots/<variant>/, so $(find lite_description) and package:// URLs resolve as before.
  • Each generated file changes only in its banner line, which now names the new command. A regeneration of all six variants with --only urdf,mjcf,xacro,package changes no other line.
  • The published package would differ only in those banner comments, so package.xml stays at 0.0.2.

Verification

  • uv run pytest: 1590 passed, 36 skipped.
  • A clean, non-editable install of the wheel, run from outside the checkout, loads all six MJCFs, and every URDF mesh resolves.
  • The ament install, run with a stub ament_cmake, gives the same tree as before and contains no cad/. All 24 assembly and backend pairs of the CI job expand with xacro against that tree. There was no ROS install, so the colcon job in CI is the first real build.

🤖 Generated with Claude Code

https://claude.ai/code/session_016v8yyJmNp67C8M5rMxHnKF

@T-K-233 T-K-233 changed the title Ship the assets in the lite_description package, so a consumer installs them Ship the assets together in the lite_description package Sep 29, 2026
@T-K-233
T-K-233 force-pushed the ship-assets-in-package branch from f18724f to 3914085 Compare September 29, 2026 23:34
…ls them

A consumer reached the assets through robot_assets.load(), which downloaded
the default branch of this repository into a data/ directory relative to the
working directory and never refreshed it. The uv.lock of the consumer pinned
only the loader code, so two machines on the same commit could train on
different robot models. The lite_biped feet are one example: they went from
two box soles to eleven contact spheres, and a machine with an older cache
kept the boxes.

The assets now sit inside the Python package, at lite_description/robots/,
so the wheel carries them and the lock of the consumer pins them. This is
the layout of mjlab and specialist_description. The package returns paths
rather than loaded models:

    from lite_description import get_mjcf_path, get_urdf_path
    mujoco.MjModel.from_xml_path(str(get_mjcf_path("lite_biped")))

The functions carry a get_ prefix, because mjcf_path and urdf_path are the
names that callers, and this repository, give to the paths they return.
ROBOTS_DIR names that robots/ directory, and VARIANTS comes from it, so no
second list can drift. The wheel leaves cad/ out, and the ament install
leaves it out as before.

The generator stays in the package as lite_description.workflow, because
this repository owns the conversion logic. The CAD toolchain stays behind
the cad extra, so the base install has no dependencies. The commands are
renamed to lite-description-*, and the generator now resolves a variant
through the package. An installed package carries no cad/, so the
generator stops with an error there instead of writing into site-packages.

lite_description.actuators.func becomes lite_description.actuators.modeling.
Its functions take the armature and the effort limit as floats instead of a
whole spec table, so each signature names what the function reads. The
results do not change for any table in the package.

The distribution is renamed from robot-assets to lite-description, to match
the import name and the ament package. The version goes to 0.5.0, because
load() is removed and the actuators API changes.

The ament install destination does not change, so $(find lite_description)
and package://lite_description/robots/... resolve as before. Only the
banner line of each generated file changed, to name the new command. A
regeneration of all six variants with --only urdf,mjcf,xacro changes no
other line.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016v8yyJmNp67C8M5rMxHnKF
@T-K-233
T-K-233 force-pushed the ship-assets-in-package branch from 3914085 to 5650787 Compare September 29, 2026 23:47
@T-K-233
T-K-233 merged commit 9a5f9c2 into main Sep 29, 2026
2 checks passed
@T-K-233
T-K-233 deleted the ship-assets-in-package branch September 29, 2026 23:51
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