NERDDISCO commited on
Commit
ebd0121
·
1 Parent(s): 0f7f2db

refactor: move types into dedicated files

Browse files
docs/conventions.md CHANGED
@@ -18,6 +18,7 @@
18
  - **Library/Demo Separation**: Standard library handles hardware communication, demos handle storage/UI concerns - never mix these responsibilities
19
  - **No Code Duplication**: Use shared utils, never reimplement the same functionality across files
20
  - **Direct Library Usage**: End users call library functions directly (e.g., `calibrate()`, `teleoperate()`) - avoid unnecessary abstraction layers
 
21
 
22
  ## Project Goals
23
 
 
18
  - **Library/Demo Separation**: Standard library handles hardware communication, demos handle storage/UI concerns - never mix these responsibilities
19
  - **No Code Duplication**: Use shared utils, never reimplement the same functionality across files
20
  - **Direct Library Usage**: End users call library functions directly (e.g., `calibrate()`, `teleoperate()`) - avoid unnecessary abstraction layers
21
+ - **Comments**: Write about the functionality, not what you did. We only need to know what the code is doing to make it more easy to understand, not a history of the changes
22
 
23
  ## Project Goals
24
 
src/lerobot/web/calibrate.ts CHANGED
@@ -8,7 +8,6 @@
8
  import { WebSerialPortWrapper } from "./utils/serial-port-wrapper.js";
9
  import {
10
  readAllMotorPositions,
11
- releaseMotors,
12
  type MotorCommunicationPort,
13
  } from "./utils/motor-communication.js";
