Refine robot milestones and make GPU setup reproducible

This commit is contained in:
ylhan
2026-09-08 15:03:32 +08:00
parent 0e1b7eaf4d
commit d71fcc7650
9 changed files with 406 additions and 537 deletions
+91 -114
View File
@@ -1,116 +1,93 @@
#!/usr/bin/env bash
# ============================================================
# LeRobot 一键环境 — 3080 主家 / 3090 训练机(两台 Ubuntu 都跑一遍)
# 用法:
# nano ~/robot/setup_lerobot.sh # 粘入本文件
# bash ~/robot/setup_lerobot.sh
# 跑完把【整段输出】粘回给助手,我带你走 P1。
# ============================================================
set -uo pipefail
WORKDIR="${HOME}/robot"
LEROBOT_DIR="${WORKDIR}/lerobot"
VENV="${WORKDIR}/.venv"
PY=3.12
# LeRobot extras:feetech(SO-101) + lekiwi(底盘) + dataset(采数) + smolvla(主力VLA) + pi0(π0/π0-FAST)
EXTRAS="feetech,lekiwi,dataset,smolvla,pi0"
hr(){ echo; echo "========== $* =========="; }
hr "[1/7] 环境探测"
if [ -r /etc/os-release ]; then . /etc/os-release; echo "OS: ${PRETTY_NAME:-?}"; fi
if command -v nvidia-smi >/dev/null 2>&1; then
nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader
else
echo "!! 未检测到 nvidia-smi —— GPU 驱动可能没装(3090 应能识别)。先装驱动再继续。"
fi
echo "系统 python3: $(python3 --version 2>&1)"
echo "有 python3.12: $([ -x "$(command -v python3.12)" ] && echo 是 || echo 否)"
echo "有 uv: $([ -x "$(command -v uv)" ] && echo 是 || echo 否)"
echo "有 git: $(git --version 2>&1)"
echo "有 ffmpeg: $([ -x "$(command -v ffmpeg)" ] && echo 是 || echo 否)"
hr "[2/7] 网络/镜像策略(直连 vs 国内镜像)"
PIP_URL="https://pypi.org/simple"
if curl -fsS --max-time 6 https://pypi.org >/dev/null 2>&1; then
echo "pypi 直连可达 → 官方源"
else
echo "pypi 直连不可达 → 清华镜像"; PIP_URL="https://pypi.tuna.tsinghua.edu.cn/simple"
fi
if curl -fsS --max-time 6 https://huggingface.co >/dev/null 2>&1; then
echo "HF 直连可达 → 官方"; HF_ENDPOINT="https://huggingface.co"
else
echo "HF 直连不可达 → hf-mirror"; HF_ENDPOINT="https://hf-mirror.com"
fi
export HF_ENDPOINT
echo "→ PIP_URL=$PIP_URL"; echo "→ HF_ENDPOINT=$HF_ENDPOINT"
hr "[3/7] Python ${PY} venv (${VENV})"
mkdir -p "${WORKDIR}"
if [ -d "${VENV}" ]; then echo "venv 已存在,复用"; else
if command -v uv >/dev/null 2>&1; then
uv venv --python ${PY} "${VENV}"
elif command -v python3.12 >/dev/null 2>&1; then
python3.12 -m venv "${VENV}"
elif command -v python3.11 >/dev/null 2>&1; then
echo "无 3.12,用 3.11 兜底(LeRobot 要 3.12,可能装不上,建议装 uv 或 deadsnakes 3.12)"
python3.11 -m venv "${VENV}"
else
echo "!! 没有 3.12/3.11/uv。装 uv: curl -LsSf https://astral.sh/uv/install.sh | sh 然后重跑"; exit 1
fi
fi
# shellcheck disable=SC1091
source "${VENV}/bin/activate"
python -m pip install -U pip -i "${PIP_URL}"
echo "venv python: $(python --version) ($(which python))"
hr "[4/7] clone LeRobot → ${LEROBOT_DIR}"
if [ -d "${LEROBOT_DIR}/.git" ]; then
echo "已存在 → git pull 更新"; ( cd "${LEROBOT_DIR}" && git pull ) || true
else
if curl -fsS --max-time 6 https://github.com >/dev/null 2>&1; then
git clone https://github.com/huggingface/lerobot.git "${LEROBOT_DIR}"
else
echo "github 直连慢/不可达 → 走 ghproxy 加速"
git clone https://ghproxy.com/https://github.com/huggingface/lerobot.git "${LEROBOT_DIR}"
fi
fi
cd "${LEROBOT_DIR}"
echo "当前 commit: $(git log -1 --oneline 2>/dev/null)"
hr "[5/7] 安装 LeRobot [${EXTRAS}]"
pip install -e ".[${EXTRAS}]" -i "${PIP_URL}" 2>&1 | tail -n 25
# ffmpeg(LeRobot 编视频需要)
if ! command -v ffmpeg >/dev/null 2>&1; then
echo "装 ffmpeg ..."; ( sudo apt-get install -y ffmpeg 2>&1 || conda install -y -c conda-forge ffmpeg 2>&1 ) | tail -n 5
fi
hr "[6/7] 验证"
python - <<'PY'
import importlib, torch
print("torch", torch.__version__,
"| cuda", torch.cuda.is_available(),
"| gpu", (torch.cuda.get_device_name(0) if torch.cuda.is_available() else "N/A"),
"| vram_GB", round(torch.cuda.get_device_properties(0).total_memory/1e9,1) if torch.cuda.is_available() else 0)
try:
import lerobot; print("lerobot", getattr(lerobot, "__version__", "?"))
except Exception as e:
print("lerobot import 失败:", e)
for m in ["lerobot.policies.smolvla","lerobot.policies.pi0","lerobot.policies.act"]:
try: importlib.import_module(m); print("OK ", m)
except Exception as e: print("MISS", m, "->", e)
PY
echo "--- CLI 命令 ---"
for c in lerobot-find-port lerobot-find-cameras lerobot-calibrate lerobot-teleoperate lerobot-record lerobot-train lerobot-eval lerobot-rollout; do
command -v "$c" >/dev/null 2>&1 && echo "OK $c" || echo "MISS $c"
# Ubuntu x86_64 GPU hosts. First host: --resolve; second host: same lock.
set -Eeuo pipefail
trap 'printf "ERROR at line %s: environment NOT verified.\n" "$LINENO" >&2' ERR
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
WORKDIR="${ROBOT_WORKDIR:-${HOME}/robot}"
VENV="${WORKDIR}/.venv-lerobot-0.6.1"
LOCK="${SCRIPT_DIR}/requirements-linux-py312.lock"
INPUT="${SCRIPT_DIR}/requirements.in"
RESOLVE=false
case "${1:-}" in
--resolve) RESOLVE=true ;;
--help) echo "Usage: bash $0 [--resolve] (Linux x86_64, uv, NVIDIA driver, ffmpeg)"; exit 0 ;;
"") ;;
*) echo "Unknown argument: $1" >&2; exit 2 ;;
esac
[[ $# -le 1 ]] || { echo "Too many arguments" >&2; exit 2; }
[[ "$(uname -s)" == Linux && "$(uname -m)" == x86_64 ]] || {
echo "Only Linux x86_64 GPU hosts are supported; RPi needs a separate environment." >&2; exit 1;
}
for cmd in uv nvidia-smi ffmpeg sha256sum; do
command -v "$cmd" >/dev/null || { echo "Missing prerequisite: $cmd" >&2; exit 1; }
done
hr "[7/7] 完成 — 之后每次用 3090 前先:"
cat <<EOF
source ${VENV}/bin/activate
cd ${LEROBOT_DIR}
export HF_ENDPOINT=${HF_ENDPOINT}
huggingface-cli login # 首次: 输你的 HF token
EOF
echo "✅ 把上面 [1]~[7] 的完整输出粘回给助手。"
echo " 若全 OK,我们就进 P1:插第一条 SO-101 → lerobot-find-port → 校准 → 遥操。"
if ! $RESOLVE && [[ ! -s "$LOCK" ]]; then
echo "Missing lock: use --resolve on 3080 first; transfer the validated lock and .input.sha256 to 3090." >&2; exit 1
fi
if $RESOLVE && [[ -e "$LOCK" || -e "$LOCK.input.sha256" ]]; then
echo "Refusing to overwrite existing lock. Review and archive it before an intentional update." >&2; exit 1
fi
mkdir -p "$WORKDIR"
REPORT="${WORKDIR}/reports/$(date -u +%Y%m%dT%H%M%SZ)-$$"
mkdir -p "$REPORT"
exec > >(tee "$REPORT/setup.log") 2>&1
echo "[1/5] Prerequisites"
nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader
uv --version
ffmpeg -version > "$REPORT/ffmpeg.txt"
# Set UV_DEFAULT_INDEX explicitly if a mirror is needed. No automatic Hub/token routing.
echo "[2/5] Dedicated Python 3.12 environment"
if [[ ! -d "$VENV" ]]; then uv venv --python 3.12 "$VENV"; fi
PYTHON="${VENV}/bin/python"
"$PYTHON" -c 'import sys; assert sys.version_info[:2] == (3, 12), sys.version'
if $RESOLVE; then
TEMP_LOCK="$(mktemp "${LOCK}.tmp.XXXXXX")"
trap 'rm -f -- "$TEMP_LOCK"' EXIT
uv pip compile "$INPUT" --python "$PYTHON" --generate-hashes --output-file "$TEMP_LOCK"
mv -- "$TEMP_LOCK" "$LOCK"
(cd "$SCRIPT_DIR" && sha256sum requirements.in) > "$LOCK.input.sha256"
trap - EXIT
fi
[[ -s "$LOCK.input.sha256" ]] || { echo "Missing input fingerprint" >&2; exit 1; }
(cd "$SCRIPT_DIR" && sha256sum --check "${LOCK}.input.sha256")
echo "[3/5] Install locked packages (dedicated venv only)"
uv pip sync --python "$PYTHON" --require-hashes "$LOCK"
uv pip check --python "$PYTHON"
echo "[4/5] GPU, policy implementations, video libraries and CLI"
"$PYTHON" - <<'PY'
import importlib
import importlib.metadata
import torch
assert importlib.metadata.version('lerobot') == '0.6.1'
assert torch.cuda.is_available(), 'CUDA unavailable: check driver and torch build'
x = torch.ones((32, 32), device='cuda')
assert (x @ x).sum().item() == 32768
torch.cuda.synchronize()
print('torch:', torch.__version__, 'CUDA:', torch.version.cuda, 'GPU:', torch.cuda.get_device_name(0))
for module in (
'lerobot.policies.act.modeling_act',
'lerobot.policies.smolvla.modeling_smolvla',
'lerobot.robots.so_follower',
'lerobot.teleoperators.so_leader',
'av', 'torchcodec',
):
importlib.import_module(module)
print('OK:', module)
PY
for cli in lerobot-find-port lerobot-find-cameras lerobot-setup-motors lerobot-calibrate lerobot-teleoperate lerobot-record lerobot-train lerobot-rollout; do
[[ -x "$VENV/bin/$cli" ]] || { echo "Missing CLI: $cli" >&2; exit 1; }
done
# find-port ignores --help and starts an interactive USB discovery procedure.
# Discovery tools are checked for existence only; never invoke them in setup.
for cli in lerobot-setup-motors lerobot-calibrate lerobot-teleoperate lerobot-record lerobot-train lerobot-rollout; do
"$VENV/bin/$cli" --help > "$REPORT/$cli-help.txt" 2>&1
done
echo "[5/5] Save verification evidence"
uv pip freeze --python "$PYTHON" > "$REPORT/packages.txt"
"$PYTHON" -VV > "$REPORT/python.txt"
sha256sum "$LOCK" > "$REPORT/lock.sha256"
cp -- "$LOCK" "$LOCK.input.sha256" "$REPORT/"
echo "PASS: software smoke checks only; recording, model training and robot safety remain unverified."
echo "Report: $REPORT"
printf 'Activate: source %q/bin/activate\n' "$VENV"
echo "Use hf auth login only if accessing the Hub; use the official endpoint for authenticated uploads."