All-in-one workspace for managing SO101 robots: map COM ports, create robots, calibrate joints, and trigger leader→follower teleoperation. The stack uses:
- Electron (
electron/main.js) to wrap the web UI. - Next.js frontend (
frontend/) for the setup flow and robot dashboard. - FastAPI backend (
backend/) for persistence, COM monitoring, and command hooks intolerobot. - Local storage at
data/robots.jsonfor robots and calibration metadata.
backend/– FastAPI app (uvicorn backend.main:app) with COM polling, REST API, and command runners.frontend/– Next.js app router UI.NEXT_PUBLIC_API_BASEdefaults tohttp://localhost:8000.electron/– Minimal Electron shell pointing at the Next.js dev server.data/robots.json– persisted robots + calibration entries. Deleting a robot also clears its calibration.
-
Install everything (JS deps)
From repo root run:npm install
This installs root tooling plus runs frontend/electron installs for you.
-
Install backend (Python)
Create/activate your venv, then:npm run install:backend # wraps: python -m pip install -r backend/requirements.with-lerobot.txt- If you do not want the vendored
./lerobot, usebackend/requirements.txtinstead. - COM detection uses
pyserialand polls every ~2s. Status isonlinewhen the stored COM port is present. - Calibration/teleop commands default to dry-run unless the
lerobotpackage is importable. SetLEROBOT_DRY_RUN=0to force real execution.
- If you do not want the vendored
-
Run all dev services from root
npm run dev
- Starts FastAPI on
:8000, Next.js on:3000, and then Electron after the frontend is ready. - Make sure your Python venv is active (so
pythonpoints to the env with dependencies) before launching. The backend now runs from the repo root (python -m uvicorn backend.main:app), so it can import thebackendpackage cleanly. - For backend-only or frontend-only, use
npm run dev:backendornpm run dev:frontend(Electron:npm run dev:electron).
- Starts FastAPI on
- Add robot wizard: refresh COM list, plug/unplug to spot the right port, pick model (SO101) and role (leader/follower), then name it. The backend stores name, model, role, and COM for later commands.
- Robots page: shows status (online/offline via COM presence), calibration flag, and actions to calibrate, inspect, or delete (deletes calibration too).
- Calibration flow: if a calibration exists you'll be asked to override. Otherwise you land on the calibration modal: set arm to neutral → start → adjust joint min/current/max → “End & save”. Backend endpoint:
POST /robots/{id}/calibration. - Teleoperation: on a calibrated leader, pick a calibrated follower of the same model. If the follower lacks calibration you'll get a warning. Starting teleop prompts you to align poses; “Stop” clears the active session marker. Backend endpoint:
POST /teleop/start.
GET /health– basic check.GET /ports– snapshot of detected COM ports{port: description}.GET /robots/POST /robots– list/create robots (name, model, role, com_port).GET /robots/{id}/DELETE /robots/{id}– fetch or remove (also clears calibration).POST /robots/{id}/calibration/start– runslerobot.scripts.lerobot_calibratewith--robot/--teleopflags based on role. Honorsoverrideflag.POST /robots/{id}/calibration– save joint ranges.GET /robots/{id}/calibration– fetch saved calibration.POST /teleop/start– validates leader/follower calibration and model match, then calls the teleop hook (placeholder for now).
- Calibration command built as:
- Follower:
python -m lerobot.scripts.lerobot_calibrate --robot.type=so101_follower --robot.port=COM13 --robot.id=<name> - Leader:
python -m lerobot.scripts.lerobot_calibrate --teleop.type=so101_leader --teleop.port=COM14 --teleop.id=<name>
- Follower:
- If a local
lerobot/srcexists inside this repo, it is added toPYTHONPATHautomatically. Editable install viapip install -r backend/requirements.with-lerobot.txt.
- Status relies on COM presence; for USB plug/unplug feedback hit “Refresh COM list”.
- Teleop hook currently returns a success message; swap
run_teleopinbackend/commands.pywith your real command when ready. - Everything uses ASCII text; adjust styling in
frontend/src/app/globals.cssand interactions infrontend/src/app/page.tsx.