LeRobot.js / docs /api-comparison.md
NERDDISCO's picture
refactor: calibrate for web
5eb1bc0
|
raw
history blame
30.8 kB

lerobot API Comparison: Python vs Node.js vs Web

This document provides a comprehensive three-way comparison of lerobot APIs across Python lerobot (original), Node.js lerobot.js, and Web lerobot.js platforms.

πŸ”„ Core Function Comparison

Function Category Python lerobot (Original) Node.js lerobot.js Web Browser lerobot.js Key Pattern
Port Discovery find_port() findPort() findPortWeb(logger) Python β†’ Node.js: Direct port, Web: Requires UI logger
Robot Creation SO100Follower(config) createSO100Follower(config) createWebTeleoperationController(port, serialNumber) Python: Class, Node.js: Factory, Web: Pre-opened port
Calibration calibrate(cfg) calibrate(config) createCalibrationController(armType, port) Python/Node.js: Function, Web: Controller pattern
Teleoperation teleoperate(cfg) teleoperate(config) createWebTeleoperationController(port, serialNumber) Python/Node.js: Function, Web: Manual state management

πŸ“‹ Detailed API Reference

Port Discovery

Aspect Python lerobot Node.js lerobot.js Web Browser lerobot.js
Function find_port() findPort() findPortWeb(logger)
Import from lerobot.find_port import find_port import { findPort } from 'lerobot.js/node' import { findPortWeb } from 'lerobot.js/web'
Parameters None None logger: (message: string) => void
User Interaction Terminal prompts via input() Terminal prompts via readline Browser modals and buttons
Port Access Direct system access via pyserial Direct system access Web Serial API permissions
Return Value None (prints to console) None (prints to console) None (calls logger function)
Example python<br>find_port()<br> js<br>await findPort();<br> js<br>await findPortWeb(console.log);<br>

Robot Connection & Creation

Aspect Python lerobot Node.js lerobot.js Web Browser lerobot.js
Creation SO100Follower(config) or make_robot_from_config(config) createSO100Follower(config) createWebTeleoperationController(port, serialNumber)
Connection robot.connect() await robot.connect() Port already opened before creation
Port Parameter RobotConfig(port='/dev/ttyUSB0') { port: 'COM4' } (string) SerialPort object
Baud Rate Handled internally Handled internally await port.open({ baudRate: 1000000 })
Factory Pattern make_robot_from_config() factory createSO100Follower() factory createWebTeleoperationController() factory
Example python<br>from lerobot.common.robots.so100_follower import SO100Follower<br>robot = SO100Follower(config)<br>robot.connect()<br> js<br>const robot = createSO100Follower({<br> type: 'so100_follower',<br> port: 'COM4',<br> id: 'my_robot'<br>});<br>await robot.connect();<br> js<br>const port = await navigator.serial.requestPort();<br>await port.open({ baudRate: 1000000 });<br>const robot = await createWebTeleoperationController(<br> port, 'my_robot'<br>);<br>

Calibration

Aspect Python lerobot Node.js lerobot.js Web Browser lerobot.js
Main Function calibrate(cfg) calibrate(config) createCalibrationController(armType, port)
Import from lerobot.calibrate import calibrate import { calibrate } from 'lerobot.js/node' import { createCalibrationController } from 'lerobot.js/web'
Configuration CalibrateConfig dataclass Single config object Controller with methods
Workflow All-in-one function calls device.calibrate() All-in-one function Step-by-step methods
Device Pattern Creates device, calls device.calibrate(), device.disconnect() Automatic within calibrate() Manual controller lifecycle
Homing Automatic within device.calibrate() Automatic within calibrate() await controller.performHomingStep()
Range Recording Automatic within device.calibrate() Automatic within calibrate() await controller.performRangeRecordingStep()
Completion Automatic save and disconnect Automatic save await controller.finishCalibration()
Data Storage File system (HF cache) File system (HF cache) localStorage + file download
Example python<br>from lerobot.calibrate import calibrate<br>from lerobot.common.robots.so100_follower import SO100FollowerConfig<br>calibrate(CalibrateConfig(<br> robot=SO100FollowerConfig(<br> port='/dev/ttyUSB0', id='my_robot'<br> )<br>))<br> js<br>await calibrate({<br> robot: {<br> type: 'so100_follower',<br> port: 'COM4',<br> id: 'my_robot'<br> }<br>});<br> js<br>const controller = await createCalibrationController(<br> 'so100_follower', port<br>);<br>await controller.performHomingStep();<br>await controller.performRangeRecordingStep(stopCondition);<br>const results = await controller.finishCalibration();<br>

Teleoperation

Aspect Python lerobot Node.js lerobot.js Web Browser lerobot.js
Main Function teleoperate(cfg) teleoperate(config) createWebTeleoperationController(port, serialNumber)
Import from lerobot.teleoperate import teleoperate import { teleoperate } from 'lerobot.js/node' import { createWebTeleoperationController } from 'lerobot.js/web'
Control Loop teleop_loop() with get_action() and send_action() Automatic 60 FPS loop Manual start/stop with controller.start()
Device Management Creates teleop and robot devices, connects both Device creation handled internally Port opened externally, controller manages state
Input Handling Teleoperator get_action() method Terminal raw mode Browser event listeners
Key State Handled by teleoperator device Internal management controller.updateKeyState(key, pressed)
Configuration TeleoperateConfig with separate robot/teleop configs js<br>{<br> robot: { type, port, id },<br> teleop: { type: 'keyboard' },<br> fps: 60,<br> step_size: 25<br>}<br> Built into controller
Example python<br>from lerobot.teleoperate import teleoperate<br>teleoperate(TeleoperateConfig(<br> robot=SO100FollowerConfig(port='/dev/ttyUSB0'),<br> teleop=SO100LeaderConfig(port='/dev/ttyUSB1')<br>))<br> js<br>await teleoperate({<br> robot: {<br> type: 'so100_follower',<br> port: 'COM4',<br> id: 'my_robot'<br> },<br> teleop: { type: 'keyboard' }<br>});<br> js<br>const controller = await createWebTeleoperationController(<br> port, 'my_robot'<br>);<br>controller.start();<br>// Handle keyboard events manually<br>document.addEventListener('keydown', (e) => {<br> controller.updateKeyState(e.key, true);<br>});<br>

