File size: 30,762 Bytes
5eb1bc0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# 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

```python
# 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

```javascript
// 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

```javascript
// 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.