Skip to content

TToTMooN/limb

Repository files navigation

limb

Lightweight arm control for robot learning.

Minimal, ROS-free Python stack for high-frequency control of direct-drive robot arms. Teleoperation, data collection, and learned policy deployment — everything between bare metal and your research code.

Built for I2RT YAM bimanual arms.


No ROS Direct CAN bus at 100 Hz. One process, one config, one launch command.
Plug-and-play teleop Viser web UI, GELLO leader arms, Pico VR — swap with a YAML change.
Policy-ready Ship your VLA as a server, point limb at it, run inference.
Data collection Hands-free episode recording with foot pedal / VR button triggers.

Docs: CLI Reference · Teleoperation · Data Collection · Policy Server Spec


Install

git clone --recurse-submodules https://github.com/TToTMooN/limb
cd limb
curl -LsSf https://astral.sh/uv/install.sh | sh  # install uv if needed
uv venv --python 3.11
uv sync

Submodule: Includes i2rt (motor driver) under dependencies/. Clone with --recurse-submodules.

VR teleop: XRoboToolkit SDK requires a separate install after uv sync:

bash scripts/install_xrobotoolkit_sdk.sh

Hardware Setup

CAN Interface (YAM arms)

echo 'SUBSYSTEM=="net", KERNEL=="can*", ACTION=="add", RUN+="/sbin/ip link set %k up type can bitrate 1000000"' \
  | sudo tee /etc/udev/rules.d/99-can.rules
sudo udevadm control --reload-rules && sudo udevadm trigger

Verify: ip link show | grep can — expect can_follow_l and can_follow_r.

See docs/teleop.md for GELLO and VR hardware setup.


Quick Start

All common operations are exposed through a single limb CLI. Full reference in docs/cli.md.

uv run limb --help                # list subcommands
uv run limb <cmd> --help          # flags for one subcommand

Teleoperation

uv run limb teleop --config-path configs/yam_viser_bimanual.yaml    # Viser web UI
uv run limb teleop --config-path configs/yam_gello_bimanual.yaml    # GELLO leader arms
uv run limb teleop --config-path configs/yam_vr_bimanual.yaml       # Pico VR

Data Collection

Collection configs are overlays — combine with any teleop config:

uv run limb record --config-path configs/yam_gello_network_bimanual.yaml configs/collection_pedal.yaml
uv run limb record --config-path configs/yam_vr_bimanual.yaml configs/collection_vr.yaml

Policy Deployment

uv run limb teleop --config-path configs/yam_pi0_bimanual.yaml       # OpenPI (pi0)
uv run limb teleop --config-path configs/yam_policy_bimanual.yaml    # Generic WebSocket

Data Tools

# Hardware discovery (cameras, CAN, pedals, etc.)
uv run limb devices

# Replay a recorded episode on hardware (robot config read from episode metadata)
uv run limb replay --episode-dir recordings/red_cube_task/episode_20260304_153045_0001

# Visualize a recorded episode in Rerun
uv run limb visualize --episode-dir recordings/red_cube_task/episode_20260304_153045_0001

# Convert a session to LeRobot v2.1 format (no lerobot dependency needed)
uv run limb convert-lerobot --input-dir recordings/red_cube_task --output-dir datasets/red_cube

# Only include successful episodes
uv run limb convert-lerobot --input-dir recordings/red_cube_task --output-dir datasets/red_cube --success-only

# Upload a dataset (S3 / GCS / HuggingFace Hub)
uv run limb upload --source datasets/red_cube --target hf://myuser/red_cube

Diagnostics

uv run scripts/diagnostics/test_realsense_cameras.py
uv run scripts/diagnostics/test_gello_input.py
uv run scripts/diagnostics/test_vr_input.py

Architecture

launch.py → control loop @ 100 Hz
  ├─ Agent.act(obs) → action        # teleop device or VLA policy server
  ├─ session.step(obs, action)       # episode recording + trigger management
  ├─ RobotEnv.step(action)           # CAN bus → DM motors
  └─ ViserMonitor.update(obs)        # camera feeds + URDF viz
limb/
  envs/           # launch.py, robot_env.py, config loader
  agents/         # teleop (Viser, GELLO, VR) + policy (OpenPI, WebSocket)
  robots/         # YAM CAN driver, IK solvers (Pink, pyroki)
  devices/        # GELLO reader, JoyCon gripper, VR client
  recording/      # episode recorder, triggers, session manager
  visualization/  # Viser URDF + camera monitor
  sensors/        # RealSense, OpenCV, ZED camera drivers
configs/          # YAML launch configs
robot_configs/    # per-arm hardware specs

Extending limb

from limb.agents.agent import Agent

class MyAgent(Agent):
    def act(self, obs):
        return {"left": {"pos": target_joints}, "right": {"pos": target_joints}}
agent:
  _target_: my_package.MyAgent

Development

uv run ruff check limb/ && uv run ruff format limb/

Python 3.11 · uv · tyro for CLI · loguru for logging · ruff (line length 119)


Inspired by GELLO and robots_realtime.

About

Lightweight arm control for robot learning

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors