File size: 9,752 Bytes
c26f879 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | #!/usr/bin/env bash
# install_pico.sh
# Sets up the gear_sonic_teleop venv for PICO VR teleop on any x86_64 or arm64
# machine (desktop, laptop, or G1 onboard).
#
# Usage:
# bash install_scripts/install_pico.sh # full install
# SKIP_SIM_AND_UNITREE=1 bash install_scripts/install_pico.sh
# # publisher-only profile
# # (Thor/Orin used as a
# # headless Isaac Teleop /
# # CloudXR ROS publisher
# # β neither sim nor the
# # unitree DDS bindings
# # are on that path)
#
# Optional env vars:
# SKIP_SIM_AND_UNITREE=1 Skip the mujoco sim extra and unitree_sdk2_python.
# On aarch64 also skips the CycloneDDS C-lib build.
# CYCLONEDDS_HOME=<path> Override the CycloneDDS install prefix on aarch64
# (default: ~/cyclonedds/install). Not used on
# x86_64 because prebuilt cyclonedds wheels exist.
#
# Run from the repo root.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# ββ 0. Print detected architecture βββββββββββββββββββββββββββββββββββββββββββ
ARCH="$(uname -m)"
echo "[OK] Architecture: $ARCH"
# ββ 1. Ensure uv is installed and available ββββββββββββββββββββββββββββββββββ
if ! command -v uv &>/dev/null; then
echo "[INFO] uv not found β installing via official installer β¦"
curl -LsSf https://astral.sh/uv/install.sh | sh
# Source the uv env so it's available in this session
if [ -f "$HOME/.local/bin/env" ]; then
# shellcheck disable=SC1091
source "$HOME/.local/bin/env"
elif [ -f "$HOME/.cargo/env" ]; then
# shellcheck disable=SC1091
source "$HOME/.cargo/env"
else
export PATH="$HOME/.local/bin:$PATH"
fi
# Verify uv is now reachable
if ! command -v uv &>/dev/null; then
echo "[ERROR] uv installation succeeded but binary not found on PATH."
echo " Please add ~/.local/bin (or ~/.cargo/bin) to your PATH and re-run."
exit 1
fi
fi
echo "[OK] uv $(uv --version)"
# ββ 2. Install a uv-managed Python 3.10 (includes dev headers / Python.h) ββββ
echo "[INFO] Installing uv-managed Python 3.10 (includes development headers) β¦"
uv python install 3.10
MANAGED_PY="$(uv python find --no-project 3.10)"
echo "[OK] Using Python: $MANAGED_PY"
# ββ 3. Clean previous venv (if any) ββββββββββββββββββββββββββββββββββββββββββ
cd "$REPO_ROOT"
echo "[INFO] Removing old .venv_teleop (if present) β¦"
rm -rf .venv_teleop
# ββ 4. Create venv & install teleop extra βββββββββββββββββββββββββββββββββββββ
echo "[INFO] Creating .venv_teleop with uv-managed Python 3.10 β¦"
uv venv .venv_teleop --python "$MANAGED_PY" --prompt gear_sonic_teleop
# shellcheck disable=SC1091
source .venv_teleop/bin/activate
echo "[INFO] Installing gear_sonic[teleop] β¦"
uv pip install -e "gear_sonic[teleop]"
# ββ 5. Install xrobotoolkit_sdk (CMake-based, not a pip package) ββββββββββββββ
echo "[INFO] Installing XRoboToolkit SDK β¦"
# Install cmake + pybind11 into the venv so the CMake-based build can find them.
# Build with --no-build-isolation so CMake inherits the venv's pybind11.
uv pip install cmake pybind11 setuptools
echo "[OK] cmake $(cmake --version | head -1)"
# Point CMake at pybind11's cmake config so find_package(pybind11) succeeds
export CMAKE_PREFIX_PATH="$(python -m pybind11 --cmakedir)"
echo "[OK] pybind11 cmake dir: $CMAKE_PREFIX_PATH"
# On aarch64 (Jetson Orin), build the PXREARobotSDK native lib from source
# because pre-built aarch64 binaries are not shipped in the repo.
XRT_DIR="$REPO_ROOT/external_dependencies/XRoboToolkit-PC-Service-Pybind_X86_and_ARM64"
if [ "$ARCH" = "aarch64" ] && [ ! -f "$XRT_DIR/lib/aarch64/libPXREARobotSDK.so" ]; then
echo "[INFO] Building PXREARobotSDK for aarch64 (Jetson Orin) β¦"
XRT_TMP="$XRT_DIR/tmp"
mkdir -p "$XRT_TMP"
if [ ! -d "$XRT_TMP/XRoboToolkit-PC-Service" ]; then
git clone -b orin https://github.com/XR-Robotics/XRoboToolkit-PC-Service.git "$XRT_TMP/XRoboToolkit-PC-Service"
fi
pushd "$XRT_TMP/XRoboToolkit-PC-Service/RoboticsService/PXREARobotSDK" > /dev/null
bash build.sh
popd > /dev/null
mkdir -p "$XRT_DIR/lib/aarch64" "$XRT_DIR/include/aarch64"
cp "$XRT_TMP/XRoboToolkit-PC-Service/RoboticsService/PXREARobotSDK/PXREARobotSDK.h" \
"$XRT_DIR/include/aarch64/"
cp -r "$XRT_TMP/XRoboToolkit-PC-Service/RoboticsService/PXREARobotSDK/nlohmann" \
"$XRT_DIR/include/aarch64/nlohmann/"
cp "$XRT_TMP/XRoboToolkit-PC-Service/RoboticsService/PXREARobotSDK/build/libPXREARobotSDK.so" \
"$XRT_DIR/lib/aarch64/"
rm -rf "$XRT_TMP"
echo "[OK] PXREARobotSDK aarch64 native library built and installed"
fi
uv pip install --no-build-isolation -e external_dependencies/XRoboToolkit-PC-Service-Pybind_X86_and_ARM64/
# ββ 5c. Install isaacteleop[cloudxr] for the in-process CloudXR / DeviceIO path
# (--input-source isaac-teleop in pico_manager_thread_server.py).
# Hosted on pypi.nvidia.com (public index, no auth). Replaces the legacy
# multi-container path (./scripts/run_cloudxr_via_docker.sh + teleop_ros2_ref).
echo "[INFO] Installing isaacteleop[cloudxr]~=1.3.0 from pypi.nvidia.com β¦"
uv pip install 'isaacteleop[cloudxr]~=1.3.0' --prerelease=allow \
--extra-index-url https://pypi.nvidia.com
# Seed ~/cloudxr.env with the device profile CloudXRLauncher negotiates against.
# Skip if the file already exists.
if [ ! -f "$HOME/cloudxr.env" ]; then
echo "NV_DEVICE_PROFILE=Quest3" > "$HOME/cloudxr.env"
echo "[OK] Seeded $HOME/cloudxr.env with NV_DEVICE_PROFILE=Quest3"
else
echo "[OK] $HOME/cloudxr.env already exists (leaving as-is)"
fi
# ββ 5b, 6, 7: CycloneDDS C lib (aarch64) + sim extra + unitree_sdk2_python ββββ
# Skip when:
# β’ onboard unitree-provisioned image (aarch64 + user==unitree): the image
# already ships CycloneDDS, sim has no display, and the on-robot deploy
# uses the C++ stack directly. Applies to both Orin and Thor onboards.
# β’ SKIP_SIM_AND_UNITREE=1 is set explicitly: e.g. a Thor or Orin used as a
# headless Isaac Teleop / CloudXR streamer β neither mujoco nor the
# unitree DDS bindings are on that path.
if { [ "$ARCH" = "aarch64" ] && [ "$(whoami)" = "unitree" ]; } \
|| [ "${SKIP_SIM_AND_UNITREE:-0}" = "1" ]; then
echo "[SKIP] Skipping CycloneDDS build, sim extra & unitree_sdk2_python"
else
# ββ 5b. Build CycloneDDS C library on aarch64 (needed by the cyclonedds
# Python binding which unitree_sdk2_python depends on).
# x86_64 hosts get prebuilt cyclonedds wheels and skip this entirely.
# Pattern follows Unitree's own README for this exact error
# (https://github.com/unitreerobotics/unitree_sdk2_python#faq):
# per-user source checkout in $HOME, sibling install/ dir, no sudo.
if [ "$ARCH" = "aarch64" ]; then
CDDS_DIR="$HOME/cyclonedds"
CDDS_PREFIX="${CYCLONEDDS_HOME:-$CDDS_DIR/install}"
if [ ! -f "$CDDS_PREFIX/lib/libddsc.so" ]; then
echo "[INFO] Building CycloneDDS releases/0.10.x β $CDDS_PREFIX β¦"
# Track the releases/0.10.x maintenance branch (per Unitree's FAQ).
# The 0.10.2 tag is unpatched 2022 code and trips glibc FORTIFY_SOURCE
# in dds_create_domain on modern Ubuntu / glibc; the branch has fixes.
if [ ! -d "$CDDS_DIR/.git" ]; then
git clone -b releases/0.10.x --depth 1 \
https://github.com/eclipse-cyclonedds/cyclonedds.git "$CDDS_DIR"
fi
cmake -S "$CDDS_DIR" -B "$CDDS_DIR/build" \
-DCMAKE_INSTALL_PREFIX="$CDDS_PREFIX" \
-DBUILD_EXAMPLES=OFF \
-DBUILD_TESTING=OFF
cmake --build "$CDDS_DIR/build" -j"$(nproc)"
cmake --install "$CDDS_DIR/build"
echo "[OK] CycloneDDS installed at $CDDS_PREFIX"
else
echo "[OK] CycloneDDS already present at $CDDS_PREFIX (libddsc.so found)"
fi
export CYCLONEDDS_HOME="$CDDS_PREFIX"
fi
# ββ 6. Install sim extra (for run_sim_loop.py / sim2sim testing)
echo "[INFO] Installing sim extra β¦"
uv pip install -e "gear_sonic[sim]"
# ββ 7. Install unitree_sdk2_python (needed by the sim2sim bridge)
echo "[INFO] Installing unitree_sdk2_python β¦"
uv pip install -e external_dependencies/unitree_sdk2_python
fi
echo ""
echo "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ"
echo " Setup complete! Activate the venv with:"
echo ""
echo " source .venv_teleop/bin/activate"
echo ""
echo " You should see (gear_sonic_teleop) in your prompt."
echo "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ"
|