14
  import {
@@ -17,42 +16,12 @@ import {
17
  } from "./utils/motor-calibration.js";
18
  import { createSO100Config } from "./robots/so100_config.js";
19
  import type { RobotConnection } from "./types/robot-connection.js";
20
-
21
- // Import shared robot hardware configuration interface
22
  import type { RobotHardwareConfig } from "./types/robot-config.js";
23
-
24
- /**
25
- * Calibration results structure matching Python lerobot format exactly
26
- */
27
- export interface WebCalibrationResults {
28
- [motorName: string]: {
29
- id: number;
30
- drive_mode: number;
31
- homing_offset: number;
32
- range_min: number;
33
- range_max: number;
34
- };
35
- }
36
-
37
- /**
38
- * Live calibration data with current positions and ranges
39
- */
40
- export interface LiveCalibrationData {
41
- [motorName: string]: {
42
- current: number;
43
- min: number;
44
- max: number;
45
- range: number;
46
- };
47
- }
48
-
49
- /**
50
- * Calibration process control object
51
- */
52
- export interface CalibrationProcess {
53
- stop(): void;
54
- result: Promise<WebCalibrationResults>;
55
- }
56
 
57
  /**
58
  * Record ranges of motion with live updates
 
8
  import { WebSerialPortWrapper } from "./utils/serial-port-wrapper.js";
9
  import {
10
  readAllMotorPositions,
 
11
  type MotorCommunicationPort,
12
  } from "./utils/motor-communication.js";
13
  import {
 
16
  } from "./utils/motor-calibration.js";
17
  import { createSO100Config } from "./robots/so100_config.js";
18
  import type { RobotConnection } from "./types/robot-connection.js";
 
 
19
  import type { RobotHardwareConfig } from "./types/robot-config.js";
20
+ import type {
21
+ WebCalibrationResults,
22
+ LiveCalibrationData,
23
+ CalibrationProcess,
24
+ } from "./types/calibration.js";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
  /**
27
  * Record ranges of motion with live updates
src/lerobot/web/find_port.ts CHANGED
@@ -28,29 +28,19 @@
28
  * await calibrate(storedRobots[0], options);
29
  */
30
 
31
- import { getRobotConnectionManager } from "./robot-connection.js";
32
  import type {
33
  RobotConnection,
34
  RobotConfig,
35
  SerialPort,
36
  } from "./types/robot-connection.js";
37
-
38
- /**
39
- * Extended WebSerial API type definitions
40
- */
41
- interface Serial extends EventTarget {
42
- getPorts(): Promise<SerialPort[]>;
43
- requestPort(options?: SerialPortRequestOptions): Promise<SerialPort>;
44
- }
45
-
46
- interface SerialPortRequestOptions {
47
- filters?: SerialPortFilter[];
48
- }
49
-
50
- interface SerialPortFilter {
51
- usbVendorId?: number;
52
- usbProductId?: number;
53
- }
54
 
55
  declare global {
56
  interface Navigator {
@@ -58,34 +48,6 @@ declare global {
58
  }
59
  }
60
 
61
- /**
62
- * Options for findPort function
63
- */
64
- export interface FindPortOptions {
65
- // Auto-connect mode: provide robot configs to connect to
66
- robotConfigs?: RobotConfig[];
67
-
68
- // Callbacks
69
- onMessage?: (message: string) => void;
70
- onRequestUserAction?: (
71
- message: string,
72
- type: "confirm" | "select"
73
- ) => Promise<boolean>;
74
- }
75
-
76
- /**
77
- * Process object returned by findPort
78
- */
79
- export interface FindPortProcess {
80
- // Result promise - Always returns RobotConnection[] (consistent API)
81
- // Interactive mode: single robot in array
82
- // Auto-connect mode: all successfully connected robots in array
83
- result: Promise<RobotConnection[]>;
84
-
85
- // Control
86
- stop: () => void;
87
- }
88
-
89
  /**
90
  * Check if WebSerial API is available
91
  */
@@ -104,34 +66,6 @@ function getPortDisplayName(port: SerialPort): string {
104
  return "Serial Device";
105
  }
106
 
107
- /**
108
- * Try to get serial number from a port by opening and reading device info
109
- */
110
- async function getPortSerialNumber(port: SerialPort): Promise<string | null> {
111
- try {
112
- const wasOpen = port.readable !== null;
113
-
114
- // Open port if not already open
115
- if (!wasOpen) {
116
- await port.open({ baudRate: 1000000 });
117
- }
118
-
119
- // For now, we'll return null since reading serial number from STS3215 motors
120
- // requires specific protocol implementation. This is a placeholder for future enhancement.
121
- // In practice, serial numbers are typically stored in device metadata or configuration.
122
-
123
- // Close port if we opened it
124
- if (!wasOpen && port.readable) {
125
- await port.close();
126
- }
127
-
128
- return null;
129
- } catch (error) {
130
- console.warn("Could not read serial number from port:", error);
131
- return null;
132
- }
133
- }
134
-
135
  /**
136
  * Interactive mode: Show native dialog for port selection
137
  */
 
28
  * await calibrate(storedRobots[0], options);
29
  */
30
 
31
+ import { getRobotConnectionManager } from "./utils/robot-connection-manager.js";
32
  import type {
33
  RobotConnection,
34
  RobotConfig,
35
  SerialPort,
36
  } from "./types/robot-connection.js";
37
+ import type {
38
+ Serial,
39
+ SerialPortRequestOptions,
40
+ SerialPortFilter,
41
+ FindPortOptions,
42
+ FindPortProcess,
43
+ } from "./types/port-discovery.js";
 
 
 
 
 
 
 
 
 
 
44
 
45
  declare global {
46
  interface Navigator {
 
48
  }
49
  }
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  /**
52
  * Check if WebSerial API is available
53
  */
 
66
  return "Serial Device";
67
  }
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  /**
70
  * Interactive mode: Show native dialog for port selection
71
  */
src/lerobot/web/teleoperate.ts CHANGED
@@ -1,6 +1,5 @@
1
  /**
2
  * Web teleoperation functionality using Web Serial API
3
- * Mirrors the Node.js implementation but adapted for browser environment
4
  */
5
 
6
  import { createSO100Config } from "./robots/so100_config.js";
@@ -15,42 +14,11 @@ import {
15
  writeMotorPosition,
16
  type MotorCommunicationPort,
17
  } from "./utils/motor-communication.js";
18
-
19
- /**
20
- * Motor position and limits for teleoperation
21
- */
22
- export interface MotorConfig {
23
- id: number;
24
- name: string;
25
- currentPosition: number;
26
- minPosition: number;
27
- maxPosition: number;
28
- }
29
-
30
- /**
31
- * Teleoperation state
32
- */
33
- export interface TeleoperationState {
34
- isActive: boolean;
35
- motorConfigs: MotorConfig[];
36
- lastUpdate: number;
37
- keyStates: { [key: string]: { pressed: boolean; timestamp: number } };
38
- }
39
-
40
- /**
41
- * Teleoperation process control object (matches calibrate pattern)
42
- */
43
- export interface TeleoperationProcess {
44
- start(): void;
45
- stop(): void;
46
- updateKeyState(key: string, pressed: boolean): void;
47
- getState(): TeleoperationState;
48
- moveMotor(motorName: string, position: number): Promise<boolean>;
49
- setMotorPositions(positions: {
50
- [motorName: string]: number;
51
- }): Promise<boolean>;
52
- disconnect(): Promise<void>;
53
- }
54
 
55
  /**
56
  * Create motor configurations from robot hardware config
 
1
  /**
2
  * Web teleoperation functionality using Web Serial API
 
3
  */
4
 
5
  import { createSO100Config } from "./robots/so100_config.js";
 
14
  writeMotorPosition,
15
  type MotorCommunicationPort,
16
  } from "./utils/motor-communication.js";