Motor Control

Aspect Python lerobot Node.js lerobot.js Web Browser lerobot.js
Get Positions robot.get_observation() (includes motor positions) await robot.getMotorPositions() controller.getMotorConfigs() or controller.getState()
Set Positions robot.send_action(action) (dict format) await robot.setMotorPositions(positions) await controller.setMotorPositions(positions)
Position Format dict[str, float] (action format) Record<string, number> Record<string, number> βœ… Same
Data Flow get_observation() β†’ send_action() loop Direct position get/set methods Controller state management
Action Features robot.action_features (motor names) Motor names hardcoded in implementation Motor configs with metadata
Calibration Limits Handled in robot implementation robot.getCalibrationLimits() controller.getMotorConfigs() (includes limits)
Home Position Manual via action dict Manual calculation await controller.goToHomePosition()
Example python<br>obs = robot.get_observation()<br>action = {motor: value for motor in robot.action_features}<br>robot.send_action(action)<br> js<br>const positions = await robot.getMotorPositions();<br>await robot.setMotorPositions({<br> shoulder_pan: 2047,<br> shoulder_lift: 1800<br>});<br> js<br>const state = controller.getState();<br>await controller.setMotorPositions({<br> shoulder_pan: 2047,<br> shoulder_lift: 1800<br>});<br>

Calibration Data Management

Aspect Node.js Web Browser
Storage Location ~/.cache/huggingface/lerobot/calibration/ localStorage + file download
File Format JSON files on disk JSON in browser storage
Loading Automatic during robot.connect() Manual via loadCalibrationConfig()
Saving robot.saveCalibration(results) saveCalibrationResults() + download
Persistence Permanent until deleted Browser-specific, can be cleared
Sharing File system sharing Manual file sharing

Error Handling & Debugging

Aspect Node.js Web Browser
Connection Errors Standard Node.js errors Web Serial API errors
Permission Issues File system permissions User permission prompts
Port Conflicts "Port in use" errors Silent failures or permission errors
Debugging Console.log + terminal Browser DevTools console
Logging Built-in terminal output Passed logger functions

🎯 Usage Pattern Summary

Python lerobot (Original) - Research & Production

# Configuration-driven, device-based approach
from lerobot.find_port import find_port
from lerobot.calibrate import calibrate, CalibrateConfig
from lerobot.teleoperate import teleoperate, TeleoperateConfig
from lerobot.common.robots.so100_follower import SO100FollowerConfig
from lerobot.common.teleoperators.so100_leader import SO100LeaderConfig

# Find port
find_port()

# Calibrate robot
calibrate(CalibrateConfig(
    robot=SO100FollowerConfig(port='/dev/ttyUSB0', id='my_robot')
))

# Teleoperation with leader-follower
teleoperate(TeleoperateConfig(
    robot=SO100FollowerConfig(port='/dev/ttyUSB0'),
    teleop=SO100LeaderConfig(port='/dev/ttyUSB1')
))

Node.js lerobot.js - Server/Desktop Applications

// High-level, all-in-one functions (mirrors Python closely)
import { findPort, calibrate, teleoperate } from "lerobot.js/node";

await findPort();
await calibrate({
  robot: { type: "so100_follower", port: "COM4", id: "my_robot" },
});
await teleoperate({
  robot: { type: "so100_follower", port: "COM4" },
  teleop: { type: "keyboard" },
});

Web Browser lerobot.js - Interactive Applications

// Controller-based, step-by-step approach (browser constraints)
import {
  findPortWeb,
  createCalibrationController,
  createWebTeleoperationController,
} from "lerobot.js/web";

// User interaction required
const port = await navigator.serial.requestPort();
await port.open({ baudRate: 1000000 });

// Step-by-step calibration
const calibrator = await createCalibrationController("so100_follower", port);
await calibrator.performHomingStep();
await calibrator.performRangeRecordingStep(() => stopRecording);

// Manual teleoperation control
const controller = await createWebTeleoperationController(port, "my_robot");
controller.start();

πŸ”‘ Key Architectural Differences

  1. User Interaction Model

    • Node.js: Terminal-based with readline prompts
    • Web: Browser UI with buttons and modals
  2. Permission Model

    • Node.js: System-level permissions
    • Web: User-granted permissions per device
  3. State Management

    • Node.js: Function-based, stateless
    • Web: Controller-based, stateful
  4. Data Persistence

    • Node.js: File system with cross-session persistence
    • Web: Browser storage with limited persistence
  5. Platform Integration

    • Node.js: Deep system integration
    • Web: Security-constrained browser environment

This comparison helps developers choose the right platform and understand the API differences when porting between Node.js and Web implementations.