Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 21 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
**/.git
**/.venv*
**/__pycache__
**/.pytest_cache
**/.ruff_cache
**/.DS_Store
**/*.local.*
examples/local/
**/runs/
**/base-control.json
**/arms-control.json
artifacts/
checkpoints/
work/
.third-party/
third_party/wirelesscomm/
**/.env
**/.env.*
**/*.pem
**/*.key
**/owner-access
119 changes: 119 additions & 0 deletions .github/workflows/recipe-software.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
name: Recipe software

# Exercise production installers/images only when their inputs change.
# Documentation-only PRs retain the existing CPU, lint and docs checks.
on:
push:
branches: [main]
paths:
- ".github/workflows/recipe-software.yml"
- ".dockerignore"
- "Dockerfile"
- "compose.yaml"
- "pyproject.toml"
- "uv.lock"
- "src/**"
- "examples/*.py"
- "examples/run.sh"
- "examples/xlerobot_snack_delivery/**"
- "!examples/xlerobot_snack_delivery/**/*.md"
- "examples/microduck_vln/**"
- "!examples/microduck_vln/**/*.md"
- "integrations/xlerobot_owner/**"
- "!integrations/xlerobot_owner/**/*.md"
- "integrations/microduck_vln/**"
- "!integrations/microduck_vln/**/*.md"
- "agents/**"
- "!agents/**/*.md"
- "scripts/check_recipe_software.py"
pull_request:
paths:
- ".github/workflows/recipe-software.yml"
- ".dockerignore"
- "Dockerfile"
- "compose.yaml"
- "pyproject.toml"
- "uv.lock"
- "src/**"
- "examples/*.py"
- "examples/run.sh"
- "examples/xlerobot_snack_delivery/**"
- "!examples/xlerobot_snack_delivery/**/*.md"
- "examples/microduck_vln/**"
- "!examples/microduck_vln/**/*.md"
- "integrations/xlerobot_owner/**"
- "!integrations/xlerobot_owner/**/*.md"
- "integrations/microduck_vln/**"
- "!integrations/microduck_vln/**/*.md"
- "agents/**"
- "!agents/**/*.md"
- "scripts/check_recipe_software.py"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: recipe-software-${{ github.ref }}
cancel-in-progress: true

jobs:
recipe-software:
name: Recipe software (${{ matrix.recipe }}, native + Docker)
runs-on: ubuntu-24.04
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- recipe: xlerobot
project: xlerobot_snack_delivery
target: xlerobot-software
- recipe: microduck
project: microduck_vln
target: microduck-software
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
version: "0.12.x"
enable-cache: false

- name: Install the native software Recipe from its frozen lock
env:
UV_CACHE_DIR: ${{ runner.temp }}/recipe-downloads
run: |
uv sync --frozen --python 3.12 --no-default-groups --group host
EMBODIRUN_SCENE_PYTHON="$RUNNER_TEMP/recipe environment/bin/python" \
.venv/bin/embodirun example "examples/${{ matrix.project }}/example.yaml" setup --mode software

- name: Check both native entrypoints and printed commands
run: |
"$RUNNER_TEMP/recipe environment/bin/python" scripts/check_recipe_software.py \
--recipe "${{ matrix.recipe }}" --report "$RUNNER_TEMP/recipe-native.json"

- name: Set up an isolated Docker builder
uses: docker/setup-buildx-action@v4

- name: Build the production software Docker target
run: docker buildx build --load --no-cache --target "${{ matrix.target }}" --tag recipe-software-ci .

- name: Check the offline container as the host UID and compare locked inventories
run: |
docker run --rm --network none --user "$(id -u):$(id -g)" \
--mount "type=bind,source=$PWD/scripts/check_recipe_software.py,target=/check.py,readonly" \
--mount "type=bind,source=$RUNNER_TEMP,target=/workspace" \
--entrypoint /opt/venv/bin/python recipe-software-ci /check.py \
--recipe "${{ matrix.recipe }}" --source-root /opt/embodirun \
--work-dir /workspace --report /workspace/recipe-docker.json
python3 - <<'PY'
import json, os, pathlib
root = pathlib.Path(os.environ["RUNNER_TEMP"])
native = json.loads((root / "recipe-native.json").read_text())
docker = json.loads((root / "recipe-docker.json").read_text())
assert native["packages"] == docker["packages"], "Native/container locked packages differ"
print(f"Native/container parity: {len(native['packages'])} packages")
PY
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,11 @@ site/
site-zh/
.tools/
.os-review/

