Skip to main content

cuRobo Metal

An Apple Silicon drop-in Python implementation of the portable API in pinned cuRoboV2.

A Franka arm following a joint-space plan generated on Apple Metal

The project currently provides:

  • a dependency-free adapter for pinned cuRoboV2 robot configuration data;
  • independent NumPy correctness oracles and canonical replay fixtures;
  • differentiable PyTorch CPU/MPS forward kinematics, collision, costs, IK, and trajectory optimization;
  • runtime-compiled Metal kernels for fused serial-chain kinematics and primitive collision queries;
  • deterministic geometric planning, mesh, voxel/SDF, ESDF, and whole-body implementations behind explicit contracts;
  • reproducible correctness, profiling, and benchmark artifacts.

The target distribution is installed as curobo-metal and exposes the original curobo Python namespace, so portable applications change only their dependency. Against the pinned revision, the strict public-facade gate is exact for 24 modules, 122 exports, and 10 comparable callable signatures. The broader generated inventory resolves 571 of 586 audited modules; the 15 partial modules are two perception internals and 13 bundled example workflows. CUDA/Warp ABI mechanisms and external integrations remain explicit substitutions or exclusions. The ecosystem corpus resolves all 171 compatibility targets mined from documentation, examples, tests, and downstream projects. See the project plan, drop-in roadmap, and compatibility boundary.

Namespace warning: NVIDIA cuRobo and curobo-metal both install the curobo Python package. They must not be co-installed. Use a dedicated virtual environment and uninstall nvidia-curobo (or any source-installed cuRobo) before installing this distribution. The release smoke test fails if another distribution also claims the namespace.

Pinned upstream

Thirty portable V2 applications now have an installed-wheel execution gate with automatic MPS selection, unchanged source hashes, and a CUDA replay bundle. See application compatibility for covered behavior, commands, paired CUDA evidence, and the bounded coverage of this gate.

Compatibility is developed against cuRoboV2 commit:

8e734f3ced1df898990bcd92de40abce475907db

The repository includes tooling that fetches this exact revision and recomputes the Git object ID:

tmpdir="$(mktemp -d /tmp/curobo-metal-upstream.XXXXXX)"
uv run python tools/upstream/manage.py fetch --destination "$tmpdir/curobo"
uv run python tools/upstream/manage.py verify --source "$tmpdir/curobo"
uv run python tools/upstream/manage.py audit --source "$tmpdir/curobo"

Requirements

  • Python 3.10–3.13
  • PyTorch 2.13 or newer
  • NumPy 1.24 or newer
  • For GPU execution: Apple Silicon with an MPS-enabled PyTorch build

Metal shaders are compiled through torch.mps.compile_shader. A full Xcode installation is not required for the current runtime-compiled kernels.

Install and test

Version 1.0.1 is the current release of the pinned portable Python contract and includes the IK reliability and performance fix described below. Exact behavior, known limitations, and exclusions are listed in the changelog and parity matrix.

Use a clean virtual environment because this package and NVIDIA cuRobo own the same curobo namespace:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install curobo-metal
python -c "import curobo; print(curobo.__file__)"

Minimal public-API example

import torch

from curobo.kinematics import Kinematics, KinematicsCfg
from curobo.types import DeviceCfg, JointState

device = torch.device("mps" if torch.backends.mps.is_available() else "cpu")
robot = Kinematics(
    KinematicsCfg.from_robot_yaml_file("franka.yml", device_cfg=DeviceCfg(device))
)
q = torch.zeros((1, robot.dof), device=device)
state = robot.compute_kinematics(
    JointState.from_position(q, joint_names=robot.joint_names)
)
print(state.tool_poses.position)

The same example is available as examples/minimal_fk.py.

Graph planning

Deterministic PRM/roadmap graph planning is supported on CPU and Apple MPS. The production API provides batched start/goal queries, A*, Dijkstra, and greedy search, uniform or Sobol sampling, reusable roadmap caches, device-batched validity checks, path shortcutting, and fixed-knot trajectory-seed handoff.

PYTORCH_ENABLE_MPS_FALLBACK=0 uv run python examples/graph_planning.py --device mps

See examples/graph_planning.py for a complete obstacle-avoiding solve using GraphPlanningProblem and PersistentRoadmap. This is geometric planning support; it is distinct from CUDA Graph execution capture. PyTorch does not expose CUDA Graph-equivalent capture for MPS, so CUDA-graph-specific APIs retain eager, shape-stable compatibility behavior.

