Skip to content
Open
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
40 changes: 40 additions & 0 deletions docker/Dockerfile.gr00t_server
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
FROM nvcr.io/nvidia/pytorch:24.07-py3

ARG WORKDIR="/workspace"
ARG GROOT_DEPS_GROUP="base"
ENV WORKDIR=${WORKDIR}
ENV GROOT_DEPS_GROUP=${GROOT_DEPS_GROUP}
WORKDIR "${WORKDIR}"

RUN apt-get update && apt-get install -y \
git \
git-lfs \
cmake \
&& rm -rf /var/lib/apt/lists/*

RUN pip install --upgrade pip

COPY ./submodules/Isaac-GR00T ${WORKDIR}/submodules/Isaac-GR00T

COPY docker/setup/install_gr00t_deps.sh /tmp/install_gr00t_deps.sh
RUN chmod +x /tmp/install_gr00t_deps.sh && \
/tmp/install_gr00t_deps.sh --server && \
rm -f /tmp/install_gr00t_deps.sh

RUN pip install -e ${WORKDIR}/submodules/Isaac-GR00T

RUN pip uninstall -y \
opencv-python opencv-python-headless \
opencv-contrib-python opencv-contrib-python-headless \
|| true && \
pip install --no-cache-dir "opencv-python-headless==4.8.0.74"

COPY isaaclab_arena/remote_policy ${WORKDIR}/isaaclab_arena/remote_policy
COPY isaaclab_arena_gr00t ${WORKDIR}/isaaclab_arena_gr00t
COPY isaaclab_arena_g1 ${WORKDIR}/isaaclab_arena_g1

RUN pip install --no-cache-dir pyzmq msgpack

ENV PYTHONPATH=${WORKDIR}

ENTRYPOINT ["python", "-u", "-m", "isaaclab_arena.remote_policy.remote_policy_server_runner"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool!

203 changes: 203 additions & 0 deletions docker/run_gr00t_server.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
#!/usr/bin/env bash
set -euo pipefail

# -------------------------
# User-configurable defaults
# -------------------------

# Default mount directories on the host machine
DATASETS_DIR="${DATASETS_DIR:-$HOME/datasets}"
MODELS_DIR="${MODELS_DIR:-$HOME/models}"
EVAL_DIR="${EVAL_DIR:-$HOME/eval}"

# Docker image name and tag for the GR00T policy server
DOCKER_IMAGE_NAME="${DOCKER_IMAGE_NAME:-gr00t_policy_server}"
DOCKER_VERSION_TAG="${DOCKER_VERSION_TAG:-latest}"

# Rebuild controls
FORCE_REBUILD="${FORCE_REBUILD:-false}"
NO_CACHE=""

# Server parameters (can also be overridden via environment variables)
HOST="${HOST:-0.0.0.0}"
PORT="${PORT:-5555}"
API_TOKEN="${API_TOKEN:-}"
TIMEOUT_MS="${TIMEOUT_MS:-5000}"
POLICY_TYPE="${POLICY_TYPE:-gr00t_closedloop}"
POLICY_CONFIG_YAML_PATH="${POLICY_CONFIG_YAML_PATH:-/workspace/isaaclab_arena_gr00t/gr1_manip_gr00t_closedloop_config.yaml}"

# -------------------------
# Help message
# -------------------------
usage() {
script_name=$(basename "$0")
cat <<EOF
Helper script to build and run the GR00T policy server Docker environment.

Usage:
$script_name [options] [-- server-args...]

Options (Docker / paths; env vars with the same name take precedence):
-v Verbose output (set -x).
-d <datasets directory> Path to datasets on the host. Default: "$DATASETS_DIR".
-m <models directory> Path to models on the host. Default: "$MODELS_DIR".
-e <eval directory> Path to evaluation data on the host. Default: "$EVAL_DIR".
-n <docker name> Docker image name. Default: "$DOCKER_IMAGE_NAME".
-r Force rebuilding of the Docker image.
-R Force rebuilding of the Docker image, without cache.

Server-specific options (passed through to the policy server entrypoint):
--host HOST
--port PORT
--api_token TOKEN
--timeout_ms MS
--policy_type TYPE
--policy_config_yaml_path PATH

Examples:
# Minimal: use defaults, just build & run server
bash $script_name

# Custom models directory and port
bash $script_name -m /data/models --port 6000 --api_token MY_TOKEN

# Custom image name, force rebuild, and datasets/eval mounts
bash $script_name -n gr00t_server -r \\
-d /data/datasets -m /data/models -e /data/eval \\
--policy_type isaaclab_arena_gr00t.policy.gr00t_remote_policy.Gr00tRemoteServerSidePolicy \\
--policy_config_yaml_path isaaclab_arena_gr00t/policy/config/gr1_manip_gr00t_closedloop_config.yaml
EOF
}

# -------------------------
# Parse docker/path options (short flags, like run_docker.sh)
# -------------------------
DOCKER_ARGS_DONE=false
SERVER_ARGS=()

while [[ $# -gt 0 ]]; do
if [ "$DOCKER_ARGS_DONE" = false ]; then
case "$1" in
-v)
set -x
shift 1
;;
-d)
DATASETS_DIR="$2"
shift 2
;;
-m)
MODELS_DIR="$2"
shift 2
;;
-e)
EVAL_DIR="$2"
shift 2
;;
-n)
DOCKER_IMAGE_NAME="$2"
shift 2
;;
-r)
FORCE_REBUILD="true"
shift 1
;;
-R)
FORCE_REBUILD="true"
NO_CACHE="--no-cache"
shift 1
;;
-h|--help)
usage
exit 0
;;
--host|--port|--api_token|--timeout_ms|--policy_type|--policy_config_yaml_path)
# From here on, treat everything as server args and stop parsing docker flags
DOCKER_ARGS_DONE=true
SERVER_ARGS+=("$1")
shift 1
;;
--*)
# Unknown long option at docker level -> treat as server arg
DOCKER_ARGS_DONE=true
SERVER_ARGS+=("$1")
shift 1
;;
*)
# Anything else -> treat as server arg
DOCKER_ARGS_DONE=true
SERVER_ARGS+=("$1")
shift 1
;;
esac
else
SERVER_ARGS+=("$1")
shift 1
fi
done

# If no server args were passed, use defaults
if [ ${#SERVER_ARGS[@]} -eq 0 ]; then
SERVER_ARGS=(
--host "${HOST}"
--port "${PORT}"
--api_token "${API_TOKEN}"
--timeout_ms "${TIMEOUT_MS}"
--policy_type "${POLICY_TYPE}"
--policy_config_yaml_path "${POLICY_CONFIG_YAML_PATH}"
)
fi

echo "Host paths:"
echo " DATASETS_DIR = ${DATASETS_DIR}"
echo " MODELS_DIR = ${MODELS_DIR}"
echo " EVAL_DIR = ${EVAL_DIR}"
echo "Docker image:"
echo " ${DOCKER_IMAGE_NAME}:${DOCKER_VERSION_TAG}"
echo "Rebuild:"
echo " FORCE_REBUILD = ${FORCE_REBUILD}, NO_CACHE = '${NO_CACHE}'"
echo "Server args:"
printf ' %q ' "${SERVER_ARGS[@]}"; echo

# -------------------------
# 1) Build the Docker image
# -------------------------

IMAGE_TAG_FULL="${DOCKER_IMAGE_NAME}:${DOCKER_VERSION_TAG}"

if docker images -q "${IMAGE_TAG_FULL}" > /dev/null 2>&1 && [ "${FORCE_REBUILD}" != "true" ]; then
echo "Docker image ${IMAGE_TAG_FULL} already exists. Skipping rebuild."
echo "Use -r or -R to force rebuilding the image."
else
echo "Building Docker image ${IMAGE_TAG_FULL}..."
docker build --pull \
${NO_CACHE} \
-f docker/Dockerfile.gr00t_server \
-t "${IMAGE_TAG_FULL}" \
.
fi

# -------------------------
# 2) Run the container
# -------------------------

DOCKER_RUN_ARGS=(
--rm
--gpus all
--net host
--name gr00t_policy_server_container
-v "${MODELS_DIR}":/models
)

# Only mount datasets / eval if the directories exist on host
if [ -d "${DATASETS_DIR}" ]; then
DOCKER_RUN_ARGS+=(-v "${DATASETS_DIR}":/datasets)
fi

if [ -d "${EVAL_DIR}" ]; then
DOCKER_RUN_ARGS+=(-v "${EVAL_DIR}":/eval)
fi

docker run "${DOCKER_RUN_ARGS[@]}" \
"${IMAGE_TAG_FULL}" \
"${SERVER_ARGS[@]}"
85 changes: 62 additions & 23 deletions docker/setup/install_gr00t_deps.sh
Original file line number Diff line number Diff line change
@@ -1,41 +1,80 @@
#!/bin/bash
set -euo pipefail

# Script to install GR00T policy dependencies
# This script is called from the Dockerfile when INSTALL_GROOT is true
PYTHON_CMD=/isaac-sim/python.sh
USE_SERVER_ENV=0
if [[ "${1:-}" == "--server" ]]; then
USE_SERVER_ENV=1
PYTHON_CMD=python
shift
fi

: "${GROOT_DEPS_GROUP:=base}"
: "${WORKDIR:=/workspace}"

if [ "$(id -u)" -eq 0 ]; then
SUDO=""
else
SUDO="sudo"
fi

echo "Installing GR00T with dependency group: $GROOT_DEPS_GROUP"

# Set CUDA environment variables for GR00T installation
export CUDA_HOME=/usr/local/cuda-12.8
export PATH=/usr/local/cuda-12.8/bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/cuda-12.8/lib64:${LD_LIBRARY_PATH:-}
export TORCH_CUDA_ARCH_LIST=8.0+PTX
if [[ "$USE_SERVER_ENV" -eq 1 ]]; then
# Script to install GR00T policy dependencies
# This script is called from the GR00T server Dockerfile

# CUDA environment variables for GR00T installation.
# In the PyTorch base image, CUDA is already configured, so we only
# set variables if CUDA_HOME exists.
if [ -d "/usr/local/cuda" ]; then
export CUDA_HOME=${CUDA_HOME:-/usr/local/cuda}
export PATH=${CUDA_HOME}/bin:${PATH}
export LD_LIBRARY_PATH=${CUDA_HOME}/lib64:${LD_LIBRARY_PATH:-}
fi

echo "CUDA environment variables:"
echo "CUDA_HOME=${CUDA_HOME:-unset}"
echo "PATH=$PATH"
echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-unset}"
else
# Script to install GR00T policy dependencies
# This script is called from the Dockerfile when INSTALL_GROOT is true

# Set CUDA environment variables for GR00T installation
export CUDA_HOME=/usr/local/cuda-12.8
export PATH=/usr/local/cuda-12.8/bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/cuda-12.8/lib64:${LD_LIBRARY_PATH:-}
export TORCH_CUDA_ARCH_LIST=8.0+PTX

echo "CUDA environment variables set:"
echo "CUDA_HOME=$CUDA_HOME"
echo "PATH=$PATH"
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH"
echo "TORCH_CUDA_ARCH_LIST=$TORCH_CUDA_ARCH_LIST"
echo "CUDA environment variables set:"
echo "CUDA_HOME=$CUDA_HOME"
echo "PATH=$PATH"
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH"
echo "TORCH_CUDA_ARCH_LIST=$TORCH_CUDA_ARCH_LIST"
fi
Comment on lines +23 to +55
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can get rid of some duplication here. Actually I'm not sure I see any difference between then the branches of the conditionals.

For example:

  • CUDA_HOME=/usr/local/cuda-12.8 can be replaced with CUDA_HOME=/usr/local/cuda (which is a symlink to /usr/local/cuda-12.8 that always exists.
  • export LD_LIBRARY_PATH=/usr/local/cuda-12.8/lib64:${LD_LIBRARY_PATH:-} can be replaced with export LD_LIBRARY_PATH={CUDA_HOME}/lib64:${LD_LIBRARY_PATH:-}
  • The echo statements are the same between both branches and can be moved outside the conditional statements.
  • etc.

After these modifications these two branches of the conditional look the same to me? What was the idea here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

44 # Set CUDA environment variables for GR00T installation
45 export CUDA_HOME=/usr/local/cuda-12.8
46 export PATH=/usr/local/cuda-12.8/bin:${PATH}
47 export LD_LIBRARY_PATH=/usr/local/cuda-12.8/lib64:${LD_LIBRARY_PATH:-}
48 export TORCH_CUDA_ARCH_LIST=8.0+PTX
49
50 echo "CUDA environment variables set:"
51 echo "CUDA_HOME=$CUDA_HOME"
52 echo "PATH=$PATH"
53 echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH"
54 echo "TORCH_CUDA_ARCH_LIST=$TORCH_CUDA_ARCH_LIST"

Actually, this part of the code comes from the existing GR00T installation process in IsaacLab Arena. It’s indeed a bit different from the standard setup (it uses /usr/local/cuda-12.8), so I didn’t modify it. Because of this special setup, I wasn’t sure if it was required for a specific reason, so I kept a separate branch.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I don't see the difference between the branches of this if/else condition. The only difference is /usr/local/cuda-12.8 vs /usr/local/cuda. On all systems I've worked on, these two are symlinked to one another. So I assume we can just use /usr/local/cuda.

But in the interests of getting this in, I'm happy to fix this after merging.


# Installing dependencies for system-level media libraries
echo "Installing system-level media libraries..."
sudo apt-get update && sudo apt-get install -y ffmpeg && rm -rf /var/lib/apt/lists/*
$SUDO apt-get update && $SUDO apt-get install -y ffmpeg && rm -rf /var/lib/apt/lists/*

# Upgrade packaging tools to avoid setuptools issues
echo "Upgrading packaging tools..."
/isaac-sim/python.sh -m pip install --upgrade setuptools packaging wheel
$PYTHON_CMD -m pip install --upgrade setuptools packaging wheel

# Install GR00T with the specified dependency group
echo "Installing Isaac-GR00T with dependency group: $GROOT_DEPS_GROUP"
/isaac-sim/python.sh -m pip install --no-build-isolation --use-pep517 -e ${WORKDIR}/submodules/Isaac-GR00T/[$GROOT_DEPS_GROUP]
$PYTHON_CMD -m pip install --no-build-isolation --use-pep517 \
-e ${WORKDIR}/submodules/Isaac-GR00T/[$GROOT_DEPS_GROUP]

# Install flash-attn (specific version for compatibility)
echo "Installing flash-attn..."
/isaac-sim/python.sh -m pip install --no-build-isolation --use-pep517 flash-attn==2.7.1.post4
if [[ "$USE_SERVER_ENV" -eq 1 ]]; then
$PYTHON_CMD -m pip install --no-build-isolation --use-pep517 flash-attn==2.7.1.post4 || \
echo "flash-attn install failed, continue without it"
else
$PYTHON_CMD -m pip install --no-build-isolation --use-pep517 flash-attn==2.7.1.post4
fi

# Ensure pytorch torchrun script is in PATH
echo "Ensuring pytorch torchrun script is in PATH..."
echo "export PATH=/isaac-sim/kit/python/bin:\$PATH" >> /etc/bash.bashrc
if [[ "$USE_SERVER_ENV" -eq 0 ]]; then
echo "Ensuring pytorch torchrun script is in PATH..."
echo "export PATH=/isaac-sim/kit/python/bin:\$PATH" >> /etc/bash.bashrc
fi

echo "GR00T dependencies installation completed successfully"
2 changes: 2 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ TABLE OF CONTENTS
pages/concepts/concept_assets_design
pages/concepts/concept_affordances_design
pages/concepts/concept_policy_design
pages/concepts/concept_remote_policies_design


.. toctree::
:maxdepth: 1
Expand Down
Loading
Loading