Skip to main content
This guide assumes you have a physical SO-101 arm connected over USB serial. For a no-hardware run, see the simulation guide.

1. Setup (one-time)

From the repo root:
bash scripts/setup-from-source.sh

2. Check environment and ports

cli/rfx.sh doctor-so101
Verifies:
  • Python / uv availability
  • Detected serial ports
  • torch, yaml, rfx, and native rfx._rfx extension imports

3. Setup motor IDs and baud (first time)

1

Normalize IDs and set baud

cli/rfx.sh so101-setup --normalize-ids --set-baud-1m
2

Fallback if uv is unstable

.venv/bin/python scripts/so101-setup.py --normalize-ids --set-baud-1m

4. Run the demo

cli/rfx.sh so101-demo --port auto
The demo connects to the SO-101 through the core robot primitive, resets to home, runs a gentle sinusoidal motion, and returns home on exit.

Bimanual setup (two arms)

Default bimanual config: rfx/configs/so101_bimanual.yaml.
cli/rfx.sh so101-bimanual
Override the config directly:
uv run --python 3.13 rfx/examples/teleop_record.py \
  --config rfx/configs/so101_bimanual.yaml

Export formats during teleop

uv run --python 3.13 rfx/examples/teleop_record.py \
  --config rfx/configs/so101_bimanual.yaml \
  --export-format lerobot \
  --lerobot-repo-id your/repo

Minimal Python API

from rfx.robot import lerobot

robot = lerobot.so101(port="/dev/ttyACM0")
robot.reset()
obs = robot.observe()
robot.disconnect()

Dataset collection

Collect directly into a LeRobot dataset:
rfx record \
  --repo-id your-org/so101-demos \
  --robot so101 \
  --episodes 5 \
  --duration 30