Visual motion-planning demo

The animation above is generated from a real public-API MotionPlanner joint-space solve and FK pass. It renders the licensed low-poly Franka meshes bundled with the robot description, not a schematic arm or canned trajectory:

uv run --extra demo python examples/visual_robot_planning_demo.py --device mps

The demo writes docs/assets/franka-motion-plan.gif. It uses Pillow only for rendering; planning itself has no demo-specific dependency.

Develop and test

Install the locked development environment with uv:

uv sync --extra test
PYTORCH_ENABLE_MPS_FALLBACK=0 uv run pytest -q

Setting PYTORCH_ENABLE_MPS_FALLBACK=0 is part of the validation contract. It prevents unsupported GPU operations from silently executing on the CPU.

Run focused benchmarks:

PYTORCH_ENABLE_MPS_FALLBACK=0 uv run python benchmarks/kinematics/fused_fk.py
PYTORCH_ENABLE_MPS_FALLBACK=0 uv run python benchmarks/collision/fused_collision.py
PYTORCH_ENABLE_MPS_FALLBACK=0 uv run python benchmarks/ik/benchmark_ik.py
PYTORCH_ENABLE_MPS_FALLBACK=0 uv run python benchmarks/trajectory/benchmark_trajectory.py

The benchmark scripts synchronize the MPS device and report compilation/first use separately from steady-state latency. The stable release regression limits and current M4 results are recorded in the performance gate.

Replay the pinned upstream forward-kinematics tutorial workload on Apple MPS:

PYTORCH_ENABLE_MPS_FALLBACK=0 uv run python \
  examples/upstream_forward_kinematics_mps.py \
  /path/to/pinned/curobo/content/configs/robot/franka.yml \
  --device mps --batch-size 1000

This loads upstream franka.yml directly and checks Metal transforms and autograd against the independent float64 oracle. See the upstream example replay for the recorded result and the exact boundary around the CUDA-hardcoded original.

Architecture

cuRoboV2 configuration
          |
  dependency-free adapter
          |
  backend-neutral contracts
      /              \
NumPy oracles     PyTorch operators
                       |
                CPU or Apple MPS
                       |
             fused Metal hot paths

The NumPy implementations are executable specifications, not performance backends. Production operators are first implemented with portable PyTorch. Profiling evidence determines which launch-heavy paths receive fused Metal kernels.

Performance: Apple M4 versus RTX 3090

Apple Silicon is not a fundamental barrier to useful robot planning, but the current Metal backend is not as fast as mature CUDA cuRobo for warm iterative IK. The largest remaining gap is software as well as hardware: NVIDIA cuRobo uses fused Warp/CUDA kernels and CUDA graph capture, while the portable IK path still launches eager PyTorch/MPS operations and synchronizes inside an iterative solve.

The following synchronized medians use matching public API calls and the same pinned cuRoboV2 revision. They were measured on an Apple M4 Mac mini (10 CPU cores, 16 GB unified memory) and an RTX 3090 (24 GB). Different PyTorch builds and host systems mean this is a practical user comparison, not a GPU-isolation study.

Public workload Apple M4 / Metal RTX 3090 / CUDA M4 warm gap
FK, batch 1,024 (1.0.0) 9.47 ms 0.372 ms 25.5× slower
FK, batch 1,024 (1.0.1) 3.79 ms 0.372 ms 10.2× slower
Moved-target IK (1.0.0, successful solves) 315 ms 5.87 ms about 54× slower
Moved-target IK (1.0.1) 17.9 ms 5.87 ms 3.05× slower
Joint-space motion plan (1.0.0) 110 ms 89.9 ms 1.22× slower

The moved-target rows are a focused, already-seeded 32-seed Franka workload. They should not be read as the latency of every IK problem. The broader local release-gate reachable case measured 1.80 s for 1.0.1 (under its 2.5 s ceiling); it uses different initialization and is therefore not compared with the RTX 3090 number above.

Cold-start behavior differs: the M4 completed the first FK call in about 53 ms versus 212 ms on the RTX 3090, and the first motion plan in about 634 ms versus 1.85 s. Warm CUDA throughput is the stronger result; Metal can be attractive for local development with low startup overhead.