# Generated local recipe workspaces and optional recipe environments
/examples/local/
**/runs/
**/base-control.json
**/arms-control.json
/.venv-xlerobot-snack/
/compose.local.yaml
55 changes: 55 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
FROM ghcr.io/astral-sh/uv:0.12.17-python3.12-trixie-slim AS host
RUN apt-get update && apt-get install -y --no-install-recommends git openssh-client ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /opt/embodirun
COPY pyproject.toml uv.lock README.md LICENSE NOTICE THIRD_PARTY_NOTICES.md ./
COPY src/ src/
COPY examples/ examples/
COPY agents/ agents/
COPY integrations/ integrations/
# Checkout file modes can be owner-only; the documented Compose flow runs as
# the host UID so generated recipe files stay editable outside the container.
RUN chmod -R a+rX /opt/embodirun
ENV UV_LINK_MODE=copy UV_PROJECT_ENVIRONMENT=/opt/venv \
PATH="/opt/venv/bin:$PATH" PYTHONPATH=/opt/embodirun \
EMBODIRUN_SOURCE_ROOT=/opt/embodirun EMBODIRUN_SCENE_PYTHON=/opt/venv/bin/python \
EMBODIRUN_EXAMPLE_PYTHON=/opt/venv/bin/python \
PYTHONUNBUFFERED=1
RUN --mount=type=cache,target=/root/.cache/uv,sharing=locked \
python examples/setup_environment.py host --environment /opt/venv
ARG EMBODIRUN_REVISION=unknown
ENV EMBODIRUN_REVISION=$EMBODIRUN_REVISION
ENTRYPOINT ["embodirun", "example"]
CMD ["--help"]

# Rehearsal uses the same small recipe lock as native setup --mode software.
FROM host AS xlerobot-software
RUN --mount=type=cache,target=/root/.cache/uv,sharing=locked \
python examples/setup_environment.py snack --mode software --environment /opt/venv