17
+ import type {
18
+ MotorConfig,
19
+ TeleoperationState,
20
+ TeleoperationProcess,
21
+ } from "./types/teleoperation.js";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  /**
24
  * Create motor configurations from robot hardware config
src/lerobot/web/types/calibration.ts ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Calibration-related types for web implementation
3
+ */
4
+
5
+ /**
6
+ * Calibration results structure matching Python lerobot format exactly
7
+ */
8
+ export interface WebCalibrationResults {
9
+ [motorName: string]: {
10
+ id: number;
11
+ drive_mode: number;
12
+ homing_offset: number;
13
+ range_min: number;
14
+ range_max: number;
15
+ };
16
+ }
17
+
18
+ /**
19
+ * Live calibration data with current positions and ranges
20
+ */
21
+ export interface LiveCalibrationData {
22
+ [motorName: string]: {
23
+ current: number;
24
+ min: number;
25
+ max: number;
26
+ range: number;
27
+ };
28
+ }
29
+
30
+ /**
31
+ * Calibration process control object
32
+ */
33
+ export interface CalibrationProcess {
34
+ stop(): void;
35
+ result: Promise<WebCalibrationResults>;
36
+ }
src/lerobot/web/types/port-discovery.ts ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Port discovery and WebSerial API types for web implementation
3
+ */
4
+
5
+ // Import types needed in this file
6
+ import type {
7
+ RobotConnection,
8
+ RobotConfig,
9
+ SerialPort,
10
+ } from "./robot-connection.js";
11
+
12
+ /**
13
+ * Extended WebSerial API type definitions
14
+ */
15
+ export interface Serial extends EventTarget {
16
+ getPorts(): Promise<SerialPort[]>;
17
+ requestPort(options?: SerialPortRequestOptions): Promise<SerialPort>;
18
+ }
19
+
20
+ export interface SerialPortRequestOptions {
21
+ filters?: SerialPortFilter[];
22
+ }
23
+
24
+ export interface SerialPortFilter {
25
+ usbVendorId?: number;
26
+ usbProductId?: number;
27
+ }
28
+
29
+ /**
30
+ * Options for findPort function
31
+ */
32
+ export interface FindPortOptions {
33
+ // Auto-connect mode: provide robot configs to connect to
34
+ robotConfigs?: RobotConfig[];
35
+
36
+ // Callbacks
37
+ onMessage?: (message: string) => void;
38
+ onRequestUserAction?: (
39
+ message: string,
40
+ type: "confirm" | "select"
41
+ ) => Promise<boolean>;
42
+ }
43
+
44
+ /**
45
+ * Process object returned by findPort
46
+ */
47
+ export interface FindPortProcess {
48
+ // Result promise - Always returns RobotConnection[] (consistent API)
49
+ // Interactive mode: single robot in array
50
+ // Auto-connect mode: all successfully connected robots in array
51
+ result: Promise<RobotConnection[]>;
52
+
53
+ // Control
54
+ stop: () => void;
55
+ }
56
+
57
+ // Re-export commonly used types for convenience
58
+ export type { RobotConnection, RobotConfig, SerialPort };
src/lerobot/web/types/robot-processes.ts ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Robot connection management and process types for web implementation
3
+ */
4
+
5
+ import type { SerialPort } from "./robot-connection.js";
6
+
7
+ /**
8
+ * Robot connection state tracking
9
+ */
10
+ export interface RobotConnectionState {
11
+ isConnected: boolean;
12
+ robotType?: "so100_follower" | "so100_leader";
13
+ robotId?: string;
14
+ serialNumber?: string;
15
+ lastError?: string;
16
+ }
17
+
18
+ /**
19
+ * Robot connection manager interface
20
+ */
21
+ export interface RobotConnectionManager {
22
+ // State
23
+ getState(): RobotConnectionState;
24
+
25
+ // Connection management
26
+ connect(
27
+ port: SerialPort,
28
+ robotType: string,
29
+ robotId: string,
30
+ serialNumber: string
31
+ ): Promise<void>;
32
+ disconnect(): Promise<void>;
33
+
34
+ // Port access
35
+ getPort(): SerialPort | null;
36
+
37
+ // Serial operations (shared by calibration, teleoperation, etc.)
38
+ writeData(data: Uint8Array): Promise<void>;
39
+ readData(timeout?: number): Promise<Uint8Array>;
40
+
41
+ // Event system
42
+ onStateChange(callback: (state: RobotConnectionState) => void): () => void;
43
+ }
src/lerobot/web/types/teleoperation.ts ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Teleoperation-related types for web implementation
3
+ */
4
+
5
+ /**
6
+ * Motor position and limits for teleoperation
7
+ */
8
+ export interface MotorConfig {
9
+ id: number;
10
+ name: string;
11
+ currentPosition: number;
12
+ minPosition: number;
13
+ maxPosition: number;
14
+ }
15
+
16
+ /**
17
+ * Teleoperation state
18
+ */
19
+ export interface TeleoperationState {
20
+ isActive: boolean;
21
+ motorConfigs: MotorConfig[];
22
+ lastUpdate: number;
23
+ keyStates: { [key: string]: { pressed: boolean; timestamp: number } };
24
+ }
25
+
26
+ /**
27
+ * Teleoperation process control object (matches calibrate pattern)
28
+ */
29
+ export interface TeleoperationProcess {
30
+ start(): void;
31
+ stop(): void;
32
+ updateKeyState(key: string, pressed: boolean): void;
33
+ getState(): TeleoperationState;
34
+ moveMotor(motorName: string, position: number): Promise<boolean>;
35
+ setMotorPositions(positions: {
36
+ [motorName: string]: number;
37
+ }): Promise<boolean>;
38
+ disconnect(): Promise<void>;
39
+ }
src/lerobot/web/{robot-connection.ts → utils/robot-connection-manager.ts} RENAMED
@@ -1,48 +1,18 @@
1
  /**
2
- * Core Robot Connection Manager
3
- * Single source of truth for robot connections in the web library
4
- * Provides singleton access to robot ports and connection state
 
 
 
5
  */