The lower-level fused kernels are substantially faster than the complete public objects around them. On the same M4, fused/low-level measurements included:

  • FK at batch 1,024: about 2.43 ms (about 422,000 configurations/second);
  • sphere-pair collision at batch 512: about 1.14 ms;
  • sphere-to-cuboid collision at batch 512: about 0.80 ms.

PyPI 1.0.0 also exposed a moved-target IK reliability issue: 10 of 20 repeated solves succeeded in one clean-environment run. Version 1.0.1 short-circuits refinement when the Levenberg–Marquardt seeds already satisfy the tolerances, checks eager-MPS convergence after each LM step, and routes the serial robot prefix through fused Metal FK. The same check produced 20/20 successes at about 17.9 ms median. The maximum position error observed in that run was 2.93 mm, inside the configured 5 mm tolerance. That fix is not part of the immutable 1.0.0 wheel; it ships in 1.0.1.

The next performance work should focus on fused IK residual/normal-equation kernels, eliminating the remaining host synchronization from optimizer loops, and fusing quaternion conversion and robot-sphere transforms around FK. An RTX 3090 should still be expected to lead warm throughput because it has far more compute and memory bandwidth and a much more mature robotics kernel stack; the remaining 3.05–10.2× IK/FK gaps are not all fundamental Apple Silicon limits.

These are machine-specific development measurements, not universal performance claims. Solver settings, seed count, robot, scene, precision, and convergence tolerances materially affect the result. Raw distributions, regression protocols, and limitations are checked into artifacts/profiling/ and docs/performance.md.

Intended use and boundaries

curobo-metal is intended for cuRobo-compatible prototyping, research, education, CI, and local robot-planning development on Apple Silicon. It is not a CUDA/Warp ABI emulator, a hard-real-time controller, or a promise that every NVIDIA example and external integration will run unchanged. Validate trajectories on the target robot and control stack before deployment.

For a useful bug report, include the package version, macOS and chip, Python and PyTorch versions, device (mps or cpu), robot/scene configuration, solver settings, and a minimal reproducible script. Include synchronized warm timings and first-call timing separately for performance reports.

Numerical and autodiff boundaries

  • Production Metal kernels currently target MPS float32.
  • Fused FK currently supports serial chains up to 64 DoF.
  • Custom Metal gradients provide tested first-order autodiff. Higher-order AD, vmap, export, and torch.compile compatibility are not claimed.
  • Static cuboid worlds use the fused Metal path. Queries requiring gradients with respect to cuboid world parameters use the composed PyTorch path.
  • Tiny batches may remain faster on CPU; benchmarked crossover points are documented rather than hidden.

Development method

Every feature progresses through:

  1. an explicit tensor/numerical contract;
  2. an independent CPU oracle and canonical fixtures;
  3. portable production CPU/MPS operations;
  4. differential, gradient, and fallback-disabled tests;
  5. synchronized profiling;
  6. a fused Metal implementation only when evidence supports it.

See the project plan for the complete gated roadmap. Report bugs through the GitHub issue tracker; the project does not provide a guaranteed support response time.

Metadata

Release files for curobo-metal 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for curobo-metal 1.0.1
File Size Uploaded
curobo_metal-1.0.1.tar.gz 5.2 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for curobo-metal 1.0.1
File Interpreter ABI Platform
curobo_metal-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 10.6 MB

Release files / curobo_metal-1.0.1.tar.gz

Download URL curobo_metal-1.0.1.tar.gz
Size 5.2 MB
Tags Source
SHA-256 checksum
How to use checksums
6a9dc4730e4838ee02ebbbce85a731cce83aaa70de025cea011eec860df71ac6
BLAKE2b-256 checksum
How to use checksums
3545bbb016e8b5196040e89f9d977aef54c2f173096eac9af832030adac71bfd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.16 {"installer":{"name":"uv","version":"0.12.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / curobo_metal-1.0.1-py3-none-any.whl

Download URL curobo_metal-1.0.1-py3-none-any.whl
Size 5.4 MB
Tags Python 3
SHA-256 checksum
How to use checksums
cccffc754f05ba4ef07fce80ca9683b67e54bceb6efaecd0cc8a285a21a7e05e
BLAKE2b-256 checksum
How to use checksums
fcf24d99387b29776f3595fe33e6dd4780f9782a714862432623b616b574c433
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.16 {"installer":{"name":"uv","version":"0.12.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page