# Local Linux robot host. Device access and verified calibration are supplied at run time.
FROM xlerobot-software AS xlerobot
RUN apt-get update && apt-get install -y --no-install-recommends libglib2.0-0 libgl1 ffmpeg build-essential \
&& rm -rf /var/lib/apt/lists/*
RUN --mount=type=cache,target=/root/.cache/uv,sharing=locked \
python examples/setup_environment.py snack --environment /opt/venv
# Compose can run as an arbitrary host UID without a passwd entry. Torch asks
# getpass for a username and uses the home directory for runtime caches.
ENV LOGNAME=embodirun USER=embodirun HOME=/tmp

# Offline configuration checks use the same small Recipe lock as native setup.
FROM host AS microduck-software
RUN --mount=type=cache,target=/root/.cache/uv,sharing=locked \
python examples/setup_environment.py microduck --mode software --environment /opt/venv

# Add simulation and inference from the same lock, separate from the robot-owner profile.
FROM microduck-software AS microduck
RUN apt-get update && apt-get install -y --no-install-recommends libegl1 libgl1 libglfw3 libopengl0 ffmpeg build-essential \
&& rm -rf /var/lib/apt/lists/*
COPY third_party/embodiinfer/ third_party/embodiinfer/
RUN chmod -R a+rX third_party/embodiinfer
RUN --mount=type=cache,target=/root/.cache/uv,sharing=locked \
test -f third_party/embodiinfer/embodiinfer/__init__.py \
&& python examples/setup_environment.py microduck --mode simulation --environment /opt/venv
ENV LOGNAME=embodirun USER=embodirun HOME=/tmp
ENV MUJOCO_GL=egl PYOPENGL_PLATFORM=egl NVIDIA_DRIVER_CAPABILITIES=compute,utility,graphics
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ planning loop.
Click a preview to watch the video and explore the setup.

[Reproduce the demos](docs/en/examples.md) with versioned YAML configurations and
the shared `examples/run.sh` launcher.
the shared `embodirun example` CLI (`examples/run.sh` remains available).

## Why EmbodiRun?

Expand Down
2 changes: 1 addition & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

点击预览图观看视频,了解运行配置。

[复现演示](docs/zh/examples.md):使用统一 YAML 配置与 `examples/run.sh` 启动入口。
[复现演示](docs/zh/examples.md):使用统一 YAML 配置与 `embodirun example` 命令行入口(`examples/run.sh` 仍可使用)。

## 为什么选择 EmbodiRun?

Expand Down
82 changes: 82 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
services:
host:
build:
context: .
target: host
image: embodirun-examples:host
init: true
stdin_open: true
tty: true
volumes:
- ./examples/local:/workspace
- launcher-tmp:/tmp
command: [--help]
xlerobot-software:
build:
context: .
target: xlerobot-software
image: embodirun-examples:xlerobot-software
init: true
stdin_open: true
tty: true
volumes:
- ./examples/local:/workspace
- launcher-tmp:/tmp
command: [--help]
xlerobot:
profiles: [hardware]
build:
context: .
target: xlerobot
image: embodirun-examples:xlerobot
init: true
stdin_open: true
tty: true
network_mode: host
stop_grace_period: 70s
volumes:
- ./examples/local:/workspace
- launcher-tmp:/tmp
# Add explicit devices and read-only SDK/calibration mounts in compose.local.yaml.
# No privileged mode or automatic hardware startup.
command: [--help]
microduck-software:
build:
context: .
target: microduck-software
image: embodirun-examples:microduck-software
init: true
stdin_open: true
tty: true
volumes:
- ./examples/local:/workspace
- launcher-tmp:/tmp
command: [--help]
microduck:
profiles: [gpu]
build:
context: .
target: microduck
image: embodirun-examples:microduck
runtime: nvidia
init: true
stdin_open: true
tty: true
stop_grace_period: 70s
volumes:
- ./examples/local:/workspace
- launcher-tmp:/tmp
- ${MICRODUCK_ASSETS:-./examples/local/microduck/assets}:/assets:ro
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
command: [--help]

volumes:
# Keep private launcher sockets reachable from another same-UID Compose run.
# Default copy-up retains the image's /tmp permissions; this volume is project-scoped.
launcher-tmp:
48 changes: 29 additions & 19 deletions docs/en/examples.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Reproduce the demos

The four demos use one entrypoint, `examples/run.sh`, and versioned YAML
The four demos use one entrypoint, `embodirun example`, and versioned YAML
manifests. Deployment files describe devices and services; the example manifest
selects the task, execution limits, and output directory.

Expand All @@ -17,17 +17,24 @@ From the repository root:

```bash
uv sync --frozen
bash examples/run.sh examples/multi_robot_serving/example.yaml validate
bash examples/run.sh examples/multi_robot_serving/example.yaml plan
uv run --frozen embodirun example init so101
CONFIG=examples/local/so101/example.local.yaml
uv run --frozen embodirun example "$CONFIG" validate
uv run --frozen embodirun example "$CONFIG" plan
```

`validate` checks fields and deployment references locally; `plan` prints the
commands that a run would execute.

Copy the selected YAML and its referenced deployment to `*.local.yaml` in the
same directory. Update the reference in `parameters.deployment`, then fill in
device paths, SSH hosts, calibration, checkpoint paths, and task settings.
Local YAML/JSON files are ignored by Git.
`init` creates a new ignored directory containing a manifest and its linked
deployment files. It does not overwrite existing configuration. Choose
`xlerobot`, `microduck`, `embodiinfer-http`, `embodiinfer-wireless`, or
`sglang-http` instead of `so101` for those recipes. Fill in device paths, SSH
hosts, calibration, checkpoint paths, and task settings before deployment.
For SO-101 and XLeRobot, `embodirun example "$CONFIG" check` lists local
missing prerequisites without opening devices. It does not establish live
hardware or model readiness. MicroDuck's `check` additionally runs a GPU/EGL
scene preflight on the target Linux host.

Manifest paths resolve relative to the YAML file. Deployment device and model
paths belong to the node where they are used. The complete field and command
Expand All @@ -38,33 +45,36 @@ reference is in [examples/README.md](https://github.com/BUAA-CI-LAB/EmbodiRun/bl
After following the selected example's calibration and environment instructions:

```bash
CONFIG=examples/multi_robot_serving/example.local.yaml
bash examples/run.sh "$CONFIG" setup
bash examples/run.sh "$CONFIG" up --allow-hardware
bash examples/run.sh "$CONFIG" run --allow-hardware
bash examples/run.sh "$CONFIG" down
CONFIG=examples/local/so101/example.local.yaml
uv run --frozen embodirun example "$CONFIG" setup
uv run --frozen embodirun example "$CONFIG" check
uv run --frozen embodirun example "$CONFIG" up --allow-hardware
uv run --frozen embodirun example "$CONFIG" run --allow-hardware
uv run --frozen embodirun example "$CONFIG" down
```

SO-101 services remain running between tasks. Reset the scene manually and use
`down` when finished. XLeRobot keeps `up` in the foreground; run the task in
a second terminal, then Ctrl-C in the service terminal to stop its stack.
a second terminal, then use `down` or Ctrl-C to stop its stack.
Keep an operator present and verify the emergency stop before enabling motion.

For a hardware-free task rehearsal:

```bash
bash examples/run.sh examples/xlerobot_snack_delivery/example.yaml dry-run
uv run --frozen embodirun example examples/local/xlerobot/example.local.yaml dry-run
```

## Run the simulator

Follow [MicroDuck setup](microduck-vln.md) to install its optional environment
and prepare the scene and checkpoint. Fill in `example.local.yaml`, then run:
Follow [MicroDuck setup](microduck-vln.md) to prepare the external scene and
checkpoint. On the Linux GPU host, run:

```bash
CONFIG=examples/microduck_vln/example.local.yaml
bash examples/run.sh "$CONFIG" check
bash examples/run.sh "$CONFIG" run
uv run --frozen embodirun example init microduck --assets /absolute/asset/root
CONFIG=examples/local/microduck/example.local.yaml
uv run --frozen embodirun example "$CONFIG" setup
uv run --frozen embodirun example "$CONFIG" check
uv run --frozen embodirun example "$CONFIG" run
```

`check` verifies assets and the GPU/rendering environment. The YAML selects
Expand Down
Loading