6
 
7
- import {
8
- readMotorPosition as readMotorPositionUtil,
9
- writeMotorPosition as writeMotorPositionUtil,
10
- readAllMotorPositions as readAllMotorPositionsUtil,
11
- writeMotorRegister,
12
- type MotorCommunicationPort,
13
- } from "./utils/motor-communication.js";
14
-
15
- export interface RobotConnectionState {
16
- isConnected: boolean;
17
- robotType?: "so100_follower" | "so100_leader";
18
- robotId?: string;
19
- serialNumber?: string;
20
- lastError?: string;
21
- }
22
-
23
- export interface RobotConnectionManager {
24
- // State
25
- getState(): RobotConnectionState;
26
-
27
- // Connection management
28
- connect(
29
- port: SerialPort,
30
- robotType: string,
31
- robotId: string,
32
- serialNumber: string
33
- ): Promise<void>;
34
- disconnect(): Promise<void>;
35
-
36
- // Port access
37
- getPort(): SerialPort | null;
38
-
39
- // Serial operations (shared by calibration, teleoperation, etc.)
40
- writeData(data: Uint8Array): Promise<void>;
41
- readData(timeout?: number): Promise<Uint8Array>;
42
-
43
- // Event system
44
- onStateChange(callback: (state: RobotConnectionState) => void): () => void;
45
- }
46
 
