-
Notifications
You must be signed in to change notification settings - Fork 2
One-command bimanual YAM quickstart (uv sync + uv run yam-demo) #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,48 +1,58 @@ | ||
| [project] | ||
| name = "reflex-quickstart" | ||
| version = "0.3.0" | ||
| version = "0.4.0" | ||
| description = "End-to-end quickstart for the Reflex Labs robotics fine-tune + inference API" | ||
| readme = "README.md" | ||
| requires-python = ">=3.12" | ||
| # Python 3.12 only: the bimanual-YAM path pulls i2rt → dm-env → dm-tree (no | ||
| # wheels on 3.13+), and lerobot (arm extra) requires >=3.12 — 3.12 is the | ||
| # single version that satisfies both. uv installs it for you automatically. | ||
| requires-python = ">=3.12,<3.13" | ||
| license = { text = "Apache-2.0" } | ||
| authors = [{ name = "Reflex Labs", email = "team@tryreflex.ai" }] | ||
| keywords = ["robotics", "vla", "fine-tuning", "inference", "reflex", "lerobot", "pi0.5"] | ||
| keywords = ["robotics", "vla", "fine-tuning", "inference", "reflex", "yam", "pi0.5"] | ||
| classifiers = [ | ||
| "Development Status :: 4 - Beta", | ||
| "Intended Audience :: Developers", | ||
| "Intended Audience :: Science/Research", | ||
| "License :: OSI Approved :: Apache Software License", | ||
| "Operating System :: POSIX :: Linux", | ||
| "Programming Language :: Python :: 3.10", | ||
| "Programming Language :: Python :: 3.11", | ||
| "Programming Language :: Python :: 3.12", | ||
| "Programming Language :: Python :: 3.13", | ||
| "Topic :: Scientific/Engineering :: Artificial Intelligence", | ||
| "Topic :: System :: Hardware", | ||
| ] | ||
|
|
||
| # Default deps cover the training + inference smoke tests (quickstart*.py). | ||
| dependencies = [ | ||
| # Reflex SDK — talks to the live API for training submission + status polling. | ||
| # 0.3.0 added the BYO-model surface used by quickstart_byom.py: | ||
| # client.models.import_from_hf / list / get / delete and | ||
| # client.keys.bind_model / unbind_model. 0.2.0 added 8 advanced | ||
| # training params (lora_alpha, lora_dropout, target_modules, | ||
| # warmup_steps, gradient_checkpointing, freeze_vision_encoder, | ||
| # dtype, save_freq) with server-side validation. | ||
| "reflex-sdk>=0.3.0", | ||
|
|
||
| # Image encoding for inference observations | ||
| "reflex-sdk>=0.6.6", | ||
| "opencv-python>=4.8", | ||
| "pillow>=10", | ||
| "numpy>=1.24", | ||
| ] | ||
|
|
||
| [project.optional-dependencies] | ||
| # `uv sync --extra yam` installs EVERYTHING for the closed-loop bimanual YAM | ||
| # demo in one command: the WebRTC transport, RealSense, and the i2rt driver | ||
| # pinned to the hardware-verified commit (newer i2rt has an fd=-1 control bug). | ||
| yam = [ | ||
| "reflex-sdk[webrtc]>=0.6.6", | ||
| "pyrealsense2>=2.54", | ||
| "i2rt", | ||
| ] | ||
|
Comment on lines
+38
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: The [tool.uv.sources] table in pyproject.toml is specific to uv and is not honored by pip [1][2]. This table is a uv-only feature designed to allow developers to define alternative sources for dependencies (such as Git repositories, local paths, remote URLs, or specific indexes) while maintaining a standards-compliant project configuration that can still be published to PyPI [1][3][2]. Because pip adheres to standard PEP 621 metadata (found in the [project] table), it does not read or respect tables under [tool.uv]. If you use [tool.uv.sources] to define dependencies, those definitions are ignored by pip [1]. If you rely on these sources, any other tool used for development will require you to re-specify those dependencies using that tool's specific format [1]. Citations:
Fix
🤖 Prompt for AI Agents |
||
| arm = [ | ||
| # Required for §3 (closed-loop SO-101 control). Skip with SKIP_ARM=1 | ||
| "lerobot>=0.5.2", | ||
| # lerobot 0.5.2 was yanked from PyPI; 0.5.1 is the latest available. | ||
| "lerobot>=0.5.0", | ||
| "feetech-servo-sdk>=1.0", | ||
| "deepdiff>=8.0", | ||
| ] | ||
|
|
||
| # i2rt has no PyPI release — pull it from git, PINNED to the commit verified | ||
| # working on real YAM hardware (HAL + box). The tip of main (1.1.2) has an | ||
| # fd=-1 CAN control regression; do NOT unpin without re-verifying on hardware. | ||
| [tool.uv.sources] | ||
| i2rt = { git = "https://github.com/i2rt-robotics/i2rt.git", rev = "7b6d5016f05ca63f9ef0185b7143e63f2c7a5708" } | ||
|
|
||
| [project.urls] | ||
| Homepage = "https://app.tryreflex.ai" | ||
| Documentation = "https://docs.tryreflex.ai" | ||
|
|
@@ -51,10 +61,15 @@ Issues = "https://github.com/reflex-inc/quickstart/issues" | |
|
|
||
| [project.scripts] | ||
| reflex-quickstart = "quickstart:main" | ||
| # Bimanual YAM: one command each. | ||
| # uv run yam-setup → detect RealSense serials, write yam_bimanual.yaml, check CAN | ||
| # uv run yam-demo → setup + run the closed-loop demo (Ctrl-C = safe-home) | ||
| yam-setup = "yam_robot:setup_cli" | ||
| yam-demo = "yam_robot:demo_cli" | ||
|
|
||
| [build-system] | ||
| requires = ["setuptools>=68", "wheel"] | ||
| build-backend = "setuptools.build_meta" | ||
|
|
||
| [tool.setuptools] | ||
| py-modules = ["quickstart", "quickstart_byom"] | ||
| py-modules = ["quickstart", "quickstart_byom", "yam_robot"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| #!/usr/bin/env bash | ||
| # ───────────────────────────────────────────────────────────────────────────── | ||
| # Reflex Labs — Bimanual YAM setup helper | ||
| # | ||
| # Gets a fresh Linux machine from nothing → ready to run closed-loop inference | ||
| # on two YAM arms. The inference model runs in the Reflex cloud (B200); this | ||
| # machine just needs the client + the robot driver + cameras. | ||
| # | ||
| # USAGE: | ||
| # ./setup_yam.sh install # install SDK + robot driver + RealSense | ||
| # ./setup_yam.sh can # bring up the CAN interfaces (needs sudo) | ||
| # ./setup_yam.sh cameras # list connected RealSense serials (for the yaml) | ||
| # ./setup_yam.sh check # verify everything is ready | ||
| # ./setup_yam.sh all # install + can + cameras + check | ||
| # ───────────────────────────────────────────────────────────────────────────── | ||
| set -euo pipefail | ||
|
|
||
| # Pin the audited-stable SDK. Bump deliberately after verifying on hardware. | ||
| REFLEX_SDK_VERSION="${REFLEX_SDK_VERSION:-0.6.6}" | ||
| CAN_BITRATE="${CAN_BITRATE:-1000000}" | ||
| CAN_INTERFACES="${CAN_INTERFACES:-can0 can1}" | ||
|
|
||
| bold() { printf '\033[1m%s\033[0m\n' "$*"; } | ||
| ok() { printf ' \033[32m✓\033[0m %s\n' "$*"; } | ||
| warn() { printf ' \033[33m!\033[0m %s\n' "$*"; } | ||
| die() { printf ' \033[31m✗ %s\033[0m\n' "$*" >&2; exit 1; } | ||
|
|
||
| # Pick a SUPPORTED interpreter. i2rt's pinned dm-env==1.6 pulls dm-tree, which | ||
| # only has usable wheels for CPython 3.10–3.12 — on 3.13/3.14 it tries to | ||
| # cmake-build from source and fails. HAL runs 3.10. Honor $PYTHON if set, | ||
| # else probe 3.12 → 3.11 → 3.10, else fall back to python3 with a version gate. | ||
| pick_python() { | ||
| if [ -n "${PYTHON:-}" ]; then echo "$PYTHON"; return; fi | ||
| for cand in python3.12 python3.11 python3.10; do | ||
| command -v "$cand" >/dev/null 2>&1 && { echo "$cand"; return; } | ||
| done | ||
| echo "python3" | ||
| } | ||
| PY="$(pick_python)" | ||
|
|
||
| require_supported_python() { | ||
| "$PY" - <<'PYEOF' || die "Unsupported Python. Install 3.10–3.12 (e.g. 'pyenv install 3.12') and re-run with PYTHON=python3.12 ./setup_yam.sh ..." | ||
| import sys | ||
| maj, minor = sys.version_info[:2] | ||
| ok = maj == 3 and 10 <= minor <= 12 | ||
| print(f" using {sys.executable} (Python {maj}.{minor}) — {'supported' if ok else 'UNSUPPORTED'}") | ||
| sys.exit(0 if ok else 1) | ||
| PYEOF | ||
| } | ||
|
|
||
| install() { | ||
| bold "Python interpreter" | ||
| require_supported_python | ||
|
|
||
| bold "Installing Reflex SDK (stable v${REFLEX_SDK_VERSION}) + WebRTC extras" | ||
| # [webrtc] pulls aiortc/av/msgpack/numpy/Pillow — required for target.kind=webrtc | ||
| "$PY" -m pip install --upgrade "reflex-sdk[webrtc]==${REFLEX_SDK_VERSION}" | ||
| ok "reflex-sdk[webrtc]==${REFLEX_SDK_VERSION}" | ||
|
|
||
| bold "Installing the i2rt YAM robot driver" | ||
| if ! "$PY" -c "import i2rt" 2>/dev/null; then | ||
| "$PY" -m pip install "i2rt @ git+https://github.com/i2rt-robotics/i2rt.git" \ | ||
| || warn "i2rt pip install failed — clone https://github.com/i2rt-robotics/i2rt and 'pip install -e .' manually" | ||
|
Comment on lines
+62
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: I couldn’t find any official release tags or published “latest release” metadata for i2rt-robotics/i2rt in the sources available to me, so there’s no authoritative immutable install target I can quote (latest release tag or commit SHA) from i2rt-robotics/i2rt for production-like scripts. What the repository’s docs do provide is an installation approach that installs directly from the repo (i.e., effectively “whatever commit you checked out”), which is not immutable by itself: it shows cloning the repo and then installing it with uv pip in editable mode ("uv pip install -e."). [1] Recommended production-like approach (immutable target): 1) Pick a specific commit SHA from the i2rt-robotics/i2rt repo and pin to it in your scripts (e.g., by cloning with --branch/--single-branch only after you hard-pin the SHA, or by checking out the SHA). 2) Then run the same install steps as in the docs after checkout: "uv pip install -e." (or a non-editable install if your deployment prefers wheels/site-packages). If you want, tell me whether you’re okay with pinning to the current default branch HEAD (main) or you need an actual GitHub Release tag; I can then give you exact clone/checkout commands tailored to your preference—however, I still need a source that exposes the tag/SHA (or you can provide the desired tag/SHA). Citations: Pin the
Suggested diff+ I2RT_REF="${I2RT_REF:-<tag-or-commit>}"
if ! "$PY" -c "import i2rt" 2>/dev/null; then
- "$PY" -m pip install "i2rt @ git+https://github.com/i2rt-robotics/i2rt.git" \
+ "$PY" -m pip install "i2rt @ git+https://github.com/i2rt-robotics/i2rt.git@${I2RT_REF}" \
|| warn "i2rt pip install failed — clone https://github.com/i2rt-robotics/i2rt and 'pip install -e .' manually"
fi🤖 Prompt for AI Agents |
||
| fi | ||
| "$PY" -c "import i2rt" 2>/dev/null && ok "i2rt importable" || warn "i2rt not importable yet" | ||
|
|
||
| bold "Installing RealSense Python bindings (skip if you use USB webcams)" | ||
| "$PY" -m pip install pyrealsense2 || warn "pyrealsense2 failed — only needed for kind: realsense cameras" | ||
| ok "install step done" | ||
| } | ||
|
|
||
| can_up() { | ||
| bold "Bringing up CAN interfaces: ${CAN_INTERFACES} @ ${CAN_BITRATE} bps" | ||
| for iface in $CAN_INTERFACES; do | ||
| if ip link show "$iface" >/dev/null 2>&1; then | ||
| sudo ip link set "$iface" down 2>/dev/null || true | ||
| sudo ip link set "$iface" type can bitrate "$CAN_BITRATE" | ||
| sudo ip link set "$iface" up | ||
| ok "$iface up @ ${CAN_BITRATE}" | ||
| else | ||
| warn "$iface not present — check your CAN adapter / USB connection" | ||
| fi | ||
| done | ||
| ip -br link | grep -E "can[0-9]" || warn "no can interfaces visible" | ||
| } | ||
|
|
||
| cameras() { | ||
| bold "Connected RealSense devices (copy serials into yam_bimanual.yaml)" | ||
| if command -v rs-enumerate-devices >/dev/null 2>&1; then | ||
| rs-enumerate-devices -s 2>/dev/null || rs-enumerate-devices 2>/dev/null | grep -iE "serial|name" | head -20 | ||
| else | ||
| "$PY" - <<'PYEOF' || warn "pyrealsense2 not installed — run ./setup_yam.sh install" | ||
| import pyrealsense2 as rs | ||
| ctx = rs.context() | ||
| devs = list(ctx.query_devices()) | ||
| if not devs: | ||
| print(" (no RealSense devices found — check USB)") | ||
| for d in devs: | ||
| print(f" {d.get_info(rs.camera_info.name):32s} serial={d.get_info(rs.camera_info.serial_number)}") | ||
| PYEOF | ||
| fi | ||
| } | ||
|
|
||
| check() { | ||
| bold "Readiness check" | ||
| "$PY" -c "import sys; v=sys.version_info; ok=v[0]==3 and 10<=v[1]<=12; print(f' Python {v[0]}.{v[1]}', '(supported)' if ok else '(UNSUPPORTED — use 3.10–3.12)')" 2>/dev/null || warn "no usable python" | ||
| "$PY" -c "import reflex; print(' reflex-sdk', reflex.__version__)" 2>/dev/null || warn "reflex-sdk not installed — run ./setup_yam.sh install" | ||
| "$PY" -c "import aiortc, av, msgpack, numpy, PIL; print(' webrtc extras OK')" 2>/dev/null || warn "webrtc extras missing — pip install 'reflex-sdk[webrtc]'" | ||
| "$PY" -c "import i2rt; print(' i2rt OK')" 2>/dev/null || warn "i2rt missing" | ||
| ip -br link | grep -qE "can[0-9].*UP" && ok "a CAN interface is UP" || warn "no CAN interface UP — run ./setup_yam.sh can" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validate all required CAN interfaces, not just one. The current check passes if any Suggested diff- ip -br link | grep -qE "can[0-9].*UP" && ok "a CAN interface is UP" || warn "no CAN interface UP — run ./setup_yam.sh can"
+ missing_can=0
+ for iface in $CAN_INTERFACES; do
+ if ip -br link show "$iface" 2>/dev/null | grep -q "UP"; then
+ ok "$iface is UP"
+ else
+ warn "$iface is not UP — run ./setup_yam.sh can"
+ missing_can=1
+ fi
+ done🧰 Tools🪛 Shellcheck (0.11.0)[info] 84-84: Note that A && B || C is not if-then-else. C may run when A is true. (SC2015) 🤖 Prompt for AI Agents |
||
| if [ -n "${REFLEX_API_KEY:-}" ]; then ok "REFLEX_API_KEY is set"; else warn "REFLEX_API_KEY not set — export it or run 'reflex login'"; fi | ||
| echo | ||
| bold "Next:" | ||
| echo " 1. ./setup_yam.sh cameras # get your 3 RealSense serials" | ||
| echo " 2. edit yam_bimanual.yaml # paste serials + set CAN channels + prompt" | ||
| echo " 3. reflex connect --config yam_bimanual.yaml # (start with mode: dry_run)" | ||
| } | ||
|
|
||
| case "${1:-all}" in | ||
| install) install ;; | ||
| can) can_up ;; | ||
| cameras) cameras ;; | ||
| check) check ;; | ||
| all) install; can_up; cameras; check ;; | ||
| *) echo "usage: $0 {install|can|cameras|check|all}"; exit 1 ;; | ||
| esac | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trove classifiers contradict
requires-python.requires-python = ">=3.12,<3.13"(line 9) restricts installation to Python 3.12, yet the classifiers still advertise 3.10 and 3.11. This is misleading package metadata and conflicts with the comment on lines 6–8.🔧 Proposed fix
"License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12",📝 Committable suggestion
🤖 Prompt for AI Agents