NERDDISCO commited on
Commit
6fa48c4
·
1 Parent(s): ebd0121

chore: remove comments that make no sense

Browse files
docs/conventions.md CHANGED
@@ -19,6 +19,7 @@
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
 
 
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
+ - **No Reference Comments**: Never write comments like "same pattern as calibrate.ts", "matches Node.js", "copied from X", etc. Comments should explain what the code does, not where it came from or what it's similar to
23
 
24
  ## Project Goals
25
 
src/lerobot/web/calibrate.ts CHANGED
@@ -39,7 +39,7 @@ async function recordRangesOfMotion(
39
  const rangeMins: { [motor: string]: number } = {};
40
  const rangeMaxes: { [motor: string]: number } = {};
41
 
42
- // Read actual current positions (matching Python exactly)
43
  const startPositions = await readAllMotorPositions(port, motorIds);
44
 
45
  for (let i = 0; i < motorNames.length; i++) {
@@ -105,7 +105,6 @@ function applyRobotSpecificRangeAdjustments(
105
  if (robotType.startsWith("so100") && rangeMins["wrist_roll"] !== undefined) {
106
  // The wrist_roll is a continuous rotation motor that should use the full
107
  // 0-4095 range regardless of what the user recorded during calibration.
108
- // This matches the hardware specification and Python lerobot behavior.
109
  rangeMins["wrist_roll"] = 0;
110
  rangeMaxes["wrist_roll"] = protocol.resolution - 1;
111
  }
@@ -185,7 +184,7 @@ export async function calibrate(
185
  rangeMaxes
186
  );
187
 
188
- // Step 5: Compile results in Python-compatible format
189
  const results: WebCalibrationResults = {};
190
 
191
  for (let i = 0; i < config.motorNames.length; i++) {
 
39
  const rangeMins: { [motor: string]: number } = {};
40
  const rangeMaxes: { [motor: string]: number } = {};
41
 
42
+ // Read actual current positions
43
  const startPositions = await readAllMotorPositions(port, motorIds);
44
 
45
  for (let i = 0; i < motorNames.length; i++) {
 
105
  if (robotType.startsWith("so100") && rangeMins["wrist_roll"] !== undefined) {
106
  // The wrist_roll is a continuous rotation motor that should use the full
107
  // 0-4095 range regardless of what the user recorded during calibration.
 
108
  rangeMins["wrist_roll"] = 0;
109
  rangeMaxes["wrist_roll"] = protocol.resolution - 1;
110
  }
 
184
  rangeMaxes
185
  );
186
 
187
+ // Step 5: Compile results
188
  const results: WebCalibrationResults = {};
189
 
190
  for (let i = 0; i < config.motorNames.length; i++) {
src/lerobot/web/find_port.ts CHANGED
@@ -28,7 +28,8 @@
28
  * await calibrate(storedRobots[0], options);
29
  */
30
 
31
- import { getRobotConnectionManager } from "./utils/robot-connection-manager.js";
 
32
  import type {
33
  RobotConnection,
34
  RobotConfig,
@@ -146,19 +147,22 @@ async function findPortAutoConnect(
146
  await port.open({ baudRate: 1000000 });
147
  }
148
 
149
- // Test connection by trying to communicate
150
- const manager = getRobotConnectionManager();
151
- await manager.connect(
152
- port,
153
- config.robotType,
154
- config.robotId,
155
- config.serialNumber
156
- );
157
-
158
- matchedPort = port;
159
- connected = true;
160
- onMessage?.(`✅ Connected to ${config.robotId}`);
161
- break;
 
 
 
162
  } catch (portError) {
163
  // This port didn't work, try next one
164
  console.log(
 
28
  * await calibrate(storedRobots[0], options);
29
  */
30
 
31
+ import { WebSerialPortWrapper } from "./utils/serial-port-wrapper.js";
32
+ import { readMotorPosition } from "./utils/motor-communication.js";
33
  import type {
34
  RobotConnection,
35
  RobotConfig,
 
147
  await port.open({ baudRate: 1000000 });
148
  }
149
 
150
+ // Test connection by trying basic motor communication
151
+ const portWrapper = new WebSerialPortWrapper(port);
152
+ await portWrapper.initialize();
153
+
154
+ // Try to read from motor ID 1 (most robots have at least one motor)
155
+ const testPosition = await readMotorPosition(portWrapper, 1);
156
+
157
+ // If we can read a position, this is likely a working robot port
158
+ if (testPosition !== null) {
159
+ matchedPort = port;
160
+ connected = true;
161
+ onMessage?.(`✅ Connected to ${config.robotId}`);
162
+ break;
163
+ } else {
164
+ throw new Error("No motor response - not a robot port");
165
+ }
166
  } catch (portError) {
167
  // This port didn't work, try next one
168
  console.log(
src/lerobot/web/robots/robot.ts CHANGED
@@ -1,7 +1,6 @@
1
  /**
2
  * Base Robot class for Web platform
3
  * Uses Web Serial API for serial communication
4
- * Mirrors Python lerobot/common/robots/robot.py but adapted for browser environment
5
  */
6
 
7
  import type { RobotConfig } from "../../node/robots/config.js";
 
1
  /**
2
  * Base Robot class for Web platform
3
  * Uses Web Serial API for serial communication
 
4
  */
5
 
6
  import type { RobotConfig } from "../../node/robots/config.js";
src/lerobot/web/robots/so100_config.ts CHANGED
@@ -1,6 +1,5 @@
1
  /**
2
  * SO-100 specific hardware configuration
3
- * Matches Node.js SO-100 config structure and Python lerobot exactly
4
  */
5
 
6
  import type { RobotHardwareConfig } from "../types/robot-config.js";
@@ -35,7 +34,7 @@ export const SO100_CONFIG = {
35
  "gripper",
36
  ],
37
  motorIds: [1, 2, 3, 4, 5, 6],
38
- // Python lerobot uses drive_mode=0 for all SO-100 motors
39
  driveModes: [0, 0, 0, 0, 0, 0],
40
  };
41
 
 
1
  /**
2
  * SO-100 specific hardware configuration
 
3
  */
4
 
5
  import type { RobotHardwareConfig } from "../types/robot-config.js";
 
34
  "gripper",
35
  ],
36
  motorIds: [1, 2, 3, 4, 5, 6],
37
+ // All SO-100 motors use drive_mode=0
38
  driveModes: [0, 0, 0, 0, 0, 0],
39
  };
40
 
src/lerobot/web/teleoperate.ts CHANGED
@@ -82,7 +82,7 @@ export class WebTeleoperationController {
82
  } = {};
83
  private onStateUpdate?: (state: TeleoperationState) => void;
84
 
85
- // Movement parameters (matches Node.js)
86
  private readonly STEP_SIZE = 8;
87
  private readonly UPDATE_RATE = 60; // 60 FPS
88
  private readonly KEY_TIMEOUT = 600; // ms - longer than browser keyboard repeat delay (~500ms)
@@ -100,7 +100,7 @@ export class WebTeleoperationController {
100
  }
101
 
102
  async initialize(): Promise<void> {
103
- // Read current positions using proven utilities
104
  for (const config of this.motorConfigs) {
105
  const position = await readMotorPosition(this.port, config.id);
106
  if (position !== null) {
@@ -213,7 +213,7 @@ export class WebTeleoperationController {
213
  );
214
  }
215
 
216
- // Send motor commands using proven utilities
217
  Object.entries(targetPositions).forEach(([motorName, targetPosition]) => {
218
  const motorConfig = this.motorConfigs.find((m) => m.name === motorName);
219
  if (motorConfig && targetPosition !== motorConfig.currentPosition) {
@@ -273,7 +273,7 @@ export class WebTeleoperationController {
273
  }
274
 
275
  /**
276
- * Main teleoperate function - simple API matching calibrate pattern
277
  * Handles robot types internally, creates appropriate motor configurations
278
  */
279
  export async function teleoperate(
@@ -290,11 +290,11 @@ export async function teleoperate(
290
  );
291
  }
292
 
293
- // Create web serial port wrapper (same pattern as calibrate.ts)
294
  const port = new WebSerialPortWrapper(robotConnection.port);
295
  await port.initialize();
296
 
297
- // Get robot-specific configuration (same pattern as calibrate.ts)
298
  let config: RobotHardwareConfig;
299
  if (robotConnection.robotType.startsWith("so100")) {
300
  config = createSO100Config(robotConnection.robotType);
@@ -322,7 +322,7 @@ export async function teleoperate(
322
  );
323
  await controller.initialize();
324
 
325
- // Wrap controller in process object (matches calibrate pattern)
326
  return {
327
  start: () => {
328
  controller.start();
 
82
  } = {};
83
  private onStateUpdate?: (state: TeleoperationState) => void;
84
 
85
+ // Movement parameters
86
  private readonly STEP_SIZE = 8;
87
  private readonly UPDATE_RATE = 60; // 60 FPS
88
  private readonly KEY_TIMEOUT = 600; // ms - longer than browser keyboard repeat delay (~500ms)
 
100
  }
101
 
102
  async initialize(): Promise<void> {
103
+ // Read current motor positions
104
  for (const config of this.motorConfigs) {
105
  const position = await readMotorPosition(this.port, config.id);
106
  if (position !== null) {
 
213
  );
214
  }
215
 
216
+ // Send motor commands
217
  Object.entries(targetPositions).forEach(([motorName, targetPosition]) => {
218
  const motorConfig = this.motorConfigs.find((m) => m.name === motorName);
219
  if (motorConfig && targetPosition !== motorConfig.currentPosition) {
 
273
  }
274
 
275
  /**
276
+ * Main teleoperate function - simple API
277
  * Handles robot types internally, creates appropriate motor configurations
278
  */
279
  export async function teleoperate(
 
290
  );
291
  }
292
 
293
+ // Create web serial port wrapper
294
  const port = new WebSerialPortWrapper(robotConnection.port);
295
  await port.initialize();
296
 
297
+ // Get robot-specific configuration
298
  let config: RobotHardwareConfig;
299
  if (robotConnection.robotType.startsWith("so100")) {
300
  config = createSO100Config(robotConnection.robotType);
 
322
  );
323
  await controller.initialize();
324
 
325
+ // Wrap controller in process object
326
  return {
327
  start: () => {
328
  controller.start();
src/lerobot/web/types/calibration.ts CHANGED
@@ -3,7 +3,7 @@
3
  */
4
 
5
  /**
6
- * Calibration results structure matching Python lerobot format exactly
7
  */
8
  export interface WebCalibrationResults {
9
  [motorName: string]: {
 
3
  */
4
 
5
  /**
6
+ * Calibration results structure
7
  */
8
  export interface WebCalibrationResults {
9
  [motorName: string]: {
src/lerobot/web/types/robot-processes.ts DELETED
@@ -1,43 +0,0 @@
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 CHANGED
@@ -24,7 +24,7 @@ export interface TeleoperationState {
24
  }
25
 
26
  /**
27
- * Teleoperation process control object (matches calibrate pattern)
28
  */
29
  export interface TeleoperationProcess {
30
  start(): void;
 
24
  }
25
 
26
  /**
27
+ * Teleoperation process control object
28
  */
29
  export interface TeleoperationProcess {
30
  start(): void;
src/lerobot/web/utils/motor-calibration.ts CHANGED
@@ -12,7 +12,7 @@ import {
12
  } from "./motor-communication.js";
13
 
14
  /**
15
- * Reset homing offsets to 0 for all motors (matches Node.js exactly)
16
  */
17
  export async function resetHomingOffsets(
18
  port: MotorCommunicationPort,
@@ -115,7 +115,7 @@ export async function writeHomingOffsetsToMotors(
115
  }
116
 
117
  /**
118
- * Set homing offsets with immediate writing (matches Node.js exactly)
119
  */
120
  export async function setHomingOffsets(
121
  port: MotorCommunicationPort,
 
12
  } from "./motor-communication.js";
13
 
14
  /**
15
+ * Reset homing offsets to 0 for all motors
16
  */
17
  export async function resetHomingOffsets(
18
  port: MotorCommunicationPort,
 
115
  }
116
 
117
  /**
118
+ * Set homing offsets with immediate writing
119
  */
120
  export async function setHomingOffsets(
121
  port: MotorCommunicationPort,
src/lerobot/web/utils/motor-communication.ts CHANGED
@@ -1,6 +1,6 @@
1
  /**
2
  * Motor Communication Utilities
3
- * Proven patterns for STS3215 motor reading and writing operations
4
  */
5
 
6
  import { STS3215_PROTOCOL } from "./sts3215-protocol.js";
@@ -15,15 +15,14 @@ export interface MotorCommunicationPort {
15
  }
16
 
17
  /**
18
- * Read single motor position with PROVEN retry logic
19
- * Extracted from calibrate.ts with all proven timing and retry patterns
20
  */
21
  export async function readMotorPosition(
22
  port: MotorCommunicationPort,
23
  motorId: number
24
  ): Promise<number | null> {
25
  try {
26
- // Create Read Position packet using proven pattern
27
  const packet = new Uint8Array([
28
  0xff,
29
  0xff, // Header
@@ -45,23 +44,23 @@ export async function readMotorPosition(
45
  ) & 0xff;
46
  packet[7] = checksum;
47
 
48
- // PROVEN PATTERN: Professional Feetech communication with retry logic
49
  let attempts = 0;
50
 
51
  while (attempts < STS3215_PROTOCOL.MAX_RETRIES) {
52
  attempts++;
53
 
54
- // CRITICAL: Clear any remaining data in buffer first (from calibration lessons)
55
  try {
56
  await port.read(0); // Non-blocking read to clear buffer
57
  } catch (e) {
58
  // Expected - buffer was empty
59
  }
60
 
61
- // Write command with PROVEN timing
62
  await port.write(packet);
63
 
64
- // PROVEN TIMING: Arduino library uses careful timing - Web Serial needs more
65
  await new Promise((resolve) =>
66
  setTimeout(resolve, STS3215_PROTOCOL.WRITE_TO_READ_DELAY)
67
  );
@@ -82,7 +81,7 @@ export async function readMotorPosition(
82
  // Read timeout, retry
83
  }
84
 
85
- // PROVEN TIMING: Professional timing between attempts
86
  if (attempts < STS3215_PROTOCOL.MAX_RETRIES) {
87
  await new Promise((resolve) =>
88
  setTimeout(resolve, STS3215_PROTOCOL.RETRY_DELAY)
@@ -98,8 +97,7 @@ export async function readMotorPosition(
98
  }
99
 
100
  /**
101
- * Read all motor positions with PROVEN patterns
102
- * Exactly matches calibrate.ts readMotorPositions() function
103
  */
104
  export async function readAllMotorPositions(
105
  port: MotorCommunicationPort,
@@ -120,7 +118,7 @@ export async function readAllMotorPositions(
120
  motorPositions.push(fallback);
121
  }
122
 
123
- // PROVEN PATTERN: Professional inter-motor delay
124
  await new Promise((resolve) =>
125
  setTimeout(resolve, STS3215_PROTOCOL.INTER_MOTOR_DELAY)
126
  );
@@ -167,7 +165,6 @@ export async function writeMotorPosition(
167
 
168
  /**
169
  * Generic function to write a 2-byte value to a motor register
170
- * Matches calibrate.ts writeMotorRegister() exactly
171
  */
172
  export async function writeMotorRegister(
173
  port: MotorCommunicationPort,
@@ -200,7 +197,7 @@ export async function writeMotorRegister(
200
  ) & 0xff;
201
  packet[8] = checksum;
202
 
203
- // Simple write then read like calibration
204
  await port.write(packet);
205
 
206
  // Wait for response (silent unless error)
 
1
  /**
2
  * Motor Communication Utilities
3
+ * STS3215 motor reading and writing operations
4
  */
5
 
6
  import { STS3215_PROTOCOL } from "./sts3215-protocol.js";
 
15
  }
16
 
17
  /**
18
+ * Read single motor position with retry logic
 
19
  */
20
  export async function readMotorPosition(
21
  port: MotorCommunicationPort,
22
  motorId: number
23
  ): Promise<number | null> {
24
  try {
25
+ // Create Read Position packet
26
  const packet = new Uint8Array([
27
  0xff,
28
  0xff, // Header
 
44
  ) & 0xff;
45
  packet[7] = checksum;
46
 
47
+ // Retry communication with timeouts
48
  let attempts = 0;
49
 
50
  while (attempts < STS3215_PROTOCOL.MAX_RETRIES) {
51
  attempts++;
52
 
53
+ // Clear any remaining data in buffer first
54
  try {
55
  await port.read(0); // Non-blocking read to clear buffer
56
  } catch (e) {
57
  // Expected - buffer was empty
58
  }
59
 
60
+ // Write command
61
  await port.write(packet);
62
 
63
+ // Wait for motor response
64
  await new Promise((resolve) =>
65
  setTimeout(resolve, STS3215_PROTOCOL.WRITE_TO_READ_DELAY)
66
  );
 
81
  // Read timeout, retry
82
  }
83
 
84
+ // Wait between retry attempts
85
  if (attempts < STS3215_PROTOCOL.MAX_RETRIES) {
86
  await new Promise((resolve) =>
87
  setTimeout(resolve, STS3215_PROTOCOL.RETRY_DELAY)
 
97
  }
98
 
99
  /**
100
+ * Read all motor positions
 
101
  */
102
  export async function readAllMotorPositions(
103
  port: MotorCommunicationPort,
 
118
  motorPositions.push(fallback);
119
  }
120
 
121
+ // Delay between motor reads
122
  await new Promise((resolve) =>
123
  setTimeout(resolve, STS3215_PROTOCOL.INTER_MOTOR_DELAY)
124
  );
 
165
 
166
  /**
167
  * Generic function to write a 2-byte value to a motor register
 
168
  */
169
  export async function writeMotorRegister(
170
  port: MotorCommunicationPort,
 
197
  ) & 0xff;
198
  packet[8] = checksum;
199
 
200
+ // Write register value
201
  await port.write(packet);
202
 
203
  // Wait for response (silent unless error)
src/lerobot/web/utils/robot-connection-manager.ts DELETED
@@ -1,168 +0,0 @@
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
19
- */
20
- class RobotConnectionManagerImpl implements RobotConnectionManager {
21
- private port: SerialPort | null = null;
22
- private state: RobotConnectionState = { isConnected: false };
23
- private stateChangeCallbacks: Set<(state: RobotConnectionState) => void> =
24
- new Set();
25
-
26
- getState(): RobotConnectionState {
27
- return { ...this.state };
28
- }
29
-
30
- async connect(
31
- port: SerialPort,
32
- robotType: string,
33
- robotId: string,
34
- serialNumber: string
35
- ): Promise<void> {
36
- try {
37
- // Validate port is open
38
- if (!port.readable || !port.writable) {
39
- throw new Error("Port is not open");
40
- }
41
-
42
- // Update connection state
43
- this.port = port;
44
- this.state = {
45
- isConnected: true,
46
- robotType: robotType as "so100_follower" | "so100_leader",
47
- robotId,
48
- serialNumber,
49
- lastError: undefined,
50
- };
51
-
52
- this.notifyStateChange();
53
- console.log(
54
- `🤖 Robot connected: ${robotType} (${robotId}) - ${serialNumber}`
55
- );
56
- } catch (error) {
57
- const errorMessage =
58
- error instanceof Error ? error.message : "Connection failed";
59
- this.state = {
60
- isConnected: false,
61
- lastError: errorMessage,
62
- };
63
- this.notifyStateChange();
64
- throw error;
65
- }
66
- }
67
-
68
- async disconnect(): Promise<void> {
69
- this.port = null;
70
- this.state = { isConnected: false };
71
- this.notifyStateChange();
72
- console.log("🤖 Robot disconnected");
73
- }
74
-
75
- getPort(): SerialPort | null {
76
- return this.port;
77
- }
78
-
79
- async writeData(data: Uint8Array): Promise<void> {
80
- if (!this.port?.writable) {
81
- throw new Error("Robot not connected or port not writable");
82
- }
83
-
84
- const writer = this.port.writable.getWriter();
85
- try {
86
- await writer.write(data);
87
- } finally {
88
- writer.releaseLock();
89
- }
90
- }
91
-
92
- async readData(timeout: number = 1000): Promise<Uint8Array> {
93
- if (!this.port?.readable) {
94
- throw new Error("Robot not connected or port not readable");
95
- }
96
-
97
- const reader = this.port.readable.getReader();
98
-
99
- try {
100
- const timeoutPromise = new Promise<never>((_, reject) => {
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 {
115
- reader.releaseLock();
116
- }
117
- }
118
-
119
- onStateChange(callback: (state: RobotConnectionState) => void): () => void {
120
- this.stateChangeCallbacks.add(callback);
121
-
122
- // Return unsubscribe function
123
- return () => {
124
- this.stateChangeCallbacks.delete(callback);
125
- };
126
- }
127
-
128
- private notifyStateChange(): void {
129
- this.stateChangeCallbacks.forEach((callback) => {
130
- try {
131
- callback(this.getState());
132
- } catch (error) {
133
- console.warn("Error in state change callback:", error);
134
- }
135
- });
136
- }
137
- }
138
-
139
- // Singleton instance
140
- const robotConnectionManager = new RobotConnectionManagerImpl();
141
-
142
- /**
143
- * Get the singleton robot connection manager
144
- * This is the single source of truth for robot connections
145
- */
146
- export function getRobotConnectionManager(): RobotConnectionManager {
147
- return robotConnectionManager;
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) {
158
- this.manager = manager;
159
- }
160
-
161
- async write(data: Uint8Array): Promise<void> {
162
- return this.manager.writeData(data);
163
- }
164
-
165
- async read(timeout?: number): Promise<Uint8Array> {
166
- return this.manager.readData(timeout);
167
- }
168
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lerobot/web/utils/serial-port-wrapper.ts CHANGED
@@ -5,7 +5,6 @@
5
 
6
  /**
7
  * Web Serial Port wrapper - direct write/read with immediate lock release
8
- * Follows Chrome documentation exactly for proper Web Serial API usage
9
  */
10
  export class WebSerialPortWrapper {
11
  private port: SerialPort;
 
5
 
6
  /**
7
  * Web Serial Port wrapper - direct write/read with immediate lock release
 
8
  */
9
  export class WebSerialPortWrapper {
10
  private port: SerialPort;
src/lerobot/web/utils/sts3215-protocol.ts CHANGED
@@ -26,7 +26,7 @@ export const STS3215_PROTOCOL = {
26
  MIN_POSITION_LIMIT_LENGTH: 2,
27
  MAX_POSITION_LIMIT_LENGTH: 2,
28
 
29
- // Communication timing (proven from calibration)
30
  WRITE_TO_READ_DELAY: 10,
31
  RETRY_DELAY: 20,
32
  INTER_MOTOR_DELAY: 10,
 
26
  MIN_POSITION_LIMIT_LENGTH: 2,
27
  MAX_POSITION_LIMIT_LENGTH: 2,
28
 
29
+ // Communication timing
30
  WRITE_TO_READ_DELAY: 10,
31
  RETRY_DELAY: 20,
32
  INTER_MOTOR_DELAY: 10,