47
  /**
48
  * Singleton Robot Connection Manager Implementation
@@ -131,12 +101,14 @@ class RobotConnectionManagerImpl implements RobotConnectionManager {
131
  setTimeout(() => reject(new Error("Read timeout")), timeout);
132
  });
133
 
134
- const readPromise = reader.read().then((result) => {
135
- if (result.done || !result.value) {
136
- throw new Error("Read failed - port closed or no data");
137
- }
138
- return result.value;
139
- });
 
 
140
 
141
  return await Promise.race([readPromise, timeoutPromise]);
142
  } finally {
@@ -176,14 +148,10 @@ export function getRobotConnectionManager(): RobotConnectionManager {
176
  }
177
 
178
  /**
179
- * Utility functions for common robot operations
180
- * Uses shared motor communication utilities for consistency
181
  */
182
-
183
- /**
184
- * Adapter to make robot connection manager compatible with motor utils
185
- */
186
- class RobotConnectionManagerAdapter implements MotorCommunicationPort {
187
  private manager: RobotConnectionManager;
188
 
189
  constructor(manager: RobotConnectionManager) {
@@ -198,31 +166,3 @@ class RobotConnectionManagerAdapter implements MotorCommunicationPort {
198
  return this.manager.readData(timeout);
199
  }
200
  }
201
-
202
- export async function writeMotorPosition(
203
- motorId: number,
204
- position: number
205
- ): Promise<void> {
206
- const manager = getRobotConnectionManager();
207
- const adapter = new RobotConnectionManagerAdapter(manager);
208
-
209
- return writeMotorPositionUtil(adapter, motorId, position);
210
- }
211
-
212
- export async function readMotorPosition(
213
- motorId: number
214
- ): Promise<number | null> {
215
- const manager = getRobotConnectionManager();
216
- const adapter = new RobotConnectionManagerAdapter(manager);
217
-
218
- return readMotorPositionUtil(adapter, motorId);
219
- }
220
-
221
- export async function readAllMotorPositions(
222
- motorIds: number[]
223
- ): Promise<number[]> {
224
- const manager = getRobotConnectionManager();
225
- const adapter = new RobotConnectionManagerAdapter(manager);
226
-
227
- return readAllMotorPositionsUtil(adapter, motorIds);
228
- }
 
1
  /**
2
+ * Internal Robot Connection Manager Utility
3
+ * Singleton manager providing shared robot connection state and communication
4
+ * Used internally by calibrate, teleoperate, find_port, etc.
5
+ *
6
+ * This is an internal utility - users should not import this directly.
7
+ * Instead, use the public APIs: calibrate(), findPort(), teleoperate()
8
  */
9
 
10
+ import type { MotorCommunicationPort } from "./motor-communication.js";
11
+ import type { SerialPort } from "../types/robot-connection.js";
12
+ import type {
13
+ RobotConnectionState,
14
+ RobotConnectionManager,
15
+ } from "../types/robot-processes.js";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
  /**
18
  * Singleton Robot Connection Manager Implementation
 
101
  setTimeout(() => reject(new Error("Read timeout")), timeout);
102
  });
103
 
104
+ const readPromise = reader
105
+ .read()
106
+ .then((result: { done: boolean; value?: Uint8Array }) => {
107
+ if (result.done || !result.value) {
108
+ throw new Error("Read failed - port closed or no data");
109
+ }
110
+ return result.value;
111
+ });
112
 
113
  return await Promise.race([readPromise, timeoutPromise]);
114
  } finally {
 
148
  }
149
 
150
  /**
151
+ * Adapter to make robot connection manager compatible with motor-communication utilities
152
+ * Provides the MotorCommunicationPort interface for the singleton manager
153
  */
154
+ export class RobotConnectionManagerAdapter implements MotorCommunicationPort {
 
 
 
 
155
  private manager: RobotConnectionManager;
156
 
157
  constructor(manager: RobotConnectionManager) {
 
166
  return this.manager.readData(timeout);
167
  }
168
  }