Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
0febc98
Fix ruff linting errors in test_onnx_rollout.py
johnzhang-rai Aug 8, 2025
ba3a98f
add spot files
johnzhang-rai Aug 11, 2025
6c0988f
spot standing runs
johnzhang-rai Aug 11, 2025
ba595b5
add boucing ball model to fr3
johnzhang-rai Aug 11, 2025
930b60e
reorg
johnzhang-rai Aug 12, 2025
6c0e9c5
Add persistent thread pool implementation for ONNX interleaved rollouts
johnzhang-rai Aug 14, 2025
241649f
Complete ruff linting fixes for dev/ directory
johnzhang-rai Aug 14, 2025
f22d65d
add spor door and box task
johnzhang-rai Aug 15, 2025
eb02a82
add backend options
johnzhang-rai Aug 18, 2025
00683d1
onnx inference working with judo app
johnzhang-rai Aug 19, 2025
da6f6d5
s
johnzhang-rai Aug 23, 2025
e129a58
fixes for arm mac
johnzhang3 Aug 27, 2025
6b7fa7c
Merge commit 'e129a58b9a8bf4ba9dcd8083e3406a111843cc1a' into spot
johnzhang3 Aug 27, 2025
c812a1c
cpp on mac
johnzhang3 Aug 27, 2025
f370baf
add spot model tracking
johnzhang3 Aug 27, 2025
2c88222
more cpp changes for mac
johnzhang3 Aug 27, 2025
84a945e
reorganize
johnzhang3 Aug 27, 2025
6a1701d
debug the policy rollout
johnzhang3 Aug 27, 2025
82662b0
add cpp build in readme
johnzhang3 Aug 28, 2025
0ecf5aa
basic version working with spot on policy onnx
johnzhang3 Aug 28, 2025
67758f8
working dummy policy setup
johnzhang3 Aug 29, 2025
b940d0b
rm unused stuff
johnzhang3 Aug 29, 2025
efaa14b
clean up
johnzhang3 Aug 29, 2025
9b6bf81
add xinghao policy
johnzhang3 Sep 2, 2025
67c69cb
update gitignore
johnzhang3 Sep 2, 2025
11a2130
wip policy wrapper
johnzhang3 Sep 2, 2025
e684e1f
add onnx
johnzhang3 Sep 2, 2025
eb7cacf
policy wrapper
johnzhang3 Sep 2, 2025
cee9471
wip integrated wrapped policy with judo cpp
johnzhang3 Sep 2, 2025
92e2d07
wip onnx inference runs in judo app
johnzhang3 Sep 2, 2025
125665f
wip
johnzhang3 Sep 3, 2025
a31d1f5
Split task space control from sim control
jbruedigam-bdai Sep 4, 2025
631aa81
add support for arm mac
johnzhang3 Sep 4, 2025
62aeddc
wip cleaning up spot policy cpp
johnzhang3 Sep 5, 2025
9ec750e
Add cpp rollout and sim
jbruedigam-bdai Sep 5, 2025
67a5780
Merge branch 'upstream-pr-86' into main-merge-pr-86
johnzhang3 Sep 5, 2025
00b36b4
Merge upstream PR #88 into main-merge-pr-86; resolve pyproject.toml a…
johnzhang3 Sep 5, 2025
6e1a98e
update gitignore
johnzhang3 Sep 5, 2025
a5a5814
add back fixes for arm mac
johnzhang3 Sep 5, 2025
bdeb081
remove tight versions
johnzhang3 Sep 5, 2025
731bd29
update change log and readme
johnzhang3 Sep 5, 2025
99e7066
update lock file
johnzhang3 Sep 5, 2025
f903021
update change log
johnzhang3 Sep 5, 2025
d22a54c
Merge branch 'bdaiinstitute:main' into main
johnzhang3 Sep 8, 2025
650ca0f
Merge commit '62aeddcfc2b935d73acaa1480cc9116e8c9cdd47' into public-m…
johnzhang3 Sep 8, 2025
bf69b18
add onnx runtime
johnzhang3 Sep 8, 2025
d41966c
add torch and test inference wrapped policy in python
johnzhang3 Sep 8, 2025
0764252
spot task runs but doesn't work yet...
johnzhang3 Sep 8, 2025
1bc220b
wip revert to base policy inference
johnzhang3 Sep 8, 2025
a101926
wip debugging spot rollout
johnzhang3 Sep 9, 2025
295c045
add debug script for spot policy sim
johnzhang3 Sep 9, 2025
2721a32
fix ctrl to standing joint pos
johnzhang3 Sep 9, 2025
4ef25fa
add mediapy and ffmpeg. sim seems to work
johnzhang3 Sep 9, 2025
38d3d56
working spot rollout and sim with onnx
johnzhang3 Sep 10, 2025
d16a4ef
working spot box
johnzhang3 Sep 10, 2025
c55754d
Merge pull request #1 from johnzhang-rai/public-merge-spot
johnzhang-rai Sep 10, 2025
2792736
replace spot xml files
johnzhang3 Sep 10, 2025
4bda4f3
add yellow chair task. working
johnzhang3 Sep 11, 2025
5b30789
remove new cylinder push
johnzhang3 Sep 11, 2025
d4a4ea5
add yellow chair ramp files
johnzhang3 Sep 11, 2025
2ce6f79
reorg yellow chair task
johnzhang3 Sep 11, 2025
22e079d
chair uprighting
johnzhang3 Sep 11, 2025
8d8e0cc
add traces back
johnzhang3 Sep 11, 2025
57ac13e
Merge pull request #2 from johnzhang-rai/public-merge-spot
johnzhang-rai Sep 11, 2025
46f9afe
add benchmark scripts
johnzhang3 Sep 11, 2025
ffc38cd
add cmaes
johnzhang3 Sep 12, 2025
450e876
add chair ramp to benchmark
johnzhang3 Sep 12, 2025
0eb338b
remove chair axis
johnzhang3 Sep 12, 2025
6bf28cc
controller and optimzier overrides for the spot task
johnzhang3 Sep 12, 2025
eeb0fdf
add vis scripts
johnzhang3 Sep 13, 2025
a2b93f4
simplify the reset logic to better match hardware
johnzhang3 Sep 13, 2025
9348dac
changes for sim benchmak experiments
johnzhang3 Sep 13, 2025
8f63f67
add blue floor
johnzhang3 Sep 13, 2025
a702c43
add cmaes min_std override + fix ramp bounds in ramp task
alberthli Sep 15, 2025
462b76e
Merge pull request #3 from johnzhang-rai/benchmark
johnzhang-rai Sep 19, 2025
cdc5014
Merge pull request #4 from johnzhang-rai/albert-fixes
johnzhang-rai Sep 19, 2025
318e943
Merge commit 'cdc5014787f0fcc8a9d48a775381381fa8388ed8'
johnzhang3 Sep 19, 2025
ee0dcd5
clean up backend implementation
johnzhang3 Sep 23, 2025
695b885
bug fix for mujoco spot rollout output
johnzhang3 Sep 23, 2025
c06e4f1
refactor cpp code to control number of threads used in rollout
johnzhang3 Sep 24, 2025
aaf5610
delete unused files
johnzhang3 Sep 24, 2025
5709f74
Merge pull request #9 from johnzhang3/cpp-thread
johnzhang3 Sep 24, 2025
14625f9
add cutoff time during rollout
johnzhang3 Sep 25, 2025
745eb99
Merge branch 'bdaiinstitute:main' into main
johnzhang3 Oct 21, 2025
76db45a
remove used files
johnzhang-rai Oct 21, 2025
f5b7565
Add Spot robot support and related tasks
johnzhang-rai Oct 21, 2025
5510b29
Fix pre-commit linting issues
johnzhang-rai Oct 21, 2025
ec9167f
Clean up task registrations and default config
johnzhang-rai Oct 21, 2025
6e655a8
Fix pyright type errors
johnzhang-rai Oct 21, 2025
e138187
Fix C++ import errors for CI environments
johnzhang-rai Oct 21, 2025
2ea51d2
Use dummy implementations for C++ imports when module not available
johnzhang-rai Oct 21, 2025
73033e8
Add type stubs for C++ imports to fix pyright in CI
johnzhang-rai Oct 21, 2025
1a50263
update readme
johnzhang3 Oct 23, 2025
3e9ea03
address comments from brandon and jan
johnzhang3 Oct 23, 2025
c7b503e
update change log
johnzhang3 Oct 23, 2025
1afacd0
add yellow chair link
johnzhang-rai Oct 23, 2025
641fb59
Merge branch 'bdaiinstitute:main' into main
johnzhang3 Oct 31, 2025
d866cb4
trying prebuilt binary
johnzhang3 Nov 1, 2025
a924245
update change log
johnzhang3 Nov 1, 2025
ee91b84
Merge branch 'main' into spot_cpp
johnzhang3 Nov 1, 2025
02deb67
Fix: Add name attribute to Spot task classes
johnzhang3 Nov 1, 2025
376096b
Fix: Pass optimizer_config to Controller constructor
johnzhang3 Nov 1, 2025
debd75a
bug fixes with new code
johnzhang3 Nov 1, 2025
27b939d
Merge upstream/main into spot_cpp
johnzhang3 Nov 1, 2025
e925330
Regenerate pixi.lock after merge with upstream/main
johnzhang3 Nov 1, 2025
b06ad85
Add mujoco and onnxruntime to CI build dependencies
johnzhang3 Nov 1, 2025
7275d3e
Fix CI: Use CIBW_BEFORE_BUILD instead of invalid CIBW_BUILD_REQUIRES
johnzhang3 Nov 1, 2025
cbbb870
Fix Eigen download URL in CI (use GitLab instead of old GitHub mirror)
johnzhang3 Nov 1, 2025
c4a1d26
Remove wheel building infrastructure
johnzhang3 Nov 1, 2025
9cb467a
Fix pyright type errors in MujocoState instantiation
johnzhang3 Nov 1, 2025
3eade4f
Use pyright-specific ignore comment for type errors
johnzhang3 Nov 1, 2025
89cf6fd
Use typing.cast to fix pyright type errors
johnzhang3 Nov 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -188,5 +188,8 @@ outputs/
MUJOCO_LOG.TXT

# assets
*.obj
*.stl
# *.obj
# *.stl

.vscode/
*.h5
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
# Unreleased

## Added
* C++ rollout implementations for MuJoCo simulations (@johnzhang3, @jbruedigam-bdai, #95)
* Implemented high-performance C++ backend for MuJoCo rollouts with significant speedup
* Added custom C++ rollout functions for Spot robot tasks with ONNX policy inference
* Separated task-space control dimensions from simulation control dimensions for better flexibility
* Added `cutoff_time` parameter to `OptimizerConfig` (@johnzhang3, #95)
* Allows specifying maximum wall-clock time (in seconds) per rollout thread before termination
* Prevents single threads from blocking optimization when rollouts take too long
* Default value: 0.2 seconds
* New Spot robot tasks (@johnzhang3, #95)
* `spot_yellow_chair`: Manipulation task for pushing a yellow office chair
* `spot_yellow_chair_ramp`: Chair manipulation with ramp navigation
* `spot_box`: Box manipulation task for Spot
* CMAES (Covariance Matrix Adaptation Evolution Strategy) optimizer (@alberthli, #95)

## Fixed
* Fixed reward sign in `spot_yellow_chair_ramp` task where torso proximity was incorrectly penalizing closeness (@johnzhang-rai, #95)
* Updated `Task.success()` and `Task.failure()` methods to raise `NotImplementedError` instead of returning `False` for clearer API expectations (@johnzhang-rai, #95)

## Changed
* Renamed policy file from `xinghao_policy_v1.onnx` to `spot_relic_policy.onnx` for better clarity (@johnzhang-rai, #95)

## Documentation
* Added detailed documentation for `cutoff_time` parameter in optimizer configuration (@johnzhang-rai, #95)

## Dev
* Removed commented-out code and cleaned up task implementations (@johnzhang-rai, #95)
* Added C++ build instructions to README for development setup (@johnzhang-rai, #95)

# v0.0.5

## Added
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ We recommend installing `judo` using `pip` as follows:
pip install judo-rai # if you want dev dependencies, use judo-rai[dev]
```

Prebuilt wheels with C++ extensions are provided for Linux and macOS (both Intel and Apple Silicon) for Python 3.10+.

### Developers
#### Conda
For developers, run the following commands from this folder after cloning:
Expand All @@ -58,6 +60,9 @@ To create our environment (and activate it each time later), run the following i
# every time you want to activate
pixi shell -e dev

# build judo cpp bindings
pixi run build

# first time only
pre-commit install
pybind11-stubgen mujoco -o typings/
Expand All @@ -68,6 +73,12 @@ To start the simulator, you can simply run:
```bash
judo
```

To start with a specific config file
```bash
pixi run -e dev judo --config-name judo_default
```

This will start the stack and print a link in the terminal that will open the app in your browser, e.g.,
```
http://localhost:8080
Expand Down
3 changes: 3 additions & 0 deletions example_configs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copyright (c) 2025 Robotics and AI Institute LLC. All rights reserved.

# Example configurations for judo
4 changes: 3 additions & 1 deletion judo/app/dora/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@ def update_task(self, event: dict) -> None:
task_cls, _ = task_entry
with self.lock:
task = task_cls()
optimizer = self.controller.optimizer_cls(self.controller.optimizer_config_cls(), task.nu)
optimizer_config = self.controller.optimizer_config_cls()
optimizer = self.controller.optimizer_cls(optimizer_config, task.nu)
self.controller = Controller(
controller_config=self.controller.controller_cfg,
task=task,
optimizer=optimizer,
optimizer_config=optimizer_config,
)
self.write_controls()
else:
Expand Down
4 changes: 4 additions & 0 deletions judo/controller/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
set_default_fr3_pick_overrides,
set_default_leap_cube_down_overrides,
set_default_leap_cube_overrides,
set_default_spot_yellow_chair_overrides,
set_default_spot_yellow_chair_ramp_overrides,
)
from judo.utils.assets import download_and_extract_meshes

Expand All @@ -24,6 +26,8 @@
set_default_fr3_pick_overrides()
set_default_leap_cube_overrides()
set_default_leap_cube_down_overrides()
set_default_spot_yellow_chair_overrides()
set_default_spot_yellow_chair_ramp_overrides()

__all__ = [
"Controller",
Expand Down
52 changes: 37 additions & 15 deletions judo/controller/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from judo.gui import slider
from judo.optimizers import Optimizer, OptimizerConfig, get_registered_optimizers
from judo.tasks import Task, TaskConfig, get_registered_tasks
from judo.utils.mujoco import RolloutBackend, make_model_data_pairs
from judo.utils.mujoco import make_model_data_pairs
from judo.utils.normalization import (
IdentityNormalizer,
Normalizer,
Expand All @@ -37,6 +37,7 @@ class ControllerConfig(OverridableConfig):
max_opt_iters: int = 1
max_num_traces: int = 5
action_normalizer: Literal["none", "min_max", "running"] = "none"
rollout_backend: Literal["mujoco", "mujoco_spot", "mujoco_cpp"] | None = None


class Controller:
Expand All @@ -47,15 +48,18 @@ def __init__(
controller_config: ControllerConfig,
task: Task,
optimizer: Optimizer,
rollout_backend: Literal["mujoco"] = "mujoco",
optimizer_config: OptimizerConfig,
rollout_backend: Literal["mujoco", "mujoco_spot", "mujoco_cpp"] | None = None,
) -> None:
"""Initialize the controller.

Args:
controller_config: The controller configuration.
task: The task to use.
optimizer: The optimizer to use.
rollout_backend: The backend to use for rollouts. Currently only "mujoco" is supported.
controller_config: The configuration for the controller.
task: The Task object that specifies the environment.
task_config: The configuration for the task.
optimizer: The optimizer object that will be used for optimization.
optimizer_config: The configuration for the optimizer.
rollout_backend: The backend to use for rollouts. If None, uses task's default or "mujoco".
"""
self._controller_cfg = controller_config
self.task = task
Expand All @@ -67,7 +71,18 @@ def __init__(
self.model = self.task.model
self.model_data_pairs = make_model_data_pairs(self.model, self.optimizer_cfg.num_rollouts)

self.rollout_backend = RolloutBackend(num_threads=self.optimizer_cfg.num_rollouts, backend=rollout_backend)
# Determine backend: config override > task default > "mujoco"
backend: Literal["mujoco", "mujoco_spot", "mujoco_cpp"] = (
controller_config.rollout_backend or rollout_backend or getattr(task, "default_backend", "mujoco")
)

self.rollout_backend = task.RolloutBackend(
num_threads=self.optimizer_cfg.num_rollouts,
backend=backend,
task_to_sim_ctrl=task.task_to_sim_ctrl,
cutoff_time=self.optimizer_cfg.cutoff_time,
)

self.action_normalizer = self._init_action_normalizer()

# a container for any metadata from the system that we want to pass to the task
Expand All @@ -76,7 +91,7 @@ def __init__(
self.states = np.zeros((self.optimizer_cfg.num_rollouts, self.num_timesteps, self.model.nq + self.model.nv))
self.current_state = np.concatenate([self.task.data.qpos, self.task.data.qvel])
self.sensors = np.zeros((self.optimizer_cfg.num_rollouts, self.num_timesteps, self.model.nsensordata))
self.rollout_controls = np.zeros((self.optimizer_cfg.num_rollouts, self.num_timesteps, self.model.nu))
self.rollout_controls = np.zeros((self.optimizer_cfg.num_rollouts, self.num_timesteps, self.task.nu))
self.rewards = np.zeros((self.optimizer_cfg.num_rollouts,))
self.reset()

Expand Down Expand Up @@ -205,7 +220,12 @@ def update_action(self) -> None:
# resizing any variables due to changes in the GUI
if len(self.model_data_pairs) != self.optimizer_cfg.num_rollouts:
self.model_data_pairs = make_model_data_pairs(self.model, self.optimizer_cfg.num_rollouts)
self.rollout_backend.update(self.optimizer_cfg.num_rollouts)
self.rollout_backend.update(self.optimizer_cfg.num_rollouts, cutoff_time=self.optimizer_cfg.cutoff_time)

# Update rollout backend when cutoff_time changes
if self.rollout_backend.cutoff_time != self.optimizer_cfg.cutoff_time:
self.rollout_backend.cutoff_time = self.optimizer_cfg.cutoff_time
self.rollout_backend.update(self.optimizer_cfg.num_rollouts, cutoff_time=self.optimizer_cfg.cutoff_time)

normalizer_cls = normalizer_registry.get(self.action_normalizer_type)
if normalizer_cls is None:
Expand All @@ -232,8 +252,8 @@ def update_action(self) -> None:
candidate_knots_normalized = self.optimizer.sample_control_knots(nominal_knots_normalized)
candidate_knots_normalized = np.clip(
candidate_knots_normalized,
self.action_normalizer.normalize(self.task.actuator_ctrlrange[:, 0]),
self.action_normalizer.normalize(self.task.actuator_ctrlrange[:, 1]),
self.action_normalizer.normalize(self.task.ctrlrange[:, 0]),
self.action_normalizer.normalize(self.task.ctrlrange[:, 1]),
)
self.candidate_knots = self.action_normalizer.denormalize(candidate_knots_normalized)

Expand Down Expand Up @@ -346,11 +366,11 @@ def _init_action_normalizer(self) -> Normalizer:
"""Initialize the action normalizer."""
action_normalizer_kwargs = {}
if self.action_normalizer_type == "min_max":
action_normalizer_kwargs["min"] = self.task.actuator_ctrlrange[:, 0]
action_normalizer_kwargs["max"] = self.task.actuator_ctrlrange[:, 1]
action_normalizer_kwargs["min"] = self.task.ctrlrange[:, 0]
action_normalizer_kwargs["max"] = self.task.ctrlrange[:, 1]
elif self.action_normalizer_type == "running":
action_normalizer_kwargs["init_std"] = 1.0 # TODO(yunhai): make this configurable
return make_normalizer(self.action_normalizer_type, self.model.nu, **action_normalizer_kwargs)
return make_normalizer(self.action_normalizer_type, self.task.nu, **action_normalizer_kwargs)


def make_spline(times: np.ndarray, controls: np.ndarray, spline_order: str) -> interp1d:
Expand Down Expand Up @@ -401,7 +421,8 @@ def make_controller(
task = task_cls()

optimizer_cls, optimizer_config_cls = optimizer_entry
optimizer = optimizer_cls(optimizer_config_cls(), task.nu)
optimizer_config = optimizer_config_cls()
optimizer = optimizer_cls(optimizer_config, task.nu)

controller_cfg = ControllerConfig()
controller_cfg.set_override(init_task)
Expand All @@ -410,5 +431,6 @@ def make_controller(
controller_config=controller_cfg,
task=task,
optimizer=optimizer,
optimizer_config=optimizer_config,
rollout_backend=rollout_backend,
)
22 changes: 22 additions & 0 deletions judo/controller/overrides.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,25 @@ def set_default_fr3_pick_overrides() -> None:
"control_freq": 20.0,
},
)


def set_default_spot_yellow_chair_overrides() -> None:
"""Sets the default task-specific controller config overrides for the spot locomotion task."""
set_config_overrides(
"spot_yellow_chair",
ControllerConfig,
{
"horizon": 3.0,
},
)


def set_default_spot_yellow_chair_ramp_overrides() -> None:
"""Sets the default task-specific controller config overrides for the spot yellow chair ramp task."""
set_config_overrides(
"spot_yellow_chair_ramp",
ControllerConfig,
{
"horizon": 3.0,
},
)
Loading
Loading